All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.editor.ActionFactory Maven / Gradle / Ivy

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import javax.swing.Action;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Document;
import javax.swing.text.Caret;
import javax.swing.text.Position;
import javax.swing.undo.UndoableEdit;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.CannotRedoException;
import java.awt.Toolkit;
import java.util.Date;
import java.text.SimpleDateFormat;
import javax.swing.JMenuItem;
import javax.swing.JCheckBoxMenuItem;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.AbstractDocument;
import javax.swing.text.View;
import org.netbeans.editor.DrawEngineDocView;
import org.netbeans.api.editor.fold.Fold;
import org.netbeans.api.editor.fold.FoldHierarchy;
import org.netbeans.api.editor.fold.FoldUtilities;

/**
* Actions that are not considered basic and therefore
* they are not included directly in BaseKit, but here.
* Their names however are still part of BaseKit.
*
* @author Miloslav Metelka
* @version 1.00
*
* TODO: I18N in RunMacroAction errors
*/

public class ActionFactory {

    private ActionFactory() {
        // no instantiation
    }
    
    public static class RemoveTabAction extends BaseAction {

        static final long serialVersionUID =-1537748600593395706L;

        public RemoveTabAction() {
            super(BaseKit.removeTabAction, MAGIC_POSITION_RESET | ABBREV_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }
                Caret caret = target.getCaret();
                BaseDocument doc = (BaseDocument)target.getDocument();
                if (caret.isSelectionVisible()) { // block selected
                    try {
                        doc.getFormatter().changeBlockIndent(doc,
                                target.getSelectionStart(), target.getSelectionEnd(), -1);
                    } catch (GuardedException e) {
                        target.getToolkit().beep();
                    } catch (BadLocationException e) {
                        e.printStackTrace();
                    }
                } else { // no selected text
                    try {
                        int startOffset = Utilities.getRowStart(doc, caret.getDot());
                        int firstNW = Utilities.getRowFirstNonWhite(doc, caret.getDot());
                        int endOffset = Utilities.getRowEnd(doc, caret.getDot());
                        if (firstNW == -1 || (firstNW >= caret.getDot()))
                            doc.getFormatter().changeBlockIndent(doc, startOffset, endOffset, -1);
                        else {
                            // TODO:
                            // after we will have action which will do opposite to "tab" action
                            // means it check whether before the caret is whole tab which can
                            // be removed, this action will be called here
                        }
                    } catch (GuardedException e) {
                        target.getToolkit().beep();
                    } catch (BadLocationException e) {
                        e.printStackTrace();
                    }
                }
            }

        }

    }

    public static class RemoveWordAction extends BaseAction {

        static final long serialVersionUID =9193117196412195554L;

        public RemoveWordAction() {
            super(BaseKit.removeWordAction, MAGIC_POSITION_RESET
                  | ABBREV_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                Caret caret = target.getCaret();
                try {
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    int dotPos = caret.getDot();
                    int bolPos = Utilities.getRowStart(doc, dotPos);
                    int wsPos = Utilities.getPreviousWord(target, dotPos);
                    wsPos = (dotPos == bolPos) ? wsPos : Math.max(bolPos, wsPos);
                    doc.remove(wsPos, dotPos - wsPos);
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class RemoveLineBeginAction extends BaseAction {

        static final long serialVersionUID =9193117196412195554L;

        public RemoveLineBeginAction() {
            super(BaseKit.removeLineBeginAction, MAGIC_POSITION_RESET
                  | ABBREV_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                Caret caret = target.getCaret();
                try {
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    int dotPos = caret.getDot();
                    int bolPos = Utilities.getRowStart(doc, dotPos);
                    if (dotPos == bolPos) { // at begining of the line
                        if (dotPos > 0) {
                            doc.remove(dotPos - 1, 1); // remove previous new-line
                        }
                    } else { // not at the line begining
                        char[] chars = doc.getChars(bolPos, dotPos - bolPos);
                        if (Analyzer.isWhitespace(chars, 0, chars.length)) {
                            doc.remove(bolPos, dotPos - bolPos); // remove whitespace
                        } else {
                            int firstNW = Utilities.getRowFirstNonWhite(doc, bolPos);
                            if (firstNW >= 0 && firstNW < dotPos) {
                                doc.remove(firstNW, dotPos - firstNW);
                            }
                        }
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class RemoveLineAction extends BaseAction {

        static final long serialVersionUID =-536315497241419877L;

        public RemoveLineAction() {
            super(BaseKit.removeLineAction, MAGIC_POSITION_RESET
                  | ABBREV_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                Caret caret = target.getCaret();
                try {
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    int dotPos = caret.getDot();
                    int bolPos = Utilities.getRowStart(target, dotPos);
                    int eolPos = Utilities.getRowEnd(target, dotPos);
                    eolPos = Math.min(eolPos + 1, doc.getLength()); // include '\n'
                    doc.remove(bolPos, eolPos - bolPos);
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    /* Useful for popup menu - remove selected block or do nothing */
    public static class RemoveSelectionAction extends BaseAction {

        static final long serialVersionUID =-1419424594746686573L;

        public RemoveSelectionAction() {
            super(BaseKit.removeSelectionAction, MAGIC_POSITION_RESET
                  | ABBREV_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
            putValue ("helpID", RemoveSelectionAction.class.getName ()); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                target.replaceSelection(null);
            }
        }
    }

    /** Switch to overwrite mode or back to insert mode */
    public static class ToggleTypingModeAction extends BaseAction {

        static final long serialVersionUID =-2431132686507799723L;

        public ToggleTypingModeAction() {
            super(BaseKit.toggleTypingModeAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                EditorUI editorUI = Utilities.getEditorUI(target);
                Boolean overwriteMode = (Boolean)editorUI.getProperty(EditorUI.OVERWRITE_MODE_PROPERTY);
                // Now toggle
                overwriteMode = (overwriteMode == null || !overwriteMode.booleanValue())
                                ? Boolean.TRUE : Boolean.FALSE;
                editorUI.putProperty(EditorUI.OVERWRITE_MODE_PROPERTY, overwriteMode);
            }
        }
    }

    public static class ToggleBookmarkAction extends BaseAction {

        static final long serialVersionUID =-8438899482709646741L;

        public ToggleBookmarkAction() {
            super(BaseKit.toggleBookmarkAction);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/toggle_bookmark.png"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Caret caret = target.getCaret();
                try {
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    doc.toggleBookmark(caret.getDot());
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class GotoNextBookmarkAction extends BaseAction {

        boolean select;

        static final long serialVersionUID =-5169554640178645108L;

        public GotoNextBookmarkAction(String nm, boolean select) {
            super(BaseKit.gotoNextBookmarkAction, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
            this.select = select;
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/next_bookmark.png"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Caret caret = target.getCaret();
                try {
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    int dotPos = doc.getNextBookmark(caret.getDot(), true); // wrap
                    if (dotPos >= 0) {
                        if (select) {
                            caret.moveDot(dotPos);
                        } else {
                            caret.setDot(dotPos);
                        }
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }



    public static class RunMacroAction extends BaseAction {

        static final long serialVersionUID =1L;

        static HashSet runningActions = new HashSet();
        private String macroName;

        public RunMacroAction( String name ) {
            super( BaseKit.macroActionPrefix + name);
            this.macroName = name;
        }

        protected void error( JTextComponent target, String messageKey ) {
            Utilities.setStatusText( target, LocaleSupport.getString(
                messageKey, "Error in macro: " + messageKey ) // NOI18N
            );
            Toolkit.getDefaultToolkit().beep();
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if( !runningActions.add( macroName ) ) { // this macro is already running, beware of loops
                error( target, "loop" ); // NOI18N
                return;
            }

            if( target == null ) return;
           
            BaseKit kit = Utilities.getKit(target);
            if( kit == null ) return;
            
            Map macroMap = (Map)Settings.getValue( kit.getClass(), SettingsNames.MACRO_MAP);
            
            String commandString = (String)macroMap.get( macroName );

            if( commandString == null ) {
                error( target, "macro-not-found" ); // NOI18N
                runningActions.remove( macroName );
                return;
            }

            StringBuffer actionName = new StringBuffer();
            char[] command = commandString.toCharArray();
            int len = command.length;

            BaseDocument doc = (BaseDocument)target.getDocument();
            try {
                doc.atomicLock();
                
                for( int i = 0; i < len; i++ ) {
                    if( Character.isWhitespace( command[i] ) ) continue;
                    if( command[i] == '"' ) {
                        while( ++i < len && command[i] != '"' ) {
                            char ch = command[i];
                            if( ch == '\\' ) {
                                if( ++i >= len ) { // '\' at the end
                                    error( target, "macro-malformed" ); // NOI18N
                                    return;
                                }
                                ch = command[i];
                                if( ch != '"' && ch != '\\' ) { // neither \\ nor \" // NOI18N
                                    error( target, "macro-malformed" ); // NOI18N
                                    return;
                                } // else fall through
                            }
                            Action a = target.getKeymap().getDefaultAction();

                            if (a != null) {
                                ActionEvent newEvt = new ActionEvent( target, 0, new String( new char[] { ch } ) );
                                if( a instanceof BaseAction ) {
                                    ((BaseAction)a).updateComponent(target);
                                    ((BaseAction)a).actionPerformed( newEvt, target );
                                } else {
                                    a.actionPerformed( newEvt );
                                }
                            }
                        }
                    } else { // parse the action name
                        actionName.setLength( 0 );
                        while( i < len && ! Character.isWhitespace( command[i] ) ) {
                            char ch = command[i++];
                            if( ch == '\\' ) {
                                if( i >= len ) { // macro ending with single '\'
                                    error( target, "macro-malformed" ); // NOI18N
                                    return;
                                }; 
                                ch = command[i++];
                                if( ch != '\\' && ! Character.isWhitespace( ch ) ) {//
                                    error( target, "macro-malformed" ); // neither "\\" nor "\ " // NOI18N
                                    return;
                                } // else fall through
                            }
                            actionName.append( ch );
                        }
                        // execute the action
                        Action a = kit.getActionByName( actionName.toString() );
                        if (a != null) {
                            ActionEvent fakeEvt = new ActionEvent( target, 0, "" );
                            if( a instanceof BaseAction ) {
                                ((BaseAction)a).updateComponent(target);
                                ((BaseAction)a).actionPerformed( fakeEvt, target );
                            } else {
                                a.actionPerformed( fakeEvt );
                            }
                        } else {
                            error( target, "macro-unknown-action" ); // NOI18N
                            return;
                        }
                    }
                }
            } finally {
                doc.atomicUnlock();
                runningActions.remove( macroName );
            }
        }
    }
    
    
    public static class StartMacroRecordingAction extends BaseAction {

        static final long serialVersionUID =1L;

        public StartMacroRecordingAction() {
            super( BaseKit.startMacroRecordingAction, NO_RECORDING );
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/start_macro_recording.png"); // NOI18N
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if( !startRecording(target) ) target.getToolkit().beep();
            }
        }
    }

    public static class StopMacroRecordingAction extends BaseAction {

        static final long serialVersionUID =1L;

        public StopMacroRecordingAction() {
            super( BaseKit.stopMacroRecordingAction, NO_RECORDING );
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/stop_macro_recording.png"); // NOI18N
        }
        
        protected MacroDialogSupport getMacroDialogSupport(Class kitClass){
            return new MacroDialogSupport(kitClass);
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                String macro = stopRecording(target);
                if( macro == null ) { // not recording
                    target.getToolkit().beep();
                } else {
                    // popup a macro dialog
                    BaseKit kit = Utilities.getKit(target);
                    MacroDialogSupport support = getMacroDialogSupport(kit.getClass());
                    support.setBody( macro );
                    support.showMacroDialog();
                }
            }
        }
    }

    
    public static class AbbrevExpandAction extends BaseAction {

        static final long serialVersionUID =-2124569510083544403L;

        public AbbrevExpandAction() {
            super(BaseKit.abbrevExpandAction,
                  MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                EditorUI editorUI = ((BaseTextUI)target.getUI()).getEditorUI();
                try {
                    editorUI.getAbbrev().checkAndExpand(evt);
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class AbbrevResetAction extends BaseAction {

        static final long serialVersionUID =-2807497346060448395L;

        public AbbrevResetAction() {
            super(BaseKit.abbrevResetAction, ABBREV_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
        }

    }

    public static class ChangeCaseAction extends BaseAction {

        int changeCaseMode;

        static final long serialVersionUID =5680212865619897402L;

        public ChangeCaseAction(String name, int changeCaseMode) {
            super(name, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
            this.changeCaseMode = changeCaseMode;
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                try {
                    Caret caret = target.getCaret();
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    if (caret.isSelectionVisible()) { // valid selection
                        int startPos = target.getSelectionStart();
                        int endPos = target.getSelectionEnd();
                        Utilities.changeCase(doc, startPos, endPos - startPos, changeCaseMode);
                        caret.setSelectionVisible(false);
                        caret.setDot(endPos);
                    } else { // no selection - change current char
                        int dotPos = caret.getDot();
                        Utilities.changeCase(doc, dotPos, 1, changeCaseMode);
                        caret.setDot(dotPos + 1);
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }


    public static class FindNextAction extends BaseAction {

        static final long serialVersionUID =6878814427731642684L;

        public FindNextAction() {
            super(BaseKit.findNextAction, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/find_next.png"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                FindSupport.getFindSupport().find(null, false);
            }
        }
    }

    public static class FindPreviousAction extends BaseAction {

        static final long serialVersionUID =-43746947902694926L;

        public FindPreviousAction() {
            super(BaseKit.findPreviousAction, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/find_previous.png"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                FindSupport.getFindSupport().find(null, true);
            }
        }
    }

    /** Finds either selection or if there's no selection it finds
    * the word where the cursor is standing.
    */
    public static class FindSelectionAction extends BaseAction {

        static final long serialVersionUID =-5601618936504699565L;

        public FindSelectionAction() {
            super(BaseKit.findSelectionAction);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/find_selection.png"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                FindSupport findSupport = FindSupport.getFindSupport();
                Caret caret = target.getCaret();
                int dotPos = caret.getDot();
                HashMap props = new HashMap(findSupport.getFindProperties());
                String searchWord = null;
                boolean revert = false;
                
                if (caret.isSelectionVisible()) { // valid selection
                    searchWord = target.getSelectedText();
                    revert = !Boolean.FALSE.equals(props.put(SettingsNames.FIND_WHOLE_WORDS, Boolean.FALSE));
                } else { // no selection, get current word
                    try {
                        searchWord = Utilities.getIdentifier((BaseDocument)target.getDocument(),
                                                             dotPos);
                        revert =  !Boolean.TRUE.equals(props.put(SettingsNames.FIND_WHOLE_WORDS, Boolean.TRUE));
                        
                    } catch (BadLocationException e) {
                        e.printStackTrace();
                    }
                }

                if (searchWord != null) {
                    int n = searchWord.indexOf( '\n' );
                    if (n >= 0 ) 
                        searchWord = searchWord.substring(0, n);
                    props.put(SettingsNames.FIND_WHAT, searchWord);
                
                    if (revert){
                        HashMap revertMap = new HashMap();                                            
                        revertMap.put(SettingsNames.FIND_WHOLE_WORDS, Boolean.TRUE);
                        props.put(FindSupport.REVERT_MAP, revertMap);
                    }

                    findSupport.putFindProperties(props);
                    findSupport.find(null, false);
                }
            }
        }
    }

    public static class ToggleHighlightSearchAction extends BaseAction {

        static final long serialVersionUID =4603809175771743200L;

        public ToggleHighlightSearchAction() {
            super(BaseKit.toggleHighlightSearchAction, CLEAR_STATUS_TEXT);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/toggle_highlight.png"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Boolean cur = (Boolean)FindSupport.getFindSupport().getFindProperty(
                                  SettingsNames.FIND_HIGHLIGHT_SEARCH);
                if (cur == null || cur.booleanValue() == false) {
                    cur = Boolean.TRUE;
                } else {
                    cur = Boolean.FALSE;
                }
                FindSupport.getFindSupport().putFindProperty(
                    SettingsNames.FIND_HIGHLIGHT_SEARCH, cur);
            }
        }
    }

    public static class UndoAction extends BaseAction {

        static final long serialVersionUID =8628586205035497612L;

        public UndoAction() {
            super(BaseKit.undoAction, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (!target.isEditable() || !target.isEnabled()) {
                target.getToolkit().beep();
                return;
            }

            Document doc = target.getDocument();
            UndoableEdit undoMgr = (UndoableEdit)doc.getProperty(
                                       BaseDocument.UNDO_MANAGER_PROP);
            if (target != null && undoMgr != null) {
                try {
                    undoMgr.undo();
                } catch (CannotUndoException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class RedoAction extends BaseAction {

        static final long serialVersionUID =6048125996333769202L;

        public RedoAction() {
            super(BaseKit.redoAction, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (!target.isEditable() || !target.isEnabled()) {
                target.getToolkit().beep();
                return;
            }

            Document doc = target.getDocument();
            UndoableEdit undoMgr = (UndoableEdit)doc.getProperty(
                                       BaseDocument.UNDO_MANAGER_PROP);
            if (target != null && undoMgr != null) {
                try {
                    undoMgr.redo();
                } catch (CannotRedoException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class WordMatchAction extends BaseAction {

        private boolean direction;

        static final long serialVersionUID =595571114685133170L;

        public WordMatchAction(String name, boolean direction) {
            super(name, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET);
            this.direction = direction;
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                direction
                    ? "org/netbeans/modules/editor/resources/next_matching.png" // NOI18N
                    : "org/netbeans/modules/editor/resources/previous_matching.png" // NOI18N
            );
                        
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                EditorUI editorUI = Utilities.getEditorUI(target);
                Caret caret = target.getCaret();
                final BaseDocument doc = Utilities.getDocument(target);

                // Possibly remove selection
                if (caret.isSelectionVisible()) {
                    target.replaceSelection(null);
                }

                int dotPos = caret.getDot();
                String s = editorUI.getWordMatch().getMatchWord(dotPos, direction);
                String prevWord = editorUI.getWordMatch().getPreviousWord();
                if (s != null) {
                    doc.atomicLock();
                    try {
                        int pos = dotPos;
                        if (prevWord != null && prevWord.length() > 0) {
                            pos -= prevWord.length();
                            doc.remove(pos, prevWord.length());
                        }
                        doc.insertString(pos, s, null);
                    } catch (BadLocationException e) {
                        target.getToolkit().beep();
                    } finally {
                        doc.atomicUnlock();
                    }
                }
            }
        }
    }


    public static class ShiftLineAction extends BaseAction {

        boolean right;

        static final long serialVersionUID =-5124732597493699582L;

        public ShiftLineAction(String name, boolean right) {
            super(name, MAGIC_POSITION_RESET | UNDO_MERGE_RESET);
            this.right = right;
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                right
                    ? "org/netbeans/modules/editor/resources/shift_line_right.png" // NOI18N
                    : "org/netbeans/modules/editor/resources/shift_line_left.png" // NOI18N
            );

        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                try {
                    Caret caret = target.getCaret();
                    BaseDocument doc = Utilities.getDocument(target);
                    if (caret.isSelectionVisible()) {
                        doc.getFormatter().changeBlockIndent(doc,
                        target.getSelectionStart(), target.getSelectionEnd(),
                        right ? +1 : -1);
                    } else {
                        doc.getFormatter().shiftLine(doc, caret.getDot(), right);
                    }
                } catch (GuardedException e) {
                    target.getToolkit().beep();
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static class AdjustWindowAction extends BaseAction {

        int percentFromWindowTop;

        static final long serialVersionUID =8864278998999643292L;

        public AdjustWindowAction(String name, int percentFromWindowTop) {
            super(name);
            this.percentFromWindowTop = percentFromWindowTop;
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Utilities.getEditorUI(target).adjustWindow(percentFromWindowTop);
            }
        }
    }

    public static class AdjustCaretAction extends BaseAction {

        int percentFromWindowTop;

        static final long serialVersionUID =3223383913531191066L;

        public AdjustCaretAction(String name, int percentFromWindowTop) {
            super(name);
            this.percentFromWindowTop = percentFromWindowTop;
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Utilities.getEditorUI(target).adjustCaret(percentFromWindowTop);
            }
        }
    }

    public static class FormatAction extends BaseAction {

        static final long serialVersionUID =-7666172828961171865L;

        public FormatAction() {
            super(BaseKit.formatAction,
                  ABBREV_RESET | MAGIC_POSITION_RESET | UNDO_MERGE_RESET);
            putValue ("helpID", FormatAction.class.getName ()); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }

                Caret caret = target.getCaret();
                BaseDocument doc = (BaseDocument)target.getDocument();
                GuardedDocument gdoc = (doc instanceof GuardedDocument)
                                       ? (GuardedDocument)doc : null;

                doc.atomicLock();
                try {

                    int startPos;
                    Position endPosition;
                    if (caret.isSelectionVisible()) {
                        startPos = target.getSelectionStart();
                        endPosition = doc.createPosition(target.getSelectionEnd());
                    } else {
                        startPos = 0;
                        endPosition = doc.createPosition(doc.getLength());
                    }

                    int pos = startPos;
                    if (gdoc != null) {
                        pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos);
                    }

                    while (pos < endPosition.getOffset()) {
                        int stopPos = endPosition.getOffset();
                        if (gdoc != null) { // adjust to start of the next guarded block
                            stopPos = gdoc.getGuardedBlockChain().adjustToNextBlockStart(pos);
                            if (stopPos == -1) {
                                stopPos = endPosition.getOffset();
                            }
                        }

                        int reformattedLen = doc.getFormatter().reformat(doc, pos, stopPos);
                        pos = pos + reformattedLen;

                        if (gdoc != null) { // adjust to end of current block
                            pos = gdoc.getGuardedBlockChain().adjustToBlockEnd(pos);
                        }
                    }

                } catch (GuardedException e) {
                    target.getToolkit().beep();
                } catch (BadLocationException e) {
                    Utilities.annotateLoggable(e);
                } finally {
                    doc.atomicUnlock();
                }

            }
        }
        
    }

    public static class FirstNonWhiteAction extends BaseAction {

        boolean select;

        static final long serialVersionUID =-5888439539790901158L;

        public FirstNonWhiteAction(String nm, boolean select) {
            super(nm, MAGIC_POSITION_RESET | ABBREV_RESET | UNDO_MERGE_RESET
                  | WORD_MATCH_RESET);
            this.select = select;
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Caret caret = target.getCaret();
                try {
                    int pos = Utilities.getRowFirstNonWhite((BaseDocument)target.getDocument(),
                                                            caret.getDot());
                    if (pos >= 0) {
                        if (select) {
                            caret.moveDot(pos);
                        } else {
                            caret.setDot(pos);
                        }
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class LastNonWhiteAction extends BaseAction {

        boolean select;

        static final long serialVersionUID =4503533041729712917L;

        public LastNonWhiteAction(String nm, boolean select) {
            super(nm, MAGIC_POSITION_RESET | ABBREV_RESET | UNDO_MERGE_RESET
                  | WORD_MATCH_RESET);
            this.select = select;
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Caret caret = target.getCaret();
                try {
                    int pos = Utilities.getRowLastNonWhite((BaseDocument)target.getDocument(),
                                                           caret.getDot());
                    if (pos >= 0) {
                        if (select) {
                            caret.moveDot(pos);
                        } else {
                            caret.setDot(pos);
                        }
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class SelectIdentifierAction extends BaseAction {

        static final long serialVersionUID =-7288216961333147873L;

        public SelectIdentifierAction() {
            super(BaseKit.selectIdentifierAction, MAGIC_POSITION_RESET);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Caret caret = target.getCaret();
                try {
                    if (caret.isSelectionVisible()) {
                        caret.setSelectionVisible(false); // unselect if anything selected
                    } else { // selection not visible
                        int block[] = Utilities.getIdentifierBlock((BaseDocument)target.getDocument(),
                                      caret.getDot());
                        if (block != null) {
                            caret.setDot(block[0]);
                            caret.moveDot(block[1]);
                        }
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class SelectNextParameterAction extends BaseAction {

        static final long serialVersionUID =8045372985336370934L;

        public SelectNextParameterAction() {
            super(BaseKit.selectNextParameterAction, MAGIC_POSITION_RESET | CLEAR_STATUS_TEXT);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                Caret caret = target.getCaret();
                BaseDocument doc = (BaseDocument)target.getDocument();
                int dotPos = caret.getDot();
                int selectStartPos = -1;
                try {
                    if (dotPos > 0) {
                        if (doc.getChars(dotPos - 1, 1)[0] == ',') { // right after the comma
                            selectStartPos = dotPos;
                        }
                    }
                    if (dotPos < doc.getLength()) {
                        char dotChar = doc.getChars(dotPos, 1)[0];
                        if (dotChar == ',') {
                            selectStartPos = dotPos + 1;
                        } else if (dotChar == ')') {
                            caret.setDot(dotPos + 1);
                        }
                    }
                    if (selectStartPos >= 0) {
                        int selectEndPos = doc.find(
                                               new FinderFactory.CharArrayFwdFinder( new char[] { ',', ')' }),
                                               selectStartPos, -1
                                           );
                        if (selectEndPos >= 0) {
                            target.select(selectStartPos, selectEndPos);
                        }
                    }
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }

    public static class JumpListNextAction extends BaseAction {

        static final long serialVersionUID =6891721278404990446L;

        public JumpListNextAction() {
            super(BaseKit.jumpListNextAction);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/edit_next.gif"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                JumpList.jumpNext(target);
            }
        }
    }

    public static class JumpListPrevAction extends BaseAction {

        static final long serialVersionUID =7174907031986424265L;

        public JumpListPrevAction() {
            super(BaseKit.jumpListPrevAction);
            putValue(BaseAction.ICON_RESOURCE_PROPERTY,
                "org/netbeans/modules/editor/resources/edit_previous.gif"); // NOI18N
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                JumpList.jumpPrev(target);
            }
        }
    }

    public static class JumpListNextComponentAction extends BaseAction {

        static final long serialVersionUID =-2059070050865876892L;

        public JumpListNextComponentAction() {
            super(BaseKit.jumpListNextComponentAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                JumpList.jumpNextComponent(target);
            }
        }
    }

    public static class JumpListPrevComponentAction extends BaseAction {

        static final long serialVersionUID =2032230534727849525L;

        public JumpListPrevComponentAction() {
            super(BaseKit.jumpListPrevComponentAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                JumpList.jumpPrevComponent(target);
            }
        }
    }

    public static class ScrollUpAction extends BaseAction {

        public ScrollUpAction() {
            super(BaseKit.scrollUpAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                EditorUI editorUI = Utilities.getEditorUI(target);
                Rectangle bounds = editorUI.getExtentBounds();
                bounds.y += editorUI.getLineHeight();
                bounds.x += editorUI.getTextMargin().left;
                editorUI.scrollRectToVisible(bounds, EditorUI.SCROLL_SMALLEST);
            }
        }

    }

    public static class ScrollDownAction extends BaseAction {

        public ScrollDownAction() {
            super(BaseKit.scrollDownAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                EditorUI editorUI = Utilities.getEditorUI(target);
                Rectangle bounds = editorUI.getExtentBounds();
                bounds.y -= editorUI.getLineHeight();
                bounds.x += editorUI.getTextMargin().left;
                editorUI.scrollRectToVisible(bounds, EditorUI.SCROLL_SMALLEST);
            }
        }

    }

    public static class InsertDateTimeAction extends BaseAction {
        
        static final long serialVersionUID =2865619897402L;
        
        public InsertDateTimeAction() {
            super(BaseKit.insertDateTimeAction,
            ABBREV_RESET | MAGIC_POSITION_RESET | UNDO_MERGE_RESET | WORD_MATCH_RESET);
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                if (!target.isEditable() || !target.isEnabled()) {
                    target.getToolkit().beep();
                    return;
                }
                
                try {
                    Caret caret = target.getCaret();
                    BaseDocument doc = (BaseDocument)target.getDocument();
                    
                    // Format the current time.
                    SimpleDateFormat formatter = new SimpleDateFormat();
                    Date currentTime = new Date();
                    String dateString = formatter.format(currentTime);
                    
                    doc.insertString(caret.getDot(), dateString, null);
                } catch (BadLocationException e) {
                    target.getToolkit().beep();
                }
            }
        }
    }
    
    /** Select text of whole document */
    public static class GenerateGutterPopupAction extends BaseAction {

        static final long serialVersionUID =-3502499718130556525L;

        public GenerateGutterPopupAction() {
            super(BaseKit.generateGutterPopupAction);
            putValue(BaseAction.NO_KEYBINDING, Boolean.TRUE);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
        }

        public JMenuItem getPopupMenuItem(JTextComponent target) {
            EditorUI ui = Utilities.getEditorUI(target);
            try {
                return ui.getDocument().getAnnotations().createMenu(Utilities.getKit(target), Utilities.getLineOffset(ui.getDocument(),target.getCaret().getDot()));
            } catch (BadLocationException ex) {
                return null;
            }
        }
    
    }

    /** Switch visibility of line numbers in editor */
    public static class ToggleLineNumbersAction extends BaseAction {

        static final long serialVersionUID =-3502499718130556526L;
        
        private JCheckBoxMenuItem item = null;

        public ToggleLineNumbersAction() {
            super(BaseKit.toggleLineNumbersAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            toggleLineNumbers();
        }
        
        public JMenuItem getPopupMenuItem(JTextComponent target) {
            
            item = new JCheckBoxMenuItem(LocaleSupport.getString("line-numbers-menuitem"), isLineNumbersVisible());
            item.addItemListener( new ItemListener() {
                public void itemStateChanged(ItemEvent e) {
                    actionPerformed(null,null);
                }
            });
            return item;
        }
        
        protected boolean isLineNumbersVisible() {
            return false;
        }
        
        protected void toggleLineNumbers() {
        }
        
    }
    
    /** Cycle through annotations on the current line */
    public static class AnnotationsCyclingAction extends BaseAction {
        
        public AnnotationsCyclingAction() {
            super(BaseKit.annotationsCyclingAction);
        }

        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            if (target != null) {
                try {
                    Caret caret = target.getCaret();
                    BaseDocument doc = Utilities.getDocument(target);
                    int caretLine = Utilities.getLineOffset(doc, caret.getDot());
                    AnnotationDesc aDesc = doc.getAnnotations().activateNextAnnotation(caretLine);
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /** Returns the fold that should be collapsed/expanded in the caret row
     *  @param hierarchy hierarchy under which all folds should be collapsed/expanded.
     *  @param dot caret position offset
     *  @param lineStart offset of the start of line
     *  @param lineEnd offset of the end of line
     *  @return the fold that meet common criteria in accordance with the caret position
     */
    private static Fold getLineFold(FoldHierarchy hierarchy, int dot, int lineStart, int lineEnd){
        Fold caretOffsetFold = FoldUtilities.findOffsetFold(hierarchy, dot);

        // beginning searching from the lineStart
        Fold fold = FoldUtilities.findNearestFold(hierarchy, lineStart);  
        
        while (fold!=null && 
                  (fold.getEndOffset()<=dot || // find next available fold if the 'fold' is one-line
                      // or it has children and the caret is in the fold body
                      // i.e. class A{ |public void method foo(){}}
                      (!fold.isCollapsed() && fold.getFoldCount() > 0  && fold.getStartOffset()+10) ? fold.getStartOffset()+1 : fold.getEndOffset());
                   if (nextFold!=null && nextFold.getStartOffset()lineEnd) {

            // in the case:
            // class A{
            // }     |
            // try to find an offset fold on the offset of the line beginning
            if (caretOffsetFold == null){
                caretOffsetFold = FoldUtilities.findOffsetFold(hierarchy, lineStart);
            }
            
            return caretOffsetFold;
        }
        
        // no fold at offset found, in this case return the fold
        if (caretOffsetFold == null) return fold;
        
        // skip possible inner class members validating if the innerclass fold is collapsed
        if (caretOffsetFold.isCollapsed()) return caretOffsetFold;
        
        // in the case:
        // class A{
        // public vo|id foo(){} }
        // 'fold' (in this case fold of the method foo) will be returned
        if ( caretOffsetFold.getEndOffset()>fold.getEndOffset() && 
             fold.getEndOffset()>dot){
            return fold;
        }
        
        // class A{
        // |} public void method foo(){}
        // inner class fold will be returned
        if (fold.getStartOffset()>caretOffsetFold.getEndOffset()) return caretOffsetFold;
        
        // class A{
        // public void foo(){} |}
        // returning innerclass fold
        if (fold.getEndOffset() dot || foldRowEnd < dot) return false; // it's not fold encapsulating dot
            return true;
            }

        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            FoldHierarchy hierarchy = FoldHierarchy.get(target);
            int dot = target.getCaret().getDot();
            hierarchy.lock();
            try{
                try{
                    int rowStart = javax.swing.text.Utilities.getRowStart(target, dot);
                    int rowEnd = javax.swing.text.Utilities.getRowEnd(target, dot);
                    Fold fold = FoldUtilities.findNearestFold(hierarchy, rowStart);
                    fold = getLineFold(hierarchy, dot, rowStart, rowEnd);
                    if (fold==null){
                        return; // no success
                    }
                    // ensure we' got the right fold
                    if (dotInFoldArea(target, fold, dot)){
                        hierarchy.collapse(fold);
                    }
                }catch(BadLocationException ble){
                    ble.printStackTrace();
                }
            }finally {
                hierarchy.unlock();
            }
        }
    }
    
    /** Expand a fold. Depends on the current caret position. */
    public static class ExpandFold extends BaseAction {
        public ExpandFold(){
            super(BaseKit.expandFoldAction);
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            FoldHierarchy hierarchy = FoldHierarchy.get(target);
            int dot = target.getCaret().getDot();
            hierarchy.lock();
            try{
                try{
                    int rowStart = javax.swing.text.Utilities.getRowStart(target, dot);
                    int rowEnd = javax.swing.text.Utilities.getRowEnd(target, dot);
                    Fold fold = getLineFold(hierarchy, dot, rowStart, rowEnd);
                    if (fold!=null){
                        hierarchy.expand(fold);
                    }
                }catch(BadLocationException ble){
                    ble.printStackTrace();
                }
            }finally {
                hierarchy.unlock();
            }
        }
    }
    
    /** Collapse all existing folds in the document. */
    public static class CollapseAllFolds extends BaseAction {
        public CollapseAllFolds(){
            super(BaseKit.collapseAllFoldsAction);
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            FoldHierarchy hierarchy = FoldHierarchy.get(target);
            // Hierarchy locking done in the utility method
            FoldUtilities.collapseAll(hierarchy);
        }
    }

    /** Expand all existing folds in the document. */
    public static class ExpandAllFolds extends BaseAction {
        public ExpandAllFolds(){
            super(BaseKit.expandAllFoldsAction);
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            FoldHierarchy hierarchy = FoldHierarchy.get(target);
            // Hierarchy locking done in the utility method
            FoldUtilities.expandAll(hierarchy);
        }
    }

    /** Expand all existing folds in the document. */
    public static class DumpViewHierarchyAction extends BaseAction {

        public DumpViewHierarchyAction() {
            super("dump-view-hierarchy"); // NOI18N
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            DrawEngineDocView rootView = (DrawEngineDocView)Utilities.getDocumentView(target);
            AbstractDocument adoc = (AbstractDocument)target.getDocument();

            // Dump fold hierarchy
            FoldHierarchy hierarchy = FoldHierarchy.get(target);
            adoc.readLock();
            try {
                hierarchy.lock();
                try {
                    /*DEBUG*/System.err.println("FOLD HIERARCHY DUMP:\n" + hierarchy);
                } finally {
                    hierarchy.unlock();
                }
            } finally {
                adoc.readUnlock();
            }

            /*DEBUG*/System.err.println("DOCUMENT VIEW: " + System.identityHashCode(rootView)
                + ", " + rootView // NOI18N
                + "\nLINE VIEWS:\n" + rootView.childrenToString() // NOI18N
            );
            
            int caretOffset = target.getCaretPosition();
            int caretViewIndex = rootView.getViewIndex(caretOffset, Position.Bias.Forward);
            /*DEBUG*/System.err.println("caretOffset=" + caretOffset + ", caretViewIndex=" + caretViewIndex);
            if (caretViewIndex >= 0 && caretViewIndex < rootView.getViewCount()) {
                View caretView = rootView.getView(caretViewIndex);
                /*DEBUG*/System.err.println("caretView: " + caretView);
            }
            /*DEBUG*/System.err.println(FixLineSyntaxState.lineInfosToString(adoc));
            
            // Check the hierarchy correctness
            org.netbeans.editor.view.spi.ViewUtilities.checkViewHierarchy(rootView);
        }
    }
    
    /** Starts a new line in code. */
    public static class StartNewLine extends BaseAction {
        public StartNewLine(){
            super( BaseKit.startNewLineAction, ABBREV_RESET
                  | MAGIC_POSITION_RESET | UNDO_MERGE_RESET);
        }
        
        public void actionPerformed(ActionEvent evt, JTextComponent target) {
            // shift-enter while editing aka startNewLineAction
            if (!target.isEditable() || !target.isEnabled()) {
                target.getToolkit().beep();
                return;
            }
            
            
            BaseDocument doc = (BaseDocument)target.getDocument();
            
            doc.atomicLock();
            try {
                target.replaceSelection(""); //NOI18N
                Caret caret = target.getCaret();
                
                // insert and remove '-' to remember caret
                // position
                int dotpos = caret.getDot();
                doc.insertString(dotpos,"-",null); //NOI18N
                doc.remove(dotpos,1);
                int eolDot = Utilities.getRowEnd(target, caret.getDot());
                int newDotPos = doc.getFormatter().indentNewLine(doc,eolDot);
                caret.setDot(newDotPos);
            } catch (BadLocationException ex) {
                ex.printStackTrace();
            } finally{
                doc.atomicUnlock();
            }
        }
    }
    
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy