001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.editor.ext;
043:
044: import java.awt.Component;
045: import java.awt.Dimension;
046: import java.awt.Rectangle;
047: import java.beans.PropertyChangeEvent;
048: import java.beans.PropertyChangeListener;
049: import java.awt.event.KeyEvent;
050: import java.awt.event.FocusListener;
051: import java.awt.event.FocusAdapter;
052: import java.awt.event.FocusEvent;
053: import java.awt.event.ActionListener;
054: import java.awt.event.ActionEvent;
055:
056: import javax.swing.JComponent;
057: import javax.swing.JPanel;
058: import javax.swing.text.JTextComponent;
059: import javax.swing.KeyStroke;
060: import javax.swing.SwingUtilities;
061: import javax.swing.Action;
062: import javax.swing.AbstractAction;
063:
064: import org.netbeans.editor.PopupManager;
065: import org.netbeans.editor.ext.ExtEditorUI;
066: import org.netbeans.editor.Utilities;
067: import org.netbeans.editor.BaseKit;
068: import org.netbeans.editor.ext.CompletionJavaDoc;
069: import org.netbeans.editor.ext.ExtKit;
070: import javax.swing.plaf.TextUI;
071: import javax.swing.text.Keymap;
072: import javax.swing.text.EditorKit;
073: import java.util.Iterator;
074: import java.util.ArrayList;
075: import java.util.List;
076: import org.netbeans.editor.SettingsChangeEvent;
077: import org.netbeans.editor.SettingsChangeListener;
078: import org.netbeans.editor.Settings;
079:
080: /**
081: * Invisible panel that contains code completion panel and javadoc panel,
082: * computes preferred size and provides access to these both components.
083: *
084: * @author Martin Roskanin
085: * @since 03/2002
086: */
087: public class JDCPopupPanel extends JPanel implements
088: PropertyChangeListener, SettingsChangeListener {
089:
090: private ExtCompletionPane completion;
091:
092: private ExtEditorUI extEditorUI;
093: private FocusListener focusL;
094: private List keyActionPairsList;
095:
096: // Completion can create documentation pane
097: //private Completion documentationProvider;
098: private JavaDocPane javadoc;
099: // last size of completion result
100: private int lastSize = -1;
101:
102: // gap between javadoc and code completion window
103: private static final int WINDOW_GAP = 1;
104:
105: private static final String POPUP_HIDE = "jdc-popup-hide"; //NOI18N
106:
107: private static final String COMPLETION_UP = "completion-up"; //NOI18N
108: private static final String COMPLETION_DOWN = "completion-down"; //NOI18N
109: private static final String COMPLETION_PGUP = "completion-pgup"; //NOI18N
110: private static final String COMPLETION_PGDN = "completion-pgdn"; //NOI18N
111: private static final String COMPLETION_BEGIN = "completion-begin"; //NOI18N
112: private static final String COMPLETION_END = "completion-end"; //NOI18N
113:
114: private static final String JAVADOC_UP = "javadoc-up"; //NOI18N
115: private static final String JAVADOC_DOWN = "javadoc-down"; //NOI18N
116: private static final String JAVADOC_PGUP = "javadoc-pgup"; //NOI18N
117: private static final String JAVADOC_PGDN = "javadoc-pgdn"; //NOI18N
118: private static final String JAVADOC_BEGIN = "javadoc-begin"; //NOI18N
119: private static final String JAVADOC_END = "javadoc-end"; //NOI18N
120: private static final String JAVADOC_LEFT = "javadoc-left"; //NOI18N
121: private static final String JAVADOC_RIGHT = "javadoc-right"; //NOI18N
122: private static final String JAVADOC_BACK = "javadoc-back"; //NOI18N
123: private static final String JAVADOC_FORWARD = "javadoc-forward"; //NOI18N
124: private static final String JAVADOC_OPEN_IN_BROWSER = "javadoc-open-in-browser"; //NOI18N
125: private static final String JAVADOC_OPEN_SOURCE = "javadoc-open-source"; //NOI18N
126:
127: public static final String COMPLETION_SUBSTITUTE_TEXT = "completion-substitute-text"; //NOI18N
128: public static final String COMPLETION_SUBSTITUTE_TEXT_SIMPLE = "completion-substitute-text-simple"; //NOI18N
129: private static final String COMPLETION_SUBSTITUTE_TEXT_KEEP_POPUP_OPEN = "completion-substitute-text-keep-popup-open"; //NOI18N
130: private static final String COMPLETION_SUBSTITUTE_COMMON_TEXT = "completion-substitutecommon-text"; //NOI18N
131:
132: private static final int ACTION_POPUP_HIDE = 1;
133:
134: private static final int ACTION_COMPLETION_UP = 2;
135: private static final int ACTION_COMPLETION_DOWN = 3;
136: private static final int ACTION_COMPLETION_PGUP = 4;
137: private static final int ACTION_COMPLETION_PGDN = 5;
138: private static final int ACTION_COMPLETION_BEGIN = 6;
139: private static final int ACTION_COMPLETION_END = 7;
140:
141: private static final int ACTION_JAVADOC_UP = 8;
142: private static final int ACTION_JAVADOC_DOWN = 9;
143: private static final int ACTION_JAVADOC_PGUP = 10;
144: private static final int ACTION_JAVADOC_PGDN = 11;
145: private static final int ACTION_JAVADOC_BEGIN = 12;
146: private static final int ACTION_JAVADOC_END = 13;
147: private static final int ACTION_JAVADOC_LEFT = 14;
148: private static final int ACTION_JAVADOC_RIGHT = 15;
149: private static final int ACTION_JAVADOC_BACK = 16;
150: private static final int ACTION_JAVADOC_FORWARD = 17;
151: private static final int ACTION_JAVADOC_OPEN_IN_BROWSER = 18;
152: private static final int ACTION_JAVADOC_OPEN_SOURCE = 19;
153:
154: private static final int ACTION_COMPLETION_SUBSTITUTE_TEXT = 20;
155: private static final int ACTION_COMPLETION_SUBSTITUTE_TEXT_SIMPLE = 21;
156: private static final int ACTION_COMPLETION_SUBSTITUTE_TEXT_KEEP_POPUP_OPEN = 22;
157: private static final int ACTION_COMPLETION_SUBSTITUTE_COMMON_TEXT = 23;
158:
159: /** Creates a new instance of JDCPopupPanel */
160: public JDCPopupPanel(ExtEditorUI extEditorUI,
161: ExtCompletionPane completion,
162: Completion documentationProvider) {
163: super ();
164: this .completion = completion;
165: //this.documentationProvider = documentationProvider;
166: this .extEditorUI = extEditorUI;
167: this .keyActionPairsList = new ArrayList();
168:
169: setLayout(null);
170: setOpaque(false); // make panel background invisible
171:
172: focusL = new FocusAdapter() {
173: public void focusLost(FocusEvent evt) {
174: SwingUtilities.invokeLater(new Runnable() {
175: public void run() {
176: if (isVisible()) {
177: JTextComponent component = JDCPopupPanel.this .extEditorUI
178: .getComponent();
179: if (component != null) {
180: java.awt.Window w = SwingUtilities
181: .windowForComponent(component);
182: Component focusOwner = (w == null) ? null
183: : w.getFocusOwner();
184:
185: if (focusOwner == null) {
186: setVisible(false);
187: }
188:
189: boolean docO = javadoc != null
190: && focusOwner == JDCPopupPanel.this
191: .getJavaDocView();
192: boolean docA = javadoc != null
193: && JDCPopupPanel.this
194: .getJavaDocPane()
195: .getComponent()
196: .isAncestorOf(
197: focusOwner);
198: boolean comO = focusOwner == JDCPopupPanel.this
199: .getCompletionView();
200: if (docO || comO || docA) {
201: component.requestFocus();
202: } else if (focusOwner != component) {
203: setVisible(false); // completion, javadoc and component don't own the focus
204: }
205: }
206: }
207: }
208: });
209: }
210: };
211:
212: synchronized (extEditorUI.getComponentLock()) {
213: // if component already installed in ExtEditorUI simulate installation
214: JTextComponent component = extEditorUI.getComponent();
215: if (component != null) {
216: propertyChange(new PropertyChangeEvent(extEditorUI,
217: ExtEditorUI.COMPONENT_PROPERTY, null, component));
218: }
219: extEditorUI.addPropertyChangeListener(this );
220: }
221:
222: super .setVisible(false);
223:
224: Settings.addSettingsChangeListener(this );
225: }
226:
227: /** Returns completion pane */
228: public ExtCompletionPane getCompletionPane() {
229: return completion;
230: }
231:
232: private void clearJavadocContent() {
233: CompletionJavaDoc cjd = extEditorUI.getCompletionJavaDoc();
234: if (cjd != null) {
235: cjd.clearContent();
236: }
237: }
238:
239: private JavaDocView getJavaDocView() {
240: CompletionJavaDoc cjd = extEditorUI.getCompletionJavaDoc();
241: if (cjd != null) {
242: return cjd.getJavaDocView();
243: }
244: return null;
245: }
246:
247: private CompletionView getCompletionView() {
248: Completion c = extEditorUI.getCompletion();
249: if (c != null) {
250: return c.getView();
251: }
252: return null;
253: }
254:
255: /** Returns javadoc pane */
256: public JavaDocPane getJavaDocPane() {
257: if (javadoc == null) {
258: Completion c = extEditorUI.getCompletion();
259: if (c != null) {
260: javadoc = c.getJavaDocPane();
261: }
262: }
263: return javadoc;
264: }
265:
266: /** Returns minimum size that this component can occupy. Because javadoc can be omitted,
267: * the minimum size is the minimum size of code completion */
268: public Dimension getMinimumSize() {
269: return completion.getComponent().getMinimumSize();
270: }
271:
272: /** Returns the maximum size of this component. Maximum size is computed from
273: * javadoc's and completion's maximum size */
274: public Dimension getMaximumSize() {
275: Dimension compDim = completion.getComponent().getMaximumSize();
276: Dimension javadocDim = new Dimension();
277: if (javadoc != null) {
278: javadocDim = javadoc.getComponent().getMaximumSize();
279: }
280: return new Dimension(Math.max(compDim.width, javadocDim.width),
281: compDim.height + javadocDim.height);
282: }
283:
284: /** Returns the preferred size of this component. Preferred size is computed from
285: * javadoc's and completion's preferred size trimmed to fit maximum size */
286: public Dimension getPreferredSize() {
287: Dimension ret = new Dimension();
288: Dimension compPref = completion.getComponent()
289: .getPreferredSize();
290: Dimension compMax = completion.getComponent().getMaximumSize();
291:
292: Dimension javadocPref = new Dimension();
293: Dimension javadocMax = new Dimension();
294: if (javadoc != null) {
295: javadocPref = javadoc.getComponent().getPreferredSize();
296: javadocMax = javadoc.getComponent().getMaximumSize();
297: }
298:
299: ret.width = Math.min(compPref.width, compMax.width)
300: + Math.min(javadocPref.width, javadocMax.width);
301: ret.height = Math.min(compPref.height, compMax.height)
302: + Math.min(javadocPref.height, javadocMax.height);
303:
304: return ret;
305: }
306:
307: /** Sets completion pane visiblility */
308: public void setCompletionVisible(boolean visible) {
309: completion.setVisible(visible);
310: setVisible(visible);
311: }
312:
313: /** Sets javadoc pane visibility */
314: public void setJavaDocVisible(boolean visible) {
315: getJavaDocPane().getComponent().setVisible(visible);
316: if (visible || !getCompletionPane().isVisible()) {
317: setVisible(visible);
318: }
319: }
320:
321: /** Sets this popup comonent visibility */
322: public void setVisible(boolean visible) {
323: if (visible) {
324: if (Utilities.getLastActiveComponent() != extEditorUI
325: .getComponent()) {
326: return; // bugfix of #43230
327: }
328:
329: boolean docv = javadoc != null
330: && javadoc.getComponent().isVisible();
331: Completion c = extEditorUI.getCompletion();
332: if (c != null) {
333: CompletionQuery.Result result = c.getLastResult();
334: int resultSize = (result == null) ? -1 : result
335: .getData().size();
336: if (lastSize != resultSize || !isVisible() || docv) {
337: extEditorUI.getPopupManager().install(this );
338: lastSize = resultSize;
339: }
340: }
341: if (docv || completion.isVisible()) {
342: super .setVisible(visible);
343: }
344: } else {
345: lastSize = -1;
346: clearJavadocContent();
347: Completion c = extEditorUI.getCompletion();
348: if (c != null) {
349: c.completionCancel();
350: }
351: if (javadoc != null) {
352: javadoc.getComponent().setVisible(visible);
353: }
354: completion.getComponent().setVisible(visible);
355: super .setVisible(visible);
356: PopupManager pm = extEditorUI.getPopupManager();
357: if (pm != null)
358: pm.uninstall(this );
359: }
360: }
361:
362: /** Setting size of popup panel. The height and size is computed to fit the best place on the screen */
363: public void setSize(int width, int height) {
364: PopupManager.Placement placement = (PopupManager.Placement) getClientProperty(PopupManager.Placement.class);
365:
366: Dimension completionMinSize = completion.getComponent()
367: .getMinimumSize();
368: if (completionMinSize.height > height) { // cannot fit
369: putClientProperty(PopupManager.Placement.class, null);
370: }
371:
372: // first we will set size to completion and then if there will be space for javadoc we will display it.
373: completion.getComponent().setSize(width, height);
374:
375: Dimension javaDocMinSize = new Dimension();
376: if (javadoc != null) {
377: javaDocMinSize = javadoc.getComponent().getMinimumSize();
378: }
379: Dimension completionMaxSize = completion.getComponent()
380: .getMaximumSize();
381:
382: Rectangle completionBounds = new Rectangle(completion
383: .getComponent().getSize());
384: Rectangle javadocBounds = new Rectangle();
385: if (javadoc != null) {
386: javadocBounds = new Rectangle(javadoc.getComponent()
387: .getMaximumSize());
388: }
389:
390: boolean showJavaDoc = true;
391: if (javadoc == null
392: || javadoc.getComponent().isVisible() == false) {
393: showJavaDoc = false;
394: }
395:
396: CompletionJavaDoc completionJavaDoc = extEditorUI
397: .getCompletionJavaDoc();
398: if (completionJavaDoc != null) {
399: if (completionJavaDoc.autoPopup()) {
400: showJavaDoc = javadoc != null;
401: }
402: }
403:
404: boolean showCompletion = getCompletionPane().isVisible();
405:
406: if (!showCompletion) {
407: completionMinSize.height = 0;
408: completionMinSize.width = 0;
409: completionBounds = new Rectangle();
410: } else {
411: completionBounds.width = Math.min(completionMaxSize.width,
412: completionBounds.width);
413: completionBounds.height = Math.min(
414: completionMaxSize.height, completionBounds.height);
415: }
416:
417: // do not show javaDoc. There is no space available
418: if ((javaDocMinSize.height + completionMinSize.height) > height)
419: showJavaDoc = false;
420:
421: if (showJavaDoc) {
422:
423: if ((completionBounds.height + javadocBounds.height) > height) {
424: // javadocBounds.height should be resized
425: completionBounds.height = Math.max(Math.min(
426: (int) (height / 2), completionBounds.height),
427: completionMinSize.height);
428: completionBounds.height = Math.min(130,
429: completionBounds.height); // [PENDING] - maybe this should be in options
430: javadocBounds.height = Math.min((height
431: - completionBounds.height - WINDOW_GAP),
432: javadocBounds.height);
433: }
434:
435: if (placement == PopupManager.Below) {
436: completionBounds.y = 0;
437: javadocBounds.y = completionBounds.height + WINDOW_GAP;
438: } else {
439: completionBounds.y = javadocBounds.height + WINDOW_GAP;
440: javadocBounds.y = 0;
441: }
442:
443: }
444:
445: //width algorhitm
446: if (width < javaDocMinSize.width) {
447: showJavaDoc = false;
448: } else {
449: // going to compute the width of both windows
450: javadocBounds.width = Math.min(width, javadocBounds.width);
451:
452: JTextComponent component = extEditorUI.getComponent();
453: Rectangle extBounds = extEditorUI.getExtentBounds();
454: Rectangle caretRect = new Rectangle();
455: try {
456: caretRect = component.getUI().modelToView(component,
457: component.getCaret().getDot(),
458: javax.swing.text.Position.Bias.Forward);
459: } catch (javax.swing.text.BadLocationException ble) {
460: }
461:
462: if (width - javadocBounds.width < caretRect.x - extBounds.x) {
463: if (caretRect.x - extBounds.x + completionBounds.width < width) {
464: completionBounds.x = caretRect.x - extBounds.x
465: - width + javadocBounds.width;
466: } else {
467: completionBounds.x = javadocBounds.width
468: - completionBounds.width;
469: }
470: } else {
471: completionBounds.x = 0;
472: }
473: }
474:
475: completion.setVisible(false);
476: boolean isJavadocVisible = getJavaDocPane().getComponent()
477: .isVisible();
478: if (isJavadocVisible && !showJavaDoc)
479: getJavaDocPane().getComponent().setVisible(false);
480:
481: remove(completion.getComponent());
482: if (javadoc != null) {
483: remove(javadoc.getComponent());
484: }
485:
486: if (showJavaDoc) {
487: if (showCompletion) {
488: completion.getComponent().setBounds(completionBounds);
489: getJavaDocPane().getComponent()
490: .setBounds(javadocBounds);
491: super .setBounds(0, 0, Math.max(completionBounds.width,
492: javadocBounds.width), completionBounds.height
493: + javadocBounds.height + WINDOW_GAP);
494: add(completion.getComponent());
495: add(getJavaDocPane().getComponent());
496: completion.setVisible(true);
497: if (isJavadocVisible)
498: getJavaDocPane().getComponent().setVisible(true);
499: } else {
500: javadocBounds.x = 0;
501: javadocBounds.y = 0;
502: getJavaDocPane().getComponent()
503: .setBounds(javadocBounds);
504: super .setBounds(0, 0, javadocBounds.width,
505: javadocBounds.height);
506: add(getJavaDocPane().getComponent());
507: if (isJavadocVisible)
508: getJavaDocPane().getComponent().setVisible(true);
509: }
510: } else {
511: completionBounds.x = 0;
512: completionBounds.y = 0;
513: completion.getComponent().setBounds(completionBounds);
514: super .setBounds(0, 0, completionBounds.width,
515: completionBounds.height + WINDOW_GAP);
516: add(completion.getComponent());
517: completion.setVisible(true);
518: }
519: }
520:
521: public void setSize(Dimension d) {
522: setSize(d.width, d.height);
523: }
524:
525: /** Refreshes the code completion content */
526: public void refresh() {
527: setVisible(true);
528: }
529:
530: private void performJavaDocAction(KeyStroke ks) {
531: ActionListener act = getJavaDocPane()
532: .getJavadocDisplayComponent().getActionForKeyStroke(ks);
533: if (act != null) {
534: act.actionPerformed(new ActionEvent(getJavaDocPane()
535: .getJavadocDisplayComponent(),
536: ActionEvent.ACTION_PERFORMED, "")); //NOI18N
537: getJavaDocPane().getJavadocDisplayComponent().repaint();
538: }
539: }
540:
541: /** Attempt to find the editor keystroke for the given editor action. */
542: private KeyStroke[] findEditorKeys(String editorActionName,
543: KeyStroke defaultKey) {
544: // This method is implemented due to the issue
545: // #25715 - Attempt to search keymap for the keybinding that logically corresponds to the action
546: KeyStroke[] ret = new KeyStroke[] { defaultKey };
547: if (editorActionName != null && extEditorUI != null) {
548: JTextComponent component = extEditorUI.getComponent();
549: if (component != null) {
550: TextUI ui = component.getUI();
551: Keymap km = component.getKeymap();
552: if (ui != null && km != null) {
553: EditorKit kit = ui.getEditorKit(component);
554: if (kit instanceof BaseKit) {
555: Action a = ((BaseKit) kit)
556: .getActionByName(editorActionName);
557: if (a != null) {
558: KeyStroke[] keys = km
559: .getKeyStrokesForAction(a);
560: if (keys != null && keys.length > 0) {
561: ret = keys;
562: }
563: }
564: }
565: }
566: }
567: }
568:
569: return ret;
570: }
571:
572: private void registerKeybinding(int action, String actionName,
573: KeyStroke stroke, String editorActionName) {
574: KeyStroke[] keys = findEditorKeys(editorActionName, stroke);
575: for (int i = 0; i < keys.length; i++) {
576: getInputMap().put(keys[i], actionName);
577: keyActionPairsList.add(actionName); // add action-name
578: keyActionPairsList.add(keys[i]); // add keystroke
579: }
580:
581: getActionMap().put(actionName, new JDCPopupAction(action));
582: }
583:
584: private void unregisterKeybinding(String actionName,
585: KeyStroke stroke) {
586: getInputMap().remove(stroke);
587: getActionMap().remove(actionName);
588: }
589:
590: private void installKeybindings() {
591: // Register escape key
592: registerKeybinding(ACTION_POPUP_HIDE, POPUP_HIDE, KeyStroke
593: .getKeyStroke(KeyEvent.VK_ESCAPE, 0),
594: ExtKit.escapeAction);
595:
596: // Register up key
597: registerKeybinding(ACTION_COMPLETION_UP, COMPLETION_UP,
598: KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
599: BaseKit.upAction);
600:
601: // Register down key
602: registerKeybinding(ACTION_COMPLETION_DOWN, COMPLETION_DOWN,
603: KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
604: BaseKit.downAction);
605:
606: // Register PgDn key
607: registerKeybinding(ACTION_COMPLETION_PGDN, COMPLETION_PGDN,
608: KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
609: BaseKit.pageDownAction);
610:
611: // Register PgUp key
612: registerKeybinding(ACTION_COMPLETION_PGUP, COMPLETION_PGUP,
613: KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
614: BaseKit.pageUpAction);
615:
616: // Register home key
617: registerKeybinding(ACTION_COMPLETION_BEGIN, COMPLETION_BEGIN,
618: KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
619: BaseKit.beginLineAction);
620:
621: // Register end key
622: registerKeybinding(ACTION_COMPLETION_END, COMPLETION_END,
623: KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
624: BaseKit.endLineAction);
625:
626: // Register javadoc up key
627: registerKeybinding(ACTION_JAVADOC_UP, JAVADOC_UP, KeyStroke
628: .getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_MASK),
629: null);
630:
631: // Register javadoc down key
632: registerKeybinding(ACTION_JAVADOC_DOWN, JAVADOC_DOWN, KeyStroke
633: .getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_MASK),
634: null);
635:
636: // Register javadoc PgDn key
637: registerKeybinding(ACTION_JAVADOC_PGDN, JAVADOC_PGDN, KeyStroke
638: .getKeyStroke(KeyEvent.VK_PAGE_DOWN,
639: KeyEvent.SHIFT_MASK), null);
640:
641: // Register javadoc PgUp key
642: registerKeybinding(ACTION_JAVADOC_PGUP, JAVADOC_PGUP,
643: KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,
644: KeyEvent.SHIFT_MASK), null);
645:
646: // Register javadoc home key
647: registerKeybinding(ACTION_JAVADOC_BEGIN, JAVADOC_BEGIN,
648: KeyStroke.getKeyStroke(KeyEvent.VK_HOME,
649: KeyEvent.SHIFT_MASK), null);
650:
651: // Register javadoc end key
652: registerKeybinding(ACTION_JAVADOC_END, JAVADOC_END, KeyStroke
653: .getKeyStroke(KeyEvent.VK_END, KeyEvent.SHIFT_MASK),
654: null);
655:
656: // Register javadoc left key
657: registerKeybinding(ACTION_JAVADOC_LEFT, JAVADOC_LEFT, KeyStroke
658: .getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_MASK),
659: null);
660:
661: // Register javadoc right key
662: registerKeybinding(ACTION_JAVADOC_RIGHT, JAVADOC_RIGHT,
663: KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
664: KeyEvent.SHIFT_MASK), null);
665:
666: // Register javadoc back key
667: registerKeybinding(ACTION_JAVADOC_BACK, JAVADOC_BACK, KeyStroke
668: .getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.ALT_MASK),
669: null);
670:
671: // Register javadoc forward key
672: registerKeybinding(ACTION_JAVADOC_FORWARD, JAVADOC_FORWARD,
673: KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
674: KeyEvent.ALT_MASK), null);
675:
676: // Register open in external browser key
677: registerKeybinding(ACTION_JAVADOC_OPEN_IN_BROWSER,
678: JAVADOC_OPEN_IN_BROWSER, KeyStroke.getKeyStroke(
679: KeyEvent.VK_F1, KeyEvent.ALT_MASK
680: | KeyEvent.SHIFT_MASK), null);
681:
682: // Register open the source in editor key
683: registerKeybinding(ACTION_JAVADOC_OPEN_SOURCE,
684: JAVADOC_OPEN_SOURCE, KeyStroke.getKeyStroke(
685: KeyEvent.VK_O, KeyEvent.ALT_MASK
686: | KeyEvent.CTRL_MASK), null);
687:
688: // Register substituteText text and close popup window
689: registerKeybinding(ACTION_COMPLETION_SUBSTITUTE_TEXT,
690: COMPLETION_SUBSTITUTE_TEXT, KeyStroke.getKeyStroke(
691: KeyEvent.VK_ENTER, 0), null);
692:
693: // Register simple substituteText text and close popup window
694: registerKeybinding(ACTION_COMPLETION_SUBSTITUTE_TEXT_SIMPLE,
695: COMPLETION_SUBSTITUTE_TEXT_SIMPLE, KeyStroke
696: .getKeyStroke(KeyEvent.VK_ENTER,
697: KeyEvent.CTRL_MASK), null);
698:
699: // Register substituteText text and keep popup window open
700: registerKeybinding(
701: ACTION_COMPLETION_SUBSTITUTE_TEXT_KEEP_POPUP_OPEN,
702: COMPLETION_SUBSTITUTE_TEXT_KEEP_POPUP_OPEN, KeyStroke
703: .getKeyStroke(KeyEvent.VK_ENTER,
704: KeyEvent.SHIFT_MASK), null);
705:
706: // Register substituteCommonText
707: registerKeybinding(ACTION_COMPLETION_SUBSTITUTE_COMMON_TEXT,
708: COMPLETION_SUBSTITUTE_COMMON_TEXT, KeyStroke
709: .getKeyStroke(KeyEvent.VK_TAB, 0), null);
710:
711: }
712:
713: private void uninstallKeybindings() {
714: for (Iterator it = keyActionPairsList.iterator(); it.hasNext();) {
715: unregisterKeybinding((String) it.next(), // action-name
716: (KeyStroke) it.next() // keystroke
717: );
718: }
719: keyActionPairsList.clear();
720: }
721:
722: public void propertyChange(PropertyChangeEvent evt) {
723: String propName = evt.getPropertyName();
724:
725: if (ExtEditorUI.COMPONENT_PROPERTY.equals(propName)) {
726: if (evt.getNewValue() != null) { // just installed
727: JTextComponent component = extEditorUI.getComponent();
728: installKeybindings();
729: component.addFocusListener(focusL);
730:
731: } else { // just deinstalled
732: JTextComponent component = (JTextComponent) evt
733: .getOldValue();
734: uninstallKeybindings();
735: component.removeFocusListener(focusL);
736: }
737:
738: }
739: }
740:
741: public void settingsChange(SettingsChangeEvent evt) {
742: // Refresh keybindings
743: uninstallKeybindings();
744: installKeybindings();
745: }
746:
747: private class JDCPopupAction extends AbstractAction {
748: private int action;
749:
750: private JDCPopupAction(int action) {
751: this .action = action;
752: }
753:
754: public void actionPerformed(
755: java.awt.event.ActionEvent actionEvent) {
756: switch (action) {
757: case ACTION_POPUP_HIDE:
758: setVisible(false);
759: break;
760: case ACTION_COMPLETION_UP:
761: if (completion.isVisible()) {
762: getCompletionView().up();
763: } else {
764: performJavaDocAction(KeyStroke.getKeyStroke(
765: KeyEvent.VK_UP, 0));
766: }
767: break;
768: case ACTION_COMPLETION_DOWN:
769: if (completion.isVisible()) {
770: getCompletionView().down();
771: } else {
772: performJavaDocAction(KeyStroke.getKeyStroke(
773: KeyEvent.VK_DOWN, 0));
774: }
775: break;
776: case ACTION_COMPLETION_PGUP:
777: if (completion.isVisible()) {
778: getCompletionView().pageUp();
779: } else {
780: performJavaDocAction(KeyStroke.getKeyStroke(
781: KeyEvent.VK_PAGE_UP, 0));
782: }
783: break;
784: case ACTION_COMPLETION_PGDN:
785: if (completion.isVisible()) {
786: getCompletionView().pageDown();
787: } else {
788: performJavaDocAction(KeyStroke.getKeyStroke(
789: KeyEvent.VK_PAGE_DOWN, 0));
790: }
791: break;
792: case ACTION_COMPLETION_BEGIN:
793: if (completion.isVisible()) {
794: getCompletionView().begin();
795: } else {
796: performJavaDocAction(KeyStroke.getKeyStroke(
797: KeyEvent.VK_HOME, 0));
798: }
799: break;
800: case ACTION_COMPLETION_END:
801: if (completion.isVisible()) {
802: getCompletionView().end();
803: } else {
804: performJavaDocAction(KeyStroke.getKeyStroke(
805: KeyEvent.VK_END, 0));
806: }
807: break;
808: case ACTION_JAVADOC_UP:
809: performJavaDocAction(KeyStroke.getKeyStroke(
810: KeyEvent.VK_UP, 0));
811: break;
812: case ACTION_JAVADOC_DOWN:
813: performJavaDocAction(KeyStroke.getKeyStroke(
814: KeyEvent.VK_DOWN, 0));
815: break;
816: case ACTION_JAVADOC_PGUP:
817: performJavaDocAction(KeyStroke.getKeyStroke(
818: KeyEvent.VK_PAGE_UP, 0));
819: break;
820: case ACTION_JAVADOC_PGDN:
821: performJavaDocAction(KeyStroke.getKeyStroke(
822: KeyEvent.VK_PAGE_DOWN, 0));
823: break;
824: case ACTION_JAVADOC_BEGIN:
825: performJavaDocAction(KeyStroke.getKeyStroke(
826: KeyEvent.VK_HOME, 0));
827: break;
828: case ACTION_JAVADOC_END:
829: performJavaDocAction(KeyStroke.getKeyStroke(
830: KeyEvent.VK_END, 0));
831: break;
832: case ACTION_JAVADOC_LEFT:
833: performJavaDocAction(KeyStroke.getKeyStroke(
834: KeyEvent.VK_LEFT, 0));
835: break;
836: case ACTION_JAVADOC_RIGHT:
837: performJavaDocAction(KeyStroke.getKeyStroke(
838: KeyEvent.VK_RIGHT, 0));
839: break;
840: case ACTION_JAVADOC_BACK: {
841: CompletionJavaDoc cjd = extEditorUI
842: .getCompletionJavaDoc();
843: if (cjd != null) {
844: cjd.backHistory();
845: }
846: }
847: break;
848: case ACTION_JAVADOC_FORWARD: {
849: CompletionJavaDoc cjd = extEditorUI
850: .getCompletionJavaDoc();
851: if (cjd != null) {
852: cjd.forwardHistory();
853: }
854: }
855: break;
856: case ACTION_JAVADOC_OPEN_IN_BROWSER: {
857: CompletionJavaDoc cjd = extEditorUI
858: .getCompletionJavaDoc();
859: if (cjd != null && cjd.isExternalJavaDocMounted()) {
860: cjd.openInExternalBrowser();
861: }
862: }
863: break;
864: case ACTION_JAVADOC_OPEN_SOURCE: {
865: CompletionJavaDoc cjd = extEditorUI
866: .getCompletionJavaDoc();
867: if (cjd != null) {
868: cjd.goToSource();
869: }
870: }
871: break;
872: case ACTION_COMPLETION_SUBSTITUTE_TEXT: {
873: Completion cc = extEditorUI.getCompletion();
874: if (cc != null && cc.isPaneVisible()) {
875: if (cc.substituteText(false)) {
876: cc.setPaneVisible(false);
877: } else {
878: cc.refresh(false);
879: }
880: }
881: }
882: break;
883: case ACTION_COMPLETION_SUBSTITUTE_TEXT_SIMPLE: {
884: Completion cc = extEditorUI.getCompletion();
885: if (cc != null && cc.isPaneVisible()) {
886: if (cc.substituteSimpleText()) {
887: cc.setPaneVisible(false);
888: } else {
889: cc.refresh(false);
890: }
891: }
892: }
893: break;
894: case ACTION_COMPLETION_SUBSTITUTE_TEXT_KEEP_POPUP_OPEN: {
895: Completion cc = extEditorUI.getCompletion();
896: if (cc != null && cc.isPaneVisible()) {
897: if (cc.substituteText(true)) {
898: } else {
899: cc.refresh(false);
900: }
901: }
902: }
903: break;
904: case ACTION_COMPLETION_SUBSTITUTE_COMMON_TEXT: {
905: Completion cc = extEditorUI.getCompletion();
906: if (cc != null && cc.isPaneVisible()) {
907: cc.refresh(false);
908: cc.substituteCommonText();
909: }
910: }
911: break;
912:
913: }
914: }
915:
916: }
917:
918: }
|