Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.swing / org.gvsig.scripting.swing.impl / src / main / java / org / gvsig / scripting / swing / impl / syntaxhighlight / JRSyntaxTextArea.java @ 1120

History | View | Annotate | Download (22.8 KB)

1
package org.gvsig.scripting.swing.impl.syntaxhighlight;
2

    
3
import java.awt.BorderLayout;
4
import java.awt.Color;
5
import java.awt.Component;
6
import java.awt.Container;
7
import java.awt.Cursor;
8
import java.awt.Dimension;
9
import java.awt.Graphics;
10
import java.awt.Point;
11
import java.awt.Rectangle;
12
import java.awt.event.ActionEvent;
13
import java.awt.event.ActionListener;
14
import java.awt.event.InputEvent;
15
import java.awt.event.KeyEvent;
16
import java.awt.event.KeyListener;
17
import java.awt.event.MouseAdapter;
18
import java.awt.event.MouseEvent;
19
import java.awt.event.MouseListener;
20
import java.net.URL;
21
import java.util.ArrayList;
22
import java.util.Arrays;
23
import java.util.Comparator;
24
import java.util.HashMap;
25
import java.util.HashSet;
26
import java.util.List;
27
import java.util.Map;
28
import java.util.Set;
29
import java.util.TreeSet;
30
import javax.swing.DefaultListCellRenderer;
31
import javax.swing.Icon;
32
import javax.swing.ImageIcon;
33
import javax.swing.JCheckBox;
34
import javax.swing.JComponent;
35
import javax.swing.JLabel;
36
import javax.swing.JList;
37
import javax.swing.JOptionPane;
38
import javax.swing.JPanel;
39

    
40
import javax.swing.JScrollPane;
41
import javax.swing.JViewport;
42
import javax.swing.KeyStroke;
43
import javax.swing.SwingUtilities;
44
import javax.swing.UIManager;
45
import javax.swing.event.CaretEvent;
46
import javax.swing.event.CaretListener;
47
import javax.swing.text.BadLocationException;
48
import javax.swing.text.Element;
49
import javax.swing.text.JTextComponent;
50
import org.apache.commons.lang3.StringUtils;
51
import org.fife.rsta.ui.CollapsibleSectionPanel;
52
import org.fife.rsta.ui.search.FindToolBar;
53
import org.fife.rsta.ui.search.ReplaceToolBar;
54
import org.fife.rsta.ui.search.SearchEvent;
55
import org.fife.rsta.ui.search.SearchListener;
56
import org.fife.ui.autocomplete.AutoCompletion;
57
import org.fife.ui.autocomplete.BasicCompletion;
58
import org.fife.ui.autocomplete.Completion;
59
import org.fife.ui.autocomplete.CompletionProvider;
60
import org.fife.ui.autocomplete.DefaultCompletionProvider;
61

    
62
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
63
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
64
import org.fife.ui.rtextarea.GutterIconInfo;
65
import org.fife.ui.rtextarea.RTextScrollPane;
66
import org.fife.ui.rtextarea.SearchContext;
67
import org.fife.ui.rtextarea.SearchEngine;
68
import org.fife.ui.rtextarea.SearchResult;
69
import org.gvsig.scripting.ScriptingLocator;
70
import org.gvsig.scripting.swing.api.ScriptingSwingLocator;
71
import org.gvsig.scripting.swing.api.ScriptingUIManager;
72
import org.gvsig.scripting.swing.api.SyntaxtHighlightTextComponent;
73
import org.slf4j.Logger;
74
import org.slf4j.LoggerFactory;
75

    
76
public class JRSyntaxTextArea implements SyntaxtHighlightTextComponent, SearchListener {
77

    
78
    private static final Logger logger = LoggerFactory.getLogger(JRSyntaxTextArea.class);
79
    
80
    public static class MyCheckBox extends JCheckBox {
81

    
82
        private static final String uiClassID = "ToggleButtonUI";
83

    
84
        @Override
85
        public String getUIClassID() {
86
            return uiClassID;
87
        }
88

    
89
    }
90

    
91
    private class MyFindToolBar extends FindToolBar {
92

    
93
        public MyFindToolBar(SearchListener listener) {
94
            super(listener);
95
        }
96

    
97
        @Override
98
        protected JCheckBox createCB(String key) {
99
            JCheckBox cb = new MyCheckBox();
100
            cb.setToolTipText(searchMsg.getString(key));
101
            cb.addActionListener(listener);
102
            cb.addMouseListener(listener);
103
            cb.setIcon(getIcon("scripting-search-" + key.toLowerCase()));
104
            return cb;
105
        }
106

    
107
    }
108

    
109
    private class MyReplaceToolBar extends ReplaceToolBar {
110

    
111
        public MyReplaceToolBar(SearchListener listener) {
112
            super(listener);
113
        }
114

    
115
        @Override
116
        protected JCheckBox createCB(String key) {
117
            JCheckBox cb = new MyCheckBox();
118
            cb.setToolTipText(searchMsg.getString(key));
119
            cb.addActionListener(listener);
120
            cb.addMouseListener(listener);
121
            cb.setIcon(getIcon("scripting-search-" + key.toLowerCase()));
122
            return cb;
123
        }
124
    }
125

    
126
    private class LineTrackerPanel extends JPanel {
127

    
128
        private static final long serialVersionUID = -1923556745197997373L;
129

    
130
        private class Line extends JLabel {
131

    
132
            private static final long serialVersionUID = 8966359978957026490L;
133
            private final int lineno;
134
            private final String tag;
135

    
136
            public Line(String tag, final int lineno, int posy, Color color, String tooltip) {
137
                this.lineno = lineno;
138
                this.tag = tag;
139
                this.setBackground(color);
140
                this.setBounds(0, posy, 15, 2);
141
                this.setOpaque(true);
142
                this.setToolTipText(tooltip);
143
                this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
144
                this.addMouseListener(new MouseAdapter() {
145

    
146
                    @Override
147
                    public void mouseClicked(MouseEvent e) {
148
                        gotoline(lineno);
149
                    }
150
                });
151
//                Rectangle r = this.getBounds();
152
//                logger.info("LineTracker: created lineno:"+lineno+", tag:"+tag+", x:"+ r.x + ", y:"+ r.y + ", w:"+ r.width+", h:"+ r.height);
153
            }
154

    
155
            public int getLineno() {
156
                return this.lineno;
157
            }
158
            
159
            public String getTag() {
160
                return this.tag;
161
            }
162
        }
163

    
164
        public LineTrackerPanel() {
165
            setLayout(null);
166
        }
167

    
168
        @Override
169
        public Dimension getPreferredSize() {
170
            Dimension d = super.getPreferredSize(); 
171
            return new Dimension(15, d.height);
172
        }
173
        
174
        public void addLineTracker(String tag, int lineno, String tooltip, Color color) {
175
            int posy = (int) (((float)lineno)*this.getSize().height / textArea.getLineCount());
176
            Line line = new Line(tag,lineno,posy,color,tooltip);
177
            this.add(line);
178
            this.repaint();
179
        }
180

    
181
        public void removeLineTrackers() {
182
            this.removeAll();
183
            this.repaint();
184
        }
185

    
186
        public void removeLineTrackers(String tag) {
187
            if( StringUtils.isEmpty(tag) ) {
188
                return;
189
            }
190
            List<Line> toremove = new ArrayList<>();
191
            for( int i=0; i<this.getComponentCount(); i++ ) {
192
                Line line = (Line) this.getComponent(i);
193
                if( tag.equalsIgnoreCase(line.getTag()) ) {
194
                    toremove.add(line);
195
                } 
196
            }
197
            for (Line line : toremove) {
198
                this.remove(line);
199
            }
200
            this.repaint();
201
        }
202
    }
203

    
204
    private static class IconsTracker {
205

    
206
        private Map<String,Set<GutterIconInfo>>iconInfos = new HashMap<>();
207
        
208
        public IconsTracker() {
209
            
210
        }
211
        
212
        public void add(String tag, GutterIconInfo x) {
213
            Set<GutterIconInfo> set = this.iconInfos.get(tag);
214
            if( set == null ) {
215
                set = new HashSet<>();
216
                this.iconInfos.put(tag, set);
217
            }
218
            set.add(x);
219
        }
220
        
221
        public void removeAll() {
222
            this.iconInfos = new HashMap<>();
223
        }
224
        
225
        public void remove(String tag) {
226
            this.iconInfos.remove(tag);
227
        }
228
        
229
        public void remove(String tag, GutterIconInfo x) {
230
            Set<GutterIconInfo> set = this.iconInfos.get(tag);
231
            if( set == null ) {
232
                return;
233
            }
234
            set.remove(x);
235
        }
236
        
237
        public boolean exists(String tag) {
238
            return this.iconInfos.containsKey(tag);
239
        }
240
        
241
        public Set<GutterIconInfo> get(String tag) {
242
            Set<GutterIconInfo> set = this.iconInfos.get(tag);
243
            return set;
244
        }
245
    }
246
    
247
    private final FindToolBar findToolBar;
248
    private final ReplaceToolBar replaceToolBar;
249
    private final CollapsibleSectionPanel csp;
250

    
251
    public class DefaultUpdateCaretPositionActionEvent extends ActionEvent implements UpdateCaretPositionActionEvent {
252

    
253
        /**
254
         *
255
         */
256
        private static final long serialVersionUID = 8238486105726094074L;
257
        int line = -1;
258
        int column = -1;
259

    
260
        public DefaultUpdateCaretPositionActionEvent(Object source, int id,
261
                String command, int line, int column) {
262
            super(source, id, command);
263
            this.line = line;
264
            this.column = column;
265
        }
266

    
267
        public int getLine() {
268
            return this.line + 1;
269
        }
270

    
271
        public int getColumn() {
272
            return this.column;
273
        }
274

    
275
        public boolean hasLineAndColumn() {
276
            return this.line >= 0 && this.column >= 0;
277
        }
278

    
279
    }
280

    
281
    protected ActionListener updateCaretPosition = null;
282
    protected RSyntaxTextArea textArea = null;
283
    private final RTextScrollPane scrollPanel;
284
    private final JPanel panel;
285
    private final Map<String, String> contentTypeAlias;
286
    private final IconsTracker iconsTracker = new IconsTracker();
287
    private LineTrackerPanel lineTrackerPanel;
288
    private ScriptingUIManager scriptingUIManager;
289
    
290

    
291
    public JRSyntaxTextArea() {
292
        this.contentTypeAlias = new HashMap<>();
293
        this.contentTypeAlias.put("text/r", SyntaxConstants.SYNTAX_STYLE_C);
294
        this.contentTypeAlias.put("text/ecmascript", SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
295
        this.contentTypeAlias.put("text/cosa", SyntaxConstants.SYNTAX_STYLE_SQL);
296

    
297
        this.textArea = new RSyntaxTextArea(20, 60);
298
        
299
        this.init();
300
        lineTrackerPanel = new LineTrackerPanel();
301
        scrollPanel = new RTextScrollPane(this.textArea);
302
        scrollPanel.setIconRowHeaderEnabled(true);
303
        scrollPanel.setLineNumbersEnabled(true);
304
        scrollPanel.setFoldIndicatorEnabled(true);
305
        
306
        panel = new JPanel();
307
        panel.setLayout(new BorderLayout());
308
        panel.add(scrollPanel, BorderLayout.CENTER);
309
        panel.add(lineTrackerPanel,BorderLayout.EAST);
310
        
311
        findToolBar = new MyFindToolBar(this);
312
        replaceToolBar = new MyReplaceToolBar(this);
313
        replaceToolBar.setSearchContext(findToolBar.getSearchContext());
314
        csp = new CollapsibleSectionPanel();
315
        csp.add(scrollPanel);
316
        panel.add(csp, BorderLayout.CENTER);
317
        int ctrl = (KeyEvent.CTRL_MASK | KeyEvent.ALT_MASK);
318
        KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F, ctrl);
319
        csp.addBottomComponent(ks, findToolBar);
320
        ks = KeyStroke.getKeyStroke(KeyEvent.VK_H, ctrl);
321
        csp.addBottomComponent(ks, replaceToolBar);
322

    
323
        textArea.addKeyListener(new KeyListener() {
324

    
325
            @Override
326
            public void keyTyped(KeyEvent ke) {
327
            }
328

    
329
            @Override
330
            public void keyPressed(KeyEvent ke) {
331
                if (ke.getModifiers() == (KeyEvent.CTRL_MASK | KeyEvent.ALT_MASK)) {
332
                    if (ke.getKeyCode() == KeyEvent.VK_H) {
333
                        csp.showBottomComponent(replaceToolBar);
334
                    } else if (ke.getKeyCode() == KeyEvent.VK_F) {
335
                        csp.showBottomComponent(findToolBar);
336
                    }
337
                }
338
            }
339

    
340
            @Override
341
            public void keyReleased(KeyEvent ke) {
342
            }
343
        });
344

    
345
    }
346

    
347
    protected void init() {
348
        textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON);
349
        textArea.setCodeFoldingEnabled(true);
350
        textArea.setClearWhitespaceLinesEnabled(true);
351
        textArea.setAutoIndentEnabled(true);
352
        textArea.setCloseCurlyBraces(true);
353
        textArea.setWhitespaceVisible(true);
354
        textArea.setAnimateBracketMatching(true);
355
        textArea.setBracketMatchingEnabled(true);
356
        textArea.setAutoIndentEnabled(true);
357
        textArea.setTabsEmulated(true);
358
        textArea.setTabSize(2);
359
        textArea.setAntiAliasingEnabled(true);
360

    
361
        textArea.addCaretListener(new CaretListener() {
362
            public void caretUpdate(CaretEvent e) {
363
                if (updateCaretPosition == null) {
364
                    return;
365
                }
366
                updateCaretPosition.actionPerformed(
367
                        new DefaultUpdateCaretPositionActionEvent(textArea, 1, "position", textArea.getCaretLineNumber(), textArea.getCaretOffsetFromLineStart())
368
                );
369
            }
370

    
371
        });
372

    
373
        CompletionProvider provider = new MyCompletionProvider(python_keywords);
374
        AutoCompletion ac = new AutoCompletion(provider);
375
        ac.setListCellRenderer(new MyListCellRenderer());
376
        ac.setTriggerKey(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_DOWN_MASK));
377
        ac.install(textArea);
378
    }
379

    
380
    private ScriptingUIManager getUIManager() {
381
        if( this.scriptingUIManager==null ) {
382
            this.scriptingUIManager = ScriptingSwingLocator.getUIManager();
383
        }
384
        return this.scriptingUIManager;
385
    }
386
    
387
    private ImageIcon getIcon(String key) {
388
        ImageIcon icon = this.getUIManager().getIcon(key);
389
        return icon;
390
    }
391

    
392

    
393
    private static class MyListCellRenderer extends DefaultListCellRenderer {
394

    
395
        @Override
396
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
397
            Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //To change body of generated methods, choose Tools | Templates.
398
            ((JLabel) comp).setIcon(((Completion) value).getIcon());
399
            return comp;
400
        }
401

    
402
    }
403

    
404
    private String[] python_keywords = new String[]{
405
        "except",
406
        "class",
407
        "continue",
408
        "else",
409
        "finally",
410
        "if",
411
        "elif",
412
        "in",
413
        "return",
414
        "raise",
415
        "try",
416
        "while",
417
        "def",
418
        "print",
419
        "globals",
420
        "for",
421
        "pass",
422
        "from",
423
        "import",
424
        "True",
425
        "False",
426
        "None",
427
        "self",
428
        "break",
429
        "__init__",
430
        "__len__",
431
        "__str__",
432
        "__repr__",
433
        "__call__",
434
        "__iter__",
435
        "__class__",
436
        "__getattr__",
437
        "__setattr__",
438
        "__delattr__",
439
        "__getitem__",
440
        "__setitem__",
441
        "__delitem__",
442
        "__getslice__",
443
        "__setslice__",
444
        "__delslice__",
445
        "__getattribute__",
446
        "__setattribute__",
447
        "__contains__",
448
        "__reduce__",
449
        "__cmp__",
450
        "__eq__",
451
        "__ne__",
452
        "__lt__",
453
        "__le__",
454
        "__gt__",
455
        "__ge__",
456
        "__mul__",
457
        "__imul__",
458
        "__rmul__",
459
        "__add__",
460
        "__iadd__",
461
        "__radd__",
462
        "__mod__",
463
        "__rmod__",
464
        "int",
465
        "unicode",
466
        "str",
467
        "float",
468
        "long",
469
        "list",
470
        "tuple",
471
        "dict",
472
        "iter",
473
        "vars",
474
        "isinstance",
475
        "dir",
476
        "repr",
477
        "reduce",
478
        "zip",
479
        "chr",
480
        "hex",
481
        "id",
482
        "max",
483
        "min",
484
        "oct",
485
        "pow",
486
        "ord",
487
        "unichr",
488
        "range",
489
        "xrange",
490
        "abs",
491
        "len",
492
        "apply",
493
        "open",
494
        "getattr",
495
        "setattr",
496
        "hasattr"
497
    };
498

    
499
    private class MyCompletionProvider extends DefaultCompletionProvider {
500

    
501
        private List<Completion> keywords;
502
        private Icon keywordIcon;
503
        private Icon wordIcon;
504

    
505
        public MyCompletionProvider(String[] keywords) {
506
            ClassLoader loader = this.getClass().getClassLoader();
507
            URL url = loader.getResource("org/gvsig/scripting/swing/impl/syntaxhighlight/images/autocompletion_keywords.png");
508
            if (url != null) {
509
                keywordIcon = new ImageIcon(url);
510
            }
511
            url = loader.getResource("org/gvsig/scripting/swing/impl/syntaxhighlight/images/autocompletion_words.png");
512
            if (url != null) {
513
                wordIcon = new ImageIcon(url);
514
            }
515

    
516
            this.keywords = new ArrayList<>();
517
            for (String keyword : keywords) {
518
                BasicCompletion completion = new BasicCompletion(this, keyword);
519
                completion.setIcon(keywordIcon);
520
                this.keywords.add(completion);
521
            }
522
        }
523

    
524
        
525
        
526
        @Override
527
        protected List<Completion> getCompletionsImpl(JTextComponent comp) {
528
            TreeSet all = new TreeSet();
529
            all.addAll(this.keywords);
530

    
531
            String s = comp.getText();
532
            String[] x = StringUtils.split(s, "\\ \n\t\r!\"><'@#|$%&/()=??,.;:{}[]*-+");
533
            TreeSet<String> words = new TreeSet(new Comparator<String>() {
534
                @Override
535
                public int compare(String o1, String o2) {
536
                    return o1.compareTo(o2);
537
                }
538
            });
539
            words.addAll(Arrays.asList(x));
540
            for (String word : words) {
541
                BasicCompletion completion = new BasicCompletion(this, word);
542
                completion.setIcon(wordIcon);
543
                completion.setRelevance(10);
544
                all.add(completion);
545
            }
546
            completions = new ArrayList<>();
547
            completions.addAll(all);
548
            return super.getCompletionsImpl(comp);
549
        }
550

    
551
    }
552

    
553
    private String normalizeContentType(String s) {
554
        s = s.toLowerCase();
555
        if (this.contentTypeAlias.containsKey(s)) {
556
            s = this.contentTypeAlias.get(s);
557
        }
558
        return s;
559
    }
560

    
561
    public void setContentType(String contentType) {
562
        this.textArea.setSyntaxEditingStyle(this.normalizeContentType(contentType));
563
    }
564

    
565
    public JScrollPane getJScrollPane() {
566
        return this.scrollPanel;
567
    }
568

    
569
    public JTextComponent getJTextComponent() {
570
        return this.textArea;
571
    }
572

    
573
    @Override
574
    public JComponent asJComponent() {
575
        return this.panel;
576
    }
577

    
578
    public String getContentType() {
579
        return this.textArea.getSyntaxEditingStyle();
580
    }
581

    
582
    public void addUpdateCaretPositionActionListener(ActionListener updateCaretPosition) {
583
        this.updateCaretPosition = updateCaretPosition;
584
    }
585

    
586
    public void setText(String text) {
587
        this.textArea.setText(text);
588
    }
589

    
590
    public String getText() {
591
        return this.textArea.getText();
592
    }
593

    
594
    public void addKeyListener(KeyListener keyListener) {
595
        this.textArea.addKeyListener(keyListener);
596
    }
597

    
598
    @Override
599
    public void searchEvent(SearchEvent e) {
600

    
601
        SearchEvent.Type type = e.getType();
602
        SearchContext context = e.getSearchContext();
603
        SearchResult result = null;
604

    
605
        switch (type) {
606
            default: // Prevent FindBugs warning later
607
            case MARK_ALL:
608
                result = SearchEngine.markAll(textArea, context);
609
                break;
610
            case FIND:
611
                result = SearchEngine.find(textArea, context);
612
                if (!result.wasFound()) {
613
                    textArea.getCaret().setDot(0);
614
                    result = SearchEngine.find(textArea, context);
615
                    if (!result.wasFound()) {
616
                        UIManager.getLookAndFeel().provideErrorFeedback(textArea);
617
                    }
618
                }
619
                break;
620
            case REPLACE:
621
                result = SearchEngine.replace(textArea, context);
622
                if (!result.wasFound()) {
623
                    UIManager.getLookAndFeel().provideErrorFeedback(textArea);
624
                }
625
                break;
626
            case REPLACE_ALL:
627
                result = SearchEngine.replaceAll(textArea, context);
628
                JOptionPane.showMessageDialog(null, result.getCount()
629
                        + " occurrences replaced.");
630
                break;
631
        }
632
        String text = null;
633
        if (result.wasFound()) {
634
            text = "Text found; occurrences marked: " + result.getMarkedCount();
635
        } else if (type == SearchEvent.Type.MARK_ALL) {
636
            if (result.getMarkedCount() > 0) {
637
                text = "Occurrences marked: " + result.getMarkedCount();
638
            } else {
639
                text = "";
640
            }
641
        } else {
642
            text = "Text not found";
643
        }
644
        //setMessage(text);
645
    }
646

    
647
    @Override
648
    public String getSelectedText() {
649
        return textArea.getSelectedText();
650
    }
651

    
652
    /**
653
     *
654
     */
655
    @Override
656
    public void discardAllEdits() {
657
        this.textArea.discardAllEdits();
658
    }
659
    
660
    @Override
661
    public void removeTrackingIcons() {
662
        this.scrollPanel.getGutter().removeAllTrackingIcons();
663
        this.iconsTracker.removeAll();
664
        this.lineTrackerPanel.removeLineTrackers();
665
    }
666
    
667
    @Override
668
    public void addLineTrackingIcon(String tag, int line, Icon icon, String tip) {
669
        addLineTrackingIcon(tag, line, icon, tip, Color.BLUE.darker());
670
    }
671
    
672
    @Override
673
    public void addLineTrackingIcon(String tag, int line, Icon icon, String tip, Color color) {
674
        try {
675
            GutterIconInfo x = this.scrollPanel.getGutter().addLineTrackingIcon(line,icon,tip);
676
            this.iconsTracker.add(tag, x);
677
            this.lineTrackerPanel.addLineTracker(tag, line, tip, color);
678
        } catch (BadLocationException ex) {
679
            throw new RuntimeException("Can't add tracking icon with tag '"+tag+"' in line '"+line+"', tip='"+tip+"'", ex);
680
        }
681
    }
682
    
683
    @Override
684
    public void removeTrackingIcons(String tag) {
685
        Set<GutterIconInfo> icontags = this.iconsTracker.get(tag);
686
        if( icontags!=null ) {
687
            for (GutterIconInfo icontag : icontags) {
688
                this.scrollPanel.getGutter().removeTrackingIcon(icontag);
689
            }
690
            this.iconsTracker.remove(tag);
691
        }
692
        this.lineTrackerPanel.removeLineTrackers(tag);
693
    }
694

    
695
    @Override
696
    public void gotoline(final int line) {
697
        JTextComponent component = getJTextComponent();
698
        
699
        Element root = component.getDocument().getDefaultRootElement();
700
        int lineno = Math.max(line, 1);
701
        int maxlines = root.getElementCount();
702
        lineno = Math.min(lineno, maxlines);
703
        int startOfLineOffset = root.getElement( lineno - 1 ).getStartOffset();
704
        component.setCaretPosition( startOfLineOffset );
705
            
706
        Container container = SwingUtilities.getAncestorOfClass(JViewport.class, component);
707
        if (container == null) {
708
            return;
709
        }
710
        try {
711
            Rectangle r = component.modelToView(component.getCaretPosition());
712
            JViewport viewport = (JViewport) container;
713
            int extentHeight = viewport.getExtentSize().height;
714
            int viewHeight = viewport.getViewSize().height;
715

    
716
            int y = Math.max(0, r.y - ((extentHeight - r.height) / 2));
717
            y = Math.min(y, viewHeight - extentHeight);
718

    
719
            viewport.setViewPosition(new Point(0, y));
720
        } catch (BadLocationException ble) {
721
            ble.printStackTrace();
722
        }
723
        try {
724
            component.setCaretPosition( startOfLineOffset+1 );
725
        } catch (Exception e) {
726
            e.printStackTrace();
727
        }
728
    }
729
    
730
}