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.modules.editor;
043:
044: import java.awt.Component;
045: import java.awt.event.ActionEvent;
046: import java.awt.event.ItemEvent;
047: import java.awt.event.ItemListener;
048: import java.awt.event.KeyEvent;
049: import java.util.Arrays;
050: import java.util.Collections;
051: import java.util.HashMap;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Map;
055: import java.util.MissingResourceException;
056: import java.util.ResourceBundle;
057: import javax.swing.JMenu;
058: import javax.swing.JMenuItem;
059: import javax.swing.JPopupMenu;
060: import javax.swing.Action;
061: import javax.swing.JCheckBoxMenuItem;
062: import javax.swing.KeyStroke;
063: import javax.swing.text.Document;
064: import javax.swing.text.JTextComponent;
065: import javax.swing.text.TextAction;
066: import javax.swing.text.Keymap;
067: import org.netbeans.editor.ActionFactory;
068: import org.netbeans.editor.EditorUI;
069: import org.netbeans.editor.ext.ExtKit;
070: import org.openide.awt.DynamicMenuContent;
071: import org.openide.loaders.DataFolder;
072: import org.openide.util.actions.SystemAction;
073: import org.openide.util.actions.Presenter;
074: import org.openide.actions.UndoAction;
075: import org.openide.actions.RedoAction;
076: import org.openide.windows.TopComponent;
077: import org.netbeans.editor.BaseKit;
078: import org.netbeans.editor.Utilities;
079: import org.netbeans.editor.BaseAction;
080: import org.netbeans.editor.MacroDialogSupport;
081: import org.netbeans.editor.Settings;
082: import org.netbeans.editor.SettingsNames;
083: import org.netbeans.editor.ext.ExtSettingsNames;
084: import org.netbeans.modules.editor.impl.ActionsList;
085: import org.netbeans.modules.editor.impl.SearchBar;
086: import org.netbeans.modules.editor.impl.PopupMenuActionsProvider;
087: import org.netbeans.modules.editor.impl.actions.NavigationHistoryBackAction;
088: import org.netbeans.modules.editor.impl.actions.NavigationHistoryForwardAction;
089: import org.netbeans.modules.editor.impl.actions.NavigationHistoryLastEditAction;
090: import org.netbeans.modules.editor.options.BaseOptions;
091: import org.netbeans.modules.editor.options.OptionUtilities;
092: import org.netbeans.modules.editor.options.AllOptionsFolder;
093: import org.netbeans.modules.editor.options.MacrosEditorPanel;
094: import org.openide.ErrorManager;
095: import org.openide.NotifyDescriptor;
096: import org.openide.awt.Mnemonics;
097: import org.openide.filesystems.FileObject;
098: import org.openide.filesystems.FileStateInvalidException;
099: import org.openide.filesystems.FileUtil;
100: import org.openide.util.ContextAwareAction;
101: import org.openide.util.Lookup;
102: import org.openide.util.NbBundle;
103:
104: /**
105: * Java editor kit with appropriate document
106: *
107: * @author Miloslav Metelka
108: * @version 1.00
109: */
110:
111: public class NbEditorKit extends ExtKit {
112:
113: /** Action property that stores the name of the corresponding nb-system-action */
114: public static final String SYSTEM_ACTION_CLASS_NAME_PROPERTY = "systemActionClassName"; // NOI18N
115:
116: static final long serialVersionUID = 4482122073483644089L;
117:
118: private static final Map contentTypeTable;
119:
120: /** Name of the action for generating of Go To popup menu*/
121: public static final String generateGoToPopupAction = "generate-goto-popup"; // NOI18N
122:
123: /** Name of the action for generating of code folding popup menu*/
124: public static final String generateFoldPopupAction = "generate-fold-popup"; // NOI18N
125:
126: private static final NbUndoAction nbUndoActionDef = new NbUndoAction();
127: private static final NbRedoAction nbRedoActionDef = new NbRedoAction();
128:
129: private Map systemAction2editorAction = new HashMap();
130:
131: static {
132: contentTypeTable = new HashMap();
133: contentTypeTable.put(
134: "org.netbeans.modules.properties.syntax.PropertiesKit",
135: "text/x-properties"); // NOI18N
136: contentTypeTable.put(
137: "org.netbeans.modules.web.core.syntax.JSPKit",
138: "text/x-jsp"); // NOI18N
139: contentTypeTable.put(
140: "org.netbeans.modules.css.text.syntax.CSSEditorKit",
141: "text/css"); // new - open source package // NOI18N
142: contentTypeTable.put(
143: "org.netbeans.modules.xml.css.editor.CSSEditorKit",
144: "text/css"); // old - close source package // NOI18N
145: contentTypeTable.put(
146: "org.netbeans.modules.xml.text.syntax.DTDKit",
147: "text/x-dtd"); // NOI18N
148: contentTypeTable.put(
149: "org.netbeans.modules.xml.text.syntax.XMLKit",
150: "text/xml"); // NOI18N
151: contentTypeTable
152: .put(
153: "org.netbeans.modules.corba.idl.editor.coloring.IDLKit",
154: "text/x-idl"); // NOI18N
155: }
156:
157: public NbEditorKit() {
158: super ();
159: // new Throwable("NbEditorKit: " + getClass()).printStackTrace();
160: NbEditorSettingsInitializer.init();
161: }
162:
163: public Document createDefaultDocument() {
164: Document doc = new NbEditorDocument(this .getClass());
165: Object mimeType = doc.getProperty("mimeType"); //NOI18N
166: if (mimeType == null) {
167: doc.putProperty("mimeType", getContentType()); //NOI18N
168: }
169: return doc;
170: }
171:
172: /**
173: * Do any locking necessary prior evaluation of tooltip annotations.
174: * <br>
175: * This method will always be followed by {@link #toolTipAnnotationsUnlock()}
176: * by using <code>try ... finally</code>.
177: * <br>
178: * This method is called prior read locking of the document.
179: */
180: protected void toolTipAnnotationsLock(Document doc) {
181: }
182:
183: /**
184: * Release any locking requested previously by {@link #toolTipAnnotationsLock()}.
185: * <br>
186: * This method is called after read unlocking of the document.
187: */
188: protected void toolTipAnnotationsUnlock(Document doc) {
189: }
190:
191: protected EditorUI createEditorUI() {
192: return new NbEditorUI();
193: }
194:
195: protected Action[] createActions() {
196: Action[] nbEditorActions = new Action[] {
197: new NbBuildPopupMenuAction(), nbUndoActionDef,
198: nbRedoActionDef, new NbBuildToolTipAction(),
199: new NbToggleLineNumbersAction(),
200: new ToggleToolbarAction(),
201: new NbGenerateGoToPopupAction(),
202: new GenerateFoldPopupAction(),
203: new NavigationHistoryLastEditAction(),
204: new NavigationHistoryBackAction(),
205: new NavigationHistoryForwardAction(),
206: new SearchBar.IncrementalSearchForwardAction(),
207: new SearchBar.IncrementalSearchBackwardAction(), };
208: return TextAction.augmentList(super .createActions(),
209: nbEditorActions);
210: }
211:
212: protected void addSystemActionMapping(String editorActionName,
213: Class systemActionClass) {
214: Action a = getActionByName(editorActionName);
215: if (a != null) {
216: a.putValue(SYSTEM_ACTION_CLASS_NAME_PROPERTY,
217: systemActionClass.getName());
218: }
219: systemAction2editorAction.put(systemActionClass.getName(),
220: editorActionName);
221: }
222:
223: protected void updateActions() {
224: addSystemActionMapping(cutAction,
225: org.openide.actions.CutAction.class);
226: addSystemActionMapping(copyAction,
227: org.openide.actions.CopyAction.class);
228: addSystemActionMapping(pasteAction,
229: org.openide.actions.PasteAction.class);
230: // #69077 - DeleteAction now delegates to deleteNextCharAction
231: addSystemActionMapping(deleteNextCharAction,
232: org.openide.actions.DeleteAction.class);
233: addSystemActionMapping(showPopupMenuAction,
234: org.openide.actions.PopupAction.class);
235:
236: addSystemActionMapping(
237: SearchBar.IncrementalSearchForwardAction.ACTION_NAME,
238: org.openide.actions.FindAction.class);
239: addSystemActionMapping(replaceAction,
240: org.openide.actions.ReplaceAction.class);
241: addSystemActionMapping(gotoAction,
242: org.openide.actions.GotoAction.class);
243:
244: addSystemActionMapping(undoAction,
245: org.openide.actions.UndoAction.class);
246: addSystemActionMapping(redoAction,
247: org.openide.actions.RedoAction.class);
248: }
249:
250: private boolean isInheritorOfNbEditorKit() {
251: Class clz = this .getClass();
252: while (clz.getSuperclass() != null) {
253: clz = clz.getSuperclass();
254: if (NbEditorKit.class == clz)
255: return true;
256: }
257: return false;
258: }
259:
260: public String getContentType() {
261: if (isInheritorOfNbEditorKit()) {
262: ErrorManager
263: .getDefault()
264: .log(
265: ErrorManager.WARNING,
266: "Warning: KitClass "
267: + this .getClass().getName()
268: + " doesn't override the method getContentType."); //NOI18N
269: }
270: return (contentTypeTable.containsKey(this .getClass().getName())) ? (String) contentTypeTable
271: .get(this .getClass().getName())
272: : "text/" + this .getClass().getName().replace('.', '_'); //NOI18N
273: }
274:
275: private static ResourceBundle getBundleFromName(String name) {
276: ResourceBundle bundle = null;
277: if (name != null) {
278: try {
279: bundle = NbBundle.getBundle(name);
280: } catch (MissingResourceException mre) {
281: //ErrorManager.getDefault ().notify (mre);
282: }
283: }
284: return bundle;
285: }
286:
287: public static class ToggleToolbarAction extends BaseAction {
288:
289: public ToggleToolbarAction() {
290: super (ExtKit.toggleToolbarAction);
291: putValue("helpID", ToggleToolbarAction.class.getName()); // NOI18N
292: }
293:
294: public void actionPerformed(ActionEvent evt,
295: JTextComponent target) {
296: boolean toolbarVisible = AllOptionsFolder.getDefault()
297: .isToolbarVisible();
298: AllOptionsFolder.getDefault().setToolbarVisible(
299: !toolbarVisible);
300: }
301:
302: public JMenuItem getPopupMenuItem(JTextComponent target) {
303: JCheckBoxMenuItem item = new JCheckBoxMenuItem(NbBundle
304: .getBundle(BaseOptions.class).getString(
305: "PROP_base_toolbarVisible"),
306: AllOptionsFolder.getDefault().isToolbarVisible());
307: item.addItemListener(new ItemListener() {
308: public void itemStateChanged(ItemEvent e) {
309: actionPerformed(null, null);
310: }
311: });
312: return item;
313: }
314:
315: protected Class getShortDescriptionBundleClass() {
316: return BaseKit.class;
317: }
318:
319: }
320:
321: public class NbBuildPopupMenuAction extends BuildPopupMenuAction {
322:
323: static final long serialVersionUID = -8623762627678464181L;
324:
325: protected JPopupMenu createPopupMenu(JTextComponent component) {
326: // to make keyboard navigation (Up/Down keys) inside popup work, we
327: // must use JPopupMenuPlus instead of JPopupMenu
328: return new org.openide.awt.JPopupMenuPlus();
329: }
330:
331: protected JPopupMenu buildPopupMenu(JTextComponent component) {
332: EditorUI ui = Utilities.getEditorUI(component);
333: if (!ui.hasExtComponent()) {
334: return null;
335: }
336:
337: JPopupMenu pm = createPopupMenu(component);
338:
339: String mimeType = NbEditorUtilities.getMimeType(component);
340: List l = PopupMenuActionsProvider
341: .getPopupMenuItems(mimeType);
342:
343: if (l.isEmpty()) {
344: l = (List) Settings
345: .getValue(
346: Utilities.getKitClass(component),
347: (ui == null || ui.hasExtComponent()) ? ExtSettingsNames.POPUP_MENU_ACTION_NAME_LIST
348: : ExtSettingsNames.DIALOG_POPUP_MENU_ACTION_NAME_LIST);
349: }
350:
351: if (l != null) {
352: for (Iterator i = l.iterator(); i.hasNext();) {
353: Object obj = i.next();
354:
355: if (obj == null
356: || obj instanceof javax.swing.JSeparator) {
357: addAction(component, pm, (String) null);
358: } else if (obj instanceof String) {
359: addAction(component, pm, (String) obj);
360: } else if (obj instanceof Action) {
361: addAction(component, pm, (Action) obj);
362: } else if (obj instanceof DataFolder) {
363: pm.add(new LayerSubFolderMenu(component,
364: ((DataFolder) obj).getPrimaryFile()));
365: }
366: }
367: }
368:
369: return pm;
370: }
371:
372: private Lookup getContextLookup(java.awt.Component component) {
373: Lookup lookup = null;
374: for (java.awt.Component c = component; c != null; c = c
375: .getParent()) {
376: if (c instanceof Lookup.Provider) {
377: lookup = ((Lookup.Provider) c).getLookup();
378: if (lookup != null) {
379: break;
380: }
381: }
382: }
383: return lookup;
384: }
385:
386: private Action translateContextLookupAction(
387: Lookup contextLookup, Action action) {
388: if (action instanceof ContextAwareAction
389: && contextLookup != null) {
390: action = ((org.openide.util.ContextAwareAction) action)
391: .createContextAwareInstance(contextLookup);
392: }
393: return action;
394: }
395:
396: private JMenuItem createLocalizedMenuItem(Action action) {
397: JMenuItem item;
398: if (action instanceof Presenter.Popup) {
399: item = ((Presenter.Popup) action).getPopupPresenter();
400: } else {
401: item = new JMenuItem(action);
402: Mnemonics.setLocalizedText(item, item.getText());
403: if (item.getIcon() != null)
404: item.setIcon(null); //filter out icons
405: }
406: return item;
407: }
408:
409: private void assignAccelerator(Keymap km, Action action,
410: JMenuItem item) {
411: if (item.getAccelerator() == null) {
412: KeyStroke ks = (KeyStroke) action
413: .getValue(Action.ACCELERATOR_KEY);
414: if (ks != null) {
415: item.setAccelerator(ks);
416: } else {
417: // Try to get the accelerator from keymap
418: if (km != null) {
419: KeyStroke[] keys = km
420: .getKeyStrokesForAction(action);
421: if (keys != null && keys.length > 0) {
422: item.setAccelerator(keys[0]);
423: }
424: }
425: }
426: }
427: }
428:
429: protected void addAction(JTextComponent component,
430: JPopupMenu popupMenu, Action action) {
431: Lookup contextLookup = getContextLookup(component);
432:
433: // issue #69688
434: if (contextLookup == null
435: && systemAction2editorAction.containsKey(action
436: .getClass().getName())) {
437: addAction(component, popupMenu,
438: (String) systemAction2editorAction.get(action
439: .getClass().getName()));
440: return;
441: }
442:
443: action = translateContextLookupAction(contextLookup, action);
444:
445: if (action != null) {
446: JMenuItem item = createLocalizedMenuItem(action);
447: if (item instanceof DynamicMenuContent) {
448: Component[] cmps = ((DynamicMenuContent) item)
449: .getMenuPresenters();
450: for (int i = 0; i < cmps.length; i++) {
451: popupMenu.add(cmps[i]);
452: }
453: } else {
454: item.setEnabled(action.isEnabled());
455: Object helpID = action.getValue("helpID"); // NOI18N
456: if (helpID != null && (helpID instanceof String)) {
457: item.putClientProperty("HelpID", helpID); // NOI18N
458: }
459: assignAccelerator(component.getKeymap(), action,
460: item);
461: debugPopupMenuItem(item, action);
462: popupMenu.add(item);
463: }
464: }
465: }
466:
467: private void addTopComponentActions(JTextComponent component,
468: JPopupMenu popupMenu) {
469: Lookup contextLookup = getContextLookup(component);
470: // Get the cloneable-editor instance
471: TopComponent tc = NbEditorUtilities
472: .getOuterTopComponent(component);
473: if (tc != null) {
474: // Add all the actions
475: Action[] actions = tc.getActions();
476: Component[] comps = org.openide.util.Utilities
477: .actionsToPopup(actions, contextLookup)
478: .getComponents();
479: for (int i = 0; i < comps.length; i++) {
480: popupMenu.add(comps[i]);
481: }
482: }
483: }
484:
485: protected void addAction(JTextComponent component,
486: JPopupMenu popupMenu, String actionName) {
487: if (actionName != null) { // try if it's an action class name
488: // Check for the TopComponent actions
489: if (TopComponent.class.getName().equals(actionName)) {
490: addTopComponentActions(component, popupMenu);
491: return;
492:
493: } else { // not cloneable-editor actions
494:
495: // Try to load the action class
496: Class saClass = null;
497: try {
498: ClassLoader loader = (ClassLoader) Lookup
499: .getDefault().lookup(ClassLoader.class);
500: saClass = Class.forName(actionName, false,
501: loader);
502: } catch (Throwable t) {
503: }
504:
505: if (saClass != null
506: && SystemAction.class
507: .isAssignableFrom(saClass)) {
508: Lookup contextLookup = getContextLookup(component);
509: Action action = SystemAction.get(saClass);
510: action = translateContextLookupAction(
511: contextLookup, action);
512:
513: JMenuItem item = createLocalizedMenuItem(action);
514: if (item != null) {
515: if (item instanceof DynamicMenuContent) {
516: Component[] cmps = ((DynamicMenuContent) item)
517: .getMenuPresenters();
518: for (int i = 0; i < cmps.length; i++) {
519: popupMenu.add(cmps[i]);
520: }
521: } else {
522: if (!(item instanceof JMenu)) {
523: assignAccelerator((Keymap) Lookup
524: .getDefault().lookup(
525: Keymap.class),
526: action, item);
527: }
528: debugPopupMenuItem(item, action);
529: popupMenu.add(item);
530: }
531: }
532:
533: return;
534: }
535: }
536:
537: }
538:
539: super .addAction(component, popupMenu, actionName);
540:
541: }
542:
543: }
544:
545: /**
546: * @deprecated Without any replacement.
547: */
548: public class NbStopMacroRecordingAction extends
549: ActionFactory.StopMacroRecordingAction {
550:
551: private BaseOptions bo;
552:
553: private Map getKBMap() {
554: Map ret;
555: List list = bo.getKeyBindingList();
556: if (list.size() > 0
557: && (list.get(0) instanceof Class || list.get(0) instanceof String)) {
558: list.remove(0); //remove kit class name
559: }
560: ret = OptionUtilities.makeKeyBindingsMap(list);
561: return ret;
562: }
563:
564: protected MacroDialogSupport getMacroDialogSupport(
565: Class kitClass) {
566: return new NbMacroDialogSupport(kitClass);
567: }
568:
569: private class NbMacroDialogSupport extends MacroDialogSupport {
570:
571: public NbMacroDialogSupport(Class kitClass) {
572: super (kitClass);
573: }
574:
575: public void actionPerformed(ActionEvent evt) {
576: bo = BaseOptions
577: .getOptions(NbEditorKit.this .getClass());
578: Map oldMacroMap = null;
579: Map oldKBMap = null;
580: if (bo != null) {
581: oldMacroMap = bo.getMacroMap();
582: oldKBMap = getKBMap();
583: }
584:
585: super .actionPerformed(evt);
586:
587: if (bo != null) {
588: Map newMacroMap = bo.getMacroMap();
589: bo.setMacroDiffMap(OptionUtilities.getMapDiff(
590: oldMacroMap, newMacroMap, true));
591: bo.setKeyBindingsDiffMap(OptionUtilities
592: .getMapDiff(oldKBMap, getKBMap(), true));
593: bo.setMacroMap(newMacroMap, false);
594: bo.setKeyBindingList(bo.getKeyBindingList(), false);
595: }
596: }
597:
598: protected int showConfirmDialog(String macroName) {
599: NotifyDescriptor confirm = new NotifyDescriptor.Confirmation(
600: NbBundle.getMessage(MacrosEditorPanel.class,
601: "MEP_Overwrite", macroName),
602: NotifyDescriptor.YES_NO_CANCEL_OPTION,
603: NotifyDescriptor.WARNING_MESSAGE);
604: org.openide.DialogDisplayer.getDefault()
605: .notify(confirm);
606: return ((Integer) confirm.getValue()).intValue();
607: }
608:
609: }
610:
611: } // End of NbStopMacroRecordingAction class
612:
613: public static class NbUndoAction extends ActionFactory.UndoAction {
614:
615: public void actionPerformed(ActionEvent evt,
616: JTextComponent target) {
617: // Delegate to system undo action
618: UndoAction ua = (UndoAction) SystemAction
619: .get(UndoAction.class);
620: if (ua != null && ua.isEnabled()) {
621: ua.actionPerformed(evt);
622: }
623: }
624:
625: }
626:
627: public static class NbRedoAction extends ActionFactory.RedoAction {
628:
629: public void actionPerformed(ActionEvent evt,
630: JTextComponent target) {
631: // Delegate to system redo action
632: RedoAction ra = (RedoAction) SystemAction
633: .get(RedoAction.class);
634: if (ra != null && ra.isEnabled()) {
635: ra.actionPerformed(evt);
636: }
637: }
638:
639: }
640:
641: /** Switch visibility of line numbers in editor */
642: public static class NbToggleLineNumbersAction extends
643: ActionFactory.ToggleLineNumbersAction {
644:
645: public NbToggleLineNumbersAction() {
646: }
647:
648: protected boolean isLineNumbersVisible() {
649: return AllOptionsFolder.getDefault().getLineNumberVisible();
650: }
651:
652: protected void toggleLineNumbers() {
653: boolean numbersVisible = AllOptionsFolder.getDefault()
654: .getLineNumberVisible();
655: AllOptionsFolder.getDefault().setLineNumberVisible(
656: !numbersVisible);
657: }
658:
659: public void actionPerformed(ActionEvent evt,
660: JTextComponent target) {
661: toggleLineNumbers();
662: }
663:
664: }
665:
666: public static class NbGenerateGoToPopupAction extends BaseAction {
667:
668: public NbGenerateGoToPopupAction() {
669: super (generateGoToPopupAction);
670: putValue(BaseAction.NO_KEYBINDING, Boolean.TRUE);
671: }
672:
673: public void actionPerformed(ActionEvent evt,
674: JTextComponent target) {
675: }
676:
677: protected Class getShortDescriptionBundleClass() {
678: return NbEditorKit.class;
679: }
680:
681: }
682:
683: public static class NbBuildToolTipAction extends BuildToolTipAction {
684:
685: public void actionPerformed(ActionEvent evt,
686: JTextComponent target) {
687: if (target != null) {
688: NbToolTip.buildToolTip(target);
689: }
690: }
691:
692: }
693:
694: public static class GenerateFoldPopupAction extends BaseAction {
695:
696: private boolean addSeparatorBeforeNextAction;
697:
698: public GenerateFoldPopupAction() {
699: super (generateFoldPopupAction);
700: putValue(BaseAction.NO_KEYBINDING, Boolean.TRUE);
701: }
702:
703: protected Class getShortDescriptionBundleClass() {
704: return NbEditorKit.class;
705: }
706:
707: public void actionPerformed(ActionEvent evt,
708: JTextComponent target) {
709: }
710:
711: private void addAcceleretors(Action a, JMenuItem item,
712: JTextComponent target) {
713: // Try to get the accelerator
714: Keymap km = (target == null) ? BaseKit
715: .getKit(BaseKit.class).getKeymap() : target
716: .getKeymap();
717: if (km != null) {
718: KeyStroke[] keys = km.getKeyStrokesForAction(a);
719: if (keys != null && keys.length > 0) {
720: boolean added = false;
721: for (int i = 0; i < keys.length; i++) {
722: if ((keys[i].getKeyCode() == KeyEvent.VK_MULTIPLY)
723: || keys[i].getKeyCode() == KeyEvent.VK_ADD) {
724: item.setAccelerator(keys[i]);
725: added = true;
726: break;
727: }
728: }
729: if (added == false)
730: item.setAccelerator(keys[0]);
731: }
732: }
733: }
734:
735: protected String getItemText(JTextComponent target,
736: String actionName, Action a) {
737: String itemText;
738: if (a instanceof BaseAction) {
739: itemText = ((BaseAction) a).getPopupMenuText(target);
740: } else {
741: itemText = actionName;
742: }
743: return itemText;
744: }
745:
746: protected void addAction(JTextComponent target, JMenu menu,
747: String actionName) {
748: if (addSeparatorBeforeNextAction) {
749: addSeparatorBeforeNextAction = false;
750: menu.addSeparator();
751: }
752:
753: BaseKit kit = (target == null) ? BaseKit
754: .getKit(BaseKit.class) : Utilities.getKit(target);
755: if (!(kit instanceof BaseKit)) { //bugfix of #45101
756: kit = BaseKit.getKit(BaseKit.class);
757: target = null;
758: }
759: if (kit == null)
760: return;
761: boolean foldingEnabled = (target == null) ? false
762: : ((Boolean) Settings.getValue(Utilities
763: .getKitClass(target),
764: SettingsNames.CODE_FOLDING_ENABLE))
765: .booleanValue();
766: Action a = kit.getActionByName(actionName);
767: if (a != null) {
768: JMenuItem item = null;
769: if (a instanceof BaseAction) {
770: item = ((BaseAction) a).getPopupMenuItem(target);
771: }
772: if (item == null) {
773: String itemText = getItemText(target, actionName, a);
774: if (itemText != null) {
775: item = new JMenuItem(itemText);
776: item.addActionListener(a);
777: Mnemonics.setLocalizedText(item, itemText);
778: addAcceleretors(a, item, target);
779: item
780: .setEnabled(a.isEnabled()
781: && foldingEnabled);
782: Object helpID = a.getValue("helpID"); // NOI18N
783: if (helpID != null
784: && (helpID instanceof String))
785: item.putClientProperty("HelpID", helpID); // NOI18N
786: }
787: }
788:
789: if (item != null) {
790: menu.add(item);
791: }
792:
793: } else { // action-name is null, add the separator
794: menu.addSeparator();
795: }
796: }
797:
798: protected void setAddSeparatorBeforeNextAction(
799: boolean addSeparator) {
800: this .addSeparatorBeforeNextAction = addSeparator;
801: }
802:
803: protected void addAdditionalItems(JTextComponent target,
804: JMenu menu) {
805: setAddSeparatorBeforeNextAction(false);
806: }
807:
808: public JMenuItem getPopupMenuItem(JTextComponent target) {
809: String menuText = org.openide.util.NbBundle.getBundle(
810: NbEditorKit.class).getString("Menu/View/CodeFolds");
811: JMenu menu = new JMenu(menuText);
812: Mnemonics.setLocalizedText(menu, menuText);
813: setAddSeparatorBeforeNextAction(false);
814: addAction(target, menu, BaseKit.collapseFoldAction);
815: addAction(target, menu, BaseKit.expandFoldAction);
816: setAddSeparatorBeforeNextAction(true);
817: addAction(target, menu, BaseKit.collapseAllFoldsAction);
818: addAction(target, menu, BaseKit.expandAllFoldsAction);
819: // By default add separator before next actions (can be overriden if unwanted)
820: setAddSeparatorBeforeNextAction(true);
821: if (target != null)
822: addAdditionalItems(target, menu);
823: return menu;
824: }
825:
826: }
827:
828: private static final class LayerSubFolderMenu extends JMenu {
829:
830: private static String getLocalizedName(FileObject f) {
831: try {
832: return f.getFileSystem().getStatus().annotateName(
833: f.getNameExt(), Collections.singleton(f));
834: } catch (FileStateInvalidException e) {
835: return f.getNameExt();
836: }
837: }
838:
839: public LayerSubFolderMenu(JTextComponent target,
840: FileObject folder) {
841: this (target, getLocalizedName(folder), ActionsList
842: .convert(sort(folder.getChildren())));
843: }
844:
845: private static List<FileObject> sort(FileObject[] children) {
846: List<FileObject> fos = Arrays.asList(children);
847: fos = FileUtil.getOrder(fos, true);
848: return fos;
849: }
850:
851: private LayerSubFolderMenu(JTextComponent target, String text,
852: List items) {
853: super ();
854: Mnemonics.setLocalizedText(this , text);
855:
856: for (Iterator i = items.iterator(); i.hasNext();) {
857: Object obj = i.next();
858:
859: if (obj == null
860: || obj instanceof javax.swing.JSeparator) {
861: addSeparator();
862: } else if (obj instanceof String) {
863: addAction(target, this , (String) obj);
864: } else if (obj instanceof Action) {
865: addAction(target, this , (Action) obj);
866: } else if (obj instanceof DataFolder) {
867: this .add(new LayerSubFolderMenu(target,
868: ((DataFolder) obj).getPrimaryFile()));
869: }
870: }
871: }
872:
873: private static void addAcceleretors(Action a, JMenuItem item,
874: JTextComponent target) {
875: // Try to get the accelerator
876: Keymap km = (target == null) ? BaseKit
877: .getKit(BaseKit.class).getKeymap() : target
878: .getKeymap();
879: if (km != null) {
880: KeyStroke[] keys = km.getKeyStrokesForAction(a);
881: if (keys != null && keys.length > 0) {
882: boolean added = false;
883: for (int i = 0; i < keys.length; i++) {
884: if ((keys[i].getKeyCode() == KeyEvent.VK_MULTIPLY)
885: || keys[i].getKeyCode() == KeyEvent.VK_ADD) {
886: item.setAccelerator(keys[i]);
887: added = true;
888: break;
889: }
890: }
891: if (added == false) {
892: item.setAccelerator(keys[0]);
893: }
894: } else if (a != null) {
895: KeyStroke ks = (KeyStroke) a
896: .getValue(Action.ACCELERATOR_KEY);
897: if (ks != null) {
898: item.setAccelerator(ks);
899: }
900: }
901: }
902: }
903:
904: private static String getItemText(JTextComponent target,
905: String actionName, Action a) {
906: String itemText;
907: if (a instanceof BaseAction) {
908: itemText = ((BaseAction) a).getPopupMenuText(target);
909: } else {
910: Object value = a.getValue(BaseAction.POPUP_MENU_TEXT);
911: itemText = (value instanceof String) ? (String) value
912: : actionName;
913: }
914: return itemText;
915: }
916:
917: private static void addAction(JTextComponent target,
918: JMenu menu, String actionName) {
919: assert target != null : "The parameter target must not be null"; //NOI18N
920: assert menu != null : "The parameter menu must not be null"; //NOI18N
921: assert actionName != null : "The parameter actionName must not be null";//NOI18N
922:
923: BaseKit kit = Utilities.getKit(target);
924: if (kit == null)
925: return;
926: Action a = kit.getActionByName(actionName);
927: if (a != null) {
928: addAction(target, menu, a);
929: }
930: }
931:
932: private static void addAction(JTextComponent target,
933: JMenu menu, Action action) {
934: assert target != null : "The parameter target must not be null"; //NOI18N
935: assert menu != null : "The parameter menu must not be null"; //NOI18N
936: assert action != null : "The parameter action must not be null"; //NOI18N
937:
938: JMenuItem item = null;
939: if (action instanceof BaseAction) {
940: item = ((BaseAction) action).getPopupMenuItem(target);
941: }
942:
943: if (item == null) {
944: String actionName = (String) action
945: .getValue(Action.NAME);
946: String itemText = getItemText(target, actionName,
947: action);
948: if (itemText != null) {
949: item = new JMenuItem(itemText);
950: item.addActionListener(action);
951: Mnemonics.setLocalizedText(item, itemText);
952: addAcceleretors(action, item, target);
953: item.setEnabled(action.isEnabled());
954: Object helpID = action.getValue("helpID"); // NOI18N
955: if (helpID != null && (helpID instanceof String)) {
956: item.putClientProperty("HelpID", helpID); // NOI18N
957: }
958: }
959: }
960:
961: if (item != null) {
962: menu.add(item);
963: }
964: }
965: }
966: }
|