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

History | View | Annotate | Download (22.7 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.swing.api.SyntaxtHighlightTextComponent;
70
import org.slf4j.Logger;
71
import org.slf4j.LoggerFactory;
72

    
73
public class JRSyntaxTextArea implements SyntaxtHighlightTextComponent, SearchListener {
74

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

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

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

    
86
    }
87

    
88
    private static class MyFindToolBar extends FindToolBar {
89

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

    
94
        @Override
95
        protected JCheckBox createCB(String key) {
96
            JCheckBox cb = new MyCheckBox();
97
            cb.setToolTipText(searchMsg.getString(key));
98
            cb.addActionListener(listener);
99
            cb.addMouseListener(listener);
100
            cb.setIcon(this.getIcon(key));
101
            return cb;
102
        }
103

    
104
        private ImageIcon getIcon(String key) {
105
            String res = "images/search-" + key.toLowerCase() + ".png";
106
            URL url = this.getClass().getResource(res);
107
            if (url == null) {
108
                return new ImageIcon();
109
            }
110
            return new ImageIcon(url);
111
        }
112

    
113
    }
114

    
115
    private static class MyReplaceToolBar extends ReplaceToolBar {
116

    
117
        public MyReplaceToolBar(SearchListener listener) {
118
            super(listener);
119
        }
120

    
121
        @Override
122
        protected JCheckBox createCB(String key) {
123
            JCheckBox cb = new MyCheckBox();
124
            cb.setToolTipText(searchMsg.getString(key));
125
            cb.addActionListener(listener);
126
            cb.addMouseListener(listener);
127
            cb.setIcon(this.getIcon(key));
128
            return cb;
129
        }
130

    
131
        private ImageIcon getIcon(String key) {
132
            String res = "images/search-" + key.toLowerCase() + ".png";
133
            URL url = this.getClass().getResource(res);
134
            if (url == null) {
135
                return new ImageIcon();
136
            }
137
            return new ImageIcon(url);
138
        }
139

    
140
    }
141

    
142
    private class LineTrackerPanel extends JPanel {
143

    
144
        private static final long serialVersionUID = -1923556745197997373L;
145

    
146
        private class Line extends JLabel {
147

    
148
            private static final long serialVersionUID = 8966359978957026490L;
149
            private final int lineno;
150
            private final String tag;
151

    
152
            public Line(String tag, final int lineno, int posy, Color color, String tooltip) {
153
                this.lineno = lineno;
154
                this.tag = tag;
155
                this.setBackground(color);
156
                this.setBounds(0, posy, 15, 2);
157
                this.setOpaque(true);
158
                this.setToolTipText(tooltip);
159
                this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
160
                this.addMouseListener(new MouseAdapter() {
161

    
162
                    @Override
163
                    public void mouseClicked(MouseEvent e) {
164
                        gotoline(lineno);
165
                    }
166
                });
167
//                Rectangle r = this.getBounds();
168
//                logger.info("LineTracker: created lineno:"+lineno+", tag:"+tag+", x:"+ r.x + ", y:"+ r.y + ", w:"+ r.width+", h:"+ r.height);
169
            }
170

    
171
            public int getLineno() {
172
                return this.lineno;
173
            }
174
            
175
            public String getTag() {
176
                return this.tag;
177
            }
178
        }
179

    
180
        public LineTrackerPanel() {
181
            setLayout(null);
182
        }
183

    
184
        @Override
185
        public Dimension getPreferredSize() {
186
            Dimension d = super.getPreferredSize(); 
187
            return new Dimension(15, d.height);
188
        }
189
        
190
        public void addLineTracker(String tag, int lineno, String tooltip, Color color) {
191
            int posy = (int) (((float)lineno)*this.getSize().height / textArea.getLineCount());
192
            Line line = new Line(tag,lineno,posy,color,tooltip);
193
            this.add(line);
194
            this.repaint();
195
        }
196

    
197
        public void removeLineTrackers() {
198
            this.removeAll();
199
            this.repaint();
200
        }
201

    
202
        public void removeLineTrackers(String tag) {
203
            if( StringUtils.isEmpty(tag) ) {
204
                return;
205
            }
206
            List<Line> toremove = new ArrayList<>();
207
            for( int i=0; i<this.getComponentCount(); i++ ) {
208
                Line line = (Line) this.getComponent(i);
209
                if( tag.equalsIgnoreCase(line.getTag()) ) {
210
                    toremove.add(line);
211
                } 
212
            }
213
            for (Line line : toremove) {
214
                this.remove(line);
215
            }
216
            this.repaint();
217
        }
218
    }
219

    
220
    private static class IconsTracker {
221

    
222
        private Map<String,Set<GutterIconInfo>>iconInfos = new HashMap<>();
223
        
224
        public IconsTracker() {
225
            
226
        }
227
        
228
        public void add(String tag, GutterIconInfo x) {
229
            Set<GutterIconInfo> set = this.iconInfos.get(tag);
230
            if( set == null ) {
231
                set = new HashSet<>();
232
                this.iconInfos.put(tag, set);
233
            }
234
            set.add(x);
235
        }
236
        
237
        public void removeAll() {
238
            this.iconInfos = new HashMap<>();
239
        }
240
        
241
        public void remove(String tag) {
242
            this.iconInfos.remove(tag);
243
        }
244
        
245
        public void remove(String tag, GutterIconInfo x) {
246
            Set<GutterIconInfo> set = this.iconInfos.get(tag);
247
            if( set == null ) {
248
                return;
249
            }
250
            set.remove(x);
251
        }
252
        
253
        public boolean exists(String tag) {
254
            return this.iconInfos.containsKey(tag);
255
        }
256
        
257
        public Set<GutterIconInfo> get(String tag) {
258
            Set<GutterIconInfo> set = this.iconInfos.get(tag);
259
            return set;
260
        }
261
    }
262
    
263
    private final FindToolBar findToolBar;
264
    private final ReplaceToolBar replaceToolBar;
265
    private final CollapsibleSectionPanel csp;
266

    
267
    public class DefaultUpdateCaretPositionActionEvent extends ActionEvent implements UpdateCaretPositionActionEvent {
268

    
269
        /**
270
         *
271
         */
272
        private static final long serialVersionUID = 8238486105726094074L;
273
        int line = -1;
274
        int column = -1;
275

    
276
        public DefaultUpdateCaretPositionActionEvent(Object source, int id,
277
                String command, int line, int column) {
278
            super(source, id, command);
279
            this.line = line;
280
            this.column = column;
281
        }
282

    
283
        public int getLine() {
284
            return this.line + 1;
285
        }
286

    
287
        public int getColumn() {
288
            return this.column;
289
        }
290

    
291
        public boolean hasLineAndColumn() {
292
            return this.line >= 0 && this.column >= 0;
293
        }
294

    
295
    }
296

    
297
    protected ActionListener updateCaretPosition = null;
298
    protected RSyntaxTextArea textArea = null;
299
    private final RTextScrollPane scrollPanel;
300
    private final JPanel panel;
301
    private final Map<String, String> contentTypeAlias;
302
    private final IconsTracker iconsTracker = new IconsTracker();
303
    private LineTrackerPanel lineTrackerPanel;
304

    
305
    public JRSyntaxTextArea() {
306
        this.contentTypeAlias = new HashMap<>();
307
        this.contentTypeAlias.put("text/r", SyntaxConstants.SYNTAX_STYLE_C);
308
        this.contentTypeAlias.put("text/ecmascript", SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
309

    
310
        this.textArea = new RSyntaxTextArea(20, 60);
311
        
312
        this.init();
313
        lineTrackerPanel = new LineTrackerPanel();
314
        scrollPanel = new RTextScrollPane(this.textArea);
315
        scrollPanel.setIconRowHeaderEnabled(true);
316
        scrollPanel.setLineNumbersEnabled(true);
317
        scrollPanel.setFoldIndicatorEnabled(true);
318
        
319
        panel = new JPanel();
320
        panel.setLayout(new BorderLayout());
321
        panel.add(scrollPanel, BorderLayout.CENTER);
322
        panel.add(lineTrackerPanel,BorderLayout.EAST);
323
        
324
        findToolBar = new MyFindToolBar(this);
325
        replaceToolBar = new MyReplaceToolBar(this);
326
        replaceToolBar.setSearchContext(findToolBar.getSearchContext());
327
        csp = new CollapsibleSectionPanel();
328
        csp.add(scrollPanel);
329
        panel.add(csp, BorderLayout.CENTER);
330
        int ctrl = (KeyEvent.CTRL_MASK | KeyEvent.ALT_MASK);
331
        KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F, ctrl);
332
        csp.addBottomComponent(ks, findToolBar);
333
        ks = KeyStroke.getKeyStroke(KeyEvent.VK_H, ctrl);
334
        csp.addBottomComponent(ks, replaceToolBar);
335

    
336
        textArea.addKeyListener(new KeyListener() {
337

    
338
            @Override
339
            public void keyTyped(KeyEvent ke) {
340
            }
341

    
342
            @Override
343
            public void keyPressed(KeyEvent ke) {
344
                if (ke.getModifiers() == (KeyEvent.CTRL_MASK | KeyEvent.ALT_MASK)) {
345
                    if (ke.getKeyCode() == KeyEvent.VK_H) {
346
                        csp.showBottomComponent(replaceToolBar);
347
                    } else if (ke.getKeyCode() == KeyEvent.VK_F) {
348
                        csp.showBottomComponent(findToolBar);
349
                    }
350
                }
351
            }
352

    
353
            @Override
354
            public void keyReleased(KeyEvent ke) {
355
            }
356
        });
357

    
358
    }
359

    
360
    protected void init() {
361
        textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON);
362
        textArea.setCodeFoldingEnabled(true);
363
        textArea.setClearWhitespaceLinesEnabled(true);
364
        textArea.setAutoIndentEnabled(true);
365
        textArea.setCloseCurlyBraces(true);
366
        textArea.setWhitespaceVisible(true);
367
        textArea.setAnimateBracketMatching(true);
368
        textArea.setBracketMatchingEnabled(true);
369
        textArea.setAutoIndentEnabled(true);
370
        textArea.setTabsEmulated(true);
371
        textArea.setTabSize(2);
372
        textArea.setAntiAliasingEnabled(true);
373

    
374
        textArea.addCaretListener(new CaretListener() {
375
            public void caretUpdate(CaretEvent e) {
376
                if (updateCaretPosition == null) {
377
                    return;
378
                }
379
                updateCaretPosition.actionPerformed(
380
                        new DefaultUpdateCaretPositionActionEvent(textArea, 1, "position", textArea.getCaretLineNumber(), textArea.getCaretOffsetFromLineStart())
381
                );
382
            }
383

    
384
        });
385

    
386
        CompletionProvider provider = new MyCompletionProvider(python_keywords);
387
        AutoCompletion ac = new AutoCompletion(provider);
388
        ac.setListCellRenderer(new MyListCellRenderer());
389
        ac.setTriggerKey(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_DOWN_MASK));
390
        ac.install(textArea);
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
}