KickJava   Java API By Example, From Geeks To Geeks.

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


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.Dimension JavaDoc;
23 import java.awt.Point JavaDoc;
24 import java.awt.Rectangle JavaDoc;
25 import java.awt.Font JavaDoc;
26 import java.awt.Color JavaDoc;
27 import java.awt.event.ActionListener JavaDoc;
28 import java.awt.event.ActionEvent JavaDoc;
29 import java.awt.event.MouseListener JavaDoc;
30 import java.awt.event.MouseMotionListener JavaDoc;
31 import java.awt.event.MouseAdapter JavaDoc;
32 import java.awt.event.MouseEvent JavaDoc;
33 import java.awt.event.ComponentEvent JavaDoc;
34 import java.awt.event.ComponentAdapter JavaDoc;
35 import java.awt.event.FocusListener JavaDoc;
36 import java.awt.event.FocusEvent JavaDoc;
37 import java.beans.PropertyChangeListener JavaDoc;
38 import java.beans.PropertyChangeEvent JavaDoc;
39 import java.beans.PropertyChangeSupport JavaDoc;
40 import javax.swing.JComponent JavaDoc;
41 import javax.swing.JLabel JavaDoc;
42 import javax.swing.JRootPane JavaDoc;
43 import javax.swing.JLayeredPane JavaDoc;
44 import javax.swing.Timer JavaDoc;
45 import javax.swing.Action JavaDoc;
46 import javax.swing.ActionMap JavaDoc;
47 import javax.swing.BorderFactory JavaDoc;
48 import javax.swing.UIManager JavaDoc;
49 import javax.swing.text.JTextComponent JavaDoc;
50 import javax.swing.text.BadLocationException JavaDoc;
51 import org.netbeans.editor.SettingsChangeListener;
52 import org.netbeans.editor.SettingsChangeEvent;
53 import org.netbeans.editor.Settings;
54 import org.netbeans.editor.Utilities;
55 import org.netbeans.editor.BaseKit;
56 import org.netbeans.editor.BaseTextUI;
57 import org.netbeans.editor.BaseDocument;
58 import org.netbeans.editor.WeakTimerListener;
59 import org.netbeans.editor.PopupManager;
60 import javax.swing.JTextArea JavaDoc;
61 import org.netbeans.editor.EditorUI;
62 import org.netbeans.editor.GlyphGutter;
63 import javax.swing.JViewport JavaDoc;
64 import javax.swing.text.Document JavaDoc;
65 import javax.swing.text.Element JavaDoc;
66
67 /**
68  * Support for editor tooltips. Once the user stops moving the mouse
69  * for the {@link #INITIAL_DELAY} milliseconds the enterTimer fires
70  * and the {@link #updateToolTip()} method is called which searches
71  * for the action named {@link ExtKit#buildToolTipAction} and if found
72  * it executes it. The tooltips can be displayed by either calling
73  * {@link #setToolTipText(java.lang.String)}
74  * or {@link #setToolTip(javax.swing.JComponent)}.<BR>
75  * However only one of the above ways should be used
76  * not a combination of both because in such case
77  * the text could be propagated in the previously set
78  * custom tooltip component.
79  *
80  * @author Miloslav Metelka
81  * @version 1.00
82  */

83
84 public class ToolTipSupport extends MouseAdapter JavaDoc
85 implements MouseMotionListener JavaDoc, ActionListener JavaDoc, PropertyChangeListener JavaDoc,
86 SettingsChangeListener, FocusListener JavaDoc {
87
88     /** Property for the tooltip component change */
89     public static final String JavaDoc PROP_TOOL_TIP = "toolTip"; // NOI18N
90

91     /** Property for the tooltip text change */
92     public static final String JavaDoc PROP_TOOL_TIP_TEXT = "toolTipText"; // NOI18N
93

94     /** Property for the visibility status change. */
95     public static final String JavaDoc PROP_STATUS = "status"; // NOI18N
96

97     /** Property for the enabled flag change */
98     public static final String JavaDoc PROP_ENABLED = "enabled"; // NOI18N
99

100     /** Property for the initial delay change */
101     public static final String JavaDoc PROP_INITIAL_DELAY = "initialDelay"; // NOI18N
102

103     /** Property for the dismiss delay change */
104     public static final String JavaDoc PROP_DISMISS_DELAY = "dismissDelay"; // NOI18N
105

106     private static final String JavaDoc UI_PREFIX = "ToolTip"; // NOI18N
107

108     /** Initial delay before the tooltip is shown in milliseconds. */
109     public static final int INITIAL_DELAY = 200;
110
111     /** Delay after which the tooltip will be hidden automatically
112      * in milliseconds.
113      */

114     public static final int DISMISS_DELAY = 60000;
115     
116     /** Status indicating that the tooltip is not showing on the screen. */
117     public static final int STATUS_HIDDEN = 0;
118     /** Status indicating that the tooltip is not showing on the screen
119      * but once either the {@link #setToolTipText(java.lang.String)}
120      * or {@link #setToolTip(javax.swing.JComponent)} gets called
121      * the tooltip will become visible.
122      */

123     public static final int STATUS_VISIBILITY_ENABLED = 1;
124     /** Status indicating that the tooltip is visible
125      * because {@link #setToolTipText(java.lang.String)}
126      * was called.
127      */

128     public static final int STATUS_TEXT_VISIBLE = 2;
129     /** Status indicating that the tooltip is visible
130      * because {@link #setToolTip(javax.swing.JComponent)}
131      * was called.
132      */

133     public static final int STATUS_COMPONENT_VISIBLE = 3;
134     
135     /** Extra height added to the rectangle of modelToView() for mouse
136      * cursor coordinates.
137      */

138     private static final int MOUSE_EXTRA_HEIGHT = 5;
139
140     private ExtEditorUI extEditorUI;
141
142     private JComponent JavaDoc toolTip;
143
144     private String JavaDoc toolTipText;
145     
146     private Timer JavaDoc enterTimer;
147
148     private Timer JavaDoc exitTimer;
149
150     private boolean enabled;
151     
152     /** Status of the tooltip visibility. */
153     private int status;
154
155     private MouseEvent JavaDoc lastMouseEvent;
156
157     private PropertyChangeSupport JavaDoc pcs;
158     
159     private PopupManager.HorizontalBounds horizontalBounds = PopupManager.ViewPortBounds;
160     private PopupManager.Placement placement = PopupManager.AbovePreferred;
161
162     private int verticalAdjustment;
163     private int horizontalAdjustment;
164     
165     private boolean glyphListenerAdded = false;
166
167     /** Construct new support for tooltips.
168      */

169     public ToolTipSupport(ExtEditorUI extEditorUI) {
170         this.extEditorUI = extEditorUI;
171
172         enterTimer = new Timer JavaDoc(INITIAL_DELAY, new WeakTimerListener(this));
173         enterTimer.setRepeats(false);
174         exitTimer = new Timer JavaDoc(DISMISS_DELAY, new WeakTimerListener(this));
175         exitTimer.setRepeats(false);
176
177         Settings.addSettingsChangeListener(this);
178         extEditorUI.addPropertyChangeListener(this);
179
180         setEnabled(true);
181     }
182
183     /** @return the component that either contains the tooltip
184      * or is responsible for displaying of text tooltips.
185      */

186     public final JComponent JavaDoc getToolTip() {
187         if (toolTip == null) {
188             setToolTip(createDefaultToolTip());
189         }
190
191         return toolTip;
192     }
193     
194     /** Set the tooltip component.
195      * It can be called either to set the custom component
196      * that will display the text tooltips or to display
197      * the generic component with the tooltip after
198      * the tooltip timer has fired.
199      * @param toolTip component that either contains the tooltip
200      * or that will display a text tooltip.
201      */

202     public void setToolTip(JComponent JavaDoc toolTip) {
203         setToolTip(toolTip, PopupManager.ViewPortBounds, PopupManager.AbovePreferred);
204     }
205
206     public void setToolTip(JComponent JavaDoc toolTip, PopupManager.HorizontalBounds horizontalBounds,
207         PopupManager.Placement placement) {
208         setToolTip(toolTip, PopupManager.ViewPortBounds, PopupManager.AbovePreferred, 0, 0);
209     }
210     
211     public void setToolTip(JComponent JavaDoc toolTip, PopupManager.HorizontalBounds horizontalBounds,
212         PopupManager.Placement placement, int horizontalAdjustment, int verticalAdjustment) {
213         JComponent JavaDoc oldToolTip = this.toolTip;
214         this.toolTip = toolTip;
215         this.horizontalBounds = horizontalBounds;
216         this.placement = placement;
217         this.horizontalAdjustment = horizontalAdjustment;
218         this.verticalAdjustment = verticalAdjustment;
219
220         if (status >= STATUS_VISIBILITY_ENABLED) {
221             ensureVisibility();
222         }
223
224         firePropertyChange(PROP_TOOL_TIP, oldToolTip, this.toolTip);
225     }
226     
227     /** Create the default tooltip component.
228      */

229     protected JComponent JavaDoc createDefaultToolTip() {
230         return createTextToolTip();
231     }
232     
233     private JTextArea JavaDoc createTextToolTip() {
234         JTextArea JavaDoc tt = new JTextArea JavaDoc() {
235             public void setSize(int width, int height) {
236                 Dimension JavaDoc prefSize = getPreferredSize();
237                 if (width >= prefSize.width) {
238                     width = prefSize.width;
239                 } else { // smaller available width
240
// Set line wrapping and do super.setSize() to determine
241
// the real height (it will change due to line wrapping)
242
super.setSize(width, 10000); // the height is unimportant
243
prefSize = getPreferredSize(); // re-read new pref width
244
}
245                 if (height >= prefSize.height) { // enough height
246
height = prefSize.height;
247                 } else { // smaller available height
248
// Check how much can be displayed - cannot rely on line count
249
// because line wrapping may display single physical line
250
// into several visual lines
251
// Before using viewToModel() a setSize() must be called
252
// because otherwise the viewToModel() would return -1.
253
super.setSize(width, 10000);
254                     int offset = viewToModel(new Point JavaDoc(0, height));
255                     Document doc = getDocument();
256                     Element JavaDoc root = doc.getDefaultRootElement();
257                     int lineIndex = root.getElementIndex(offset);
258                     lineIndex--; // go to previous line
259
if (lineIndex >= 0) {
260                         Element JavaDoc lineElem = root.getElement(lineIndex);
261                         if (lineElem != null) {
262                             try {
263                                 offset = lineElem.getStartOffset();
264                                 doc.remove(offset, doc.getLength() - offset);
265                                 doc.insertString(offset, "...", null);
266                             } catch (BadLocationException JavaDoc e) {
267                                 // "..." will likely not be displayed but otherwise should be ok
268
}
269                             // Recalculate the prefSize as it may be smaller
270
// than the present preferred height
271
height = Math.min(height, getPreferredSize().height);
272                         }
273                     }
274                 }
275                 super.setSize(width, height);
276             }
277         };
278
279         // bugfix of #43174
280
tt.setActionMap(new ActionMap JavaDoc());
281         tt.setInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
282         
283         Font JavaDoc font = UIManager.getFont(UI_PREFIX + ".font"); // NOI18N
284
Color JavaDoc backColor = UIManager.getColor(UI_PREFIX + ".background"); // NOI18N
285
Color JavaDoc foreColor = UIManager.getColor(UI_PREFIX + ".foreground"); // NOI18N
286

287         if (font != null) {
288             tt.setFont(font);
289         }
290         if (foreColor != null) {
291             tt.setForeground(foreColor);
292         }
293         if (backColor != null) {
294             tt.setBackground(backColor);
295         }
296
297         tt.setOpaque(true);
298         tt.setBorder(BorderFactory.createCompoundBorder(
299             BorderFactory.createLineBorder(tt.getForeground()),
300             BorderFactory.createEmptyBorder(0, 3, 0, 3)
301         ));
302
303         return tt;
304     }
305
306     public void settingsChange(SettingsChangeEvent evt) {
307     }
308
309     public void propertyChange(PropertyChangeEvent JavaDoc evt) {
310         String JavaDoc propName = evt.getPropertyName();
311
312         if (extEditorUI.COMPONENT_PROPERTY.equals(propName)) {
313             JTextComponent JavaDoc component = (JTextComponent JavaDoc)evt.getNewValue();
314             if (component != null) { // just installed
315

316                 component.addPropertyChangeListener(this);
317                 
318                 disableSwingToolTip(component);
319
320                 component.addFocusListener(this);
321                 if (component.hasFocus()) {
322                     focusGained(new FocusEvent JavaDoc(component, FocusEvent.FOCUS_GAINED));
323                 }
324                 component.addMouseListener(this);
325                 component.addMouseMotionListener(this);
326
327                 GlyphGutter gg = extEditorUI.getGlyphGutter();
328                 if (gg != null && !glyphListenerAdded) {
329                     glyphListenerAdded = true;
330                     gg.addMouseListener(this);
331                     gg.addMouseMotionListener(this);
332                 }
333                 
334                 
335             } else { // just deinstalled
336
component = (JTextComponent JavaDoc)evt.getOldValue();
337
338                 component.removeFocusListener(this);
339                 component.removePropertyChangeListener(this);
340                 
341                 component.removeMouseListener(this);
342                 component.removeMouseMotionListener(this);
343                 
344                 GlyphGutter gg = extEditorUI.getGlyphGutter();
345                 if (gg != null) {
346                     gg.removeMouseListener(this);
347                     gg.removeMouseMotionListener(this);
348                 }
349                 setToolTipVisible(false);
350
351             }
352         }
353         
354         if (JComponent.TOOL_TIP_TEXT_KEY.equals(propName)) {
355             JComponent JavaDoc component = (JComponent JavaDoc)evt.getSource();
356             disableSwingToolTip(component);
357             
358             componentToolTipTextChanged(evt);
359         }
360                         
361     }
362
363     private void disableSwingToolTip(final JComponent JavaDoc component) {
364         javax.swing.SwingUtilities.invokeLater(
365             new Runnable JavaDoc() {
366                 public void run() {
367                     // Prevent default swing tooltip manager
368
javax.swing.ToolTipManager.sharedInstance().unregisterComponent(component);
369                     
370                     // Also disable the swing tooltip manager on gutter component
371
GlyphGutter gg = extEditorUI.getGlyphGutter();
372                     if (gg != null) {
373                         javax.swing.ToolTipManager.sharedInstance().unregisterComponent(gg);
374                     }
375                 }
376             }
377         );
378     }
379     
380     /** Update the tooltip by running corresponding action
381      * {@link ExtKit#buildToolTipAction}. This method gets
382      * called once the enterTimer fires and it can be overriden
383      * by children.
384      */

385     protected void updateToolTip() {
386         ExtEditorUI ui = extEditorUI;
387         if (ui == null)
388             return;
389         JTextComponent JavaDoc comp = ui.getComponent();
390         if (comp == null)
391             return;
392         
393         if (isGlyphGutterMouseEvent(lastMouseEvent)) {
394             setToolTipText(extEditorUI.getGlyphGutter().getToolTipText(lastMouseEvent));
395         } else { // over the text component
396
BaseKit kit = Utilities.getKit(comp);
397             if (kit != null) {
398                 Action JavaDoc a = kit.getActionByName(ExtKit.buildToolTipAction);
399                 if (a != null) {
400                     a.actionPerformed(new ActionEvent JavaDoc(comp, 0, "")); // NOI18N
401
}
402             }
403         }
404     }
405
406     /** Set the visibility of the tooltip.
407      * @param visible whether tooltip should become visible or not.
408      * If true the status is changed
409      * to {@link { #STATUS_VISIBILITY_ENABLED}
410      * and @link #updateToolTip()} is called.<BR>
411      * It is still possible that the tooltip will not be showing
412      * on the screen in case the tooltip or tooltip text are left
413      * unchanged.
414      */

415     protected void setToolTipVisible(boolean visible) {
416         if (!visible) { // ensure the timers are stopped
417
enterTimer.stop();
418             exitTimer.stop();
419         }
420
421         if (visible && status < STATUS_VISIBILITY_ENABLED
422             || !visible && status >= STATUS_VISIBILITY_ENABLED
423         ) {
424             if (visible) { // try to show the tooltip
425
if (enabled) {
426                     setStatus(STATUS_VISIBILITY_ENABLED);
427                     updateToolTip();
428                 }
429
430             } else { // hide tip
431
if (toolTip != null) {
432                     if (toolTip.isVisible()){
433                         toolTip.setVisible(false);
434                         PopupManager pm = extEditorUI.getPopupManager();
435                         if (pm!=null){
436                             pm.uninstall(toolTip);
437                         }
438                     }
439                 }
440
441                 setStatus(STATUS_HIDDEN);
442             }
443         }
444     }
445     
446     /** @return Whether the tooltip is showing on the screen.
447      * {@link #getStatus() } gives the exact visibility state.
448      */

449     public boolean isToolTipVisible() {
450         return status > STATUS_VISIBILITY_ENABLED;
451     }
452     
453     /** @return status of the tooltip visibility. It can
454      * be {@link #STATUS_HIDDEN}
455      * or {@link #STATUS_VISIBILITY_ENABLED}
456      * or {@link #STATUS_TEXT_VISIBLE}
457      * or {@link #STATUS_COMPONENT_VISIBLE}.
458      */

459     public final int getStatus() {
460         return status;
461     }
462     
463     private void setStatus(int status) {
464         if (this.status != status) {
465             int oldStatus = this.status;
466             this.status = status;
467             firePropertyChange(PROP_STATUS,
468                 new Integer JavaDoc(oldStatus), new Integer JavaDoc(this.status));
469         }
470     }
471
472     /** @return the current tooltip text.
473      */

474     public String JavaDoc getToolTipText() {
475         return toolTipText;
476     }
477     
478     
479     
480     /**
481      * Makes the given String displayble. Probably there doesn't exists
482      * perfect solution for all situation. (someone prefer display those
483      * squares for undisplayable chars, someone unicode placeholders). So lets
484      * try do the best compromise.
485      */

486     private static String JavaDoc makeDisplayable(String JavaDoc str , Font JavaDoc f) {
487         if( str == null || f == null){
488             return str;
489         }
490         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(str.length());
491         char[] chars = str.toCharArray();
492         for (int i = 0; i < chars.length; i++) {
493             char c = chars[i];
494             switch (c) {
495                 case '\t': buf.append(c); break;
496                 case '\n': buf.append(c); break;
497                 case '\r': buf.append(c); break;
498                 case '\b': buf.append("\\b"); break; // NOI18N
499
case '\f': buf.append("\\f"); break; // NOI18N
500
default:
501                     if( f == null || f.canDisplay( c ) ){
502                         buf.append(c);
503                     } else {
504                         buf.append("\\u"); // NOI18N
505
String JavaDoc hex = Integer.toHexString(c);
506                         for (int j = 0; j < 4 - hex.length(); j++){
507                             buf.append('0'); //NOI18N
508
}
509                         buf.append(hex);
510                     }
511             }
512         }
513         return buf.toString();
514     }
515     
516     /** Set the tooltip text to make the tooltip
517      * to be shown on the screen.
518      * @param text tooltip text to be displayed.
519      */

520     public void setToolTipText(String JavaDoc text) {
521         
522         final String JavaDoc displayableText = makeDisplayable(text, UIManager.getFont(UI_PREFIX + ".font")); //NOI18N
523

524         Utilities.runInEventDispatchThread(new Runnable JavaDoc() {
525             public void run() {
526                 String JavaDoc oldText = toolTipText;
527                 toolTipText = displayableText;
528
529                 firePropertyChange(PROP_TOOL_TIP_TEXT, oldText, toolTipText);
530                 
531                 if (toolTipText != null) {
532                     JTextArea JavaDoc ta = createTextToolTip();
533                     ta.setText(toolTipText);
534                     setToolTip(ta);
535
536                 } else { // null text
537
if (status == STATUS_TEXT_VISIBLE) {
538                         setToolTipVisible(false);
539                     }
540                 }
541             }
542         });
543     }
544     
545     private void applyToolTipText() {
546         JComponent JavaDoc tt = getToolTip();
547         if (tt != null) {
548             if (tt instanceof JLabel JavaDoc) {
549                 ((JLabel JavaDoc)tt).setText(toolTipText);
550
551             } else if (tt instanceof JTextComponent JavaDoc) {
552                 ((JTextComponent JavaDoc)tt).setText(toolTipText);
553
554             } else if (tt instanceof javax.swing.JToolTip JavaDoc) {
555                 ((javax.swing.JToolTip JavaDoc)tt).setTipText(toolTipText);
556
557             } else {
558                 try {
559                     java.lang.reflect.Method JavaDoc m = tt.getClass().getMethod("setText", // NOI18N
560
new Class JavaDoc[] { String JavaDoc.class });
561                     if (m != null) {
562                         m.invoke(toolTip, new Object JavaDoc[] { toolTipText });
563                     }
564                 } catch (NoSuchMethodException JavaDoc e) {
565                 } catch (IllegalAccessException JavaDoc e) {
566                 } catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
567                 }
568             }
569         }
570     }
571     
572     private boolean isGlyphGutterMouseEvent(MouseEvent JavaDoc evt) {
573         return (evt != null && evt.getSource() == extEditorUI.getGlyphGutter());
574     }
575
576     private void ensureVisibility() {
577         // Find the visual position in the document
578
JTextComponent JavaDoc component = extEditorUI.getComponent();
579         if (component != null) {
580             // Try to display the tooltip above (or below) the line it corresponds to
581
int pos = component.viewToModel(getLastMouseEventPoint());
582             Rectangle JavaDoc cursorBounds = null;
583             if (pos >= 0) {
584                 try {
585                     cursorBounds = component.modelToView(pos);
586                     if (horizontalBounds == PopupManager.ScrollBarBounds){
587                         
588                     }else{
589                         if (placement == PopupManager.AbovePreferred || placement == PopupManager.Above){
590                             // Enlarge the height slightly to not interfere with mouse cursor
591
cursorBounds.y -= MOUSE_EXTRA_HEIGHT;
592                             cursorBounds.height += 2 * MOUSE_EXTRA_HEIGHT; // above and below
593
} else if (placement == PopupManager.BelowPreferred || placement == PopupManager.Below){
594                             cursorBounds.y = cursorBounds.y + cursorBounds.height + MOUSE_EXTRA_HEIGHT + 1;
595                             cursorBounds.height += MOUSE_EXTRA_HEIGHT; // above and below
596
}
597                     }
598
599                 } catch (BadLocationException JavaDoc e) {
600                 }
601             }
602             if (cursorBounds == null) { // get mose rect
603
cursorBounds = new Rectangle JavaDoc(getLastMouseEventPoint(), new Dimension JavaDoc(1, 1));
604             }
605
606             // updateToolTipBounds();
607
PopupManager pm = extEditorUI.getPopupManager();
608             
609             if (toolTip != null && toolTip.isVisible()) toolTip.setVisible(false);
610             pm.install(toolTip, cursorBounds, placement, horizontalBounds, horizontalAdjustment, verticalAdjustment);
611             if (toolTip != null) toolTip.setVisible(true);
612         }
613         exitTimer.restart();
614     }
615
616     /** Helper method to get the identifier
617      * under the mouse cursor.
618      * @return string containing identifier under
619      * mouse cursor.
620      */

621     public String JavaDoc getIdentifierUnderCursor() {
622         String JavaDoc word = null;
623         if (!isGlyphGutterMouseEvent(lastMouseEvent)) {
624             try {
625                 JTextComponent JavaDoc component = extEditorUI.getComponent();
626                 BaseTextUI ui = (BaseTextUI)component.getUI();
627                 Point JavaDoc lmePoint = getLastMouseEventPoint();
628                 int pos = ui.viewToModel(component, lmePoint);
629                 if (pos >= 0) {
630                     BaseDocument doc = (BaseDocument)component.getDocument();
631                     int eolPos = Utilities.getRowEnd(doc, pos);
632                     Rectangle JavaDoc eolRect = ui.modelToView(component, eolPos);
633                     int lineHeight = extEditorUI.getLineHeight();
634                     if (lmePoint.x <= eolRect.x && lmePoint.y <= eolRect.y + lineHeight) {
635                         word = Utilities.getIdentifier(doc, pos);
636                     }
637                 }
638             } catch (BadLocationException JavaDoc e) {
639                 // word will be null
640
}
641         }
642
643         return word;
644     }
645
646     /** @return whether the tooltip support is enabled. If it's
647      * disabled the tooltip does not become visible.
648      */

649     public boolean isEnabled() {
650         return enabled;
651     }
652     
653     /** Set whether the tooltip support is enabled. If it's
654      * disabled the tooltip does not become visible.
655      * @param enabled whether the tooltip will be enabled or not.
656      */

657     public void setEnabled(boolean enabled) {
658         if (enabled != this.enabled) {
659             this.enabled = enabled;
660
661             firePropertyChange(PROP_ENABLED,
662                 enabled ? Boolean.FALSE : Boolean.TRUE,
663                 enabled ? Boolean.TRUE : Boolean.FALSE
664             );
665
666             if (!enabled) {
667                 setToolTipVisible(false);
668             }
669         }
670     }
671
672     /** @return the delay between stopping
673      * mouse movement and displaying
674      * of the tooltip in milliseconds.
675      */

676     public int getInitialDelay() {
677         return enterTimer.getDelay();
678     }
679
680     /** Set the delay between stopping
681      * mouse movement and displaying
682      * of the tooltip in milliseconds.
683      */

684     public void setInitialDelay(int delay) {
685         if (enterTimer.getDelay() != delay) {
686             int oldDelay = enterTimer.getDelay();
687             enterTimer.setDelay(delay);
688
689             firePropertyChange(PROP_INITIAL_DELAY,
690                 new Integer JavaDoc(oldDelay), new Integer JavaDoc(enterTimer.getDelay()));
691         }
692     }
693
694     /** @return the delay between displaying
695      * of the tooltip and its automatic hiding
696      * in milliseconds.
697      */

698     public int getDismissDelay() {
699         return exitTimer.getDelay();
700     }
701
702     /** Set the delay between displaying
703      * of the tooltip and its automatic hiding
704      * in milliseconds.
705      */

706     public void setDismissDelay(int delay) {
707         if (exitTimer.getDelay() != delay) {
708             int oldDelay = exitTimer.getDelay();
709             exitTimer.setDelay(delay);
710             
711             firePropertyChange(PROP_DISMISS_DELAY,
712                 new Integer JavaDoc(oldDelay), new Integer JavaDoc(exitTimer.getDelay()));
713         }
714     }
715
716     public void actionPerformed(ActionEvent JavaDoc evt) {
717         if (evt.getSource() == enterTimer) {
718             setToolTipVisible(true);
719
720         } else if (evt.getSource() == exitTimer) {
721             setToolTipVisible(false);
722         }
723     }
724
725     public void mouseClicked(MouseEvent JavaDoc evt) {
726         lastMouseEvent = evt;
727         setToolTipVisible(false);
728     }
729
730     public void mousePressed(MouseEvent JavaDoc evt) {
731         lastMouseEvent = evt;
732         setToolTipVisible(false);
733     }
734
735     public void mouseReleased(MouseEvent JavaDoc evt) {
736         lastMouseEvent = evt;
737         setToolTipVisible(false);
738         
739         // Check that if a selection becomes visible by dragging a mouse
740
// the tooltip evaluation should be posted.
741
ExtEditorUI ui = extEditorUI;
742         if (ui != null) {
743             JTextComponent JavaDoc component = ui.getComponent();
744             if (enabled && component != null && component.getCaret().isSelectionVisible()) {
745                 enterTimer.restart();
746             }
747         }
748     }
749
750     public void mouseEntered(MouseEvent JavaDoc evt) {
751         lastMouseEvent = evt;
752     }
753
754     public void mouseExited(MouseEvent JavaDoc evt) {
755         lastMouseEvent = evt;
756         setToolTipVisible(false);
757     }
758
759     public void mouseDragged(MouseEvent JavaDoc evt) {
760         lastMouseEvent = evt;
761         setToolTipVisible(false);
762     }
763
764     public void mouseMoved(MouseEvent JavaDoc evt) {
765         setToolTipVisible(false);
766         if (enabled) {
767             enterTimer.restart();
768             
769         }
770         lastMouseEvent = evt;
771     }
772
773     /** @return last mouse event captured by this support.
774      * This method can be used by the action that evaluates
775      * the tooltip.
776      */

777     public final MouseEvent JavaDoc getLastMouseEvent() {
778         return lastMouseEvent;
779     }
780     
781     /** Possibly do translation when over the gutter.
782      */

783     private Point JavaDoc getLastMouseEventPoint() {
784         Point JavaDoc p = null;
785         MouseEvent JavaDoc lme = lastMouseEvent;
786         if (lme != null) {
787             p = lme.getPoint();
788             if (lme.getSource() == extEditorUI.getGlyphGutter()) {
789                 // Over glyph gutter - change coords
790
JTextComponent JavaDoc c = extEditorUI.getComponent();
791                 if (c != null) {
792                     if (c.getParent() instanceof JViewport JavaDoc) {
793                         JViewport JavaDoc vp = (JViewport JavaDoc)c.getParent();
794                         p = new Point JavaDoc(vp.getViewPosition().x, p.y);
795                     }
796                 }
797             }
798         }
799
800         return p;
801     }
802                 
803                 
804
805     /** Called automatically when the
806      * {@link javax.swing.JComponent#TOOL_TIP_TEXT_KEY}
807      * property of the corresponding editor component
808      * gets changed.<BR>
809      * By default it calls {@link #setToolTipText(java.lang.String)}
810      * with the new tooltip text of the component.
811      */

812     protected void componentToolTipTextChanged(PropertyChangeEvent JavaDoc evt) {
813         JComponent JavaDoc component = (JComponent JavaDoc)evt.getSource();
814         setToolTipText(component.getToolTipText());
815     }
816
817     private synchronized PropertyChangeSupport JavaDoc getPCS() {
818         if (pcs == null) {
819             pcs = new PropertyChangeSupport JavaDoc(this);
820         }
821         return pcs;
822     }
823
824     /** Add the listener for the property changes. The names
825      * of the supported properties are defined
826      * as "PROP_" public static string constants.
827      * @param listener listener to be added.
828      */

829     public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
830         getPCS().addPropertyChangeListener(listener);
831     }
832     
833     public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
834         getPCS().removePropertyChangeListener(listener);
835     }
836     
837     /** Fire the change of the given property.
838      * @param propertyName name of the fired property
839      * @param oldValue old value of the property
840      * @param newValue new value of the property.
841      */

842     protected void firePropertyChange(String JavaDoc propertyName,
843     Object JavaDoc oldValue, Object JavaDoc newValue) {
844         getPCS().firePropertyChange(propertyName, oldValue, newValue);
845     }
846     
847     public void focusGained(FocusEvent JavaDoc e) {
848 // JComponent component = (JComponent)e.getSource();
849
// component.addMouseListener(this);
850
// component.addMouseMotionListener(this);
851
GlyphGutter gg = extEditorUI.getGlyphGutter();
852         if (gg != null && !glyphListenerAdded) {
853             glyphListenerAdded = true;
854             gg.addMouseListener(this);
855             gg.addMouseMotionListener(this);
856         }
857     }
858
859     public void focusLost(FocusEvent JavaDoc e) {
860         /*
861         JComponent component = (JComponent)e.getSource();
862         component.removeMouseListener(this);
863         component.removeMouseMotionListener(this);
864         GlyphGutter gg = extEditorUI.getGlyphGutter();
865         if (gg != null) {
866             gg.removeMouseListener(this);
867             gg.removeMouseMotionListener(this);
868         }
869         setToolTipVisible(false);
870          */

871     }
872
873 }
874
Popular Tags