KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > ExtCaret


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor.ext;
21
22 import java.awt.Rectangle JavaDoc;
23 import java.awt.Font JavaDoc;
24 import java.awt.event.MouseEvent JavaDoc;
25 import java.awt.event.ActionListener JavaDoc;
26 import java.awt.event.ActionEvent JavaDoc;
27 import javax.swing.SwingUtilities JavaDoc;
28 import javax.swing.Timer JavaDoc;
29 import javax.swing.text.JTextComponent JavaDoc;
30 import javax.swing.text.BadLocationException JavaDoc;
31 import org.netbeans.editor.BaseCaret;
32 import org.netbeans.editor.Coloring;
33 import org.netbeans.editor.EditorUI;
34 import org.netbeans.editor.MarkFactory;
35 import org.netbeans.editor.DrawLayerFactory;
36 import org.netbeans.editor.Utilities;
37 import org.netbeans.editor.BaseDocument;
38 import org.netbeans.editor.BaseTextUI;
39 import org.netbeans.editor.InvalidMarkException;
40 import org.netbeans.editor.DrawContext;
41 import org.netbeans.editor.DrawLayer;
42 import org.netbeans.editor.SettingsUtil;
43 import org.netbeans.editor.SettingsChangeEvent;
44 import org.netbeans.editor.SettingsNames;
45 import org.netbeans.editor.WeakTimerListener;
46
47 /**
48 * Extended caret implementation
49 *
50 * @author Miloslav Metelka
51 * @version 1.00
52 */

53
54 public class ExtCaret extends BaseCaret {
55
56     /**
57      * Highlight row draw layer name.
58      *
59      * <p>Using <code>DrawLayer</code>s has been deprecated and this constant
60      * has no longer any meaning.
61      *
62      * @deprecated Please use Highlighting SPI instead, for details see
63      * <a HREF="@org-netbeans-modules-editor-lib2@/overview-summary.html">Editor Library 2</a>.
64      */

65     public static final String JavaDoc HIGHLIGHT_ROW_LAYER_NAME = "highlight-row-layer"; // NOI18N
66

67     /**
68      * Highlight row draw layer visibility.
69      *
70      * <p>Using <code>DrawLayer</code>s has been deprecated and this constant
71      * has no longer any meaning.
72      *
73      * @deprecated Please use Highlighting SPI instead, for details see
74      * <a HREF="@org-netbeans-modules-editor-lib2@/overview-summary.html">Editor Library 2</a>.
75      */

76     public static final int HIGHLIGHT_ROW_LAYER_VISIBILITY = 2050;
77
78     /** Highlight matching brace draw layer name */
79     public static final String JavaDoc HIGHLIGHT_BRACE_LAYER_NAME = "highlight-brace-layer"; // NOI18N
80

81     /** Highlight matching brace draw layer visibility */
82     public static final int HIGHLIGHT_BRACE_LAYER_VISIBILITY = 11000;
83
84     /** Whether to hightlight the matching brace */
85     boolean highlightBrace;
86
87     /** Coloring used for highlighting the matching brace */
88     Coloring highlightBraceColoring;
89
90     /** Mark holding the starting position of the matching brace. */
91     MarkFactory.DrawMark highlightBraceStartMark;
92
93     /** Mark holding the ending position of the matching brace. */
94     MarkFactory.DrawMark highlightBraceEndMark;
95
96     /** Timer that fires when the matching brace should be displayed */
97     private Timer JavaDoc braceTimer;
98     private ActionListener JavaDoc braceTimerListener; // because of unwanted GC
99

100     /** Signal that the next matching brace update
101     * will be immediate without waiting for the brace
102     * timer to fire the action.
103     */

104     private boolean matchBraceUpdateSync;
105
106     /** Whether the brace starting and ending marks are currently valid or not.
107      * If they are not valid the block they delimit is not highlighted.
108      */

109     boolean braceMarksValid;
110
111     boolean simpleMatchBrace;
112     
113     private boolean popupMenuEnabled;
114
115     static final long serialVersionUID =-4292670043122577690L;
116
117     
118     protected void modelChanged(BaseDocument oldDoc, BaseDocument newDoc) {
119         // Fix for #7108
120
braceMarksValid = false; // brace marks are out of date - new document
121
if (highlightBraceStartMark != null) {
122             try {
123                 highlightBraceStartMark.remove();
124             } catch (InvalidMarkException e) {
125             }
126             highlightBraceStartMark = null;
127         }
128
129         if (highlightBraceEndMark != null) {
130             try {
131                 highlightBraceEndMark.remove();
132             } catch (InvalidMarkException e) {
133             }
134             highlightBraceEndMark = null;
135         }
136
137         super.modelChanged( oldDoc, newDoc );
138     }
139     
140     /** Called when settings were changed. The method is called
141     * also in constructor, so the code must count with the evt being null.
142     */

143     public void settingsChange(SettingsChangeEvent evt) {
144         super.settingsChange(evt);
145         JTextComponent JavaDoc c = component;
146         if (c != null) {
147
148             EditorUI editorUI = Utilities.getEditorUI(c);
149             Class JavaDoc kitClass = Utilities.getKitClass(c);
150             highlightBraceColoring = editorUI.getColoring(
151                                            ExtSettingsNames.HIGHLIGHT_MATCH_BRACE_COLORING);
152
153             highlightBrace = SettingsUtil.getBoolean(kitClass,
154                                ExtSettingsNames.HIGHLIGHT_MATCH_BRACE,
155                                ExtSettingsDefaults.defaultHighlightMatchBrace);
156             int highlightBraceDelay = SettingsUtil.getInteger(kitClass,
157                                         ExtSettingsNames.HIGHLIGHT_MATCH_BRACE_DELAY,
158                                         ExtSettingsDefaults.defaultHighlightMatchBraceDelay);
159
160             if (highlightBrace) {
161                 if (highlightBraceDelay > 0) {
162                     // jdk12 compiler doesn't allow inside run()
163
final JTextComponent JavaDoc c2 = component;
164
165                     braceTimer = new Timer JavaDoc(highlightBraceDelay, null);
166                     braceTimerListener =
167                          new ActionListener JavaDoc() {
168                              public void actionPerformed(ActionEvent JavaDoc evt2) {
169                                  SwingUtilities.invokeLater(
170                                      new Runnable JavaDoc() {
171                                          public void run() {
172                                              if (c2 != null) {
173                                                  BaseDocument doc = Utilities.getDocument(c2);
174                                                  if( doc != null ) {
175                                                      doc.readLock();
176                                                      try {
177                                                          updateMatchBrace();
178                                                      } finally {
179                                                          doc.readUnlock();
180                                                      }
181                                                  }
182                                              }
183                                          }
184                                      }
185                                  );
186                              }
187                          };
188                          
189                     braceTimer.addActionListener(new WeakTimerListener(braceTimerListener));
190                     braceTimer.setRepeats(false);
191                 } else {
192                     braceTimer = null; // signal no delay
193
}
194                 c.repaint();
195             }
196
197             simpleMatchBrace = SettingsUtil.getBoolean(kitClass,
198                                     ExtSettingsNames.CARET_SIMPLE_MATCH_BRACE,
199                                     ExtSettingsDefaults.defaultCaretSimpleMatchBrace);
200             
201             popupMenuEnabled = SettingsUtil.getBoolean(kitClass,
202                 ExtSettingsNames.POPUP_MENU_ENABLED, true);
203         }
204     }
205
206     public void install(JTextComponent JavaDoc c) {
207         EditorUI editorUI = Utilities.getEditorUI(c);
208         editorUI.addLayer(new HighlightBraceLayer(), HIGHLIGHT_BRACE_LAYER_VISIBILITY);
209         super.install(c);
210     }
211
212     public void deinstall(JTextComponent JavaDoc c) {
213         EditorUI editorUI = Utilities.getEditorUI(c);
214         editorUI.removeLayer(HIGHLIGHT_BRACE_LAYER_NAME);
215         super.deinstall(c);
216     }
217
218     /** Update the matching brace of the caret. The document is read-locked
219      * while this method is called.
220      */

221     protected void updateMatchBrace() {
222         JTextComponent JavaDoc c = component;
223         if (c != null && highlightBrace) {
224             try {
225                 EditorUI editorUI = Utilities.getEditorUI(c);
226                 BaseDocument doc = (BaseDocument)c.getDocument();
227                 int dotPos = getDot();
228                 boolean madeValid = false; // whether brace marks display were validated
229
if (dotPos > 0) {
230                     int[] matchBlk = ((ExtSyntaxSupport)doc.getSyntaxSupport())
231                         .findMatchingBlock(dotPos - 1, simpleMatchBrace);
232                     if (matchBlk != null) {
233                         if (highlightBraceStartMark != null) {
234                             int markStartPos = highlightBraceStartMark.getOffset();
235                             int markEndPos = highlightBraceEndMark.getOffset();
236                             if (markStartPos != matchBlk[0] || markEndPos != matchBlk[1]) {
237                                 editorUI.repaintBlock(markStartPos, markEndPos);
238                                 Utilities.moveMark(doc, highlightBraceStartMark, matchBlk[0]);
239                                 Utilities.moveMark(doc, highlightBraceEndMark, matchBlk[1]);
240                                 editorUI.repaintBlock(matchBlk[0], matchBlk[1]);
241                             } else { // on the same position
242
if (!braceMarksValid) { // was not valid, must repaint
243
editorUI.repaintBlock(matchBlk[0], matchBlk[1]);
244                                 }
245                             }
246                         } else { // highlight mark is null
247
highlightBraceStartMark = new MarkFactory.DrawMark(
248                                                        HIGHLIGHT_BRACE_LAYER_NAME, editorUI);
249                             highlightBraceEndMark = new MarkFactory.DrawMark(
250                                                        HIGHLIGHT_BRACE_LAYER_NAME, editorUI);
251                             highlightBraceStartMark.setActivateLayer(true);
252                             Utilities.insertMark(doc, highlightBraceStartMark, matchBlk[0]);
253                             Utilities.insertMark(doc, highlightBraceEndMark, matchBlk[1]);
254                             editorUI.repaintBlock(matchBlk[0], matchBlk[1]);
255                         }
256                         braceMarksValid = true;
257                         madeValid = true;
258                     }
259                 }
260
261                 if (!madeValid) {
262                     if (braceMarksValid) {
263                         braceMarksValid = false;
264                         editorUI.repaintBlock(highlightBraceStartMark.getOffset(),
265                                 highlightBraceEndMark.getOffset());
266                     }
267                 }
268             } catch (BadLocationException JavaDoc e) {
269                 Utilities.annotateLoggable(e);
270                 highlightBrace = false;
271             } catch (InvalidMarkException e) {
272                 Utilities.annotateLoggable(e);
273                 highlightBrace = false;
274             }
275         }
276     }
277
278     protected void update(boolean scrollViewToCaret) {
279         if (highlightBrace) {
280             if (matchBraceUpdateSync || braceTimer == null) {
281                 updateMatchBrace();
282                 matchBraceUpdateSync = false;
283
284             } else { // delay the brace update
285
braceTimer.restart();
286             }
287         }
288
289         super.update(scrollViewToCaret);
290     }
291
292     /** Signal that the next matching brace update
293     * will be immediate without waiting for the brace
294     * timer to fire the action. This is usually done
295     * for the key-typed action.
296     */

297     public void requestMatchBraceUpdateSync() {
298         matchBraceUpdateSync = true;
299     }
300     
301     public void mousePressed(MouseEvent JavaDoc evt) {
302         Completion completion = ExtUtilities.getCompletion(component);
303         if (completion != null && completion.isPaneVisible()) {
304             // Hide completion if visible
305
completion.setPaneVisible(false);
306         }
307         super.mousePressed(evt);
308     showPopup(evt);
309     }
310     
311     private boolean showPopup (MouseEvent JavaDoc evt) {
312         // Show popup menu for right click
313
if (component != null && evt.isPopupTrigger() && popupMenuEnabled) {
314             ExtUtilities.getExtEditorUI(component).showPopupMenu(evt.getX(), evt.getY());
315             return true;
316         }
317         return false;
318     }
319     
320     public void mouseReleased(MouseEvent JavaDoc evt) {
321         if (!showPopup(evt)) {
322             super.mouseReleased(evt);
323         }
324     }
325
326     /**
327      * Draw layer to highlight the matching brace.
328      *
329      * XXX: The HighlightBraceLayer needs to be rewritten using the new Highlighting SPI.
330      */

331     class HighlightBraceLayer extends DrawLayer.AbstractLayer {
332
333         public HighlightBraceLayer() {
334             super(HIGHLIGHT_BRACE_LAYER_NAME);
335         }
336
337         public void init(DrawContext ctx) {
338         }
339
340         public boolean isActive(DrawContext ctx, MarkFactory.DrawMark mark) {
341             if (braceMarksValid) {
342                 if (mark != null)
343                     return mark.getActivateLayer();
344                 try {
345                     if (ctx.getStartOffset() > highlightBraceEndMark.getOffset())
346                         return highlightBraceEndMark.getActivateLayer();
347                     if (ctx.getStartOffset() > highlightBraceStartMark.getOffset())
348                         return highlightBraceStartMark.getActivateLayer();
349                 } catch (InvalidMarkException ex) {
350                 }
351             }
352
353             return false;
354         }
355
356         public void updateContext(DrawContext ctx) {
357             if (highlightBraceColoring != null) {
358                 highlightBraceColoring.apply(ctx);
359             }
360         }
361
362     }
363
364 }
365
Popular Tags