Source Code Cross Referenced for MoeActions.java in  » IDE » bluej-editor » bluej » editor » moe » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » bluej editor » bluej.editor.moe 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // Copyright (c) 2000, 2005 BlueJ Group, Deakin University
0002:        //
0003:        // This software is made available under the terms of the "MIT License"
0004:        // A copy of this license is included with this source distribution
0005:        // in "license.txt" and is also available at:
0006:        // http://www.opensource.org/licenses/mit-license.html 
0007:        // Any queries should be directed to Michael Kolling mik@bluej.org
0008:
0009:        package bluej.editor.moe;
0010:
0011:        import java.awt.Container;
0012:        import java.awt.Event;
0013:        import java.awt.Toolkit;
0014:        import java.awt.datatransfer.*;
0015:        import java.awt.event.ActionEvent;
0016:        import java.awt.event.KeyAdapter;
0017:        import java.awt.event.KeyEvent;
0018:        import java.io.*;
0019:        import java.util.ArrayList;
0020:        import java.util.Hashtable;
0021:        import java.util.Iterator;
0022:
0023:        import javax.swing.*;
0024:        import javax.swing.event.DocumentEvent;
0025:        import javax.swing.text.*;
0026:        import javax.swing.undo.CannotRedoException;
0027:        import javax.swing.undo.CannotUndoException;
0028:
0029:        import bluej.Config;
0030:        import bluej.prefmgr.PrefMgr;
0031:        import bluej.prefmgr.PrefMgrDialog;
0032:        import bluej.utility.Debug;
0033:        import bluej.utility.DialogManager;
0034:
0035:        /**
0036:         * A set of actions supported by the Moe editor. This is a singleton: the
0037:         * actions are shared between all editor instances.
0038:         * 
0039:         * Actions are stored both in a hashtable and in an array. The hashtable is used
0040:         * for fast lookup by name, whereas the array is needed to support complete,
0041:         * ordered access.
0042:         * 
0043:         * @author Michael Kolling
0044:         * @author Bruce Quig
0045:         */
0046:
0047:        public final class MoeActions {
0048:            // -------- CONSTANTS --------
0049:
0050:            private static final String KEYS_FILE = "editor.keys";
0051:
0052:            private static int SHORTCUT_MASK;
0053:            private static int ALT_SHORTCUT_MASK;
0054:            private static int SHIFT_SHORTCUT_MASK;
0055:            private static int SHIFT_ALT_SHORTCUT_MASK;
0056:            private static int DOUBLE_SHORTCUT_MASK; // two masks (ie. CTRL + META)
0057:
0058:            private static final int tabSize = Config.getPropInteger(
0059:                    "bluej.editor.tabsize", 4);
0060:            private static final String spaces = "                                        ";
0061:            private static final char TAB_CHAR = '\t';
0062:
0063:            // -------- INSTANCE VARIABLES --------
0064:
0065:            private Action[] actionTable; // table of all known actions
0066:            private Hashtable actions; // the same actions in a hashtable
0067:            private String[] categories;
0068:            private int[] categoryIndex;
0069:
0070:            private Keymap keymap; // the editor's keymap
0071:            private KeyCatcher keyCatcher;
0072:
0073:            private boolean lastActionWasCut; // true if last action was a cut action
0074:            // undo helpers
0075:            public UndoAction undoAction;
0076:            public RedoAction redoAction;
0077:
0078:            // frequently needed actions
0079:            public Action compileAction;
0080:
0081:            // for bug workaround:
0082:            private InputMap componentInputMap;
0083:
0084:            // =========================== STATIC METHODS ===========================
0085:
0086:            private static MoeActions moeActions;
0087:
0088:            /**
0089:             * Get the actions object (a singleton) and, at the same time, install the
0090:             * action keymap as the main keymap for the given textComponent..
0091:             */
0092:            public static MoeActions getActions(JTextComponent textComponent) {
0093:                if (moeActions == null)
0094:                    moeActions = new MoeActions(textComponent);
0095:
0096:                if (textComponent != null)
0097:                    textComponent.setKeymap(moeActions.keymap);
0098:                return moeActions;
0099:            }
0100:
0101:            // ========================== INSTANCE METHODS ==========================
0102:
0103:            /**
0104:             * Constructor. Singleton, thus private.
0105:             */
0106:            private MoeActions(JTextComponent textComponent) {
0107:                // sort out modifier keys...
0108:                SHORTCUT_MASK = Toolkit.getDefaultToolkit()
0109:                        .getMenuShortcutKeyMask();
0110:
0111:                if (SHORTCUT_MASK == Event.CTRL_MASK)
0112:                    ALT_SHORTCUT_MASK = Event.META_MASK; // alternate (second) modifier
0113:                else
0114:                    ALT_SHORTCUT_MASK = Event.CTRL_MASK;
0115:
0116:                SHIFT_SHORTCUT_MASK = SHORTCUT_MASK + Event.SHIFT_MASK;
0117:                SHIFT_ALT_SHORTCUT_MASK = Event.SHIFT_MASK + ALT_SHORTCUT_MASK;
0118:                DOUBLE_SHORTCUT_MASK = SHORTCUT_MASK + ALT_SHORTCUT_MASK;
0119:
0120:                // install our own keymap, with the existing one as parent
0121:                keymap = JTextComponent.addKeymap("BlueJ map", textComponent
0122:                        .getKeymap());
0123:
0124:                createActionTable(textComponent);
0125:                keyCatcher = new KeyCatcher();
0126:                if (!load())
0127:                    setDefaultKeyBindings();
0128:                lastActionWasCut = false;
0129:
0130:                // for bug workaround (below)
0131:                componentInputMap = textComponent.getInputMap();
0132:            }
0133:
0134:            public void setUndoEnabled(boolean enabled) {
0135:                undoAction.setEnabled(enabled);
0136:            }
0137:
0138:            public void setRedoEnabled(boolean enabled) {
0139:                redoAction.setEnabled(enabled);
0140:            }
0141:
0142:            /**
0143:             * Return an action with a given name.
0144:             */
0145:            public Action getActionByName(String name) {
0146:                return (Action) (actions.get(name));
0147:            }
0148:
0149:            /**
0150:             * Get a keystroke for an action. Return null is there is none.
0151:             */
0152:            public KeyStroke[] getKeyStrokesForAction(Action action) {
0153:                KeyStroke[] keys = keymap.getKeyStrokesForAction(action);
0154:                keys = addComponentKeyStrokes(action, keys); // BUG workaround
0155:                if (keys != null && keys.length > 0)
0156:                    return keys;
0157:                else
0158:                    return null;
0159:            }
0160:
0161:            /**
0162:             * BUG WORKAROUND: currently, keymap.getKeyStrokesForAction() misses
0163:             * keystrokes that come from JComponents inputMap. Here, we add those
0164:             * ourselves...
0165:             */
0166:            public KeyStroke[] addComponentKeyStrokes(Action action,
0167:                    KeyStroke[] keys) {
0168:                ArrayList keyStrokes = null;
0169:                KeyStroke[] componentKeys = componentInputMap.allKeys();
0170:
0171:                // find all component keys that bind to this action
0172:                for (int i = 0; i < componentKeys.length; i++) {
0173:                    if (componentInputMap.get(componentKeys[i]).equals(
0174:                            action.getValue(Action.NAME))) {
0175:                        if (keyStrokes == null)
0176:                            keyStrokes = new ArrayList();
0177:                        keyStrokes.add(componentKeys[i]);
0178:                    }
0179:                }
0180:
0181:                // test whether this keyStroke was redefined in keymap
0182:                if (keyStrokes != null) {
0183:                    for (Iterator i = keyStrokes.iterator(); i.hasNext();) {
0184:                        if (keymap.getAction((KeyStroke) i.next()) != null) {
0185:                            i.remove();
0186:                        }
0187:                    }
0188:                }
0189:
0190:                // merge found keystrokes into key array
0191:                if ((keyStrokes == null) || (keyStrokes.size() == 0))
0192:                    return keys;
0193:
0194:                KeyStroke[] allKeys;
0195:                if (keys == null) {
0196:                    allKeys = new KeyStroke[keyStrokes.size()];
0197:                    keyStrokes.toArray(allKeys);
0198:                } else { // merge new keystrokes into keys
0199:                    allKeys = new KeyStroke[keyStrokes.size() + keys.length];
0200:                    keyStrokes.toArray(allKeys);
0201:                    System.arraycopy(allKeys, 0, allKeys, keys.length,
0202:                            keyStrokes.size());
0203:                    System.arraycopy(keys, 0, allKeys, 0, keys.length);
0204:                }
0205:                return allKeys;
0206:            }
0207:
0208:            /**
0209:             * Add a new key binding into the action table.
0210:             */
0211:            public void addActionForKeyStroke(KeyStroke key, Action a) {
0212:                keymap.addActionForKeyStroke(key, a);
0213:            }
0214:
0215:            /**
0216:             * Remove a key binding from the action table.
0217:             */
0218:            public void removeKeyStrokeBinding(KeyStroke key) {
0219:                keymap.removeKeyStrokeBinding(key);
0220:            }
0221:
0222:            /**
0223:             * Save the key bindings. Return true if successful.
0224:             */
0225:            public boolean save() {
0226:                try {
0227:                    File file = Config.getUserConfigFile(KEYS_FILE);
0228:                    FileOutputStream ostream = new FileOutputStream(file);
0229:                    ObjectOutputStream stream = new ObjectOutputStream(ostream);
0230:                    KeyStroke[] keys = keymap.getBoundKeyStrokes();
0231:                    stream.writeInt(MoeEditor.version);
0232:                    stream.writeInt(keys.length);
0233:                    for (int i = 0; i < keys.length; i++) {
0234:                        stream.writeObject(keys[i]);
0235:                        stream.writeObject(keymap.getAction(keys[i]).getValue(
0236:                                Action.NAME));
0237:                    }
0238:                    stream.flush();
0239:                    ostream.close();
0240:                    return true;
0241:                } catch (Exception exc) {
0242:                    Debug.message("Cannot save key bindings: " + exc);
0243:                    return false;
0244:                }
0245:            }
0246:
0247:            /**
0248:             * Load the key bindings. Return true if successful.
0249:             */
0250:            public boolean load() {
0251:                try {
0252:                    File file = Config.getUserConfigFile(KEYS_FILE);
0253:                    FileInputStream istream = new FileInputStream(file);
0254:                    ObjectInputStream stream = new ObjectInputStream(istream);
0255:                    //KeyStroke[] keys = keymap.getBoundKeyStrokes();
0256:                    int version = 0;
0257:                    int count = stream.readInt();
0258:                    if (count > 100) { // it was new format: version number stored first
0259:                        version = count;
0260:                        count = stream.readInt();
0261:                    }
0262:                    if (Config.isMacOS() && (version < 140)) {
0263:                        // do not attempt to load old bindings on MacOS when switching
0264:                        // to jdk 1.4.1
0265:                        return false;
0266:                    }
0267:
0268:                    for (int i = 0; i < count; i++) {
0269:                        KeyStroke key = (KeyStroke) stream.readObject();
0270:                        String actionName = (String) stream.readObject();
0271:                        Action action = (Action) (actions.get(actionName));
0272:                        if (action != null) {
0273:                            keymap.addActionForKeyStroke(key, action);
0274:                        }
0275:                    }
0276:                    istream.close();
0277:
0278:                    // set up bindings for new actions in recent releases
0279:
0280:                    if (version < 130) {
0281:                        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
0282:                                KeyEvent.VK_TAB, 0), (Action) (actions
0283:                                .get("indent")));
0284:                        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
0285:                                KeyEvent.VK_TAB, Event.SHIFT_MASK),
0286:                                (Action) (actions.get("insert-tab")));
0287:                        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
0288:                                KeyEvent.VK_ENTER, 0), (Action) (actions
0289:                                .get("new-line")));
0290:                        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
0291:                                KeyEvent.VK_ENTER, Event.SHIFT_MASK),
0292:                                (Action) (actions.get("insert-break")));
0293:                    }
0294:                    if (version < 200) {
0295:                        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
0296:                                KeyEvent.VK_TAB, Event.SHIFT_MASK),
0297:                                (Action) (actions.get("de-indent")));
0298:                        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
0299:                                KeyEvent.VK_I, SHORTCUT_MASK),
0300:                                (Action) (actions.get("insert-tab")));
0301:                    }
0302:                    return true;
0303:                } catch (Exception exc) {
0304:                    // ignore - file probably didn't exist (yet)
0305:                    return false;
0306:                }
0307:            }
0308:
0309:            /**
0310:             * Called to inform that any one of the user actions (text edit or caret
0311:             * move) was executed.
0312:             */
0313:            public void userAction() {
0314:                lastActionWasCut = false;
0315:            }
0316:
0317:            /**
0318:             * Called at every insertion of text into the document.
0319:             */
0320:            public void textInsertAction(DocumentEvent evt,
0321:                    JTextComponent textPane) {
0322:                try {
0323:                    if (evt.getLength() == 1) { // single character inserted
0324:                        Document doc = evt.getDocument();
0325:                        int offset = evt.getOffset();
0326:                        char ch = doc.getText(offset, 1).charAt(0);
0327:
0328:                        // 'ch' is the character that was just typed
0329:                        // currently, the only character upon which we act is the
0330:                        // closing brace ('}')
0331:
0332:                        if (ch == '}') {
0333:                            closingBrace(textPane, doc, offset);
0334:                        }
0335:                    }
0336:                } catch (BadLocationException e) {
0337:                }
0338:            }
0339:
0340:            /**
0341:             * We just typed a closing brace character - indent appropriately.
0342:             */
0343:            private void closingBrace(JTextComponent textPane, Document doc,
0344:                    int offset) throws BadLocationException {
0345:                int lineIndex = getCurrentLineIndex(textPane);
0346:                Element line = getLine(textPane, lineIndex);
0347:                int lineStart = line.getStartOffset();
0348:                String prefix = doc.getText(lineStart, offset - lineStart);
0349:
0350:                if (prefix.trim().length() == 0) { // only if there is no other text before '}'
0351:                    textPane.setCaretPosition(lineStart);
0352:                    doIndent(textPane, true);
0353:                    textPane.setCaretPosition(textPane.getCaretPosition() + 1);
0354:                }
0355:            }
0356:
0357:            /**
0358:             * Get a keystroke for an action by action name. Return null is there is
0359:             * none.
0360:             */
0361:            //      public KeyStroke[] getKeyStrokesForName(String actionName)
0362:            //      {
0363:            //  	Action action = getActionByName(actionName);
0364:            //  	KeyStroke[] keys = keymap.getKeyStrokesForAction(action);
0365:            //  	if (keys != null && keys.length > 0)
0366:            //  	    return keys;
0367:            //  	else
0368:            //  	    return null;
0369:            //      }
0370:            // ============================ USER ACTIONS =============================
0371:            abstract class MoeAbstractAction extends TextAction {
0372:
0373:                public MoeAbstractAction(String name) {
0374:                    super (name);
0375:                }
0376:
0377:                /* side effect: clears message in editor! */
0378:                protected final MoeEditor getEditor(ActionEvent e) {
0379:                    MoeEditor ed = null;
0380:
0381:                    // the source of the event is the first place to look
0382:                    Object source = e.getSource();
0383:                    if (source instanceof  JComponent) {
0384:                        Container c = ((JComponent) source)
0385:                                .getTopLevelAncestor();
0386:                        if (c instanceof  MoeEditor)
0387:                            ed = (MoeEditor) c;
0388:                    }
0389:
0390:                    // otherwise use 'getTextComponent'
0391:                    if (ed == null) {
0392:                        JTextComponent textComponent = getTextComponent(e);
0393:                        if (textComponent != null) {
0394:                            Container c = textComponent.getTopLevelAncestor();
0395:                            if (c instanceof  MoeEditor)
0396:                                ed = (MoeEditor) c;
0397:                        }
0398:                    }
0399:
0400:                    if (ed != null)
0401:                        ed.clearMessage();
0402:                    return ed;
0403:                }
0404:            }
0405:
0406:            // === File: ===
0407:            // --------------------------------------------------------------------
0408:
0409:            class SaveAction extends MoeAbstractAction {
0410:
0411:                public SaveAction() {
0412:                    super ("save");
0413:                }
0414:
0415:                public void actionPerformed(ActionEvent e) {
0416:                    getEditor(e).userSave();
0417:                }
0418:            }
0419:
0420:            // --------------------------------------------------------------------
0421:
0422:            /**
0423:             * Reload has been chosen. Ask "Really?" and call "doReload" if the answer
0424:             * is yes.
0425:             */
0426:            class ReloadAction extends MoeAbstractAction {
0427:
0428:                public ReloadAction() {
0429:                    super ("reload");
0430:                }
0431:
0432:                public void actionPerformed(ActionEvent e) {
0433:                    getEditor(e).reload();
0434:                }
0435:            }
0436:
0437:            // --------------------------------------------------------------------
0438:
0439:            class PrintAction extends MoeAbstractAction {
0440:
0441:                public PrintAction() {
0442:                    super ("print");
0443:                }
0444:
0445:                public void actionPerformed(ActionEvent e) {
0446:                    getEditor(e).print();
0447:                }
0448:            }
0449:
0450:            // --------------------------------------------------------------------
0451:
0452:            class PageSetupAction extends MoeAbstractAction {
0453:
0454:                public PageSetupAction() {
0455:                    super ("page-setup");
0456:                }
0457:
0458:                public void actionPerformed(ActionEvent e) {
0459:                    getEditor(e).pageSetup();
0460:                }
0461:            }
0462:
0463:            // --------------------------------------------------------------------
0464:
0465:            class CloseAction extends MoeAbstractAction {
0466:
0467:                public CloseAction() {
0468:                    super ("close");
0469:                }
0470:
0471:                public void actionPerformed(ActionEvent e) {
0472:                    getEditor(e).close();
0473:                }
0474:            }
0475:
0476:            // === Edit: ===
0477:            // --------------------------------------------------------------------
0478:
0479:            class UndoAction extends MoeAbstractAction {
0480:
0481:                public UndoAction() {
0482:                    super ("undo");
0483:                    this .setEnabled(false);
0484:                }
0485:
0486:                public void actionPerformed(ActionEvent e) {
0487:                    MoeEditor editor = getEditor(e);
0488:                    try {
0489:                        editor.undoManager.undo();
0490:                    } catch (CannotUndoException ex) {
0491:                        Debug.message("moe: cannot undo...");
0492:                    }
0493:                    editor.updateUndoControls();
0494:                    editor.updateRedoControls();
0495:                }
0496:            }
0497:
0498:            // --------------------------------------------------------------------
0499:
0500:            class RedoAction extends MoeAbstractAction {
0501:
0502:                public RedoAction() {
0503:                    super ("redo");
0504:                    this .setEnabled(false);
0505:                }
0506:
0507:                public void actionPerformed(ActionEvent e) {
0508:                    MoeEditor editor = getEditor(e);
0509:                    try {
0510:                        editor.undoManager.redo();
0511:                    } catch (CannotRedoException ex) {
0512:                        Debug.message("moe: cannot redo...");
0513:                    }
0514:                    editor.updateUndoControls();
0515:                    editor.updateRedoControls();
0516:                }
0517:            }
0518:
0519:            // --------------------------------------------------------------------
0520:
0521:            class CommentBlockAction extends MoeAbstractAction {
0522:
0523:                public CommentBlockAction() {
0524:                    super ("comment-block");
0525:                }
0526:
0527:                public void actionPerformed(ActionEvent e) {
0528:                    MoeEditor editor = getEditor(e);
0529:                    editor.undoManager.beginCompoundEdit();
0530:                    blockAction(getTextComponent(e), new CommentLineAction());
0531:                    editor.undoManager.endCompoundEdit();
0532:                }
0533:            }
0534:
0535:            // --------------------------------------------------------------------
0536:
0537:            class UncommentBlockAction extends MoeAbstractAction {
0538:
0539:                public UncommentBlockAction() {
0540:                    super ("uncomment-block");
0541:                }
0542:
0543:                public void actionPerformed(ActionEvent e) {
0544:                    MoeEditor editor = getEditor(e);
0545:                    editor.undoManager.beginCompoundEdit();
0546:                    blockAction(getTextComponent(e), new UncommentLineAction());
0547:                    editor.undoManager.endCompoundEdit();
0548:                }
0549:            }
0550:
0551:            // --------------------------------------------------------------------
0552:
0553:            class IndentBlockAction extends MoeAbstractAction {
0554:
0555:                public IndentBlockAction() {
0556:                    super ("indent-block");
0557:                }
0558:
0559:                public void actionPerformed(ActionEvent e) {
0560:                    MoeEditor editor = getEditor(e);
0561:                    editor.undoManager.beginCompoundEdit();
0562:                    blockAction(getTextComponent(e), new IndentLineAction());
0563:                    editor.undoManager.endCompoundEdit();
0564:                }
0565:            }
0566:
0567:            // --------------------------------------------------------------------
0568:
0569:            class DeindentBlockAction extends MoeAbstractAction {
0570:
0571:                public DeindentBlockAction() {
0572:                    super ("deindent-block");
0573:                }
0574:
0575:                public void actionPerformed(ActionEvent e) {
0576:                    MoeEditor editor = getEditor(e);
0577:                    editor.undoManager.beginCompoundEdit();
0578:                    blockAction(getTextComponent(e), new DeindentLineAction());
0579:                    editor.undoManager.endCompoundEdit();
0580:                }
0581:            }
0582:
0583:            // --------------------------------------------------------------------
0584:
0585:            class InsertMethodAction extends MoeAbstractAction {
0586:
0587:                public InsertMethodAction() {
0588:                    super ("insert-method");
0589:                }
0590:
0591:                public void actionPerformed(ActionEvent e) {
0592:                    MoeEditor editor = getEditor(e);
0593:                    editor.undoManager.beginCompoundEdit();
0594:                    insertTemplate(getTextComponent(e), "method");
0595:                    editor.undoManager.endCompoundEdit();
0596:                }
0597:            }
0598:
0599:            // --------------------------------------------------------------------
0600:
0601:            class IndentAction extends MoeAbstractAction {
0602:
0603:                public IndentAction() {
0604:                    super ("indent");
0605:                }
0606:
0607:                public void actionPerformed(ActionEvent e) {
0608:                    JTextComponent textPane = getTextComponent(e);
0609:                    MoeEditor ed = getEditor(e);
0610:
0611:                    // if necessary, convert all TABs in the current editor to spaces
0612:                    int converted = 0;
0613:                    if (ed.checkExpandTabs()) // do TABs need expanding?
0614:                        converted = convertTabsToSpaces(textPane);
0615:
0616:                    if (PrefMgr.getFlag(PrefMgr.AUTO_INDENT))
0617:                        doIndent(textPane, false);
0618:                    else
0619:                        insertSpacedTab(textPane);
0620:
0621:                    if (converted > 0)
0622:                        ed.writeMessage(Config
0623:                                .getString("editor.info.tabsExpanded"));
0624:                }
0625:            }
0626:
0627:            // --------------------------------------------------------------------
0628:
0629:            class DeIndentAction extends MoeAbstractAction {
0630:
0631:                public DeIndentAction() {
0632:                    super ("de-indent");
0633:                }
0634:
0635:                public void actionPerformed(ActionEvent e) {
0636:                    JTextComponent textPane = getTextComponent(e);
0637:                    MoeEditor ed = getEditor(e);
0638:
0639:                    // if necessary, convert all TABs in the current editor to spaces
0640:                    if (ed.checkExpandTabs()) { // do TABs need expanding?
0641:                        int converted = convertTabsToSpaces(textPane);
0642:
0643:                        if (converted > 0)
0644:                            ed.writeMessage(Config
0645:                                    .getString("editor.info.tabsExpanded"));
0646:                    }
0647:                    doDeIndent(textPane);
0648:                }
0649:            }
0650:
0651:            // --------------------------------------------------------------------
0652:
0653:            class NewLineAction extends MoeAbstractAction {
0654:
0655:                public NewLineAction() {
0656:                    super ("new-line");
0657:                }
0658:
0659:                public void actionPerformed(ActionEvent e) {
0660:
0661:                    Action action = (Action) (actions
0662:                            .get(DefaultEditorKit.insertBreakAction));
0663:                    action.actionPerformed(e);
0664:
0665:                    if (PrefMgr.getFlag(PrefMgr.AUTO_INDENT)) {
0666:                        JTextComponent textPane = getTextComponent(e);
0667:                        doIndent(textPane, true);
0668:                    }
0669:                }
0670:            }
0671:
0672:            // --------------------------------------------------------------------
0673:
0674:            class CopyLineAction extends MoeAbstractAction {
0675:
0676:                public CopyLineAction() {
0677:                    super ("copy-line");
0678:                }
0679:
0680:                public void actionPerformed(ActionEvent e) {
0681:                    boolean addToClipboard = lastActionWasCut;
0682:                    getActionByName("caret-begin-line").actionPerformed(e);
0683:                    getActionByName("selection-down").actionPerformed(e);
0684:                    if (addToClipboard)
0685:                        addSelectionToClipboard(getTextComponent(e));
0686:                    else
0687:                        getActionByName("copy-to-clipboard").actionPerformed(e);
0688:                    lastActionWasCut = true;
0689:                }
0690:            }
0691:
0692:            // --------------------------------------------------------------------
0693:
0694:            class CutLineAction extends MoeAbstractAction {
0695:
0696:                public CutLineAction() {
0697:                    super ("cut-line");
0698:                }
0699:
0700:                public void actionPerformed(ActionEvent e) {
0701:                    boolean addToClipboard = lastActionWasCut;
0702:                    getActionByName("caret-begin-line").actionPerformed(e);
0703:                    getActionByName("selection-down").actionPerformed(e);
0704:                    if (addToClipboard) {
0705:                        addSelectionToClipboard(getTextComponent(e));
0706:                        getActionByName("delete-previous").actionPerformed(e);
0707:                    } else
0708:                        getActionByName("cut-to-clipboard").actionPerformed(e);
0709:                    lastActionWasCut = true;
0710:                }
0711:            }
0712:
0713:            // --------------------------------------------------------------------
0714:
0715:            class CutEndOfLineAction extends MoeAbstractAction {
0716:
0717:                public CutEndOfLineAction() {
0718:                    super ("cut-end-of-line");
0719:                }
0720:
0721:                public void actionPerformed(ActionEvent e) {
0722:                    boolean addToClipboard = lastActionWasCut;
0723:
0724:                    getActionByName("selection-end-line").actionPerformed(e);
0725:                    JTextComponent textComponent = getTextComponent(e);
0726:                    String selection = textComponent.getSelectedText();
0727:                    if (selection == null)
0728:                        getActionByName("selection-forward").actionPerformed(e);
0729:
0730:                    if (addToClipboard) {
0731:                        addSelectionToClipboard(textComponent);
0732:                        getActionByName("delete-previous").actionPerformed(e);
0733:                    } else
0734:                        getActionByName("cut-to-clipboard").actionPerformed(e);
0735:                    lastActionWasCut = true;
0736:                }
0737:            }
0738:
0739:            // --------------------------------------------------------------------
0740:
0741:            class CutWordAction extends MoeAbstractAction {
0742:
0743:                public CutWordAction() {
0744:                    super ("cut-word");
0745:                }
0746:
0747:                public void actionPerformed(ActionEvent e) {
0748:                    boolean addToClipboard = lastActionWasCut;
0749:                    getActionByName("caret-previous-word").actionPerformed(e);
0750:                    getActionByName("selection-next-word").actionPerformed(e);
0751:                    if (addToClipboard) {
0752:                        addSelectionToClipboard(getTextComponent(e));
0753:                        getActionByName("delete-previous").actionPerformed(e);
0754:                    } else
0755:                        getActionByName("cut-to-clipboard").actionPerformed(e);
0756:                    lastActionWasCut = true;
0757:                }
0758:            }
0759:
0760:            // --------------------------------------------------------------------
0761:
0762:            class CutEndOfWordAction extends MoeAbstractAction {
0763:
0764:                public CutEndOfWordAction() {
0765:                    super ("cut-end-of-word");
0766:                }
0767:
0768:                public void actionPerformed(ActionEvent e) {
0769:                    boolean addToClipboard = lastActionWasCut;
0770:                    getActionByName("selection-next-word").actionPerformed(e);
0771:                    if (addToClipboard) {
0772:                        addSelectionToClipboard(getTextComponent(e));
0773:                        getActionByName("delete-previous").actionPerformed(e);
0774:                    } else
0775:                        getActionByName("cut-to-clipboard").actionPerformed(e);
0776:                    lastActionWasCut = true;
0777:                }
0778:            }
0779:
0780:            // === Tools: ===
0781:
0782:            // --------------------------------------------------------------------
0783:
0784:            class FindAction extends MoeAbstractAction {
0785:
0786:                public FindAction() {
0787:                    super ("find");
0788:                }
0789:
0790:                public void actionPerformed(ActionEvent e) {
0791:                    getEditor(e).find();
0792:                }
0793:            }
0794:
0795:            // --------------------------------------------------------------------
0796:
0797:            class FindNextAction extends MoeAbstractAction {
0798:
0799:                public FindNextAction() {
0800:                    super ("find-next");
0801:                }
0802:
0803:                public void actionPerformed(ActionEvent e) {
0804:                    getEditor(e).findNext();
0805:                }
0806:            }
0807:
0808:            // --------------------------------------------------------------------
0809:
0810:            class FindNextBackwardAction extends MoeAbstractAction {
0811:
0812:                public FindNextBackwardAction() {
0813:                    super ("find-next-backward");
0814:                }
0815:
0816:                public void actionPerformed(ActionEvent e) {
0817:                    getEditor(e).findNextBackward();
0818:                }
0819:            }
0820:
0821:            // --------------------------------------------------------------------
0822:
0823:            class ReplaceAction extends MoeAbstractAction {
0824:
0825:                public ReplaceAction() {
0826:                    super ("replace");
0827:                }
0828:
0829:                public void actionPerformed(ActionEvent e) {
0830:                    getEditor(e).replace();
0831:                }
0832:            }
0833:
0834:            // --------------------------------------------------------------------
0835:
0836:            class CompileAction extends MoeAbstractAction {
0837:
0838:                public CompileAction() {
0839:                    super ("compile");
0840:                }
0841:
0842:                public void actionPerformed(ActionEvent e) {
0843:                    getEditor(e).compile();
0844:                }
0845:            }
0846:
0847:            // --------------------------------------------------------------------
0848:
0849:            class ToggleInterfaceAction extends MoeAbstractAction {
0850:
0851:                public ToggleInterfaceAction() {
0852:                    super ("toggle-interface-view");
0853:                }
0854:
0855:                public void actionPerformed(ActionEvent e) {
0856:                    Object source = e.getSource();
0857:                    if (source instanceof  JComboBox)
0858:                        getEditor(e).toggleInterface();
0859:                    else
0860:                        getEditor(e).toggleInterfaceMenu();
0861:                }
0862:            }
0863:
0864:            // === Debug: ===
0865:            // --------------------------------------------------------------------
0866:
0867:            class ToggleBreakPointAction extends MoeAbstractAction {
0868:
0869:                public ToggleBreakPointAction() {
0870:                    super ("toggle-breakpoint");
0871:                }
0872:
0873:                public void actionPerformed(ActionEvent e) {
0874:                    getEditor(e).toggleBreakpoint();
0875:                }
0876:            }
0877:
0878:            // === Options: ===
0879:            // --------------------------------------------------------------------
0880:
0881:            class KeyBindingsAction extends MoeAbstractAction {
0882:
0883:                public KeyBindingsAction() {
0884:                    super ("key-bindings");
0885:                }
0886:
0887:                public void actionPerformed(ActionEvent e) {
0888:                    FunctionDialog dlg = new FunctionDialog(getEditor(e),
0889:                            actionTable, categories, categoryIndex);
0890:
0891:                    dlg.setVisible(true);
0892:                }
0893:            }
0894:
0895:            // --------------------------------------------------------------------
0896:
0897:            class PreferencesAction extends MoeAbstractAction {
0898:
0899:                public PreferencesAction() {
0900:                    super ("preferences");
0901:                }
0902:
0903:                public void actionPerformed(ActionEvent e) {
0904:                    PrefMgrDialog.showDialog(0); // 0 is the index of the editor pane in
0905:                    // the pref dialog
0906:                }
0907:            }
0908:
0909:            // === Help: ===
0910:            // --------------------------------------------------------------------
0911:
0912:            class AboutAction extends MoeAbstractAction {
0913:
0914:                public AboutAction() {
0915:                    super ("about-editor");
0916:                }
0917:
0918:                public void actionPerformed(ActionEvent e) {
0919:                    JOptionPane
0920:                            .showMessageDialog(
0921:                                    getEditor(e),
0922:                                    new String[] {
0923:                                            "Moe",
0924:                                            "Version "
0925:                                                    + MoeEditor.versionString,
0926:                                            " ",
0927:                                            "Moe is the editor of the BlueJ programming environment.",
0928:                                            "Written by Michael K\u00F6lling (mik@bluej.org)." },
0929:                                    "About Moe",
0930:                                    JOptionPane.INFORMATION_MESSAGE);
0931:                }
0932:            }
0933:
0934:            // --------------------------------------------------------------------
0935:
0936:            class DescribeKeyAction extends MoeAbstractAction {
0937:
0938:                public DescribeKeyAction() {
0939:                    super ("describe-key");
0940:                }
0941:
0942:                public void actionPerformed(ActionEvent e) {
0943:                    JTextComponent textComponent = getTextComponent(e);
0944:                    textComponent.addKeyListener(keyCatcher);
0945:                    MoeEditor ed = getEditor(e);
0946:                    keyCatcher.setEditor(ed);
0947:                    ed.writeMessage("Describe key: ");
0948:                }
0949:            }
0950:
0951:            // --------------------------------------------------------------------
0952:
0953:            class HelpMouseAction extends MoeAbstractAction {
0954:
0955:                public HelpMouseAction() {
0956:                    super ("help-mouse");
0957:                }
0958:
0959:                public void actionPerformed(ActionEvent e) {
0960:                    JOptionPane.showMessageDialog(getEditor(e), new String[] {
0961:                            "Moe Mouse Buttons:", " ", "left button:",
0962:                            "   click: place cursor",
0963:                            "   double-click: select word",
0964:                            "   triple-click: select line",
0965:                            "   drag: make selection", " ", "right button:",
0966:                            "   (currently unused)", }, "Moe Mouse Buttons",
0967:                            JOptionPane.INFORMATION_MESSAGE);
0968:                }
0969:            }
0970:
0971:            // --------------------------------------------------------------------
0972:
0973:            class ShowManualAction extends MoeAbstractAction {
0974:
0975:                public ShowManualAction() {
0976:                    super ("show-manual");
0977:                }
0978:
0979:                public void actionPerformed(ActionEvent e) {
0980:                    DialogManager.NYI(getEditor(e));
0981:                }
0982:            }
0983:
0984:            // --------------------------------------------------------------------
0985:
0986:            class GoToLineAction extends MoeAbstractAction {
0987:
0988:                public GoToLineAction() {
0989:                    super ("go-to-line");
0990:                }
0991:
0992:                public void actionPerformed(ActionEvent e) {
0993:                    getEditor(e).goToLine();
0994:                }
0995:            }
0996:
0997:            // --------------------------------------------------------------------
0998:            //     class Action extends MoeAbstractAction {
0999:            //
1000:            //       public Action() {
1001:            //  	 super("");
1002:            //       }
1003:            //
1004:            //       public void actionPerformed(ActionEvent e) {
1005:            // 	  DialogManager.NYI(editor);
1006:            //       }
1007:            //     }
1008:
1009:            // ========================= SUPPORT ROUTINES ==========================
1010:
1011:            /**
1012:             * Add the current selection of the text component to the clipboard.
1013:             */
1014:            public void addSelectionToClipboard(JTextComponent textComponent) {
1015:                Clipboard clipboard = textComponent.getToolkit()
1016:                        .getSystemClipboard();
1017:
1018:                // get text from clipboard
1019:                Transferable content = clipboard.getContents(this );
1020:                String clipContent = "";
1021:                if (content != null) {
1022:                    try {
1023:                        clipContent = (String) (content
1024:                                .getTransferData(DataFlavor.stringFlavor));
1025:                    } catch (Exception exc) {
1026:                    } // content was not string
1027:                }
1028:
1029:                // add current selection and store back in clipboard
1030:                StringSelection contents = new StringSelection(clipContent
1031:                        + textComponent.getSelectedText());
1032:                clipboard.setContents(contents, contents);
1033:            }
1034:
1035:            // --------------------------------------------------------------------
1036:            /**
1037:             * Return the current line.
1038:             */
1039:            //    private Element getCurrentLine(JTextComponent text)
1040:            //    {
1041:            //        MoeSyntaxDocument document = (MoeSyntaxDocument)text.getDocument();
1042:            //        return document.getParagraphElement(text.getCaretPosition());
1043:            //    }
1044:            // --------------------------------------------------------------------
1045:            /**
1046:             * Return the current column number.
1047:             */
1048:            private int getCurrentColumn(JTextComponent textPane) {
1049:                Caret caret = textPane.getCaret();
1050:                int pos = Math.min(caret.getMark(), caret.getDot());
1051:                AbstractDocument doc = (AbstractDocument) textPane
1052:                        .getDocument();
1053:                int lineStart = doc.getParagraphElement(pos).getStartOffset();
1054:                return (pos - lineStart);
1055:            }
1056:
1057:            // --------------------------------------------------------------------
1058:            /**
1059:             * Find and return a line by line number
1060:             */
1061:            private Element getLine(JTextComponent text, int lineNo) {
1062:                return text.getDocument().getDefaultRootElement().getElement(
1063:                        lineNo);
1064:            }
1065:
1066:            // -------------------------------------------------------------------
1067:            /**
1068:             * Find and return a line by text position
1069:             */
1070:            private Element getLineAt(JTextComponent text, int pos) {
1071:                MoeSyntaxDocument document = (MoeSyntaxDocument) text
1072:                        .getDocument();
1073:                return document.getParagraphElement(pos);
1074:            }
1075:
1076:            // -------------------------------------------------------------------
1077:            /**
1078:             * Return the number of the current line.
1079:             */
1080:            private int getCurrentLineIndex(JTextComponent text) {
1081:                MoeSyntaxDocument document = (MoeSyntaxDocument) text
1082:                        .getDocument();
1083:                return document.getDefaultRootElement().getElementIndex(
1084:                        text.getCaretPosition());
1085:            }
1086:
1087:            // ===================== ACTION IMPLEMENTATION ======================
1088:
1089:            /**
1090:             * Do some semi-intelligent indentation. That is: indent the current line to
1091:             * the same depth, using the same characters (TABs or spaces) as the line
1092:             * immediately above.
1093:             */
1094:            private void doIndent(JTextComponent textPane, boolean isNewLine) {
1095:                int lineIndex = getCurrentLineIndex(textPane);
1096:                if (lineIndex == 0) { // first line
1097:                    if (!isNewLine)
1098:                        insertSpacedTab(textPane);
1099:                    return;
1100:                }
1101:
1102:                MoeSyntaxDocument doc = (MoeSyntaxDocument) textPane
1103:                        .getDocument();
1104:
1105:                Element line = getLine(textPane, lineIndex);
1106:                int lineStart = line.getStartOffset();
1107:                int pos = textPane.getCaretPosition();
1108:
1109:                try {
1110:                    boolean isOpenBrace = false;
1111:                    boolean isCommentEnd = false, isCommentEndOnly = false;
1112:
1113:                    // if there is any text before the cursor, just insert a tab
1114:
1115:                    String prefix = doc.getText(lineStart, pos - lineStart);
1116:                    if (prefix.trim().length() > 0) {
1117:                        insertSpacedTab(textPane);
1118:                        return;
1119:                    }
1120:
1121:                    // get indentation string from previous line
1122:
1123:                    boolean foundLine = false;
1124:                    int lineOffset = 1;
1125:                    String prevLineText = null;
1126:                    while ((lineIndex - lineOffset >= 0) && !foundLine) {
1127:                        Element prevline = getLine(textPane, lineIndex
1128:                                - lineOffset);
1129:                        int prevLineStart = prevline.getStartOffset();
1130:                        int prevLineEnd = prevline.getEndOffset();
1131:                        prevLineText = doc.getText(prevLineStart, prevLineEnd
1132:                                - prevLineStart);
1133:                        if (!isWhiteSpaceOnly(prevLineText)) {
1134:                            foundLine = true;
1135:                        } else {
1136:                            lineOffset++;
1137:                        }
1138:                    }
1139:                    if (!foundLine) {
1140:                        if (!isNewLine)
1141:                            insertSpacedTab(textPane);
1142:                        return;
1143:                    }
1144:
1145:                    if (isOpenBrace(prevLineText))
1146:                        isOpenBrace = true;
1147:                    else {
1148:                        isCommentEnd = prevLineText.trim().endsWith("*/");
1149:                        isCommentEndOnly = prevLineText.trim().equals("*/");
1150:                    }
1151:
1152:                    int indentPos = findFirstNonIndentChar(prevLineText,
1153:                            isCommentEnd);
1154:
1155:                    // if the cursor is already past the indentation point, insert tab
1156:                    // (unless we just did a line break, then we just stop)
1157:
1158:                    int caretColumn = getCurrentColumn(textPane);
1159:                    if (caretColumn >= indentPos) {
1160:                        if (!isNewLine)
1161:                            insertSpacedTab(textPane);
1162:                        return;
1163:                    }
1164:
1165:                    String indent = prevLineText.substring(0, indentPos);
1166:
1167:                    if (isNewLine && isCommentStart(indent)) {
1168:                        completeNewCommentBlock(textPane, indent);
1169:                        return;
1170:                    }
1171:
1172:                    // find and replace indentation of current line
1173:
1174:                    int lineEnd = line.getEndOffset();
1175:                    String lineText = doc.getText(lineStart, lineEnd
1176:                            - lineStart);
1177:                    indentPos = findFirstNonIndentChar(lineText, true);
1178:                    char firstChar = lineText.charAt(indentPos);
1179:                    doc.remove(lineStart, indentPos);
1180:                    doc.insertString(lineStart, nextIndent(indent, isOpenBrace,
1181:                            isCommentEndOnly), null);
1182:                    if (firstChar == '}')
1183:                        removeTab(textPane, doc);
1184:                } catch (BadLocationException exc) {
1185:                }
1186:            }
1187:
1188:            /**
1189:             * Return true if s contains only whitespace (or nothing).
1190:             */
1191:            private boolean isWhiteSpaceOnly(String s) {
1192:                return s.trim().length() == 0;
1193:            }
1194:
1195:            /**
1196:             * Do some semi-intelligent de-indentation. That is: indent the current line
1197:             * one indentation level less that the line above, or less than it currently
1198:             * is.
1199:             */
1200:            private void doDeIndent(JTextComponent textPane) {
1201:                // set cursor to first non-blank character (or eol if none)
1202:                // if indentation is more than line above: indent as line above
1203:                // if indentation is same or less than line above: indent one level back
1204:
1205:                int lineIndex = getCurrentLineIndex(textPane);
1206:                MoeSyntaxDocument doc = (MoeSyntaxDocument) textPane
1207:                        .getDocument();
1208:
1209:                try {
1210:                    Element line = getLine(textPane, lineIndex);
1211:                    int lineStart = line.getStartOffset();
1212:                    int lineEnd = line.getEndOffset();
1213:                    String lineText = doc.getText(lineStart, lineEnd
1214:                            - lineStart);
1215:
1216:                    int currentIndentPos = findFirstNonIndentChar(lineText,
1217:                            true);
1218:                    char firstChar = lineText.charAt(currentIndentPos);
1219:
1220:                    textPane.setCaretPosition(lineStart + currentIndentPos);
1221:
1222:                    if (lineIndex == 0) { // first line
1223:                        removeTab(textPane, doc);
1224:                        return;
1225:                    }
1226:
1227:                    // get indentation details from previous line
1228:
1229:                    Element prevline = getLine(textPane, lineIndex - 1);
1230:                    int prevLineStart = prevline.getStartOffset();
1231:                    int prevLineEnd = prevline.getEndOffset();
1232:                    String prevLineText = doc.getText(prevLineStart,
1233:                            prevLineEnd - prevLineStart);
1234:
1235:                    int targetIndentPos = findFirstNonIndentChar(prevLineText,
1236:                            true);
1237:
1238:                    if (currentIndentPos > targetIndentPos) {
1239:                        // indent same as line above
1240:                        String indent = prevLineText.substring(0,
1241:                                targetIndentPos);
1242:                        doc.remove(lineStart, currentIndentPos);
1243:                        doc.insertString(lineStart, indent, null);
1244:                        if (firstChar == '}')
1245:                            removeTab(textPane, doc);
1246:                    } else {
1247:                        // we are at same level as line above or less - go one indentation
1248:                        // level back
1249:                        removeTab(textPane, doc);
1250:                    }
1251:                } catch (BadLocationException exc) {
1252:                }
1253:            }
1254:
1255:            /**
1256:             * Check whether the indentation s opens a new multi-line comment
1257:             */
1258:            private boolean isCommentStart(String s) {
1259:                s = s.trim();
1260:                return s.endsWith("/**") || s.endsWith("/*");
1261:            }
1262:
1263:            /**
1264:             * Insert text to complete a new, started block comment and place the cursor
1265:             * appropriately.
1266:             * 
1267:             * The indentString passed in always ends with "/*".
1268:             */
1269:            private void completeNewCommentBlock(JTextComponent textPane,
1270:                    String indentString) {
1271:                String nextIndent = indentString.substring(0, indentString
1272:                        .length() - 2);
1273:                textPane.replaceSelection(nextIndent + " * ");
1274:                int pos = textPane.getCaretPosition();
1275:                textPane.replaceSelection("\n");
1276:                textPane.replaceSelection(nextIndent + " */");
1277:                textPane.setCaretPosition(pos);
1278:            }
1279:
1280:            /**
1281:             * Check whether the given line ends with an opening brace.
1282:             */
1283:            private boolean isOpenBrace(String s) {
1284:                int index = s.lastIndexOf('{');
1285:                if (index == -1)
1286:                    return false;
1287:
1288:                return s.indexOf('}', index + 1) == -1;
1289:            }
1290:
1291:            /**
1292:             * Find the position of the first non-indentation character in a string.
1293:             * Indentation characters are <whitespace>, //, *, /*, /**.
1294:             */
1295:            private int findFirstNonIndentChar(String s, boolean whitespaceOnly) {
1296:                int cnt = 0;
1297:                char ch = s.charAt(0);
1298:
1299:                // if this line ends a comment, indent whitepace only;
1300:                // otherwise indent across whitespace, asterisks and comment starts
1301:
1302:                if (whitespaceOnly) {
1303:                    while (ch == ' ' || ch == '\t') { // SPACE or TAB
1304:                        cnt++;
1305:                        ch = s.charAt(cnt);
1306:                    }
1307:                } else {
1308:                    while (ch == ' ' || ch == '\t' || ch == '*') { // SPACE, TAB or *
1309:                        cnt++;
1310:                        ch = s.charAt(cnt);
1311:                    }
1312:                    if ((s.charAt(cnt) == '/') && (s.charAt(cnt + 1) == '*'))
1313:                        cnt += 2;
1314:                }
1315:                return cnt;
1316:            }
1317:
1318:            /**
1319:             * Transform indentation string to ensure: after " / *" follows " *" after " / * *"
1320:             * follows " *" after " * /" follows ""
1321:             */
1322:            private String nextIndent(String s, boolean openBrace,
1323:                    boolean commentEndOnly) {
1324:                // after an opening brace, add some spaces to the indentation
1325:                if (openBrace)
1326:                    return s + spaces.substring(0, tabSize);
1327:
1328:                if (commentEndOnly)
1329:                    return s.substring(0, s.length() - 1);
1330:
1331:                if (s.endsWith("/*"))
1332:                    return s.substring(0, s.length() - 2) + " * ";
1333:
1334:                return s;
1335:            }
1336:
1337:            /**
1338:             * Insert a spaced tab at the current caret position in to the textPane.
1339:             */
1340:            private void insertSpacedTab(JTextComponent textPane) {
1341:                int numSpaces = tabSize
1342:                        - (getCurrentColumn(textPane) % tabSize);
1343:                textPane.replaceSelection(spaces.substring(0, numSpaces));
1344:            }
1345:
1346:            /**
1347:             * Remove characters before the current caret position to take the 
1348:             * caret back to the previous TAB position. No check is made what kind
1349:             * of characters those are - the caller should make sure they can be 
1350:             * removed (usually they should be whitespace).
1351:             */
1352:            private void removeTab(JTextComponent textPane, Document doc)
1353:                    throws BadLocationException {
1354:                int col = getCurrentColumn(textPane);
1355:                if (col > 0) {
1356:                    int remove = col % tabSize;
1357:                    if (remove == 0)
1358:                        remove = tabSize;
1359:                    int pos = textPane.getCaretPosition();
1360:                    doc.remove(pos - remove, remove);
1361:                }
1362:            }
1363:
1364:            /**
1365:             * Convert all tabs in this text to spaces, maintaining the current
1366:             * indentation.
1367:             * 
1368:             * @param textPane The text pane to convert
1369:             * @return  The number of tab characters converted
1370:             */
1371:            private int convertTabsToSpaces(JTextComponent textPane) {
1372:                int count = 0;
1373:                int lineNo = 0;
1374:                AbstractDocument doc = (AbstractDocument) textPane
1375:                        .getDocument();
1376:                Element root = doc.getDefaultRootElement();
1377:                Element line = root.getElement(lineNo);
1378:                try {
1379:                    while (line != null) {
1380:                        int start = line.getStartOffset();
1381:                        int length = line.getEndOffset() - start;
1382:                        String text = doc.getText(start, length);
1383:                        int startCount = count;
1384:                        int tabIndex = text.indexOf('\t');
1385:                        while (tabIndex != -1) {
1386:                            text = expandTab(text, tabIndex);
1387:                            count++;
1388:                            tabIndex = text.indexOf('\t');
1389:                        }
1390:                        if (count != startCount) { // there was a TAB in this line...
1391:                            doc.remove(start, length);
1392:                            doc.insertString(start, text, null);
1393:                        }
1394:                        lineNo++;
1395:                        line = root.getElement(lineNo);
1396:                    }
1397:                } catch (BadLocationException exc) {
1398:                    Debug.reportError("stuffed up in 'convertTabsToSpaces'");
1399:                }
1400:                return count;
1401:            }
1402:
1403:            private String expandTab(String s, int idx) {
1404:                int numSpaces = tabSize - (idx % tabSize);
1405:                return s.substring(0, idx) + spaces.substring(0, numSpaces)
1406:                        + s.substring(idx + 1);
1407:            }
1408:
1409:            /**
1410:             * Insert text from a named template into the editor at the current cursor
1411:             * position. Every line in the template will be indented to the current
1412:             * cursor position (in addition to possible indentation in the template
1413:             * itself), and TAB characters at beginnings of lines in the template will
1414:             * be converted to a spaced tab according to the current tabsize.
1415:             * 
1416:             * @param textPane
1417:             *            The editor pane to enter the text into
1418:             * @param templateName
1419:             *            The name of the template (without path or suffix)
1420:             */
1421:            private void insertTemplate(JTextComponent textPane,
1422:                    String templateName) {
1423:                try {
1424:                    File template = Config.getTemplateFile(templateName);
1425:                    BufferedReader in = new BufferedReader(new FileReader(
1426:                            template));
1427:                    int pos = textPane.getCaretPosition();
1428:                    int column = getCurrentColumn(textPane);
1429:                    if (column > 40)
1430:                        column = 40;
1431:                    String line = in.readLine();
1432:                    while (line != null) {
1433:                        while ((line.length() > 0) && (line.charAt(0) == '\t')) {
1434:                            insertSpacedTab(textPane);
1435:                            line = line.substring(1);
1436:                        }
1437:                        textPane.replaceSelection(line);
1438:                        textPane.replaceSelection("\n");
1439:                        textPane.replaceSelection(spaces.substring(0, column)); // indent
1440:                        line = in.readLine();
1441:                    }
1442:                    textPane.setCaretPosition(pos);
1443:                } catch (IOException exc) {
1444:                    Debug.reportError("Could not read method template.");
1445:                    Debug.reportError("Exception: " + exc);
1446:                }
1447:            }
1448:
1449:            /**
1450:             *  
1451:             */
1452:            private void blockAction(JTextComponent textPane,
1453:                    LineAction lineAction) {
1454:                Caret caret = textPane.getCaret();
1455:                int selectionStart = caret.getMark();
1456:                int selectionEnd = caret.getDot();
1457:                if (selectionStart > selectionEnd) {
1458:                    int tmp = selectionStart;
1459:                    selectionStart = selectionEnd;
1460:                    selectionEnd = tmp;
1461:                }
1462:                if (selectionStart != selectionEnd)
1463:                    selectionEnd = selectionEnd - 1; // skip last position
1464:
1465:                MoeSyntaxDocument doc = (MoeSyntaxDocument) textPane
1466:                        .getDocument();
1467:                Element text = doc.getDefaultRootElement();
1468:
1469:                int firstLineIndex = text.getElementIndex(selectionStart);
1470:                int lastLineIndex = text.getElementIndex(selectionEnd);
1471:                for (int i = firstLineIndex; i <= lastLineIndex; i++) {
1472:                    Element line = text.getElement(i);
1473:                    lineAction.apply(line, doc);
1474:                }
1475:
1476:                textPane.setCaretPosition(text.getElement(firstLineIndex)
1477:                        .getStartOffset());
1478:                textPane.moveCaretPosition(text.getElement(lastLineIndex)
1479:                        .getEndOffset());
1480:            }
1481:
1482:            // --------------------------------------------------------------------
1483:
1484:            /**
1485:             * Create the table of action supported by this editor
1486:             */
1487:            private void createActionTable(JTextComponent textComponent) {
1488:                undoAction = new UndoAction();
1489:                redoAction = new RedoAction();
1490:                compileAction = new CompileAction();
1491:
1492:                // get all actions into arrays
1493:
1494:                Action[] textActions = textComponent.getActions();
1495:                Action[] myActions = { new SaveAction(), new ReloadAction(),
1496:                        new PageSetupAction(), new PrintAction(),
1497:                        new CloseAction(),
1498:
1499:                        undoAction, redoAction, new CommentBlockAction(),
1500:                        new UncommentBlockAction(), new IndentBlockAction(),
1501:                        new DeindentBlockAction(), new InsertMethodAction(),
1502:                        new IndentAction(), new DeIndentAction(),
1503:                        new NewLineAction(), new CopyLineAction(),
1504:                        new CutLineAction(), new CutEndOfLineAction(),
1505:                        new CutWordAction(), new CutEndOfWordAction(),
1506:
1507:                        new FindAction(), new FindNextAction(),
1508:                        new FindNextBackwardAction(), new ReplaceAction(),
1509:                        compileAction, new GoToLineAction(),
1510:                        new ToggleInterfaceAction(),
1511:                        new ToggleBreakPointAction(),
1512:
1513:                        new KeyBindingsAction(), new PreferencesAction(),
1514:
1515:                        new AboutAction(), new DescribeKeyAction(),
1516:                        new HelpMouseAction(), new ShowManualAction(), };
1517:
1518:                // insert all actions into a hashtable
1519:
1520:                actions = new Hashtable();
1521:
1522:                Action action;
1523:                for (int i = 0; i < textActions.length; i++) {
1524:                    action = textActions[i];
1525:                    //Debug.message("a: " + action.getValue(Action.NAME));
1526:                    actions.put(action.getValue(Action.NAME), action);
1527:                }
1528:                for (int i = 0; i < myActions.length; i++) {
1529:                    action = myActions[i];
1530:                    actions.put(action.getValue(Action.NAME), action);
1531:                }
1532:
1533:                // sort all actions into a big, ordered table
1534:
1535:                actionTable = new Action[] {
1536:
1537:                        // edit functions
1538:
1539:                        (Action) (actions
1540:                                .get(DefaultEditorKit.deletePrevCharAction)), // 0
1541:                        (Action) (actions
1542:                                .get(DefaultEditorKit.deleteNextCharAction)),
1543:                        (Action) (actions.get(DefaultEditorKit.copyAction)),
1544:                        (Action) (actions.get(DefaultEditorKit.cutAction)),
1545:                        (Action) (actions.get("copy-line")),
1546:                        (Action) (actions.get("cut-line")),
1547:                        (Action) (actions.get("cut-end-of-line")),
1548:                        (Action) (actions.get("cut-word")),
1549:                        (Action) (actions.get("cut-end-of-word")),
1550:                        (Action) (actions.get(DefaultEditorKit.pasteAction)),
1551:                        (Action) (actions.get("indent")),
1552:                        (Action) (actions.get("de-indent")),
1553:                        (Action) (actions.get(DefaultEditorKit.insertTabAction)),
1554:                        (Action) (actions.get("new-line")),
1555:                        (Action) (actions
1556:                                .get(DefaultEditorKit.insertBreakAction)),
1557:                        (Action) (actions.get("insert-method")),
1558:                        (Action) (actions.get("comment-block")),
1559:                        (Action) (actions.get("uncomment-block")),
1560:                        (Action) (actions.get("indent-block")),
1561:                        (Action) (actions.get("deindent-block")),
1562:
1563:                        (Action) (actions
1564:                                .get(DefaultEditorKit.selectWordAction)), // 20
1565:                        (Action) (actions
1566:                                .get(DefaultEditorKit.selectLineAction)),
1567:                        (Action) (actions
1568:                                .get(DefaultEditorKit.selectParagraphAction)),
1569:                        (Action) (actions.get(DefaultEditorKit.selectAllAction)),
1570:                        (Action) (actions
1571:                                .get(DefaultEditorKit.selectionBackwardAction)),
1572:                        (Action) (actions
1573:                                .get(DefaultEditorKit.selectionForwardAction)),
1574:                        (Action) (actions
1575:                                .get(DefaultEditorKit.selectionUpAction)),
1576:                        (Action) (actions
1577:                                .get(DefaultEditorKit.selectionDownAction)),
1578:                        (Action) (actions
1579:                                .get(DefaultEditorKit.selectionBeginWordAction)),
1580:                        (Action) (actions
1581:                                .get(DefaultEditorKit.selectionEndWordAction)),
1582:                        (Action) (actions
1583:                                .get(DefaultEditorKit.selectionPreviousWordAction)), // 30
1584:                        (Action) (actions
1585:                                .get(DefaultEditorKit.selectionNextWordAction)),
1586:                        (Action) (actions
1587:                                .get(DefaultEditorKit.selectionBeginLineAction)),
1588:                        (Action) (actions
1589:                                .get(DefaultEditorKit.selectionEndLineAction)),
1590:                        (Action) (actions
1591:                                .get(DefaultEditorKit.selectionBeginParagraphAction)),
1592:                        (Action) (actions
1593:                                .get(DefaultEditorKit.selectionEndParagraphAction)),
1594:                        (Action) (actions.get("selection-page-up")),
1595:                        (Action) (actions.get("selection-page-down")),
1596:                        (Action) (actions
1597:                                .get(DefaultEditorKit.selectionBeginAction)),
1598:                        (Action) (actions
1599:                                .get(DefaultEditorKit.selectionEndAction)),
1600:                        (Action) (actions.get("unselect")),
1601:
1602:                        // move and scroll functions
1603:
1604:                        (Action) (actions.get(DefaultEditorKit.backwardAction)), // 41
1605:                        (Action) (actions.get(DefaultEditorKit.forwardAction)),
1606:                        (Action) (actions.get(DefaultEditorKit.upAction)),
1607:                        (Action) (actions.get(DefaultEditorKit.downAction)),
1608:                        (Action) (actions.get(DefaultEditorKit.beginWordAction)),
1609:                        (Action) (actions.get(DefaultEditorKit.endWordAction)),
1610:                        (Action) (actions
1611:                                .get(DefaultEditorKit.previousWordAction)),
1612:                        (Action) (actions.get(DefaultEditorKit.nextWordAction)),
1613:                        (Action) (actions.get(DefaultEditorKit.beginLineAction)),
1614:                        (Action) (actions.get(DefaultEditorKit.endLineAction)), // 50
1615:                        (Action) (actions
1616:                                .get(DefaultEditorKit.beginParagraphAction)),
1617:                        (Action) (actions
1618:                                .get(DefaultEditorKit.endParagraphAction)),
1619:                        (Action) (actions.get(DefaultEditorKit.pageUpAction)),
1620:                        (Action) (actions.get(DefaultEditorKit.pageDownAction)),
1621:                        (Action) (actions.get(DefaultEditorKit.beginAction)),
1622:                        (Action) (actions.get(DefaultEditorKit.endAction)),
1623:
1624:                        // class functions
1625:                        (Action) (actions.get("save")), // 57
1626:                        (Action) (actions.get("reload")),
1627:                        (Action) (actions.get("close")),
1628:                        (Action) (actions.get("print")),
1629:                        (Action) (actions.get("page-setup")),
1630:
1631:                        // customisation functions
1632:                        (Action) (actions.get("key-bindings")), // 62
1633:                        (Action) (actions.get("preferences")),
1634:
1635:                        // help functions
1636:                        (Action) (actions.get("describe-key")), // 64
1637:                        (Action) (actions.get("help-mouse")),
1638:                        (Action) (actions.get("show-manual")),
1639:                        (Action) (actions.get("about-editor")),
1640:
1641:                        // misc functions
1642:                        undoAction, // 68
1643:                        redoAction, (Action) (actions.get("find")),
1644:                        (Action) (actions.get("find-next")),
1645:                        (Action) (actions.get("find-next-backward")),
1646:                        (Action) (actions.get("replace")),
1647:                        (Action) (actions.get("compile")),
1648:                        (Action) (actions.get("toggle-interface-view")),
1649:                        (Action) (actions.get("toggle-breakpoint")),
1650:                        (Action) (actions.get("go-to-line")), }; // 78
1651:
1652:                categories = new String[] {
1653:                        Config.getString("editor.functions.editFunctions"),
1654:                        Config.getString("editor.functions.moveScroll"),
1655:                        Config.getString("editor.functions.classFunctions"),
1656:                        Config.getString("editor.functions.customisation"),
1657:                        Config.getString("editor.functions.help"),
1658:                        Config.getString("editor.functions.misc") };
1659:
1660:                categoryIndex = new int[] { 0, 41, 57, 62, 64, 68, 78 };
1661:            }
1662:
1663:            /**
1664:             * Set up the default key bindings. Used for initial setup, or restoring the
1665:             * default later on.
1666:             */
1667:            public void setDefaultKeyBindings() {
1668:                keymap.removeBindings();
1669:
1670:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1671:                        KeyEvent.VK_S, SHORTCUT_MASK), (Action) (actions
1672:                        .get("save")));
1673:                // "reload" not bound
1674:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1675:                        KeyEvent.VK_P, SHORTCUT_MASK), (Action) (actions
1676:                        .get("print")));
1677:                // "page-setup" not bound
1678:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1679:                        KeyEvent.VK_W, SHORTCUT_MASK), (Action) (actions
1680:                        .get("close")));
1681:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1682:                        KeyEvent.VK_Z, SHORTCUT_MASK), (Action) (actions
1683:                        .get("undo")));
1684:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1685:                        KeyEvent.VK_Y, SHORTCUT_MASK), (Action) (actions
1686:                        .get("redo")));
1687:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1688:                        KeyEvent.VK_F8, 0), (Action) (actions
1689:                        .get("comment-block")));
1690:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1691:                        KeyEvent.VK_F7, 0), (Action) (actions
1692:                        .get("uncomment-block")));
1693:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1694:                        KeyEvent.VK_F6, 0), (Action) (actions
1695:                        .get("indent-block")));
1696:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1697:                        KeyEvent.VK_F5, 0), (Action) (actions
1698:                        .get("deindent-block")));
1699:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1700:                        KeyEvent.VK_M, SHORTCUT_MASK), (Action) (actions
1701:                        .get("insert-method")));
1702:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1703:                        KeyEvent.VK_TAB, 0), (Action) (actions.get("indent")));
1704:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1705:                        KeyEvent.VK_TAB, Event.SHIFT_MASK), (Action) (actions
1706:                        .get("de-indent")));
1707:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1708:                        KeyEvent.VK_I, SHORTCUT_MASK), (Action) (actions
1709:                        .get("insert-tab")));
1710:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1711:                        KeyEvent.VK_ENTER, 0), (Action) (actions
1712:                        .get("new-line")));
1713:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1714:                        KeyEvent.VK_ENTER, Event.SHIFT_MASK), (Action) (actions
1715:                        .get("insert-break")));
1716:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1717:                        KeyEvent.VK_F, SHORTCUT_MASK), (Action) (actions
1718:                        .get("find")));
1719:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1720:                        KeyEvent.VK_G, SHORTCUT_MASK), (Action) (actions
1721:                        .get("find-next")));
1722:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1723:                        KeyEvent.VK_G, SHIFT_SHORTCUT_MASK), (Action) (actions
1724:                        .get("find-next-backward")));
1725:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1726:                        KeyEvent.VK_R, SHORTCUT_MASK), (Action) (actions
1727:                        .get("replace")));
1728:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1729:                        KeyEvent.VK_L, SHORTCUT_MASK), (Action) (actions
1730:                        .get("go-to-line")));
1731:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1732:                        KeyEvent.VK_K, SHORTCUT_MASK), (Action) (actions
1733:                        .get("compile")));
1734:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1735:                        KeyEvent.VK_J, SHORTCUT_MASK), (Action) (actions
1736:                        .get("toggle-interface-view")));
1737:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1738:                        KeyEvent.VK_B, SHORTCUT_MASK), (Action) (actions
1739:                        .get("toggle-breakpoint")));
1740:                // "key-bindings" not bound
1741:                // "preferences" not bound
1742:                // "about-editor" not bound
1743:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1744:                        KeyEvent.VK_D, SHORTCUT_MASK), (Action) (actions
1745:                        .get("describe-key")));
1746:                // "help-mouse" not bound
1747:                // "show-manual" not bound
1748:
1749:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1750:                        KeyEvent.VK_C, SHORTCUT_MASK), (Action) (actions
1751:                        .get(DefaultEditorKit.copyAction)));
1752:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1753:                        KeyEvent.VK_X, SHORTCUT_MASK), (Action) (actions
1754:                        .get(DefaultEditorKit.cutAction)));
1755:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1756:                        KeyEvent.VK_V, SHORTCUT_MASK), (Action) (actions
1757:                        .get(DefaultEditorKit.pasteAction)));
1758:
1759:                // F2, F3, F4
1760:                keymap
1761:                        .addActionForKeyStroke(KeyStroke.getKeyStroke(
1762:                                KeyEvent.VK_F2, 0), (Action) (actions
1763:                                .get("copy-line")));
1764:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1765:                        KeyEvent.VK_F3, 0), (Action) (actions
1766:                        .get(DefaultEditorKit.pasteAction)));
1767:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1768:                        KeyEvent.VK_F4, 0), (Action) (actions.get("cut-line")));
1769:
1770:                // cursor block
1771:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1772:                        KeyEvent.VK_UP, ALT_SHORTCUT_MASK), (Action) (actions
1773:                        .get(DefaultEditorKit.pasteAction)));
1774:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1775:                        KeyEvent.VK_LEFT, ALT_SHORTCUT_MASK), (Action) (actions
1776:                        .get(DefaultEditorKit.deletePrevCharAction)));
1777:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1778:                        KeyEvent.VK_RIGHT, ALT_SHORTCUT_MASK),
1779:                        (Action) (actions
1780:                                .get(DefaultEditorKit.deleteNextCharAction)));
1781:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1782:                        KeyEvent.VK_LEFT, SHIFT_ALT_SHORTCUT_MASK),
1783:                        (Action) (actions.get("cut-line")));
1784:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1785:                        KeyEvent.VK_RIGHT, SHIFT_ALT_SHORTCUT_MASK),
1786:                        (Action) (actions.get("cut-end-of-line")));
1787:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1788:                        KeyEvent.VK_LEFT, DOUBLE_SHORTCUT_MASK),
1789:                        (Action) (actions.get("cut-word")));
1790:                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(
1791:                        KeyEvent.VK_RIGHT, DOUBLE_SHORTCUT_MASK),
1792:                        (Action) (actions.get("cut-end-of-word")));
1793:            }
1794:
1795:            /**
1796:             * Interface LineAction - a superclass for all line actions. Line actions
1797:             * manipulate a single line of text and are used by the blockAction method.
1798:             * The blockAction applies a LineAction to each line in a block of text.
1799:             */
1800:            interface LineAction {
1801:                /**
1802:                 * Apply some action to a line in the document.
1803:                 */
1804:                public void apply(Element line, MoeSyntaxDocument doc);
1805:            }
1806:
1807:            /**
1808:             * Class CommentLineAction - add a comment symbol to the given line.
1809:             */
1810:            class CommentLineAction implements  LineAction {
1811:                /**
1812:                 * Comment the given line
1813:                 */
1814:                public void apply(Element line, MoeSyntaxDocument doc) {
1815:                    int lineStart = line.getStartOffset();
1816:                    try {
1817:                        doc.insertString(lineStart, "// ", null);
1818:                    } catch (Exception exc) {
1819:                    }
1820:                }
1821:            }
1822:
1823:            /**
1824:             * Class UncommentLineAction - remove the comment symbol (if any) from the
1825:             * given line.
1826:             */
1827:            class UncommentLineAction implements  LineAction {
1828:                public void apply(Element line, MoeSyntaxDocument doc) {
1829:                    int lineStart = line.getStartOffset();
1830:                    int lineEnd = line.getEndOffset();
1831:                    try {
1832:                        String lineText = doc.getText(lineStart, lineEnd
1833:                                - lineStart);
1834:                        if (lineText.trim().startsWith("//")) {
1835:                            int cnt = 0;
1836:                            while (lineText.charAt(cnt) != '/')
1837:                                // whitespace chars
1838:                                cnt++;
1839:                            if (lineText.charAt(cnt + 2) == ' ')
1840:                                doc.remove(lineStart, cnt + 3);
1841:                            else
1842:                                doc.remove(lineStart, cnt + 2);
1843:                        }
1844:                    } catch (Exception exc) {
1845:                    }
1846:                }
1847:            }
1848:
1849:            /**
1850:             * Class IndentLineAction - add one level of indentation to the given line.
1851:             */
1852:            class IndentLineAction implements  LineAction {
1853:                public void apply(Element line, MoeSyntaxDocument doc) {
1854:                    int lineStart = line.getStartOffset();
1855:                    try {
1856:                        doc.insertString(lineStart, spaces
1857:                                .substring(0, tabSize), null);
1858:                    } catch (Exception exc) {
1859:                    }
1860:                }
1861:            }
1862:
1863:            /**
1864:             * Class DeindentLineAction - remove one indentation level from the given
1865:             * line.
1866:             */
1867:            class DeindentLineAction implements  LineAction {
1868:                public void apply(Element line, MoeSyntaxDocument doc) {
1869:                    int lineStart = line.getStartOffset();
1870:                    int lineEnd = line.getEndOffset();
1871:                    try {
1872:                        String lineText = doc.getText(lineStart, lineEnd
1873:                                - lineStart);
1874:                        String spacedTab = spaces.substring(0, tabSize);
1875:                        if (lineText.startsWith(spacedTab))
1876:                            doc.remove(lineStart, tabSize); // remove spaced tab
1877:                        else if (lineText.charAt(0) == TAB_CHAR)
1878:                            doc.remove(lineStart, 1); // remove hard tab
1879:                        else {
1880:                            int cnt = 0;
1881:                            while (lineText.charAt(cnt) == ' ')
1882:                                // remove spaces
1883:                                cnt++;
1884:                            doc.remove(lineStart, cnt);
1885:                        }
1886:                    } catch (Exception exc) {
1887:                    }
1888:                }
1889:            }
1890:
1891:            /**
1892:             * Class KeyCatcher - used for implementation of "describe-key" command to
1893:             * catch the next key press so that we can see what it does.
1894:             */
1895:            class KeyCatcher extends KeyAdapter {
1896:                MoeEditor editor;
1897:
1898:                public void keyPressed(KeyEvent e) {
1899:                    int keyCode = e.getKeyCode();
1900:
1901:                    if (keyCode == KeyEvent.VK_CAPS_LOCK
1902:                            || // the keys we want to
1903:                            // ignore...
1904:                            keyCode == KeyEvent.VK_SHIFT
1905:                            || keyCode == KeyEvent.VK_CONTROL
1906:                            || keyCode == KeyEvent.VK_META
1907:                            || keyCode == KeyEvent.VK_ALT
1908:                            || keyCode == KeyEvent.VK_ALT_GRAPH
1909:                            || keyCode == KeyEvent.VK_COMPOSE
1910:                            || keyCode == KeyEvent.VK_NUM_LOCK
1911:                            || keyCode == KeyEvent.VK_SCROLL_LOCK
1912:                            || keyCode == KeyEvent.VK_UNDEFINED)
1913:                        return;
1914:
1915:                    KeyStroke key = KeyStroke.getKeyStrokeForEvent(e);
1916:                    String modifierName = KeyEvent.getKeyModifiersText(key
1917:                            .getModifiers());
1918:                    String keyName = KeyEvent.getKeyText(keyCode);
1919:                    if (modifierName.length() > 0)
1920:                        keyName = modifierName + "+" + keyName;
1921:
1922:                    Keymap map = keymap;
1923:                    Action action = null;
1924:
1925:                    while (map != null && action == null) {
1926:                        action = map.getAction(key);
1927:                        map = map.getResolveParent();
1928:                    }
1929:
1930:                    if (action == null) {
1931:                        // BUG workaround: bindings inhertited from component are not
1932:                        // found
1933:                        // through the keymap. we search for them explicitly here...
1934:                        Object binding = componentInputMap.get(key);
1935:                        if (binding == null) {
1936:                            //editor.writeMessage(keyName + " is not bound to a function.");
1937:                            editor
1938:                                    .writeMessage(keyName
1939:                                            + Config
1940:                                                    .getString("editor.keypressed.keyIsNotBound"));
1941:                        } else {
1942:                            editor
1943:                                    .writeMessage(keyName
1944:                                            + Config
1945:                                                    .getString("editor.keypressed.callsTheFunction")
1946:                                            + binding + "\"");
1947:                        }
1948:                    } else {
1949:                        String name = (String) action.getValue(Action.NAME);
1950:                        editor
1951:                                .writeMessage(keyName
1952:                                        + Config
1953:                                                .getString("editor.keypressed.callsTheFunction")
1954:                                        + name + "\"");
1955:                    }
1956:                    e.getComponent().removeKeyListener(keyCatcher);
1957:                    e.consume();
1958:                }
1959:
1960:                public void setEditor(MoeEditor ed) {
1961:                    editor = ed;
1962:                }
1963:
1964:            }
1965:
1966:        } // end class MoeActions
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.