KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > editor > hints > HintsUI


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.modules.editor.hints;
21
22 import java.awt.*;
23 import java.awt.event.AWTEventListener JavaDoc;
24 import java.awt.event.KeyEvent JavaDoc;
25 import java.awt.event.KeyListener JavaDoc;
26 import java.awt.event.MouseEvent JavaDoc;
27 import java.awt.event.MouseListener JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import java.util.logging.LogRecord JavaDoc;
30 import java.util.logging.Logger JavaDoc;
31 import javax.swing.*;
32 import javax.swing.border.LineBorder JavaDoc;
33 import javax.swing.event.ChangeEvent JavaDoc;
34 import javax.swing.event.ChangeListener JavaDoc;
35 import javax.swing.text.BadLocationException JavaDoc;
36 import javax.swing.text.Document JavaDoc;
37 import javax.swing.text.JTextComponent JavaDoc;
38 import javax.swing.text.Position JavaDoc;
39 import org.netbeans.editor.AnnotationDesc;
40 import org.netbeans.editor.Annotations;
41 import org.netbeans.editor.BaseDocument;
42 import org.netbeans.editor.Registry;
43 import org.netbeans.editor.Utilities;
44 import org.netbeans.modules.editor.hints.borrowed.ListCompletionView;
45 import org.netbeans.modules.editor.hints.borrowed.ScrollCompletionPane;
46 import org.netbeans.spi.editor.hints.ChangeInfo;
47 import org.netbeans.spi.editor.hints.Fix;
48 import org.netbeans.spi.editor.hints.LazyFixList;
49 import org.openide.ErrorManager;
50 import org.openide.cookies.EditCookie;
51 import org.openide.cookies.EditorCookie;
52 import org.openide.cookies.OpenCookie;
53 import org.openide.filesystems.FileObject;
54 import org.openide.loaders.DataObject;
55 import org.openide.loaders.DataObjectNotFoundException;
56 import org.openide.text.Annotation;
57 import org.openide.util.NbBundle;
58 import org.openide.util.RequestProcessor;
59 import org.openide.util.Task;
60 import org.openide.util.TaskListener;
61
62
63 /**
64  * Responsible for painting the things the user sees that indicate available
65  * hints.
66  *
67  * @author Tim Boudreau
68  */

69 public class HintsUI implements MouseListener JavaDoc, KeyListener JavaDoc, ChangeListener JavaDoc, AWTEventListener JavaDoc {
70     
71     private static HintsUI INSTANCE;
72     private static final String JavaDoc POPUP_NAME = "hintsPopup"; // NOI18N
73

74     public static synchronized HintsUI getDefault() {
75         if (INSTANCE == null)
76             INSTANCE = new HintsUI();
77         
78         return INSTANCE;
79     }
80     
81     static Logger JavaDoc UI_GESTURES_LOGGER = Logger.getLogger("org.netbeans.ui.editor.hints");
82     
83     private JTextComponent JavaDoc comp;
84     private LazyFixList hints = new StaticFixList();
85     private Popup listPopup;
86     private JLabel hintIcon;
87     private ScrollCompletionPane hintListComponent;
88     private JLabel errorTooltip;
89     
90     /** Creates a new instance of HintsUI */
91     private HintsUI() {
92         Registry.addChangeListener(this);
93         stateChanged(null);
94     }
95     
96     public JTextComponent JavaDoc getComponent() {
97         return comp;
98     }
99     
100     public void setHints (LazyFixList hints, JTextComponent JavaDoc comp, boolean showPopup) {
101         if (this.hints.equals(hints) && this.comp == comp) {
102             return;
103         }
104         if (comp != this.comp || !this.hints.equals(hints) && comp != null) {
105             removePopups();
106         }
107         boolean show = hints != null && comp != null/* && !hints.isEmpty()*/;
108         if (!show && this.comp != null) {
109             removePopups();
110         }
111         this.hints = hints == null ? new StaticFixList() : hints;
112         setComponent (comp);
113         if (show) {
114             showHints();
115             if (showPopup) {
116                 showPopup();
117             }
118         }
119     }
120     
121     public void setComponent (JTextComponent JavaDoc comp) {
122         boolean change = this.comp != comp;
123         if (change) {
124             unregister();
125             this.comp = comp;
126             register();
127         }
128     }
129     
130     private void register() {
131         if (comp == null) {
132             return;
133         }
134         comp.addKeyListener (this);
135     }
136     
137     private void unregister() {
138         if (comp == null) {
139             return;
140         }
141         comp.removeKeyListener (this);
142     }
143     
144     
145     public void removePopups() {
146         if (comp == null) {
147             return;
148         }
149         removeIconHint();
150         removePopup();
151     }
152     
153     private void removeIconHint() {
154         if (hintIcon != null) {
155             Container c = hintIcon.getParent();
156             if (c != null) {
157                 Rectangle bds = hintIcon.getBounds();
158                 c.remove (hintIcon);
159                 c.repaint (bds.x, bds.y, bds.width, bds.height);
160             }
161         }
162     }
163     
164     private void removePopup() {
165         Toolkit.getDefaultToolkit().removeAWTEventListener(this);
166         if (listPopup != null) {
167             listPopup.hide();
168             if (hintListComponent != null) {
169                 hintListComponent.getView().removeMouseListener(this);
170             }
171             if (errorTooltip != null) {
172                 errorTooltip.removeMouseListener(this);
173             }
174             hintListComponent = null;
175             errorTooltip = null;
176             listPopup = null;
177             if (hintIcon != null)
178                 hintIcon.setToolTipText(NbBundle.getMessage(HintsUI.class, "HINT_Bulb")); // NOI18N
179
}
180     }
181     
182     boolean isKnownComponent(Component JavaDoc c) {
183         return c != null &&
184                (c == comp
185                 || c == hintIcon
186                 || c == hintListComponent
187                 || (c instanceof Container && ((Container)c).isAncestorOf(hintListComponent))
188                 )
189         ;
190     }
191     
192     private void showHints() {
193         if (comp == null || !comp.isDisplayable() || !comp.isShowing()) {
194             return;
195         }
196         configureBounds (getHintIcon());
197     }
198     
199     private void configureBounds (JComponent jc) {
200         JRootPane pane = comp.getRootPane();
201         JLayeredPane lp = pane.getLayeredPane();
202         Rectangle r = null;
203         try {
204             int pos = javax.swing.text.Utilities.getRowStart(comp, comp.getCaret().getDot());
205             r = comp.modelToView (pos);
206         } catch (BadLocationException JavaDoc e) {
207             setHints (null, null, false);
208             ErrorManager.getDefault().notify (e);
209             return;
210         }
211         Point p = new Point(r.x - comp.getX(), r.y );
212          
213         Dimension d = jc.getPreferredSize();
214         
215         SwingUtilities.convertPointToScreen(p, comp);
216         SwingUtilities.convertPointFromScreen(p, lp);
217         jc.setBounds (p.x, p.y, d.width, d.height);
218         lp.add (jc, JLayeredPane.POPUP_LAYER);
219         jc.setVisible(true);
220         jc.repaint();
221     }
222     
223     private JLabel getHintIcon() {
224         if (hintIcon == null) {
225             hintIcon = new JLabel();
226             hintIcon.addMouseListener (this);
227             hintIcon.setToolTipText(NbBundle.getMessage(HintsUI.class, "HINT_Bulb")); // NOI18N
228
}
229         String JavaDoc iconBase =
230                 "org/netbeans/modules/editor/hints/resources/error.png"; //NOI18N
231
hintIcon.setIcon (new ImageIcon (org.openide.util.Utilities.loadImage(iconBase)));
232         return hintIcon;
233     }
234     
235     public void showPopup() {
236         if (comp == null || (hints.isComputed() && hints.getFixes().isEmpty())) {
237             return;
238         }
239         if (hintIcon != null)
240             hintIcon.setToolTipText(null);
241         // be sure that hint will hide when popup is showing
242
ToolTipManager.sharedInstance().setEnabled(false);
243         ToolTipManager.sharedInstance().setEnabled(true);
244         assert hintListComponent == null;
245         hintListComponent =
246                 new ScrollCompletionPane(comp, hints, null, null);
247         
248         hintListComponent.getView().addMouseListener (this);
249         hintListComponent.setName(POPUP_NAME);
250         Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK);
251         
252         try {
253             int pos = javax.swing.text.Utilities.getRowStart(comp, comp.getCaret().getDot());
254             Rectangle r = comp.modelToView (pos);
255
256             Point p = new Point (r.x + 5, r.y + 20);
257             SwingUtilities.convertPointToScreen(p, comp);
258             
259             assert listPopup == null;
260             listPopup = getPopupFactory().getPopup(
261                     comp, hintListComponent, p.x, p.y);
262             listPopup.show();
263         } catch (BadLocationException JavaDoc ble) {
264             ErrorManager.getDefault().notify (ble);
265             setHints (null, null, false);
266         }
267     }
268     
269     public void showPopup(LazyFixList fixes, String JavaDoc description, JTextComponent JavaDoc component, Point position) {
270         setHints(null, null, false);
271         setComponent(component);
272         
273         if (comp == null || fixes == null)
274             return ;
275
276         this.hints = fixes;
277         
278         Point p = new Point(position);
279         SwingUtilities.convertPointToScreen(p, comp);
280         
281         if (hintIcon != null)
282             hintIcon.setToolTipText(null);
283         // be sure that hint will hide when popup is showing
284
ToolTipManager.sharedInstance().setEnabled(false);
285         ToolTipManager.sharedInstance().setEnabled(true);
286         Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK);
287         
288         if (!fixes.isComputed() || fixes.getFixes().isEmpty()) {
289             //show tooltip:
290
assert listPopup == null;
291             errorTooltip = new JLabel("<html>" + translate(description)); // NOI18N
292
errorTooltip.setBorder(new LineBorder JavaDoc(Color.BLACK));
293             errorTooltip.addMouseListener(this);
294             
295             listPopup = getPopupFactory().getPopup(
296                     comp, errorTooltip, p.x, p.y);
297         } else {
298             assert hintListComponent == null;
299             hintListComponent =
300                     new ScrollCompletionPane(comp, fixes, null, null);
301             
302             hintListComponent.getView().addMouseListener (this);
303             hintListComponent.setName(POPUP_NAME);
304             assert listPopup == null;
305             listPopup = getPopupFactory().getPopup(
306                     comp, hintListComponent, p.x, p.y);
307         }
308         
309         listPopup.show();
310     }
311     
312     private PopupFactory pf = null;
313     private PopupFactory getPopupFactory() {
314         if (pf == null) {
315             pf = PopupFactory.getSharedInstance();
316         }
317         return pf;
318     }
319
320     public void mouseClicked(java.awt.event.MouseEvent JavaDoc e) {
321         if (e.getSource() == hintListComponent || e.getSource() instanceof ListCompletionView) {
322             Fix f = null;
323             Object JavaDoc selected = hintListComponent.getView().getSelectedValue();
324             
325             if (selected instanceof Fix) {
326                 f = (Fix) selected;
327             }
328             
329             if (f != null) {
330                 JTextComponent JavaDoc c = this.comp;
331                 invokeHint (f);
332                 setHints (null, null, false);
333                 //the component was reset when setHints was called, set it back so further hints will work:
334
setComponent(c);
335             }
336         }
337     }
338
339     public void mouseEntered(java.awt.event.MouseEvent JavaDoc e) {
340     }
341
342     public void mouseExited(java.awt.event.MouseEvent JavaDoc e) {
343     }
344
345     public void mousePressed(java.awt.event.MouseEvent JavaDoc e) {
346         if (e.getSource() instanceof JLabel) {
347             if (!isPopupActive()) {
348                 showPopup();
349             }
350         }
351     }
352
353     public void mouseReleased(java.awt.event.MouseEvent JavaDoc e) {
354     }
355     
356     public boolean isActive() {
357         boolean bulbShowing = hintIcon != null && hintIcon.isShowing();
358         boolean popupShowing = hintListComponent != null && hintListComponent.isShowing();
359         return bulbShowing || popupShowing;
360     }
361     
362     public boolean isPopupActive() {
363         return hintListComponent != null && hintListComponent.isShowing();
364     }
365     
366     private ParseErrorAnnotation findAnnotation(Document JavaDoc doc, AnnotationDesc desc, int lineNum) {
367         DataObject od = (DataObject) doc.getProperty(Document.StreamDescriptionProperty);
368         
369         if (od == null)
370             return null;
371         
372         AnnotationHolder annotations = AnnotationHolder.getInstance(od.getPrimaryFile());
373         
374         for (Annotation a : annotations.getAnnotations()) {
375             if (a instanceof ParseErrorAnnotation) {
376                 ParseErrorAnnotation pa = (ParseErrorAnnotation) a;
377                 
378                 if (lineNum == pa.getLineNumber()
379                         && org.openide.util.Utilities.compareObjects(desc.getShortDescription(), a.getShortDescription())) {
380                     return pa;
381                 }
382             }
383         }
384         
385         return null;
386     }
387     
388     boolean invokeDefaultAction() {
389         if (comp == null) {
390             Logger.getLogger(HintsUI.class.getName()).log(Level.WARNING, "HintsUI.invokeDefaultAction called, but comp == null");
391             return false;
392         }
393         
394         Document JavaDoc doc = comp.getDocument();
395         
396         if (doc instanceof BaseDocument) {
397             Annotations annotations = ((BaseDocument) doc).getAnnotations();
398
399             try {
400                 Rectangle carretRectangle = comp.modelToView(comp.getCaretPosition());
401                 int line = Utilities.getLineOffset((BaseDocument) doc, comp.getCaretPosition());
402                 AnnotationDesc desc = annotations.getActiveAnnotation(line);
403                 Point p = comp.modelToView(Utilities.getRowStartFromLineOffset((BaseDocument) doc, line)).getLocation();
404                 p.y += carretRectangle.height;
405                 ParseErrorAnnotation annotation = findAnnotation(doc, desc, line);
406                 
407                 if (annotation == null)
408                     return false;
409                 
410                 showPopup(annotation.getFixes(), annotation.getDescription(), comp, p);
411                 
412                 return true;
413             } catch (BadLocationException JavaDoc ex) {
414                 ErrorManager.getDefault().notify(ex);
415             }
416         }
417         
418         return false;
419     }
420     
421     public void keyPressed(KeyEvent JavaDoc e) {
422         if (comp == null) {
423             return;
424         }
425         boolean bulbShowing = hintIcon != null && hintIcon.isShowing();
426         boolean errorTooltipShowing = errorTooltip != null && errorTooltip.isShowing();
427         
428         if (errorTooltipShowing) {
429             //any key should disable the errorTooltip:
430
removePopup();
431             return ;
432         }
433         boolean popupShowing = hintListComponent != null && hintListComponent.isShowing();
434         if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
435             if ( e.getModifiersEx() == (KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)
436                 || e.getModifiersEx() == KeyEvent.ALT_DOWN_MASK) {
437                 if ( !popupShowing) {
438                     invokeDefaultAction();
439                     e.consume();
440                 }
441             } else if ( e.getModifiersEx() == 0 ) {
442                 if (popupShowing) {
443                     Fix f = null;
444                     Object JavaDoc selected = hintListComponent.getView().getSelectedValue();
445                     
446                     if (selected instanceof Fix) {
447                         f = (Fix) selected;
448                     }
449                     
450                     if (f != null) {
451                         invokeHint(f);
452                     }
453                     
454                     e.consume();
455                 }
456             }
457         } else if ( e.getKeyCode() == KeyEvent.VK_ESCAPE ) {
458             if ( popupShowing ) {
459                 removePopup();
460             }
461         } else if ( popupShowing ) {
462             InputMap input = hintListComponent.getInputMap();
463             Object JavaDoc actionTag = input.get(KeyStroke.getKeyStrokeForEvent(e));
464             if (actionTag != null) {
465                 Action a = hintListComponent.getActionMap().get(actionTag);
466                 a.actionPerformed(null);
467                 e.consume();
468                 return ;
469             }
470         }
471     }
472
473     public void keyReleased(KeyEvent JavaDoc e) {
474     }
475
476     public void keyTyped(KeyEvent JavaDoc e) {
477     }
478     
479     private ChangeInfo changes;
480     
481     private void invokeHint (final Fix f) {
482         if (UI_GESTURES_LOGGER.isLoggable(Level.FINE)) {
483             LogRecord JavaDoc rec = new LogRecord JavaDoc(Level.FINE, "GEST_HINT_INVOKED");
484             
485             rec.setResourceBundle(NbBundle.getBundle(HintsUI.class));
486             rec.setParameters(new Object JavaDoc[] {f.getText()});
487             UI_GESTURES_LOGGER.log(rec);
488         }
489         
490         removePopups();
491         final JTextComponent JavaDoc component = comp;
492         final Cursor cur = component.getCursor();
493         component.setCursor (Cursor.getPredefinedCursor (Cursor.WAIT_CURSOR));
494         Task t = null;
495         try {
496             t = RequestProcessor.getDefault().post(new Runnable JavaDoc() {
497                 public void run() {
498                     changes = f.implement();
499                 }
500             });
501         } finally {
502             if (t != null) {
503                 t.addTaskListener(new TaskListener() {
504                     public void taskFinished(Task task) {
505                         SwingUtilities.invokeLater(new Runnable JavaDoc() {
506                             public void run() {
507                                 open(changes, component);
508                                 component.setCursor (cur);
509                             }
510                         });
511                     }
512                 });
513             }
514         }
515     }
516     
517     private static void open(ChangeInfo changes, JTextComponent JavaDoc component) {
518         JTextComponent JavaDoc c = component;
519         if (changes != null && changes.size() > 0) {
520             ChangeInfo.Change change = changes.get(0);
521             FileObject file = change.getFileObject();
522             if (file != null) {
523                 try {
524                     DataObject dob =
525                         DataObject.find (file);
526
527                     EditCookie ck = dob.getCookie(EditCookie.class);
528
529                     if (ck != null) {
530                         //Try EditCookie first so we don't open the form
531
//editor
532
ck.edit();
533                     } else {
534                         OpenCookie oc = dob.getCookie(OpenCookie.class);
535
536                         oc.open();
537                     }
538                     EditorCookie edit = dob.getCookie(EditorCookie.class);
539
540                     JEditorPane[] panes = edit.getOpenedPanes();
541                     if (panes != null && panes.length > 0) {
542                         c = panes[0];
543                     } else {
544                         return;
545                     }
546
547                 } catch (DataObjectNotFoundException donfe) {
548                     ErrorManager.getDefault().notify(donfe);
549                     return;
550                 }
551             }
552             /////////////////////////////////
553
Position JavaDoc start = change.getStart();
554             Position JavaDoc end = change.getEnd();
555             if (start != null) {
556                 c.setSelectionStart(start.getOffset());
557             }
558             if (end != null) {
559                 c.setSelectionEnd(end.getOffset());
560             }
561         }
562     }
563
564     public void stateChanged(ChangeEvent JavaDoc e) {
565         JTextComponent JavaDoc active = Registry.getMostActiveComponent();
566         
567         if (getComponent() != active) {
568             setHints(null, null, false);
569             setComponent(active);
570         }
571     }
572     
573     public void eventDispatched(java.awt.AWTEvent JavaDoc aWTEvent) {
574         if (aWTEvent instanceof MouseEvent JavaDoc) {
575             MouseEvent JavaDoc mv = (MouseEvent JavaDoc)aWTEvent;
576             if (mv.getID() == MouseEvent.MOUSE_CLICKED && mv.getClickCount() > 0) {
577                 Component JavaDoc comp = (Component JavaDoc)aWTEvent.getSource();
578                 Container par = SwingUtilities.getAncestorNamed(POPUP_NAME, comp); //NOI18N
579
// Container barpar = SwingUtilities.getAncestorOfClass(PopupUtil.class, comp);
580
// if (par == null && barpar == null) {
581
if ( par == null ) {
582                     removePopup();
583                 }
584             }
585         }
586     }
587
588     private static String JavaDoc[] c = new String JavaDoc[] {"&", "<", ">", "\n", "\""}; // NOI18N
589
private static String JavaDoc[] tags = new String JavaDoc[] {"&amp;", "&lt;", "&gt;", "<br>", "&quot;"}; // NOI18N
590

591     private String JavaDoc translate(String JavaDoc input) {
592         for (int cntr = 0; cntr < c.length; cntr++) {
593             input = input.replaceAll(c[cntr], tags[cntr]);
594         }
595         
596         return input;
597     }
598     
599 }
600
Popular Tags