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 @ 1200

History | View | Annotate | Download (23.3 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.Point;
10
import java.awt.Rectangle;
11
import java.awt.event.ActionEvent;
12
import java.awt.event.ActionListener;
13
import java.awt.event.InputEvent;
14
import java.awt.event.KeyEvent;
15
import java.awt.event.KeyListener;
16
import java.awt.event.MouseAdapter;
17
import java.awt.event.MouseEvent;
18
import java.net.URL;
19
import java.util.ArrayList;
20
import java.util.Arrays;
21
import java.util.Comparator;
22
import java.util.HashMap;
23
import java.util.HashSet;
24
import java.util.List;
25
import java.util.Map;
26
import java.util.Set;
27
import java.util.TreeSet;
28
import javax.swing.DefaultListCellRenderer;
29
import javax.swing.Icon;
30
import javax.swing.ImageIcon;
31
import javax.swing.JCheckBox;
32
import javax.swing.JComponent;
33
import javax.swing.JLabel;
34
import javax.swing.JList;
35
import javax.swing.JOptionPane;
36
import javax.swing.JPanel;
37

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

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

    
74
public class JRSyntaxTextArea implements SyntaxtHighlightTextComponent, SearchListener {
75

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

    
80
        private static final String uiClassID = "ToggleButtonUI";
81

    
82
        @Override
83
        public String getUIClassID() {
84
            return uiClassID;
85
        }
86

    
87
    }
88

    
89
    private class MyFindToolBar extends FindToolBar {
90

    
91
        public MyFindToolBar(SearchListener listener) {
92
            super(listener);
93
        }
94

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

    
105
    }
106

    
107
    private class MyReplaceToolBar extends ReplaceToolBar {
108

    
109
        public MyReplaceToolBar(SearchListener listener) {
110
            super(listener);
111
        }
112

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

    
124
    private class LineTrackerPanel extends JPanel {
125

    
126
        private static final long serialVersionUID = -1923556745197997373L;
127

    
128
        private class Line extends JLabel {
129

    
130
            private static final long serialVersionUID = 8966359978957026490L;
131
            private final int lineno;
132
            private final String tag;
133

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

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

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

    
162
        public LineTrackerPanel() {
163
            setLayout(null);
164
        }
165

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

    
179
        public void removeLineTrackers() {
180
            this.removeAll();
181
            this.repaint();
182
        }
183

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

    
202
    private static class IconsTracker {
203

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

    
249
    public class DefaultUpdateCaretPositionActionEvent extends ActionEvent implements UpdateCaretPositionActionEvent {
250

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

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

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

    
269
        public int getColumn() {
270
            return this.column;
271
        }
272

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

    
277
    }
278

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

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

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

    
321
        textArea.addKeyListener(new KeyListener() {
322

    
323
            @Override
324
            public void keyTyped(KeyEvent ke) {
325
            }
326

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

    
338
            @Override
339
            public void keyReleased(KeyEvent ke) {
340
            }
341
        });
342

    
343
    }
344

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

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

    
369
        });
370

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

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

    
390

    
391
    private static class MyListCellRenderer extends DefaultListCellRenderer {
392

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

    
400
    }
401

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

    
497
    private class MyCompletionProvider extends DefaultCompletionProvider {
498

    
499
        private List<Completion> keywords;
500
        private Icon keywordIcon;
501
        private Icon wordIcon;
502

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

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

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

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

    
549
    }
550

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

    
559
    public void setContentType(String contentType) {
560
        TokenMakerFactory factory = TokenMakerFactory.getDefaultInstance();
561
        Set<String> mimetypes = factory.keySet();
562
        String mimetype = this.normalizeContentType(contentType);
563
        if( !mimetypes.contains(mimetype)) {
564
          mimetype = mimetype.replace("-source", "");
565
          if( !mimetypes.contains(mimetype)) {
566
            mimetype = mimetype.replace("/x-", "/");
567
            if( !mimetypes.contains(mimetype)) {
568
              mimetype = this.normalizeContentType(contentType);
569
            }
570
          }
571
        }
572
        this.textArea.setSyntaxEditingStyle(mimetype);
573
    }
574

    
575
    public JScrollPane getJScrollPane() {
576
        return this.scrollPanel;
577
    }
578

    
579
    public JTextComponent getJTextComponent() {
580
        return this.textArea;
581
    }
582

    
583
    @Override
584
    public JComponent asJComponent() {
585
        return this.panel;
586
    }
587

    
588
    public String getContentType() {
589
        return this.textArea.getSyntaxEditingStyle();
590
    }
591

    
592
    public void addUpdateCaretPositionActionListener(ActionListener updateCaretPosition) {
593
        this.updateCaretPosition = updateCaretPosition;
594
    }
595

    
596
    public void setText(String text) {
597
        this.textArea.setText(text);
598
    }
599

    
600
    public String getText() {
601
        return this.textArea.getText();
602
    }
603

    
604
    public void addKeyListener(KeyListener keyListener) {
605
        this.textArea.addKeyListener(keyListener);
606
    }
607

    
608
    @Override
609
    public void searchEvent(SearchEvent e) {
610

    
611
        SearchEvent.Type type = e.getType();
612
        SearchContext context = e.getSearchContext();
613
        SearchResult result = null;
614

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

    
657
    @Override
658
    public String getSelectedText() {
659
        return textArea.getSelectedText();
660
    }
661

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

    
705
    @Override
706
    public void gotoline(final int line) {
707
        JTextComponent component = getJTextComponent();
708
        
709
        Element root = component.getDocument().getDefaultRootElement();
710
        int lineno = Math.max(line, 1);
711
        int maxlines = root.getElementCount();
712
        lineno = Math.min(lineno, maxlines);
713
        int startOfLineOffset = root.getElement( lineno - 1 ).getStartOffset();
714
        component.setCaretPosition( startOfLineOffset );
715
            
716
        Container container = SwingUtilities.getAncestorOfClass(JViewport.class, component);
717
        if (container == null) {
718
            return;
719
        }
720
        try {
721
            Rectangle r = component.modelToView(component.getCaretPosition());
722
            JViewport viewport = (JViewport) container;
723
            int extentHeight = viewport.getExtentSize().height;
724
            int viewHeight = viewport.getViewSize().height;
725

    
726
            int y = Math.max(0, r.y - ((extentHeight - r.height) / 2));
727
            y = Math.min(y, viewHeight - extentHeight);
728

    
729
            viewport.setViewPosition(new Point(0, y));
730
        } catch (BadLocationException ble) {
731
            ble.printStackTrace();
732
        }
733
        try {
734
            component.setCaretPosition( startOfLineOffset+1 );
735
        } catch (Exception e) {
736
            e.printStackTrace();
737
        }
738
    }
739
    
740
}