0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.editor.ext;
0043:
0044: import java.awt.Rectangle;
0045: import java.awt.event.ActionEvent;
0046: import java.io.IOException;
0047: import java.util.ArrayList;
0048: import java.util.List;
0049: import java.util.Iterator;
0050: import javax.swing.Action;
0051: import javax.swing.JPopupMenu;
0052: import javax.swing.JMenuItem;
0053: import javax.swing.KeyStroke;
0054: import javax.swing.text.Caret;
0055: import javax.swing.text.Keymap;
0056: import javax.swing.text.JTextComponent;
0057: import javax.swing.text.TextAction;
0058: import javax.swing.text.BadLocationException;
0059: import org.netbeans.editor.BaseKit;
0060: import org.netbeans.editor.EditorUI;
0061: import org.netbeans.editor.BaseAction;
0062: import org.netbeans.editor.Utilities;
0063: import org.netbeans.editor.Settings;
0064: import org.netbeans.editor.BaseDocument;
0065: import org.netbeans.editor.SyntaxSupport;
0066: import org.netbeans.editor.Formatter;
0067: import org.netbeans.lib.editor.util.CharSequenceUtilities;
0068: import org.netbeans.lib.editor.util.swing.DocumentUtilities;
0069: import org.openide.util.NbBundle;
0070:
0071: /**
0072: * Extended kit offering advanced functionality
0073: *
0074: * @author Miloslav Metelka
0075: * @version 1.00
0076: */
0077: public class ExtKit extends BaseKit {
0078:
0079: /** This action is searched and executed when the popup menu should
0080: * be displayed to build the popup menu.
0081: */
0082: public static final String buildPopupMenuAction = "build-popup-menu"; // NOI18N
0083:
0084: /** Show popup menu.
0085: */
0086: public static final String showPopupMenuAction = "show-popup-menu"; // NOI18N
0087:
0088: /** This action is searched and executed when the tool-tip should
0089: * be displayed by tool-tip support to build the tool-tip.
0090: */
0091: public static final String buildToolTipAction = "build-tool-tip"; // NOI18N
0092:
0093: /** Open find dialog action - this action is defined in view package, but
0094: * its name is defined here for clarity
0095: * @deprecated Without any replacement.
0096: */
0097: public static final String findAction = "find"; // NOI18N
0098:
0099: /** Open replace dialog action - this action is defined in view package, but
0100: * its name is defined here for clarity
0101: */
0102: public static final String replaceAction = "replace"; // NOI18N
0103:
0104: /** Open goto dialog action - this action is defined in view package, but
0105: * its name is defined here for clarity
0106: */
0107: public static final String gotoAction = "goto"; // NOI18N
0108:
0109: /** Goto declaration depending on the context under the caret */
0110: public static final String gotoDeclarationAction = "goto-declaration"; // NOI18N
0111:
0112: /** Goto source depending on the context under the caret */
0113: public static final String gotoSourceAction = "goto-source"; // NOI18N
0114:
0115: public static final String gotoSuperImplementationAction = "goto-super-implementation"; // NOI18N
0116:
0117: /** Goto help depending on the context under the caret */
0118: public static final String gotoHelpAction = "goto-help"; // NOI18N
0119:
0120: /** Match brace */
0121: public static final String matchBraceAction = "match-brace"; // NOI18N
0122:
0123: /** Select the text to the matching bracket */
0124: public static final String selectionMatchBraceAction = "selection-match-brace"; // NOI18N
0125:
0126: /** Toggle the case for the first character of the word under caret */
0127: public static final String toggleCaseIdentifierBeginAction = "toggle-case-identifier-begin"; // NOI18N
0128:
0129: /** Advanced code selection technique
0130: * @deprecated this action name is not actively used by ExtKit and will be removed in future releases.
0131: */
0132: public static final String codeSelectAction = "code-select"; // NOI18N
0133:
0134: /** Action used when escape is pressed. By default it hides popup-menu
0135: * @deprecated this action name is not actively used by ExtKit and will be removed in future releases.
0136: */
0137: public static final String escapeAction = "escape"; // NOI18N
0138:
0139: /** Find the completion help and show it in the completion pane. */
0140: public static final String completionShowAction = "completion-show"; // NOI18N
0141: public static final String allCompletionShowAction = "all-completion-show"; // NOI18N
0142:
0143: /** Show documentation popup panel */
0144: public static final String documentationShowAction = "documentation-show"; // NOI18N
0145:
0146: /** Show completion tooltip */
0147: public static final String completionTooltipShowAction = "tooltip-show"; // NOI18N
0148:
0149: /** Comment out the selected block */
0150: public static final String commentAction = "comment"; // NOI18N
0151:
0152: /** Uncomment the selected block */
0153: public static final String uncommentAction = "uncomment"; // NOI18N
0154:
0155: /** Comment/Uncomment the selected block */
0156: public static final String toggleCommentAction = "toggle-comment"; // NOI18N
0157:
0158: /** Toggle the toolbar */
0159: public static final String toggleToolbarAction = "toggle-toolbar"; // NOI18N
0160:
0161: /** Trimmed text for go to submenu*/
0162: public static final String TRIMMED_TEXT = "trimmed-text"; //NOI18N
0163:
0164: /** Shared suport for find and replace dialogs */
0165: private static FindDialogSupport findDialogSupport;
0166:
0167: private static FindAction findActionDef = new FindAction();
0168: private static ReplaceAction replaceActionDef = new ReplaceAction();
0169: private static GotoAction gotoActionDef = new GotoAction();
0170:
0171: /** Whether editor popup menu creation should be dumped to console */
0172: private static final boolean debugPopupMenu = Boolean
0173: .getBoolean("netbeans.debug.editor.popup.menu"); // NOI18N
0174:
0175: public ExtKit() {
0176: }
0177:
0178: /** Create caret to navigate through document */
0179: public Caret createCaret() {
0180: return new ExtCaret();
0181: }
0182:
0183: public SyntaxSupport createSyntaxSupport(BaseDocument doc) {
0184: return new ExtSyntaxSupport(doc);
0185: }
0186:
0187: public Completion createCompletion(ExtEditorUI extEditorUI) {
0188: return null;
0189: }
0190:
0191: public CompletionJavaDoc createCompletionJavaDoc(
0192: ExtEditorUI extEditorUI) {
0193: return null;
0194: }
0195:
0196: protected EditorUI createEditorUI() {
0197: return new ExtEditorUI();
0198: }
0199:
0200: protected Action[] createActions() {
0201: ArrayList<Action> actions = new ArrayList<Action>();
0202:
0203: actions.add(new BuildPopupMenuAction());
0204: actions.add(new ShowPopupMenuAction());
0205: actions.add(new BuildToolTipAction());
0206: actions.add(replaceActionDef);
0207: actions.add(gotoActionDef);
0208: actions.add(new ToggleCaseIdentifierBeginAction());
0209: // XXX: remove
0210: // if (!ExtCaret.NO_HIGHLIGHT_BRACE_LAYER) {
0211: // actions.add(new MatchBraceAction(matchBraceAction, false));
0212: // actions.add(new MatchBraceAction(selectionMatchBraceAction, true));
0213: // }
0214: actions.add(new ExtDefaultKeyTypedAction());
0215: actions.add(new CompletionShowAction());
0216: actions.add(new AllCompletionShowAction());
0217: actions.add(new DocumentationShowAction());
0218: actions.add(new CompletionTooltipShowAction());
0219: actions.add(new CommentAction()); // to make ctrl-shift-T in Netbeans55 profile work
0220: actions.add(new UncommentAction()); // to make ctrl-shift-D in Netbeans55 profile work
0221:
0222: return TextAction.augmentList(super .createActions(), actions
0223: .toArray(new Action[actions.size()]));
0224: }
0225:
0226: /**
0227: * Action that is localized in org.netbeans.editor package.
0228: * <br/>
0229: * <code>BaseKit.class</code> is used as a bundle class.
0230: */
0231: private abstract static class BaseKitLocalizedAction extends
0232: BaseAction {
0233:
0234: public BaseKitLocalizedAction(String name) {
0235: super (name);
0236: }
0237:
0238: public BaseKitLocalizedAction(String name, int updateMask) {
0239: super (name, updateMask);
0240: }
0241:
0242: protected Class getShortDescriptionBundleClass() {
0243: return BaseKit.class;
0244: }
0245:
0246: }
0247:
0248: /** Called before the popup menu is shown to possibly rebuild
0249: * the popup menu.
0250: */
0251: public static class BuildPopupMenuAction extends
0252: BaseKitLocalizedAction {
0253:
0254: static final long serialVersionUID = 4257043398248915291L;
0255:
0256: public BuildPopupMenuAction() {
0257: super (buildPopupMenuAction, NO_RECORDING);
0258: putValue(BaseAction.NO_KEYBINDING, Boolean.TRUE);
0259: }
0260:
0261: public void actionPerformed(ActionEvent evt,
0262: JTextComponent target) {
0263: if (target != null) {
0264: if (debugPopupMenu) {
0265: /*DEBUG*/System.err
0266: .println("POPUP CREATION START <<<<<"); // NOI18N
0267: }
0268: JPopupMenu pm = buildPopupMenu(target);
0269: if (debugPopupMenu) {
0270: /*DEBUG*/System.err
0271: .println("POPUP CREATION END >>>>>"); // NOI18N
0272: }
0273: ExtUtilities.getExtEditorUI(target).setPopupMenu(pm);
0274: }
0275: }
0276:
0277: protected JPopupMenu createPopupMenu(JTextComponent target) {
0278: return new JPopupMenu();
0279: }
0280:
0281: protected JPopupMenu buildPopupMenu(JTextComponent target) {
0282: JPopupMenu pm = createPopupMenu(target);
0283:
0284: EditorUI ui = Utilities.getEditorUI(target);
0285: List l = (List) Settings
0286: .getValue(
0287: Utilities.getKitClass(target),
0288: (ui == null || ui.hasExtComponent()) ? ExtSettingsNames.POPUP_MENU_ACTION_NAME_LIST
0289: : ExtSettingsNames.DIALOG_POPUP_MENU_ACTION_NAME_LIST);
0290:
0291: if (l != null) {
0292: Iterator i = l.iterator();
0293: while (i.hasNext()) {
0294: String an = (String) i.next();
0295: addAction(target, pm, an);
0296: }
0297: }
0298: return pm;
0299: }
0300:
0301: /** Add the action to the popup menu. This method is called
0302: * for each action-name found in the action-name-list. It should
0303: * add the appopriate menu item to the popup menu.
0304: * @param target target component for which the menu is being
0305: * constructed.
0306: * @param popupMenu popup menu to which this method should add
0307: * the item corresponding to the action-name.
0308: * @param actionName name of the action to add. The real action
0309: * can be retrieved from the kit by calling <tt>getActionByName()</tt>.
0310: */
0311: protected void addAction(JTextComponent target,
0312: JPopupMenu popupMenu, String actionName) {
0313: Action a = Utilities.getKit(target).getActionByName(
0314: actionName);
0315: if (a != null) {
0316: JMenuItem item = null;
0317: if (a instanceof BaseAction) {
0318: item = ((BaseAction) a).getPopupMenuItem(target);
0319: }
0320: if (item == null) {
0321: String itemText = getItemText(target, actionName, a);
0322: if (itemText != null) {
0323: item = new JMenuItem(itemText);
0324: item.addActionListener(a);
0325: // Try to get the accelerator
0326: Keymap km = target.getKeymap();
0327: if (km != null) {
0328: KeyStroke[] keys = km
0329: .getKeyStrokesForAction(a);
0330: if (keys != null && keys.length > 0) {
0331: item.setAccelerator(keys[0]);
0332: }
0333: }
0334: item.setEnabled(a.isEnabled());
0335: Object helpID = a.getValue("helpID"); // NOI18N
0336: if (helpID != null
0337: && (helpID instanceof String))
0338: item.putClientProperty("HelpID", helpID); // NOI18N
0339: }
0340: }
0341:
0342: if (item != null) {
0343: debugPopupMenuItem(item, a);
0344: popupMenu.add(item);
0345: }
0346:
0347: } else if (actionName == null) { // action-name is null, add the separator
0348: if (popupMenu.getComponentCount() > 0) {
0349: debugPopupMenuItem(null, null);
0350: popupMenu.addSeparator();
0351: }
0352: }
0353: }
0354:
0355: protected final void debugPopupMenuItem(JMenuItem item,
0356: Action action) {
0357: if (debugPopupMenu) {
0358: StringBuffer sb = new StringBuffer("POPUP: "); // NOI18N
0359: if (item != null) {
0360: sb.append('"');
0361: sb.append(item.getText());
0362: sb.append('"');
0363: ;
0364: if (!item.isVisible()) {
0365: sb.append(", INVISIBLE"); // NOI18N
0366: }
0367: if (action != null) {
0368: sb.append(", action="); // NOI18N
0369: sb.append(action.getClass().getName());
0370: }
0371:
0372: } else { // null item means separator
0373: sb.append("--Separator--"); // NOI18N
0374: }
0375:
0376: /*DEBUG*/System.err.println(sb.toString());
0377: }
0378:
0379: }
0380:
0381: protected String getItemText(JTextComponent target,
0382: String actionName, Action a) {
0383: String itemText;
0384: if (a instanceof BaseAction) {
0385: itemText = ((BaseAction) a).getPopupMenuText(target);
0386: } else {
0387: itemText = actionName;
0388: }
0389: return itemText;
0390: }
0391:
0392: }
0393:
0394: /** Show the popup menu.
0395: */
0396: public static class ShowPopupMenuAction extends
0397: BaseKitLocalizedAction {
0398:
0399: static final long serialVersionUID = 4257043398248915291L;
0400:
0401: public ShowPopupMenuAction() {
0402: super (showPopupMenuAction, NO_RECORDING);
0403: }
0404:
0405: public void actionPerformed(ActionEvent evt,
0406: JTextComponent target) {
0407: if (target != null) {
0408: try {
0409: int dotPos = target.getCaret().getDot();
0410: Rectangle r = target.getUI().modelToView(target,
0411: dotPos);
0412: if (r != null) {
0413: ExtEditorUI eui = ExtUtilities
0414: .getExtEditorUI(target);
0415: if (eui != null) {
0416: eui.showPopupMenu(r.x, r.y + r.height);
0417: }
0418: }
0419: } catch (BadLocationException e) {
0420: target.getToolkit().beep();
0421: }
0422: }
0423: }
0424:
0425: }
0426:
0427: public static class BuildToolTipAction extends BaseAction {
0428:
0429: static final long serialVersionUID = -2701131863705941250L;
0430:
0431: public BuildToolTipAction() {
0432: super (buildToolTipAction, NO_RECORDING);
0433: putValue(BaseAction.NO_KEYBINDING, Boolean.TRUE);
0434: putValue(Action.SHORT_DESCRIPTION, ""); // No explicit description NOI18N
0435: }
0436:
0437: protected String buildText(JTextComponent target) {
0438: ToolTipSupport tts = ExtUtilities.getExtEditorUI(target)
0439: .getToolTipSupport();
0440: return (tts != null) ? target.getToolTipText(tts
0441: .getLastMouseEvent()) : target.getToolTipText();
0442: }
0443:
0444: public void actionPerformed(ActionEvent evt,
0445: JTextComponent target) {
0446: if (target != null) {
0447: ToolTipSupport tts = ExtUtilities
0448: .getExtEditorUI(target).getToolTipSupport();
0449: if (tts != null) {
0450: tts.setToolTipText(buildText(target));
0451: }
0452: }
0453: }
0454:
0455: }
0456:
0457: /**
0458: * @deprecated Without any replacement.
0459: */
0460: public static class FindAction extends BaseKitLocalizedAction {
0461:
0462: static final long serialVersionUID = 719554648887497427L;
0463:
0464: public FindAction() {
0465: super (findAction, ABBREV_RESET | MAGIC_POSITION_RESET
0466: | UNDO_MERGE_RESET | NO_RECORDING);
0467: putValue(BaseAction.ICON_RESOURCE_PROPERTY,
0468: "org/netbeans/modules/editor/resources/find"); //NOI18N
0469: }
0470:
0471: public FindDialogSupport getSupport() {
0472: return FindDialogSupport.getFindDialogSupport();
0473: }
0474:
0475: public void actionPerformed(ActionEvent evt,
0476: JTextComponent target) {
0477: if (target != null) {
0478: getSupport().showFindDialog(
0479: new KeyEventBlocker(target, false));
0480: }
0481: }
0482:
0483: }
0484:
0485: public static class ReplaceAction extends BaseKitLocalizedAction {
0486:
0487: static final long serialVersionUID = 1828017436079834384L;
0488:
0489: public ReplaceAction() {
0490: super (replaceAction, ABBREV_RESET | MAGIC_POSITION_RESET
0491: | UNDO_MERGE_RESET | NO_RECORDING);
0492: }
0493:
0494: public FindDialogSupport getSupport() {
0495: return FindDialogSupport.getFindDialogSupport();
0496: }
0497:
0498: public void actionPerformed(ActionEvent evt,
0499: JTextComponent target) {
0500: if (target != null) {
0501: // make KeyEventBlocker to discard the first key typed event (Ctrl-H)
0502: // because it is mapped to backspace in the replace dialog
0503: getSupport().showReplaceDialog(
0504: new KeyEventBlocker(target, true));
0505: }
0506: }
0507:
0508: }
0509:
0510: public static class GotoAction extends BaseKitLocalizedAction {
0511:
0512: static final long serialVersionUID = 8425585413146373256L;
0513:
0514: public GotoAction() {
0515: super (gotoAction, ABBREV_RESET | MAGIC_POSITION_RESET
0516: | UNDO_MERGE_RESET);
0517: String name = NbBundle.getBundle(BaseKit.class).getString(
0518: "goto_trimmed");
0519: putValue(TRIMMED_TEXT, name);
0520: putValue(POPUP_MENU_TEXT, name);
0521: }
0522:
0523: /** This method is called by the dialog support
0524: * to translate the line offset to the document position. This
0525: * can be changed for example for the diff operations.
0526: * @param doc document to operate over
0527: * @param lineOffset the line offset to convert to position
0528: * @return document offset that corresponds to the row-start
0529: * of the line with the line-number equal to (lineOffset + 1).
0530: */
0531: protected int getOffsetFromLine(BaseDocument doc, int lineOffset) {
0532: return Utilities.getRowStartFromLineOffset(doc, lineOffset);
0533: }
0534:
0535: public void actionPerformed(ActionEvent evt,
0536: JTextComponent target) {
0537: if (target != null) {
0538: new GotoDialogSupport()
0539: .showGotoDialog(new KeyEventBlocker(target,
0540: false));
0541: }
0542: }
0543:
0544: }
0545:
0546: /** Action to go to the declaration of the variable under the caret.
0547: */
0548: public static class GotoDeclarationAction extends
0549: BaseKitLocalizedAction {
0550:
0551: static final long serialVersionUID = -6440495023918097760L;
0552:
0553: public GotoDeclarationAction() {
0554: super (gotoDeclarationAction, ABBREV_RESET
0555: | MAGIC_POSITION_RESET | UNDO_MERGE_RESET
0556: | SAVE_POSITION);
0557: String name = NbBundle.getBundle(BaseKit.class).getString(
0558: "goto-declaration-trimmed");
0559: putValue(TRIMMED_TEXT, name); //NOI18N
0560: putValue(POPUP_MENU_TEXT, name); //NOI18N
0561: }
0562:
0563: public boolean gotoDeclaration(JTextComponent target) {
0564: BaseDocument doc = Utilities.getDocument(target);
0565: if (doc == null)
0566: return false;
0567: try {
0568: Caret caret = target.getCaret();
0569: int dotPos = caret.getDot();
0570: int[] idBlk = Utilities.getIdentifierBlock(doc, dotPos);
0571: ExtSyntaxSupport extSup = (ExtSyntaxSupport) doc
0572: .getSyntaxSupport();
0573: if (idBlk != null) {
0574: int decPos = extSup.findDeclarationPosition(doc
0575: .getText(idBlk), idBlk[1]);
0576: if (decPos >= 0) {
0577: caret.setDot(decPos);
0578: return true;
0579: }
0580: }
0581: } catch (BadLocationException e) {
0582: }
0583: return false;
0584: }
0585:
0586: public void actionPerformed(ActionEvent evt,
0587: JTextComponent target) {
0588: if (target != null) {
0589: gotoDeclaration(target); // try to go to the declaration position
0590: }
0591: }
0592: }
0593:
0594: public static class ToggleCaseIdentifierBeginAction extends
0595: BaseKitLocalizedAction {
0596:
0597: static final long serialVersionUID = 584392193824931979L;
0598:
0599: ToggleCaseIdentifierBeginAction() {
0600: super (toggleCaseIdentifierBeginAction, ABBREV_RESET
0601: | MAGIC_POSITION_RESET | UNDO_MERGE_RESET
0602: | WORD_MATCH_RESET);
0603: }
0604:
0605: public void actionPerformed(ActionEvent evt,
0606: JTextComponent target) {
0607: if (target != null) {
0608: if (!target.isEditable() || !target.isEnabled()) {
0609: target.getToolkit().beep();
0610: return;
0611: }
0612:
0613: try {
0614: Caret caret = target.getCaret();
0615: BaseDocument doc = (BaseDocument) target
0616: .getDocument();
0617: int[] idBlk = Utilities.getIdentifierBlock(doc,
0618: caret.getDot());
0619: if (idBlk != null) {
0620: Utilities.changeCase(doc, idBlk[0], 1,
0621: Utilities.CASE_SWITCH);
0622: }
0623: } catch (BadLocationException e) {
0624: target.getToolkit().beep();
0625: }
0626: }
0627: }
0628: }
0629:
0630: /**
0631: * This action does nothing.
0632: *
0633: * @deprecated Please use Braces Matching SPI instead, for details see
0634: * <a href="@org-netbeans-modules-editor-bracesmatching@/overview-summary.html">Editor Braces Matching</a>.
0635: */
0636: public static class MatchBraceAction extends BaseKitLocalizedAction {
0637: // XXX: remove
0638: // boolean select;
0639:
0640: static final long serialVersionUID = -184887499045886231L;
0641:
0642: public MatchBraceAction(String name, boolean select) {
0643: super (name, 0);
0644: // XXX: remove
0645: // this.select = select;
0646: }
0647:
0648: public void actionPerformed(ActionEvent evt,
0649: JTextComponent target) {
0650: // XXX: remove
0651: // if (target != null) {
0652: // try {
0653: // Caret caret = target.getCaret();
0654: // BaseDocument doc = Utilities.getDocument(target);
0655: // int dotPos = caret.getDot();
0656: // ExtSyntaxSupport sup = (ExtSyntaxSupport)doc.getSyntaxSupport();
0657: // int[] matchBlk = null;
0658: // int setDotOffset = 0;
0659: // if(caret instanceof ExtCaret) {
0660: // int how = ((ExtCaret)caret).getMatchBraceOffset();
0661: // if(dotPos > 0 && (how == ExtCaret.MATCH_BRACE_BEFORE
0662: // || how == ExtCaret.MATCH_BRACE_EITHER)) {
0663: // matchBlk = sup.findMatchingBlock(dotPos - 1, false);
0664: // }
0665: // if(matchBlk == null && (how == ExtCaret.MATCH_BRACE_AFTER
0666: // || how == ExtCaret.MATCH_BRACE_EITHER)) {
0667: // matchBlk = sup.findMatchingBlock(dotPos, false);
0668: // if(how == ExtCaret.MATCH_BRACE_AFTER) {
0669: // // back it up so caret is on the match
0670: // setDotOffset = -1;
0671: // }
0672: // }
0673: // } else if(dotPos > 0) {
0674: // matchBlk = sup.findMatchingBlock(dotPos - 1, false);
0675: // }
0676: // if (matchBlk != null) {
0677: // if (select) {
0678: // caret.moveDot(matchBlk[1]);
0679: // } else {
0680: // caret.setDot(matchBlk[1] + setDotOffset);
0681: // }
0682: // }
0683: // } catch (BadLocationException e) {
0684: // target.getToolkit().beep();
0685: // }
0686: // }
0687: }
0688: }
0689:
0690: /**
0691: * @deprecated this action is deprecated and will be removed in future releases.
0692: */
0693: public static class CodeSelectAction extends BaseKitLocalizedAction {
0694:
0695: static final long serialVersionUID = 4033474080778585860L;
0696:
0697: public CodeSelectAction() {
0698: super (codeSelectAction);
0699: }
0700:
0701: public void actionPerformed(ActionEvent evt,
0702: JTextComponent target) {
0703: /* if (target != null) {
0704: BaseDocument doc = (BaseDocument)target.getDocument();
0705: SyntaxSupport sup = doc.getSyntaxSupport();
0706: Caret caret = target.getCaret();
0707: try {
0708: int bracketPos = sup.findUnmatchedBracket(caret.getDot(), sup.getRightBrackets());
0709: if (bracketPos >= 0) {
0710: caret.setDot(bracketPos);
0711: while (true) {
0712: int bolPos = Utilities.getRowStart(doc, bracketPos);
0713: boolean isWSC = sup.isCommentOrWhitespace(bolPos, bracketPos);
0714: if (isWSC) { // get previous line end
0715:
0716: }
0717: }
0718: }
0719: } catch (BadLocationException e) {
0720: target.getToolkit().beep();
0721: }
0722: }
0723: */
0724: }
0725: }
0726:
0727: /** Prefix maker adds the prefix before the identifier under cursor.
0728: * The prefix is not added if it's already present. The prefix to be
0729: * added is specified in the constructor of the action together
0730: * with the prefix group. If there's already any prefix from the prefix
0731: * group at the begining of the identifier, that prefix is replaced
0732: * by the actual prefix.
0733: */
0734: public static class PrefixMakerAction extends
0735: BaseKitLocalizedAction {
0736:
0737: static final long serialVersionUID = -2305157963664484920L;
0738:
0739: private String prefix;
0740:
0741: private String[] prefixGroup;
0742:
0743: public PrefixMakerAction(String name, String prefix,
0744: String[] prefixGroup) {
0745: super (name);
0746: this .prefix = prefix;
0747: this .prefixGroup = prefixGroup;
0748:
0749: // [PENDING] This should be done in a better way
0750: String iconRes = null;
0751: if ("get".equals(prefix)) { // NOI18N
0752: iconRes = "org/netbeans/modules/editor/resources/var_get.gif"; // NOI18N
0753: } else if ("set".equals(prefix)) { // NOI18N
0754: iconRes = "org/netbeans/modules/editor/resources/var_set.gif"; // NOI18N
0755: } else if ("is".equals(prefix)) { // NOI18N
0756: iconRes = "org/netbeans/modules/editor/resources/var_is.gif"; // NOI18N
0757: }
0758: if (iconRes != null) {
0759: putValue(BaseAction.ICON_RESOURCE_PROPERTY, iconRes);
0760: }
0761: }
0762:
0763: public void actionPerformed(ActionEvent evt,
0764: JTextComponent target) {
0765: if (target != null) {
0766: if (!target.isEditable() || !target.isEnabled()) {
0767: target.getToolkit().beep();
0768: return;
0769: }
0770:
0771: BaseDocument doc = (BaseDocument) target.getDocument();
0772: int dotPos = target.getCaret().getDot();
0773: try {
0774: // look for identifier around caret
0775: int[] block = org.netbeans.editor.Utilities
0776: .getIdentifierBlock(doc, dotPos);
0777:
0778: // If there is no identifier around, warn user
0779: if (block == null) {
0780: target.getToolkit().beep();
0781: return;
0782: }
0783:
0784: // Get the identifier to operate on
0785: CharSequence identifier = DocumentUtilities
0786: .getText(doc, block[0], block[1] - block[0]);
0787:
0788: // Handle the case we already have the work done - e.g. if we got called over 'getValue'
0789: if (CharSequenceUtilities.startsWith(identifier,
0790: prefix)
0791: && Character.isUpperCase(identifier
0792: .charAt(prefix.length())))
0793: return;
0794:
0795: // Handle the case we have other type of known xEr: eg isRunning -> getRunning
0796: for (int i = 0; i < prefixGroup.length; i++) {
0797: String actPref = prefixGroup[i];
0798: if (CharSequenceUtilities.startsWith(
0799: identifier, actPref)
0800: && identifier.length() > actPref
0801: .length()
0802: && Character.isUpperCase(identifier
0803: .charAt(actPref.length()))) {
0804: doc.remove(block[0], actPref.length());
0805: doc.insertString(block[0], prefix, null);
0806: return;
0807: }
0808: }
0809:
0810: // Upcase the first letter
0811: Utilities.changeCase(doc, block[0], 1,
0812: Utilities.CASE_UPPER);
0813: // Prepend the prefix before it
0814: doc.insertString(block[0], prefix, null);
0815: } catch (BadLocationException e) {
0816: target.getToolkit().beep();
0817: }
0818: }
0819: }
0820: }
0821:
0822: public static class CommentAction extends BaseKitLocalizedAction {
0823:
0824: static final long serialVersionUID = -1422954906554289179L;
0825:
0826: private ToggleCommentAction delegateAction;
0827:
0828: private CommentAction() {
0829: this (null);
0830: }
0831:
0832: public CommentAction(String lineCommentString) {
0833: super (commentAction);
0834: this .delegateAction = lineCommentString != null ? new ToggleCommentAction(
0835: lineCommentString)
0836: : null;
0837: putValue(BaseAction.ICON_RESOURCE_PROPERTY,
0838: "org/netbeans/modules/editor/resources/comment.png"); // NOI18N
0839: }
0840:
0841: public void actionPerformed(ActionEvent evt,
0842: JTextComponent target) {
0843: ToggleCommentAction action = null;
0844:
0845: if (delegateAction != null) {
0846: action = delegateAction;
0847: } else {
0848: BaseKit kit = Utilities.getKit(target);
0849: Action a = kit == null ? null : kit
0850: .getActionByName(toggleCommentAction);
0851: if (a instanceof ToggleCommentAction) {
0852: action = (ToggleCommentAction) a;
0853: }
0854: }
0855:
0856: if (action != null) {
0857: ((ToggleCommentAction) action).commentUncomment(evt,
0858: target, Boolean.TRUE);
0859: } else {
0860: target.getToolkit().beep();
0861: }
0862: }
0863: } // End of CommentAction class
0864:
0865: public static class UncommentAction extends BaseKitLocalizedAction {
0866:
0867: static final long serialVersionUID = -7005758666529862034L;
0868:
0869: private ToggleCommentAction delegateAction;
0870:
0871: private UncommentAction() {
0872: this (null);
0873: }
0874:
0875: public UncommentAction(String lineCommentString) {
0876: super (uncommentAction);
0877: this .delegateAction = lineCommentString != null ? new ToggleCommentAction(
0878: lineCommentString)
0879: : null;
0880: putValue(BaseAction.ICON_RESOURCE_PROPERTY,
0881: "org/netbeans/modules/editor/resources/uncomment.png"); // NOI18N
0882: }
0883:
0884: public void actionPerformed(ActionEvent evt,
0885: JTextComponent target) {
0886: ToggleCommentAction action = null;
0887:
0888: if (delegateAction != null) {
0889: action = delegateAction;
0890: } else {
0891: BaseKit kit = Utilities.getKit(target);
0892: Action a = kit == null ? null : kit
0893: .getActionByName(toggleCommentAction);
0894: if (a instanceof ToggleCommentAction) {
0895: action = (ToggleCommentAction) a;
0896: }
0897: }
0898:
0899: if (action != null) {
0900: ((ToggleCommentAction) action).commentUncomment(evt,
0901: target, Boolean.FALSE);
0902: } else {
0903: target.getToolkit().beep();
0904: }
0905: }
0906: } // End of UncommentAction class
0907:
0908: /**
0909: * @since 1.16
0910: */
0911: public static class ToggleCommentAction extends BaseAction {
0912:
0913: static final long serialVersionUID = -1L;
0914:
0915: private final String lineCommentString;
0916: private final int lineCommentStringLen;
0917:
0918: public ToggleCommentAction(String lineCommentString) {
0919: super (toggleCommentAction);
0920: putValue(SHORT_DESCRIPTION, NbBundle.getMessage(
0921: ToggleCommentAction.class,
0922: "ToggleCommentAction_shortDescription")); //NOI18N
0923:
0924: assert lineCommentString != null : "The lineCommentString parameter must not be null."; //NOI18N
0925: this .lineCommentString = lineCommentString;
0926: this .lineCommentStringLen = lineCommentString.length();
0927:
0928: putValue(BaseAction.ICON_RESOURCE_PROPERTY,
0929: "org/netbeans/modules/editor/resources/comment.png"); // NOI18N
0930: }
0931:
0932: public void actionPerformed(ActionEvent evt,
0933: JTextComponent target) {
0934: commentUncomment(evt, target, null);
0935: }
0936:
0937: private void commentUncomment(ActionEvent evt,
0938: JTextComponent target, Boolean forceComment) {
0939: if (target != null) {
0940: if (!target.isEditable() || !target.isEnabled()) {
0941: target.getToolkit().beep();
0942: return;
0943: }
0944: Caret caret = target.getCaret();
0945: BaseDocument doc = (BaseDocument) target.getDocument();
0946: try {
0947: doc.atomicLock();
0948: try {
0949: int startPos;
0950: int endPos;
0951:
0952: if (Utilities.isSelectionShowing(caret)) {
0953: startPos = Utilities.getRowStart(doc,
0954: target.getSelectionStart());
0955: endPos = target.getSelectionEnd();
0956: if (endPos > 0
0957: && Utilities.getRowStart(doc,
0958: endPos) == endPos) {
0959: endPos--;
0960: }
0961: endPos = Utilities.getRowEnd(doc, endPos);
0962: } else { // selection not visible
0963: startPos = Utilities.getRowStart(doc, caret
0964: .getDot());
0965: endPos = Utilities.getRowEnd(doc, caret
0966: .getDot());
0967: }
0968:
0969: int lineCount = Utilities.getRowCount(doc,
0970: startPos, endPos);
0971: boolean comment = forceComment != null ? forceComment
0972: : !allComments(doc, startPos, lineCount);
0973:
0974: if (comment) {
0975: comment(doc, startPos, lineCount);
0976: } else {
0977: uncomment(doc, startPos, lineCount);
0978: }
0979: } finally {
0980: doc.atomicUnlock();
0981: }
0982: } catch (BadLocationException e) {
0983: target.getToolkit().beep();
0984: }
0985: }
0986: }
0987:
0988: private boolean allComments(BaseDocument doc, int startOffset,
0989: int lineCount) throws BadLocationException {
0990: for (int offset = startOffset; lineCount > 0; lineCount--) {
0991: int firstNonWhitePos = Utilities.getRowFirstNonWhite(
0992: doc, offset);
0993: if (firstNonWhitePos == -1) {
0994: return false;
0995: }
0996:
0997: if (Utilities.getRowEnd(doc, firstNonWhitePos)
0998: - firstNonWhitePos < lineCommentStringLen) {
0999: return false;
1000: }
1001:
1002: CharSequence maybeLineComment = DocumentUtilities
1003: .getText(doc, firstNonWhitePos,
1004: lineCommentStringLen);
1005: if (!CharSequenceUtilities.textEquals(maybeLineComment,
1006: lineCommentString)) {
1007: return false;
1008: }
1009:
1010: offset = Utilities.getRowStart(doc, offset, +1);
1011: }
1012: return true;
1013: }
1014:
1015: private void comment(BaseDocument doc, int startOffset,
1016: int lineCount) throws BadLocationException {
1017: for (int offset = startOffset; lineCount > 0; lineCount--) {
1018: doc.insertString(offset, lineCommentString, null); // NOI18N
1019: offset = Utilities.getRowStart(doc, offset, +1);
1020: }
1021: }
1022:
1023: private void uncomment(BaseDocument doc, int startOffset,
1024: int lineCount) throws BadLocationException {
1025: for (int offset = startOffset; lineCount > 0; lineCount--) {
1026: // Get the first non-whitespace char on the current line
1027: int firstNonWhitePos = Utilities.getRowFirstNonWhite(
1028: doc, offset);
1029:
1030: // If there is any, check wheter it's the line-comment-chars and remove them
1031: if (firstNonWhitePos != -1) {
1032: if (Utilities.getRowEnd(doc, firstNonWhitePos)
1033: - firstNonWhitePos >= lineCommentStringLen) {
1034: CharSequence maybeLineComment = DocumentUtilities
1035: .getText(doc, firstNonWhitePos,
1036: lineCommentStringLen);
1037: if (CharSequenceUtilities.textEquals(
1038: maybeLineComment, lineCommentString)) {
1039: doc.remove(firstNonWhitePos,
1040: lineCommentStringLen);
1041: }
1042: }
1043: }
1044:
1045: offset = Utilities.getRowStart(doc, offset, +1);
1046: }
1047: }
1048:
1049: } // End of CommentUncommentAction class
1050:
1051: /** Executed when the Escape key is pressed. By default it hides
1052: * the popup menu if visible.
1053: */
1054: public static class EscapeAction extends BaseKitLocalizedAction {
1055:
1056: public EscapeAction() {
1057: super (escapeAction);
1058: }
1059:
1060: public void actionPerformed(ActionEvent evt,
1061: JTextComponent target) {
1062: if (target != null) {
1063: ExtUtilities.getExtEditorUI(target).hidePopupMenu();
1064: }
1065: }
1066: }
1067:
1068: // Completion customized actions
1069: public static class ExtDefaultKeyTypedAction extends
1070: DefaultKeyTypedAction {
1071:
1072: static final long serialVersionUID = 5273032708909044812L;
1073:
1074: public void actionPerformed(ActionEvent evt,
1075: JTextComponent target) {
1076: String cmd = evt.getActionCommand();
1077: int mod = evt.getModifiers();
1078:
1079: // Dirty fix for Completion shortcut on Unix !!!
1080: if (cmd != null && cmd.equals(" ")
1081: && (mod == ActionEvent.CTRL_MASK)) { // NOI18N
1082: // Ctrl + SPACE
1083: } else {
1084: Caret caret = target.getCaret();
1085: if (caret instanceof ExtCaret) {
1086: ((ExtCaret) caret).requestMatchBraceUpdateSync(); // synced bracket update
1087: }
1088: super .actionPerformed(evt, target);
1089: }
1090:
1091: if ((target != null) && (evt != null)) {
1092: if ((cmd != null)
1093: && (cmd.length() == 1)
1094: && ((mod & ActionEvent.ALT_MASK) == 0 && (mod & ActionEvent.CTRL_MASK) == 0)) {
1095: // Check whether char that should reindent the line was inserted
1096: checkIndentHotChars(target, cmd);
1097:
1098: // Check the completion
1099: checkCompletion(target, cmd);
1100: }
1101: }
1102: }
1103:
1104: /** Check the characters that should cause reindenting the line. */
1105: protected void checkIndentHotChars(JTextComponent target,
1106: String typedText) {
1107: BaseDocument doc = Utilities.getDocument(target);
1108: if (doc != null) {
1109: Caret caret = target.getCaret();
1110: Formatter f = doc.getFormatter();
1111: if (f instanceof ExtFormatter) {
1112: ExtFormatter ef = (ExtFormatter) f;
1113: int[] fmtBlk = ef.getReformatBlock(target,
1114: typedText);
1115:
1116: if (fmtBlk != null) {
1117: try {
1118: fmtBlk[0] = Utilities.getRowStart(doc,
1119: fmtBlk[0]);
1120: fmtBlk[1] = Utilities.getRowEnd(doc,
1121: fmtBlk[1]);
1122:
1123: //this was the of #18922, that causes the bug #20198
1124: //ef.reformat(doc, fmtBlk[0], fmtBlk[1]);
1125:
1126: //bugfix of the bug #20198. Bug #18922 is fixed too as well as #6968
1127: ef
1128: .reformat(doc, fmtBlk[0],
1129: fmtBlk[1], true);
1130:
1131: } catch (BadLocationException e) {
1132: } catch (IOException e) {
1133: }
1134: }
1135: }
1136: }
1137: }
1138:
1139: /** Check and possibly popup, hide or refresh the completion */
1140: protected void checkCompletion(JTextComponent target,
1141: String typedText) {
1142: Completion completion = ExtUtilities.getCompletion(target);
1143:
1144: BaseDocument doc = (BaseDocument) target.getDocument();
1145: ExtSyntaxSupport extSup = (ExtSyntaxSupport) doc
1146: .getSyntaxSupport();
1147:
1148: if (completion != null && typedText.length() > 0) {
1149: if (!completion.isPaneVisible()) {
1150: if (completion.isAutoPopupEnabled()) {
1151: int result = extSup.checkCompletion(target,
1152: typedText, false);
1153: if (result == ExtSyntaxSupport.COMPLETION_POPUP) {
1154: completion.popup(true);
1155: } else if (result == ExtSyntaxSupport.COMPLETION_CANCEL) {
1156: completion.cancelRequest();
1157: }
1158: }
1159: } else {
1160: int result = extSup.checkCompletion(target,
1161: typedText, true);
1162: switch (result) {
1163: case ExtSyntaxSupport.COMPLETION_HIDE:
1164: completion.setPaneVisible(false);
1165: break;
1166: case ExtSyntaxSupport.COMPLETION_REFRESH:
1167: completion.refresh(false);
1168: break;
1169: case ExtSyntaxSupport.COMPLETION_POST_REFRESH:
1170: completion.refresh(true);
1171: break;
1172: }
1173: }
1174: }
1175: }
1176: }
1177:
1178: public static class CompletionShowAction extends
1179: BaseKitLocalizedAction {
1180:
1181: static final long serialVersionUID = 1050644925893851146L;
1182:
1183: public CompletionShowAction() {
1184: super (completionShowAction);
1185: }
1186:
1187: public void actionPerformed(ActionEvent evt,
1188: JTextComponent target) {
1189: }
1190:
1191: }
1192:
1193: public static class AllCompletionShowAction extends
1194: BaseKitLocalizedAction {
1195:
1196: public AllCompletionShowAction() {
1197: super (allCompletionShowAction);
1198: }
1199:
1200: public void actionPerformed(ActionEvent evt,
1201: JTextComponent target) {
1202: }
1203:
1204: }
1205:
1206: public static class DocumentationShowAction extends
1207: BaseKitLocalizedAction {
1208:
1209: public DocumentationShowAction() {
1210: super (documentationShowAction);
1211: }
1212:
1213: public void actionPerformed(ActionEvent evt,
1214: JTextComponent target) {
1215: }
1216:
1217: }
1218:
1219: public static class CompletionTooltipShowAction extends
1220: BaseKitLocalizedAction {
1221:
1222: public CompletionTooltipShowAction() {
1223: super (completionTooltipShowAction);
1224: }
1225:
1226: public void actionPerformed(ActionEvent evt,
1227: JTextComponent target) {
1228: }
1229:
1230: }
1231:
1232: public static class ExtDeleteCharAction extends DeleteCharAction {
1233:
1234: public ExtDeleteCharAction(String nm, boolean nextChar) {
1235: super(nm, nextChar);
1236: }
1237:
1238: }
1239:
1240: }
|