KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > editor > completion > DocumentationScrollPane


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
21 package org.netbeans.modules.editor.completion;
22
23 import java.awt.*;
24 import java.awt.event.ActionEvent JavaDoc;
25 import java.awt.event.InputEvent JavaDoc;
26 import java.awt.event.KeyEvent JavaDoc;
27 import java.awt.event.MouseAdapter JavaDoc;
28 import java.awt.event.MouseEvent JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.net.MalformedURLException JavaDoc;
31 import java.net.URL JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.List JavaDoc;
34 import javax.swing.*;
35 import javax.swing.event.HyperlinkEvent JavaDoc;
36 import javax.swing.event.HyperlinkListener JavaDoc;
37 import javax.swing.plaf.TextUI JavaDoc;
38 import javax.swing.text.EditorKit JavaDoc;
39 import javax.swing.text.JTextComponent JavaDoc;
40 import javax.swing.text.Keymap JavaDoc;
41 import javax.swing.text.html.HTMLDocument JavaDoc;
42
43 import org.netbeans.editor.*;
44 import org.netbeans.editor.ext.ExtKit;
45 import org.netbeans.spi.editor.completion.CompletionDocumentation;
46
47 import org.openide.awt.HtmlBrowser;
48 import org.openide.awt.StatusDisplayer;
49 import org.openide.util.NbBundle;
50
51 /**
52  *
53  * @author Martin Roskanin, Dusan Balek
54  */

55 public class DocumentationScrollPane extends JScrollPane {
56
57     private static final String JavaDoc BACK = "org/netbeans/modules/editor/completion/resources/back.png"; //NOI18N
58
private static final String JavaDoc FORWARD = "org/netbeans/modules/editor/completion/resources/forward.png"; //NOI18N
59
private static final String JavaDoc GOTO_SOURCE = "org/netbeans/modules/editor/completion/resources/open_source_in_editor.png"; //NOI18N
60
private static final String JavaDoc SHOW_WEB = "org/netbeans/modules/editor/completion/resources/open_in_external_browser.png"; //NOI18N
61

62     private static final String JavaDoc JAVADOC_ESCAPE = "javadoc-escape"; //NOI18N
63
private static final String JavaDoc JAVADOC_BACK = "javadoc-back"; //NOI18N
64
private static final String JavaDoc JAVADOC_FORWARD = "javadoc-forward"; //NOI18N
65
private static final String JavaDoc JAVADOC_OPEN_IN_BROWSER = "javadoc-open-in-browser"; //NOI18N
66
private static final String JavaDoc JAVADOC_OPEN_SOURCE = "javadoc-open-source"; //NOI18N
67

68     private static final int ACTION_JAVADOC_ESCAPE = 0;
69     private static final int ACTION_JAVADOC_BACK = 1;
70     private static final int ACTION_JAVADOC_FORWARD = 2;
71     private static final int ACTION_JAVADOC_OPEN_IN_BROWSER = 3;
72     private static final int ACTION_JAVADOC_OPEN_SOURCE = 4;
73
74     private JButton bBack, bForward, bGoToSource, bShowWeb;
75     private HTMLDocView view;
76     
77     // doc browser history
78
private List JavaDoc<CompletionDocumentation> history = new ArrayList JavaDoc<CompletionDocumentation>(5);
79     private int currentHistoryIndex = -1;
80     protected CompletionDocumentation currentDocumentation = null;
81     
82     private Dimension documentationPreferredSize;
83
84     /** Creates a new instance of ScrollJavaDocPane */
85     public DocumentationScrollPane(JTextComponent JavaDoc editorComponent) {
86         super();
87  
88         // Determine and use fixed preferred size
89
documentationPreferredSize = CompletionSettings.INSTANCE.documentationPopupPreferredSize();
90         setPreferredSize(null); // Use the documentationPopupPreferredSize
91

92         Color bgColor = CompletionSettings.INSTANCE.documentationBackgroundColor();
93
94         // Add the completion doc view
95
view = new HTMLDocView(bgColor);
96         view.addHyperlinkListener(new HyperlinkAction());
97         setViewportView(view);
98         
99         installTitleComponent();
100         installKeybindings(editorComponent);
101         setFocusable(false);
102     }
103     
104     public void setPreferredSize(Dimension preferredSize) {
105         if (preferredSize == null) {
106             preferredSize = documentationPreferredSize;
107         }
108         super.setPreferredSize(preferredSize);
109     }
110     
111     
112     public void setData(CompletionDocumentation doc) {
113         setDocumentation(doc);
114         addToHistory(doc);
115     }
116     
117     private ImageIcon resolveIcon(String JavaDoc res){
118         return new ImageIcon(org.openide.util.Utilities.loadImage (res));
119     }
120
121     private void installTitleComponent() {
122         JToolBar toolbar = new JToolBar();
123         toolbar.setFloatable(false);
124         toolbar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager.getColor("controlDkShadow"))); //NOI18N
125
toolbar.setLayout(new GridBagLayout());
126
127         GridBagConstraints gdc = new GridBagConstraints();
128         gdc.gridx = 0;
129         gdc.gridy = 0;
130         gdc.anchor = GridBagConstraints.WEST;
131         ImageIcon icon = resolveIcon(BACK);
132         if (icon != null) {
133             bBack = new BrowserButton(icon);
134             bBack.addMouseListener(new MouseEventListener(bBack));
135             bBack.setEnabled(false);
136             bBack.setFocusable(false);
137             bBack.setContentAreaFilled(false);
138             bBack.setMargin(new Insets(0, 0, 0, 0));
139             bBack.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_back_button")); //NOI18N
140
toolbar.add(bBack, gdc);
141         }
142         
143         gdc.gridx = 1;
144         gdc.gridy = 0;
145         gdc.anchor = GridBagConstraints.WEST;
146         icon = resolveIcon(FORWARD);
147         if (icon != null) {
148             bForward = new BrowserButton(icon);
149             bForward.addMouseListener(new MouseEventListener(bForward));
150             bForward.setEnabled(false);
151             bForward.setFocusable(false);
152             bForward.setContentAreaFilled(false);
153             bForward.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_forward_button")); //NOI18N
154
bForward.setMargin(new Insets(0, 0, 0, 0));
155             toolbar.add(bForward, gdc);
156         }
157         
158         gdc.gridx = 2;
159         gdc.gridy = 0;
160         gdc.anchor = GridBagConstraints.WEST;
161         icon = resolveIcon(SHOW_WEB);
162         if (icon != null) {
163             bShowWeb = new BrowserButton(icon);
164             bShowWeb.addMouseListener(new MouseEventListener(bShowWeb));
165             bShowWeb.setEnabled(false);
166             bShowWeb.setFocusable(false);
167             bShowWeb.setContentAreaFilled(false);
168             bShowWeb.setMargin(new Insets(0, 0, 0, 0));
169             bShowWeb.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_show_web_button")); //NOI18N
170
toolbar.add(bShowWeb, gdc);
171         }
172         
173         gdc.gridx = 3;
174         gdc.gridy = 0;
175         gdc.weightx = 1.0;
176         gdc.anchor = GridBagConstraints.WEST;
177         icon = resolveIcon(GOTO_SOURCE);
178         if (icon != null) {
179             bGoToSource = new BrowserButton(icon);
180             bGoToSource.addMouseListener(new MouseEventListener(bGoToSource));
181             bGoToSource.setEnabled(false);
182             bGoToSource.setFocusable(false);
183             bGoToSource.setContentAreaFilled(false);
184             bGoToSource.setMargin(new Insets(0, 0, 0, 0));
185             bGoToSource.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_goto_source_button")); //NOI18N
186
toolbar.add(bGoToSource, gdc);
187         }
188         setColumnHeaderView(toolbar);
189     }
190     
191     private synchronized void setDocumentation(CompletionDocumentation doc) {
192         currentDocumentation = doc;
193         String JavaDoc text = currentDocumentation.getText();
194         URL JavaDoc url = currentDocumentation.getURL();
195         if (text != null){
196             if (url!=null){
197                 // fix of issue #58658
198
javax.swing.text.Document JavaDoc document = view.getDocument();
199                 if (document instanceof HTMLDocument JavaDoc){
200                     ((HTMLDocument JavaDoc)document).setBase(url);
201                 }
202             }
203             if (currentDocumentation instanceof DefaultDoc) {
204                 String JavaDoc ref = ((DefaultDoc)currentDocumentation).desc;
205                 view.setContent(text, ref.startsWith("#") ? ref.substring(1) : null); //NOI18N
206
} else {
207                 view.setContent(text, null);
208             }
209         } else if (url != null){
210             try{
211                 view.setPage(url);
212             }catch(IOException JavaDoc ioe){
213                 StatusDisplayer.getDefault().setStatusText(ioe.toString());
214             }
215         }
216         bShowWeb.setEnabled(url != null);
217         bGoToSource.setEnabled(currentDocumentation.getGotoSourceAction() != null);
218     }
219     
220     private synchronized void addToHistory(CompletionDocumentation doc) {
221         int histSize = history.size();
222         for (int i = currentHistoryIndex + 1; i < histSize; i++){
223             history.remove(history.size() - 1);
224         }
225         history.add(doc);
226         currentHistoryIndex = history.size() - 1;
227         if (currentHistoryIndex > 0)
228             bBack.setEnabled(true);
229         bForward.setEnabled(false);
230     }
231     
232     private synchronized void backHistory() {
233         if (currentHistoryIndex > 0) {
234             currentHistoryIndex--;
235             setDocumentation(history.get(currentHistoryIndex));
236             if (currentHistoryIndex == 0)
237                 bBack.setEnabled(false);
238             bForward.setEnabled(true);
239         }
240     }
241     
242     private synchronized void forwardHistory(){
243         if (currentHistoryIndex <history.size()-1){
244             currentHistoryIndex++;
245             setDocumentation(history.get(currentHistoryIndex));
246             if (currentHistoryIndex == history.size() - 1)
247                 bForward.setEnabled(false);
248             bBack.setEnabled(true);
249         }
250     }
251     
252     synchronized void clearHistory(){
253         currentHistoryIndex = -1;
254         history.clear();
255         bBack.setEnabled(false);
256         bForward.setEnabled(false);
257     }
258
259     private void openInExternalBrowser(){
260         URL JavaDoc url = currentDocumentation.getURL();
261         if (url != null)
262             HtmlBrowser.URLDisplayer.getDefault().showURL(url);
263     }
264     
265     private void goToSource() {
266         Action action = currentDocumentation.getGotoSourceAction();
267         if (action != null)
268             action.actionPerformed(new ActionEvent JavaDoc(currentDocumentation, 0, null));
269     }
270
271     /** Attempt to find the editor keystroke for the given editor action. */
272     private KeyStroke[] findEditorKeys(String JavaDoc editorActionName, KeyStroke defaultKey, JTextComponent JavaDoc component) {
273         // This method is implemented due to the issue
274
// #25715 - Attempt to search keymap for the keybinding that logically corresponds to the action
275
KeyStroke[] ret = new KeyStroke[] { defaultKey };
276         if (component != null) {
277             TextUI JavaDoc ui = component.getUI();
278             Keymap JavaDoc km = component.getKeymap();
279             if (ui != null && km != null) {
280                 EditorKit JavaDoc kit = ui.getEditorKit(component);
281                 if (kit instanceof BaseKit) {
282                     Action a = ((BaseKit)kit).getActionByName(editorActionName);
283                     if (a != null) {
284                         KeyStroke[] keys = km.getKeyStrokesForAction(a);
285                         if (keys != null && keys.length > 0) {
286                             ret = keys;
287                         }
288                     }
289                 }
290             }
291         }
292         return ret;
293     }
294
295     private void registerKeybinding(int action, String JavaDoc actionName, KeyStroke stroke, String JavaDoc editorActionName, JTextComponent JavaDoc component){
296         KeyStroke[] keys = findEditorKeys(editorActionName, stroke, component);
297         for (int i = 0; i < keys.length; i++) {
298             getInputMap().put(keys[i], actionName);
299         }
300         getActionMap().put(actionName, new DocPaneAction(action));
301     }
302     
303     private void installKeybindings(JTextComponent JavaDoc component) {
304     // Register Escape key
305
registerKeybinding(ACTION_JAVADOC_ESCAPE, JAVADOC_ESCAPE,
306         KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
307         ExtKit.escapeAction, component);
308
309         // Register javadoc back key
310
registerKeybinding(ACTION_JAVADOC_BACK, JAVADOC_BACK,
311         KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.ALT_MASK),
312         null, component);
313
314         // Register javadoc forward key
315
registerKeybinding(ACTION_JAVADOC_FORWARD, JAVADOC_FORWARD,
316         KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.ALT_MASK),
317         null, component);
318
319         // Register open in external browser key
320
registerKeybinding(ACTION_JAVADOC_OPEN_IN_BROWSER, JAVADOC_OPEN_IN_BROWSER,
321         KeyStroke.getKeyStroke(KeyEvent.VK_F1, KeyEvent.ALT_MASK | KeyEvent.SHIFT_MASK),
322         null, component);
323
324         // Register open the source in editor key
325
registerKeybinding(ACTION_JAVADOC_OPEN_SOURCE, JAVADOC_OPEN_SOURCE,
326         KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK),
327         null, component);
328         
329         // Register movement keystrokes to be reachable through Shift+<orig-keystroke>
330
mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
331         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
332         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0));
333         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0));
334         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, KeyEvent.CTRL_MASK));
335         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK));
336         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
337         mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
338     }
339     
340     private void mapWithShift(KeyStroke key) {
341         InputMap inputMap = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
342         Object JavaDoc actionKey = inputMap.get(key);
343         if (actionKey != null) {
344             key = KeyStroke.getKeyStroke(key.getKeyCode(), key.getModifiers() | InputEvent.SHIFT_MASK);
345             getInputMap().put(key, actionKey);
346         }
347     }
348     
349     private class BrowserButton extends JButton {
350         public BrowserButton() {
351             setBorderPainted(false);
352             setFocusPainted(false);
353         }
354         
355         public BrowserButton(String JavaDoc text){
356             super(text);
357             setBorderPainted(false);
358             setFocusPainted(false);
359         }
360         
361         public BrowserButton(Icon icon){
362             super(icon);
363             setBorderPainted(false);
364             setFocusPainted(false);
365         }
366
367         public void setEnabled(boolean b) {
368             super.setEnabled(b);
369         }
370         
371         
372     }
373
374     private class MouseEventListener extends MouseAdapter JavaDoc {
375         private JButton button;
376         
377         MouseEventListener(JButton button) {
378             this.button = button;
379         }
380         
381         public void mouseEntered(MouseEvent JavaDoc ev) {
382             if (button.isEnabled()){
383                 button.setContentAreaFilled(true);
384                 button.setBorderPainted(true);
385             }
386         }
387         public void mouseExited(MouseEvent JavaDoc ev) {
388             button.setContentAreaFilled(false);
389             button.setBorderPainted(false);
390         }
391         
392         public void mouseClicked(MouseEvent JavaDoc evt) {
393             if (button.equals(bBack)){
394                 backHistory();
395             }else if(button.equals(bForward)){
396                 forwardHistory();
397             }else if(button.equals(bGoToSource)){
398                 goToSource();
399             }else if (button.equals(bShowWeb)){
400                 openInExternalBrowser();
401             }
402         }
403     }
404
405     private class HyperlinkAction implements HyperlinkListener JavaDoc {
406         
407         public void hyperlinkUpdate(HyperlinkEvent JavaDoc e) {
408             if (e != null && HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
409                 final String JavaDoc desc = e.getDescription();
410                 if (desc != null) {
411                     CompletionDocumentation doc = currentDocumentation.resolveLink(desc);
412                     if (doc == null)
413                         doc = new DefaultDoc(currentDocumentation, desc);
414                     setData(doc);
415                 }
416             }
417         }
418     }
419     
420     private class DefaultDoc implements CompletionDocumentation {
421         
422         private CompletionDocumentation baseDoc = null;
423         private URL JavaDoc url = null;
424         private String JavaDoc desc = null;
425         
426         private DefaultDoc(CompletionDocumentation baseDoc, String JavaDoc desc) {
427             try {
428                 url = new URL JavaDoc(baseDoc.getURL(), desc);
429             } catch (MalformedURLException JavaDoc ex) {
430                 this.baseDoc = baseDoc;
431                 this.desc = desc;
432             }
433         }
434     
435         public String JavaDoc getText() {
436             return baseDoc != null ? baseDoc.getText() : null;
437         }
438         
439         public URL JavaDoc getURL() {
440             return url;
441         }
442         
443         public CompletionDocumentation resolveLink(String JavaDoc link) {
444             return baseDoc != null ? baseDoc.resolveLink(link) : null;
445         }
446         
447         public Action getGotoSourceAction() {
448             return null;
449         }
450     }
451     
452     private class DocPaneAction extends AbstractAction {
453         private int action;
454         
455         private DocPaneAction(int action) {
456             this.action = action;
457         }
458         
459         public void actionPerformed(java.awt.event.ActionEvent JavaDoc actionEvent) {
460             switch (action) {
461         case ACTION_JAVADOC_ESCAPE:
462             CompletionImpl.get().hideDocumentation(false);
463             break;
464                 case ACTION_JAVADOC_BACK:
465                     backHistory();
466                     break;
467                 case ACTION_JAVADOC_FORWARD:
468                     forwardHistory();
469                     break;
470                 case ACTION_JAVADOC_OPEN_IN_BROWSER:
471                     openInExternalBrowser();
472                     break;
473                 case ACTION_JAVADOC_OPEN_SOURCE:
474                     goToSource();
475                     break;
476             }
477             
478         }
479     }
480 }
481
Popular Tags