Source Code Cross Referenced for Editor.java in  » IDE » J » org » armedbear » j » 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 » J » org.armedbear.j 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Editor.java
0003:         *
0004:         * Copyright (C) 1998-2004 Peter Graves
0005:         * $Id: Editor.java,v 1.130 2004/09/19 18:27:45 piso Exp $
0006:         *
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License
0009:         * as published by the Free Software Foundation; either version 2
0010:         * of the License, or (at your option) any later version.
0011:         *
0012:         * This program is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015:         * GNU General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU General Public License
0018:         * along with this program; if not, write to the Free Software
0019:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0020:         */
0021:
0022:        package org.armedbear.j;
0023:
0024:        import gnu.regexp.RE;
0025:        import gnu.regexp.REException;
0026:        import gnu.regexp.REMatch;
0027:        import gnu.regexp.UncheckedRE;
0028:        import java.awt.AWTEvent;
0029:        import java.awt.BorderLayout;
0030:        import java.awt.Cursor;
0031:        import java.awt.Dimension;
0032:        import java.awt.Point;
0033:        import java.awt.Rectangle;
0034:        import java.awt.Toolkit;
0035:        import java.awt.datatransfer.DataFlavor;
0036:        import java.awt.datatransfer.Transferable;
0037:        import java.awt.dnd.DropTarget;
0038:        import java.awt.event.ComponentEvent;
0039:        import java.awt.event.ComponentListener;
0040:        import java.awt.event.KeyEvent;
0041:        import java.awt.event.MouseEvent;
0042:        import java.awt.event.MouseWheelEvent;
0043:        import java.awt.event.MouseWheelListener;
0044:        import java.awt.event.WindowEvent;
0045:        import java.io.BufferedReader;
0046:        import java.io.BufferedWriter;
0047:        import java.io.IOException;
0048:        import java.io.InputStreamReader;
0049:        import java.io.OutputStream;
0050:        import java.io.OutputStreamWriter;
0051:        import java.io.StringReader;
0052:        import java.io.UnsupportedEncodingException;
0053:        import java.lang.reflect.Method;
0054:        import java.net.ConnectException;
0055:        import java.net.MalformedURLException;
0056:        import java.net.Socket;
0057:        import java.text.SimpleDateFormat;
0058:        import java.util.ArrayList;
0059:        import java.util.Date;
0060:        import java.util.Enumeration;
0061:        import java.util.Hashtable;
0062:        import java.util.List;
0063:        import java.util.Properties;
0064:        import java.util.Stack;
0065:        import java.util.StringTokenizer;
0066:        import java.util.Vector;
0067:        import javax.swing.Box;
0068:        import javax.swing.BoxLayout;
0069:        import javax.swing.FocusManager;
0070:        import javax.swing.JComponent;
0071:        import javax.swing.JDialog;
0072:        import javax.swing.JLabel;
0073:        import javax.swing.JMenuBar;
0074:        import javax.swing.JPanel;
0075:        import javax.swing.JPopupMenu;
0076:        import javax.swing.SwingUtilities;
0077:        import javax.swing.undo.CompoundEdit;
0078:        import org.armedbear.j.mail.MailCommands;
0079:        import org.armedbear.j.mail.MailboxURL;
0080:        import org.armedbear.lisp.Condition;
0081:        import org.armedbear.lisp.ConditionThrowable;
0082:        import org.armedbear.lisp.Interpreter;
0083:        import org.armedbear.lisp.Lisp;
0084:        import org.armedbear.lisp.LispObject;
0085:        import org.armedbear.lisp.LispThread;
0086:
0087:        public final class Editor extends JPanel implements  Constants,
0088:                ComponentListener, MouseWheelListener {
0089:            private static final long startTimeMillis = System
0090:                    .currentTimeMillis();
0091:
0092:            private static boolean debug = false;
0093:            private static boolean saveSession = true;
0094:
0095:            static File portfile;
0096:
0097:            private static EditorList editorList = new EditorList();
0098:
0099:            private static PendingOperations pendingOperations = new PendingOperations();
0100:
0101:            private static Editor currentEditor;
0102:
0103:            private static KillRing killRing = new KillRing();
0104:
0105:            public static final KillRing getKillRing() {
0106:                return killRing;
0107:            }
0108:
0109:            private static String killedColumn;
0110:
0111:            private static SessionProperties sessionProperties;
0112:
0113:            public static SessionProperties getSessionProperties() {
0114:                return sessionProperties;
0115:            }
0116:
0117:            private static final Preferences prefs = new Preferences();
0118:
0119:            public static final Preferences preferences() {
0120:                return prefs;
0121:            }
0122:
0123:            private static boolean isRecordingMacro;
0124:
0125:            public static synchronized boolean isRecordingMacro() {
0126:                return isRecordingMacro;
0127:            }
0128:
0129:            public static synchronized void setRecordingMacro(boolean b) {
0130:                isRecordingMacro = b;
0131:            }
0132:
0133:            static String lookAndFeel;
0134:
0135:            private Buffer buffer;
0136:
0137:            private final Display display;
0138:            private final Dispatcher dispatcher;
0139:            private final Frame frame;
0140:
0141:            private Search lastSearch;
0142:
0143:            public final Search getLastSearch() {
0144:                return lastSearch;
0145:            }
0146:
0147:            public final void setLastSearch(Search search) {
0148:                lastSearch = search;
0149:            }
0150:
0151:            // The current position in the buffer (that is, in the actual text).
0152:            private Position dot;
0153:
0154:            // The position of the other end of the selection, if any,
0155:            private Position mark;
0156:
0157:            private Selection selection;
0158:            private boolean isColumnSelection;
0159:
0160:            Hashtable views = new Hashtable();
0161:
0162:            // BUG! This stuff should be factored somehow...
0163:            private int currentCommand = COMMAND_NOTHING;
0164:            private int lastCommand = COMMAND_NOTHING;
0165:
0166:            public final int getCurrentCommand() {
0167:                return currentCommand;
0168:            }
0169:
0170:            public final void setCurrentCommand(int command) {
0171:                currentCommand = command;
0172:            }
0173:
0174:            public final int getLastCommand() {
0175:                return lastCommand;
0176:            }
0177:
0178:            public final void setLastCommand(int command) {
0179:                lastCommand = command;
0180:            }
0181:
0182:            private static Marker[] bookmarks = new Marker[11];
0183:
0184:            private static TagFileManager tagFileManager;
0185:
0186:            private static boolean tabsAreVisible = false;
0187:
0188:            public static final boolean tabsAreVisible() {
0189:                return tabsAreVisible;
0190:            }
0191:
0192:            static boolean isMenuSelected = false;
0193:
0194:            DirectoryTree localDirectoryTree;
0195:
0196:            private static ModeList modeList;
0197:
0198:            public static final ModeList getModeList() {
0199:                if (modeList == null)
0200:                    modeList = ModeList.getInstance();
0201:                return modeList;
0202:            }
0203:
0204:            private static final BufferList bufferList = new BufferList();
0205:
0206:            public static final BufferList getBufferList() {
0207:                return bufferList;
0208:            }
0209:
0210:            public static long getStartTimeMillis() {
0211:                return startTimeMillis;
0212:            }
0213:
0214:            private static String when() {
0215:                return String.valueOf(System.currentTimeMillis()
0216:                        - startTimeMillis)
0217:                        + " ms";
0218:            }
0219:
0220:            public static void main(String[] args) {
0221:                final File currentDir = File.getInstance(System
0222:                        .getProperty("user.dir"));
0223:                boolean forceNewInstance = false;
0224:                boolean restoreSession = true;
0225:                boolean startServer = true;
0226:                int quick = 0;
0227:                File userHomeDir = null;
0228:                List files = null;
0229:
0230:                // Process command line.
0231:                for (int i = 0; i < args.length; i++) {
0232:                    final String arg = args[i];
0233:                    if (arg.startsWith("-")) {
0234:                        if (arg.equals("-h") || arg.equals("-help")
0235:                                || arg.equals("--help")) {
0236:                            usage();
0237:                            System.exit(0);
0238:                        }
0239:                        if (arg.equals("-version")) {
0240:                            version();
0241:                            System.exit(0);
0242:                        }
0243:                        if (arg.equals("-d") || arg.equals("--debug")) {
0244:                            debug = true;
0245:                            continue;
0246:                        }
0247:                        if (arg.equals("-q")) {
0248:                            if (quick < 1)
0249:                                quick = 1;
0250:                            continue;
0251:                        }
0252:                        if (arg.equals("-n") || arg.equals("--no-restore")) {
0253:                            restoreSession = false;
0254:                            continue;
0255:                        }
0256:                        if (arg.equals("-session")) {
0257:                            if (i < args.length - 1)
0258:                                sessionName = args[++i];
0259:                            continue;
0260:                        }
0261:                        if (arg.equals("--force-new-instance")) {
0262:                            forceNewInstance = true;
0263:                            continue;
0264:                        }
0265:                        if (arg.equals("--no-session")) {
0266:                            restoreSession = false;
0267:                            saveSession = false;
0268:                            continue;
0269:                        }
0270:                        if (arg.equals("--no-server")) {
0271:                            startServer = false;
0272:                            continue;
0273:                        }
0274:                        if (arg.startsWith("--home")) {
0275:                            String home = null;
0276:                            if (arg.equals("--home")) {
0277:                                if (i < args.length - 1)
0278:                                    home = args[++i];
0279:                            } else if (arg.startsWith("--home="))
0280:                                home = arg.substring(7);
0281:                            else
0282:                                unknown(arg);
0283:
0284:                            if (home == null || home.length() == 0)
0285:                                fatal("Option \"--home\" requires an argument.");
0286:
0287:                            userHomeDir = File.getInstance(currentDir, home);
0288:
0289:                            if (userHomeDir == null
0290:                                    || !userHomeDir.isDirectory()) {
0291:                                fatal("Specified home directory \""
0292:                                        + userHomeDir.canonicalPath()
0293:                                        + "\" does not exist.");
0294:                            }
0295:
0296:                            if (!userHomeDir.canWrite()) {
0297:                                fatal("Specified home directory \""
0298:                                        + userHomeDir.canonicalPath()
0299:                                        + "\" is not writable.");
0300:                            }
0301:
0302:                            // Specified directory is OK.
0303:                            Utilities.setUserHome(userHomeDir.canonicalPath());
0304:
0305:                            continue;
0306:                        }
0307:                        // If we get here, it's an unknown option.
0308:                        unknown(arg);
0309:                    } else {
0310:                        // It's a file to be opened.
0311:                        if (files == null)
0312:                            files = new ArrayList();
0313:                        files.add(arg);
0314:                    }
0315:                }
0316:
0317:                // At this point the user has had a chance to tell us where his home
0318:                // directory is.
0319:                Directories.initialize(userHomeDir);
0320:
0321:                boolean alreadyRunning = false;
0322:                portfile = File.getInstance(Directories.getEditorDirectory(),
0323:                        "port");
0324:                if (portfile.exists()) {
0325:                    try {
0326:                        BufferedReader in = new BufferedReader(
0327:                                new InputStreamReader(portfile.getInputStream()));
0328:                        String s = in.readLine();
0329:                        in.close();
0330:
0331:                        int port = Integer.parseInt(s);
0332:
0333:                        Socket socket = new Socket("localhost", port);
0334:
0335:                        // No ConnectException. We found a running instance.
0336:                        alreadyRunning = true;
0337:
0338:                        if (!forceNewInstance) {
0339:                            BufferedWriter out = new BufferedWriter(
0340:                                    new OutputStreamWriter(socket
0341:                                            .getOutputStream()));
0342:                            File dir = File.getInstance(System
0343:                                    .getProperty("user.dir"));
0344:                            out.write(dir.canonicalPath());
0345:                            out.newLine();
0346:                            if (files != null) {
0347:                                for (int i = 0; i < files.size(); i++) {
0348:                                    out.write((String) files.get(i));
0349:                                    out.newLine();
0350:                                }
0351:                            }
0352:                            out.flush();
0353:                            out.close();
0354:                            socket.close();
0355:                            System.exit(0);
0356:                        }
0357:                    } catch (ConnectException e) {
0358:                        portfile.delete();
0359:                    } catch (IOException e) {
0360:                        Log.error(e);
0361:                    }
0362:                }
0363:
0364:                loadPreferences();
0365:                Log.initialize();
0366:                Directories.moveUnsentMessagesToDraftsFolder();
0367:                loadExtensions();
0368:                if (quick == 0) {
0369:                    runStartupScript();
0370:                }
0371:                DefaultLookAndFeel.setLookAndFeel();
0372:
0373:                sessionProperties = new SessionProperties();
0374:
0375:                if (!alreadyRunning)
0376:                    Autosave.recover();
0377:
0378:                tagFileManager = new TagFileManager();
0379:
0380:                setCurrentEditor(new Editor(null));
0381:
0382:                currentEditor.getFrame().updateControls();
0383:
0384:                // With Java 1.4, we only need to do this to support the key-pressed
0385:                // hook.
0386:                FocusManager.setCurrentManager(new CustomFocusManager());
0387:
0388:                currentEditor.getFrame().placeWindow();
0389:
0390:                Buffer toBeActivated = null;
0391:
0392:                if (restoreSession) {
0393:                    Session session = null;
0394:                    if (sessionName != null)
0395:                        session = Session.getSession(sessionName);
0396:                    if (session == null)
0397:                        session = Session.getDefaultSession();
0398:                    toBeActivated = session.restore();
0399:                }
0400:
0401:                if (files != null) {
0402:                    ArrayList list = new ArrayList();
0403:                    list.add(currentDir.canonicalPath());
0404:                    for (int i = 0; i < files.size(); i++)
0405:                        list.add(files.get(i));
0406:                    Buffer buf = currentEditor.openFiles(list);
0407:                    if (buf != null) {
0408:                        Debug.assertTrue(bufferList.contains(buf));
0409:                        toBeActivated = buf;
0410:                    }
0411:                }
0412:
0413:                if (toBeActivated == null)
0414:                    toBeActivated = new Directory(currentDir);
0415:
0416:                currentEditor.activate(toBeActivated);
0417:
0418:                if (startServer)
0419:                    Server.startServer();
0420:
0421:                Runnable r = new Runnable() {
0422:                    public void run() {
0423:                        currentEditor.getFrame().setVisible(true);
0424:                        Sidebar sidebar = currentEditor.getSidebar();
0425:                        if (sidebar != null)
0426:                            sidebar.setUpdateFlag(SIDEBAR_ALL);
0427:                    }
0428:                };
0429:                SwingUtilities.invokeLater(r);
0430:
0431:                Log.debug("leaving main " + when());
0432:            }
0433:
0434:            private static final void usage() {
0435:                version();
0436:                System.out.println("Usage: j [options] [+linenum] file");
0437:                System.out.println("Options:");
0438:                System.out.println("  -h, -help");
0439:                System.out.println("  -d, --debug");
0440:                System.out.println("  -n, --no-restore");
0441:                System.out.println("  -version");
0442:                System.out.println("  --force-new-instance");
0443:                System.out.println("  --no-session");
0444:                System.out.println("  --no-server");
0445:                System.out.println("  --home=directory");
0446:            }
0447:
0448:            private static final void version() {
0449:                String longVersionString = Version.getLongVersionString();
0450:                if (longVersionString != null)
0451:                    System.out.println(longVersionString);
0452:                String snapshotInformation = Version.getSnapshotInformation();
0453:                if (snapshotInformation != null)
0454:                    System.out.println(snapshotInformation);
0455:            }
0456:
0457:            public static final void fatal(String message) {
0458:                System.err.println(message);
0459:                System.exit(1);
0460:            }
0461:
0462:            private static final void unknown(String arg) {
0463:                usage();
0464:                fatal("Unknown option \"" + arg + "\"");
0465:            }
0466:
0467:            public Editor(Frame f) {
0468:                display = new Display(this );
0469:                dispatcher = new Dispatcher(this );
0470:                init();
0471:                frame = f != null ? f : new Frame(this );
0472:            }
0473:
0474:            private void init() {
0475:                // Add this editor to the global editor list.
0476:                editorList.add(this );
0477:
0478:                setLayout(new BorderLayout());
0479:                display.setDoubleBuffered(true);
0480:                add(display, BorderLayout.CENTER);
0481:
0482:                new DropTarget(display, dispatcher);
0483:
0484:                addLocationBar();
0485:                addVerticalScrollBar();
0486:                addHorizontalScrollBar();
0487:
0488:                display.addKeyListener(dispatcher);
0489:                display.addMouseListener(dispatcher);
0490:                display.addMouseMotionListener(dispatcher);
0491:
0492:                addMouseWheelListener(this );
0493:                addComponentListener(this );
0494:            }
0495:
0496:            public static final boolean isDebugEnabled() {
0497:                return debug;
0498:            }
0499:
0500:            public static final boolean isMailEnabled() {
0501:                if (!prefs
0502:                        .getBooleanProperty(Property.ENABLE_EXPERIMENTAL_FEATURES))
0503:                    return false;
0504:                if (!prefs.getBooleanProperty(Property.ENABLE_MAIL))
0505:                    return false;
0506:                // Mail address must be configured!
0507:                if (prefs.getStringProperty(Property.USER_MAIL_ADDRESS) == null)
0508:                    return false;
0509:                return true;
0510:            }
0511:
0512:            private LocationBar locationBar;
0513:
0514:            public final LocationBar getLocationBar() {
0515:                return locationBar;
0516:            }
0517:
0518:            public final HistoryTextField getLocationBarTextField() {
0519:                return locationBar == null ? null : locationBar.getTextField();
0520:            }
0521:
0522:            public void addLocationBar() {
0523:                if (locationBar == null) {
0524:                    locationBar = new LocationBar(this );
0525:                    add(locationBar, BorderLayout.NORTH);
0526:                }
0527:            }
0528:
0529:            public void removeLocationBar() {
0530:                if (locationBar != null) {
0531:                    remove(locationBar);
0532:                    locationBar = null;
0533:                }
0534:            }
0535:
0536:            public void updateLocation() {
0537:                if (locationBar != null) {
0538:                    HistoryTextField textField = locationBar.getTextField();
0539:                    if (textField == null
0540:                            || textField != frame.getFocusedComponent())
0541:                        locationBar.update();
0542:                } else
0543:                    Debug.bug();
0544:            }
0545:
0546:            public boolean isPrimaryEditor() {
0547:                return frame.isPrimaryEditor(this );
0548:            }
0549:
0550:            public final Editor getOtherEditor() {
0551:                return isPrimaryEditor() ? frame.getSecondaryEditor() : frame
0552:                        .getPrimaryEditor();
0553:            }
0554:
0555:            public static int indexOf(Editor editor) {
0556:                for (int i = getEditorCount() - 1; i >= 0; i--) {
0557:                    if (editor == getEditor(i))
0558:                        return i;
0559:                }
0560:
0561:                return -1;
0562:            }
0563:
0564:            public static final EditorList getEditorList() {
0565:                return editorList;
0566:            }
0567:
0568:            public static final int getEditorCount() {
0569:                return editorList.size();
0570:            }
0571:
0572:            public static final Editor getEditor(int i) {
0573:                return editorList.get(i);
0574:            }
0575:
0576:            public static final void removeEditor(Editor editor) {
0577:                editorList.remove(editor);
0578:            }
0579:
0580:            public final Frame getFrame() {
0581:                return frame;
0582:            }
0583:
0584:            static Vector frames = new Vector();
0585:
0586:            public static int indexOf(Frame frame) {
0587:                for (int i = getFrameCount() - 1; i >= 0; i--) {
0588:                    if (frame == getFrame(i))
0589:                        return i;
0590:                }
0591:
0592:                return -1;
0593:            }
0594:
0595:            public static final int getFrameCount() {
0596:                return frames.size();
0597:            }
0598:
0599:            public static final Frame getFrame(int i) {
0600:                if (i >= 0 && i < frames.size())
0601:                    return (Frame) frames.get(i);
0602:                return null;
0603:            }
0604:
0605:            public final Buffer getBuffer() {
0606:                return buffer;
0607:            }
0608:
0609:            public final Mode getMode() {
0610:                return buffer.getMode();
0611:            }
0612:
0613:            public final int getModeId() {
0614:                return buffer.getModeId();
0615:            }
0616:
0617:            public final Formatter getFormatter() {
0618:                return buffer.getFormatter();
0619:            }
0620:
0621:            public final Display getDisplay() {
0622:                return display;
0623:            }
0624:
0625:            public final Dispatcher getDispatcher() {
0626:                return dispatcher;
0627:            }
0628:
0629:            public static final TagFileManager getTagFileManager() {
0630:                return tagFileManager;
0631:            }
0632:
0633:            public final Sidebar getSidebar() {
0634:                return frame.getSidebar();
0635:            }
0636:
0637:            public final StatusBar getStatusBar() {
0638:                return frame.getStatusBar();
0639:            }
0640:
0641:            public static final PendingOperations getPendingOperations() {
0642:                return pendingOperations;
0643:            }
0644:
0645:            private VerticalScrollBar verticalScrollBar;
0646:
0647:            private VerticalScrollBarListener verticalScrollBarListener;
0648:
0649:            public void addVerticalScrollBar() {
0650:                if (verticalScrollBar == null) {
0651:                    verticalScrollBar = new VerticalScrollBar(this );
0652:                    verticalScrollBar.setMinimum(0);
0653:                    add(verticalScrollBar, BorderLayout.EAST);
0654:                    verticalScrollBarListener = new VerticalScrollBarListener(
0655:                            this , verticalScrollBar);
0656:                    verticalScrollBar
0657:                            .addAdjustmentListener(verticalScrollBarListener);
0658:                }
0659:            }
0660:
0661:            public void removeVerticalScrollBar() {
0662:                if (verticalScrollBar != null) {
0663:                    if (verticalScrollBarListener == null) {
0664:                        verticalScrollBar
0665:                                .removeAdjustmentListener(verticalScrollBarListener);
0666:                        verticalScrollBarListener = null;
0667:                    }
0668:                    remove(verticalScrollBar);
0669:                    verticalScrollBar = null;
0670:                }
0671:            }
0672:
0673:            private HorizontalScrollBar horizontalScrollBar;
0674:
0675:            private HorizontalScrollBarListener horizontalScrollBarListener;
0676:
0677:            public void addHorizontalScrollBar() {
0678:                if (horizontalScrollBar == null) {
0679:                    horizontalScrollBar = new HorizontalScrollBar(this );
0680:                    horizontalScrollBar.setMinimum(0);
0681:                    JPanel panel = new JPanel();
0682:                    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
0683:                    panel.add(horizontalScrollBar);
0684:                    final int height = horizontalScrollBar.getPreferredSize().height;
0685:                    panel.add(Box
0686:                            .createRigidArea(new Dimension(height, height)));
0687:                    add(panel, BorderLayout.SOUTH);
0688:                    horizontalScrollBarListener = new HorizontalScrollBarListener(
0689:                            this );
0690:                    horizontalScrollBar
0691:                            .addAdjustmentListener(horizontalScrollBarListener);
0692:                }
0693:            }
0694:
0695:            public void removeHorizontalScrollBar() {
0696:                if (horizontalScrollBar != null) {
0697:                    if (horizontalScrollBarListener == null) {
0698:                        horizontalScrollBar
0699:                                .removeAdjustmentListener(horizontalScrollBarListener);
0700:                        horizontalScrollBarListener = null;
0701:                    }
0702:                    // Remove JPanel containing scroll bar.
0703:                    remove(horizontalScrollBar.getParent());
0704:                    horizontalScrollBar = null;
0705:                }
0706:            }
0707:
0708:            public static synchronized final Editor currentEditor() {
0709:                return currentEditor;
0710:            }
0711:
0712:            public static synchronized final void setCurrentEditor(Editor editor) {
0713:                Editor oldCurrentEditor = currentEditor;
0714:                currentEditor = editor;
0715:                editor.getFrame().setCurrentEditor(editor);
0716:                if (currentEditor != oldCurrentEditor) {
0717:                    if (currentEditor != null)
0718:                        currentEditor.getLocationBar().repaint();
0719:                    if (oldCurrentEditor != null)
0720:                        oldCurrentEditor.getLocationBar().repaint();
0721:                    if (isLispInitialized())
0722:                        LispAPI.invokeBufferActivatedHook(currentEditor
0723:                                .getBuffer());
0724:                }
0725:            }
0726:
0727:            public static synchronized final Buffer currentBuffer() {
0728:                return currentEditor.buffer;
0729:            }
0730:
0731:            public static synchronized final Frame getCurrentFrame() {
0732:                return currentEditor.getFrame();
0733:            }
0734:
0735:            public static Editor createNewFrame() {
0736:                Editor ed = new Editor(null);
0737:                ed.getFrame().updateControls();
0738:                ed.getFrame().placeWindow();
0739:                return ed;
0740:            }
0741:
0742:            public void newFrame() {
0743:                saveView();
0744:                Editor ed = createNewFrame();
0745:                ed.activate(buffer);
0746:                ed.getFrame().setVisible(true);
0747:                setCurrentEditor(ed);
0748:                ed.updateDisplay();
0749:                display.repaint();
0750:                Runnable r = new Runnable() {
0751:                    public void run() {
0752:                        currentEditor.setFocusToDisplay();
0753:                    }
0754:                };
0755:                SwingUtilities.invokeLater(r);
0756:            }
0757:
0758:            public View getCurrentView() {
0759:                return (View) views.get(buffer);
0760:            }
0761:
0762:            // Might return null.
0763:            public final View getView(SystemBuffer buf) {
0764:                return (View) views.get(buf);
0765:            }
0766:
0767:            public final void setView(SystemBuffer buf, View view) {
0768:                views.put(buf, view);
0769:            }
0770:
0771:            public void removeView(SystemBuffer buf) {
0772:                views.remove(buf);
0773:            }
0774:
0775:            // Find or create a view of buf.
0776:            private View findOrCreateView(Buffer buf) {
0777:                View view = (View) views.get(buf);
0778:                if (view == null) {
0779:                    view = buf.getLastView();
0780:                    if (view == null)
0781:                        view = buf.getInitialView();
0782:                    views.put(buf, view);
0783:                }
0784:                return view;
0785:            }
0786:
0787:            public final void saveView() {
0788:                buffer.saveView(this );
0789:            }
0790:
0791:            private final void restoreView() {
0792:                buffer.restoreView(this );
0793:            }
0794:
0795:            public final Position getDot() {
0796:                return dot;
0797:            }
0798:
0799:            public final Position getDotCopy() {
0800:                return dot != null ? new Position(dot) : null;
0801:            }
0802:
0803:            public final void setDot(Position pos) {
0804:                dot = pos;
0805:            }
0806:
0807:            public final void setDot(Line line, int offset) {
0808:                dot = new Position(line, offset);
0809:            }
0810:
0811:            public void setDot(int lineNumber, int offset) {
0812:                Line line = buffer.getLine(lineNumber);
0813:                if (line != null)
0814:                    setDot(line, offset);
0815:            }
0816:
0817:            public final Line getDotLine() {
0818:                return dot.getLine();
0819:            }
0820:
0821:            public final int getDotLineNumber() {
0822:                return dot.lineNumber();
0823:            }
0824:
0825:            public final int getDotOffset() {
0826:                return dot.getOffset();
0827:            }
0828:
0829:            public final Selection getSelection() {
0830:                return selection;
0831:            }
0832:
0833:            public final void setSelection(Selection selection) {
0834:                this .selection = selection;
0835:            }
0836:
0837:            public final Position getMark() {
0838:                return mark;
0839:            }
0840:
0841:            public void setMarkAtDot() {
0842:                setMark(new Position(dot));
0843:                selection = new Selection();
0844:            }
0845:
0846:            public void setMark(Position pos) {
0847:                mark = pos;
0848:                if (mark == null) {
0849:                    selection = null;
0850:                    setColumnSelection(false);
0851:                }
0852:            }
0853:
0854:            public void setMark(int lineNumber, int offset) {
0855:                Line line = buffer.getLine(lineNumber);
0856:                if (line != null)
0857:                    setMark(new Position(line, offset));
0858:            }
0859:
0860:            public final void setColumnSelection(boolean b) {
0861:                isColumnSelection = b;
0862:            }
0863:
0864:            public final boolean isColumnSelection() {
0865:                return isColumnSelection;
0866:            }
0867:
0868:            public final void notSupportedForColumnSelections() {
0869:                MessageDialog.showMessageDialog(this ,
0870:                        "Operation not supported for column selections",
0871:                        "Error");
0872:            }
0873:
0874:            public final Line getMarkLine() {
0875:                return mark.getLine();
0876:            }
0877:
0878:            public final int getMarkLineNumber() {
0879:                return mark.lineNumber();
0880:            }
0881:
0882:            public final int getMarkOffset() {
0883:                return mark.getOffset();
0884:            }
0885:
0886:            public File getCurrentDirectory() {
0887:                return buffer.getCurrentDirectory();
0888:            }
0889:
0890:            public File getCompletionDirectory() {
0891:                return buffer.getCompletionDirectory();
0892:            }
0893:
0894:            // Cycle through the most plausible possibilities for the tab width of the
0895:            // current buffer.
0896:            public void cycleTabWidth() {
0897:                switch (buffer.getTabWidth()) {
0898:                case 2:
0899:                    buffer.setTabWidth(4);
0900:                    break;
0901:                case 4:
0902:                    buffer.setTabWidth(8);
0903:                    break;
0904:                case 8:
0905:                default:
0906:                    buffer.setTabWidth(2);
0907:                    break;
0908:                }
0909:                buffer.saveProperties();
0910:                status("Tab width set to " + buffer.getTabWidth());
0911:                buffer.repaint();
0912:            }
0913:
0914:            // Cycle through the most plausible possibilities for the indent size of
0915:            // the current buffer.
0916:            public void cycleIndentSize() {
0917:                switch (buffer.getIndentSize()) {
0918:                case 2:
0919:                    buffer.setIndentSize(3);
0920:                    break;
0921:                case 3:
0922:                    buffer.setIndentSize(4);
0923:                    break;
0924:                case 4:
0925:                    buffer.setIndentSize(8);
0926:                    break;
0927:                case 8:
0928:                default:
0929:                    buffer.setIndentSize(2);
0930:                    break;
0931:                }
0932:                buffer.saveProperties();
0933:                status("Indent size set to " + buffer.getIndentSize());
0934:            }
0935:
0936:            public void adjustMarkers(Line line) {
0937:                if (line == null)
0938:                    return;
0939:                Position pos = null; // Where all displaced markers go.
0940:                if (line.next() != null)
0941:                    pos = new Position(line.next(), 0);
0942:                else if (line.previous() != null)
0943:                    pos = new Position(line.previous(), line.previous()
0944:                            .length());
0945:                if (pos == null)
0946:                    return;
0947:                for (int i = 0; i < Editor.getEditorCount(); i++) {
0948:                    Editor ed = Editor.getEditor(i);
0949:                    if (ed.getBuffer() == buffer) {
0950:                        if (ed.getDotLine() == line) {
0951:                            ed.getDot().moveTo(pos);
0952:                            ed.moveCaretToDotCol();
0953:                        }
0954:                        if (ed.getMark() != null && ed.getMarkLine() == line)
0955:                            ed.setMark(null); // Take no chances.
0956:                        if (ed.getTopLine() == line) {
0957:                            ed.setTopLine(pos.getLine());
0958:                            ed.setUpdateFlag(REPAINT);
0959:                        }
0960:                    } else {
0961:                        // Not presently displayed, but possibly in a stored view.
0962:                        View view = (View) ed.views.get(buffer);
0963:                        if (view != null) {
0964:                            if (view.dot != null && view.dot.getLine() == line)
0965:                                view.dot.moveTo(pos);
0966:                            if (view.mark != null
0967:                                    && view.mark.getLine() == line)
0968:                                view.mark = null;
0969:                            if (view.topLine == line)
0970:                                view.topLine = pos.getLine();
0971:                        }
0972:                    }
0973:                }
0974:                for (int i = 0; i < bookmarks.length; i++) {
0975:                    Marker m = bookmarks[i];
0976:                    if (m != null && m.getLine() == line)
0977:                        m.setPosition(pos);
0978:                }
0979:            }
0980:
0981:            public static Marker[] getBookmarks() {
0982:                return bookmarks;
0983:            }
0984:
0985:            public void dropBookmark() {
0986:                AWTEvent e = dispatcher.getLastEvent();
0987:                if (e != null && e.getID() == KeyEvent.KEY_PRESSED) {
0988:                    int keyCode = ((KeyEvent) e).getKeyCode();
0989:                    int index = keyCode - KeyEvent.VK_0;
0990:                    if (index >= 0 && index < bookmarks.length) {
0991:                        if (bookmarks[index] == null
0992:                                || confirm("Drop Bookmark",
0993:                                        "Overwrite existing bookmark?")) {
0994:                            bookmarks[index] = new Marker(buffer, dot);
0995:                            status("Bookmark dropped");
0996:                        }
0997:                    }
0998:                }
0999:            }
1000:
1001:            public void gotoBookmark() {
1002:                AWTEvent e = dispatcher.getLastEvent();
1003:                if (e != null && e.getID() == KeyEvent.KEY_PRESSED) {
1004:                    int keyCode = ((KeyEvent) e).getKeyCode();
1005:                    int index = keyCode - KeyEvent.VK_0;
1006:                    if (index >= 0 && index < bookmarks.length) {
1007:                        Marker m = bookmarks[index];
1008:                        if (m != null)
1009:                            m.gotoMarker(this );
1010:                    }
1011:                }
1012:            }
1013:
1014:            // Drop a temporary bookmark, overwriting the existing temporary bookmark
1015:            // if one exists.
1016:            public void dropTemporaryMarker() {
1017:                bookmarks[10] = new Marker(buffer, dot);
1018:                status("Temporary marker dropped");
1019:            }
1020:
1021:            public void gotoTemporaryMarker() {
1022:                Marker m = bookmarks[10];
1023:                if (m != null)
1024:                    m.gotoMarker(this );
1025:            }
1026:
1027:            public void deleteLineSeparator() {
1028:                final Line dotLine = getDotLine();
1029:                final Line nextLine = dotLine.next();
1030:                if (nextLine == null)
1031:                    return;
1032:                try {
1033:                    buffer.lockWrite();
1034:                } catch (InterruptedException e) {
1035:                    Log.error(e);
1036:                    return;
1037:                }
1038:                try {
1039:                    if (dotLine.length() == 0) {
1040:                        adjustMarkers(dotLine);
1041:                        // Save original text.
1042:                        FastStringBuffer sb = new FastStringBuffer();
1043:                        if (dotLine.getOriginalText() != null)
1044:                            sb.append(dotLine.getOriginalText());
1045:                        sb.append('\n');
1046:                        if (nextLine.getOriginalText() != null)
1047:                            sb.append(nextLine.getOriginalText());
1048:                        else
1049:                            sb.append(nextLine.getText());
1050:                        nextLine.setOriginalText(sb.toString());
1051:                        // Unlink the current line.
1052:                        final Line prevLine = dotLine.previous();
1053:                        if (prevLine != null)
1054:                            prevLine.setNext(nextLine);
1055:                        nextLine.setPrevious(prevLine);
1056:                        if (dotLine == buffer.getFirstLine()) {
1057:                            Log
1058:                                    .debug("deleteLineSeparator calling buffer.setFirstLine()");
1059:                            buffer.setFirstLine(nextLine);
1060:                            Log.debug("first line = |"
1061:                                    + buffer.getFirstLine().getText() + "|");
1062:                        }
1063:                        if (dotLine == display.getTopLine())
1064:                            display.setTopLine(nextLine);
1065:                        dot.moveTo(nextLine, 0);
1066:                    } else {
1067:                        // Append the next line's text to end of this line.
1068:                        dotLine.setText(dotLine.getText() + nextLine.getText());
1069:                        // Save original text.
1070:                        FastStringBuffer sb = new FastStringBuffer();
1071:                        if (dotLine.getOriginalText() != null)
1072:                            sb.append(dotLine.getOriginalText());
1073:                        else
1074:                            sb.append(dotLine.getText());
1075:                        if (!nextLine.isNew()) {
1076:                            sb.append('\n');
1077:                            if (nextLine.getOriginalText() != null)
1078:                                sb.append(nextLine.getOriginalText());
1079:                            else
1080:                                sb.append(nextLine.getText());
1081:                        }
1082:                        dotLine.setOriginalText(sb.toString());
1083:                        // Move any markers that might be on the next line.
1084:                        adjustMarkers(nextLine);
1085:                        // Unlink the next line.
1086:                        if (nextLine.next() != null)
1087:                            nextLine.next().setPrevious(dotLine);
1088:                        dotLine.setNext(nextLine.next());
1089:                    }
1090:                    buffer.repaint();
1091:                    setUpdateFlag(REFRAME);
1092:                    buffer.needsRenumbering = true;
1093:                    buffer.modified();
1094:                } finally {
1095:                    buffer.unlockWrite();
1096:                }
1097:            }
1098:
1099:            private void deleteNormalChar() {
1100:                addUndo(SimpleEdit.LINE_EDIT);
1101:                final Line dotLine = getDotLine();
1102:                final int dotOffset = getDotOffset();
1103:                String head = dotLine.substring(0, dotOffset);
1104:                String tail = "";
1105:                if (dotOffset < dotLine.length() - 1)
1106:                    tail = dotLine.substring(dotOffset + 1);
1107:                dotLine.setText(head.concat(tail));
1108:                buffer.modified();
1109:                updateInAllEditors(dotLine);
1110:            }
1111:
1112:            // A deletion, not a kill!
1113:            public void delete() {
1114:                if (!checkReadOnly())
1115:                    return;
1116:                try {
1117:                    buffer.lockWrite();
1118:                } catch (InterruptedException e) {
1119:                    Log.error(e);
1120:                    return;
1121:                }
1122:                try {
1123:                    if (mark != null) {
1124:                        deleteRegion();
1125:                    } else {
1126:                        final Line dotLine = getDotLine();
1127:                        final int dotOffset = getDotOffset();
1128:                        final int length = dotLine.length();
1129:                        if (dotOffset < length) {
1130:                            deleteNormalChar();
1131:                        } else if (dotOffset == length) {
1132:                            if (dotLine.next() != null) {
1133:                                CompoundEdit compoundEdit = beginCompoundEdit();
1134:                                fillToCaret();
1135:                                addUndo(SimpleEdit.DELETE_LINE_SEP);
1136:                                deleteLineSeparator();
1137:                                endCompoundEdit(compoundEdit);
1138:                            } else
1139:                                status("End of buffer");
1140:                        } else {
1141:                            // Shouldn't happen.
1142:                            Debug.bug();
1143:                        }
1144:                    }
1145:                } finally {
1146:                    buffer.unlockWrite();
1147:                }
1148:            }
1149:
1150:            // A deletion, not a kill!
1151:            public void backspace() {
1152:                if (!checkReadOnly())
1153:                    return;
1154:                try {
1155:                    buffer.lockWrite();
1156:                } catch (InterruptedException e) {
1157:                    Log.error(e);
1158:                    return;
1159:                }
1160:                try {
1161:                    if (mark != null) {
1162:                        delete();
1163:                    } else if (display.getCaretCol() > buffer.getCol(
1164:                            getDotLine(), getDotLine().length())) {
1165:                        // The caret is beyond the end of the actual text on the current line.
1166:                        addUndo(SimpleEdit.MOVE);
1167:                        --display.caretCol;
1168:                        updateDotLine();
1169:                    } else if (dot.getOffset() > 0) {
1170:                        addUndo(SimpleEdit.LINE_EDIT);
1171:                        dot.moveLeft();
1172:                        deleteNormalChar();
1173:                        moveCaretToDotCol();
1174:                    } else if (getDotLine().previous() != null) {
1175:                        CompoundEdit compoundEdit = beginCompoundEdit();
1176:                        addUndo(SimpleEdit.MOVE);
1177:                        dot.moveTo(getDotLine().previous(), getDotLine()
1178:                                .previous().length());
1179:                        addUndo(SimpleEdit.DELETE_LINE_SEP);
1180:                        deleteLineSeparator();
1181:                        endCompoundEdit(compoundEdit);
1182:                        moveCaretToDotCol();
1183:                    }
1184:                } finally {
1185:                    buffer.unlockWrite();
1186:                }
1187:            }
1188:
1189:            private boolean nextChar() {
1190:                if (getDotOffset() < getDotLine().length()) {
1191:                    dot.skip(1);
1192:                    return true;
1193:                }
1194:                if (getDotLine().next() != null) {
1195:                    dot.moveTo(getDotLine().next(), 0);
1196:                    return true;
1197:                }
1198:                return false;
1199:            }
1200:
1201:            private boolean prevChar() {
1202:                if (getDotOffset() > 0) {
1203:                    dot.skip(-1);
1204:                    return true;
1205:                }
1206:                final Line previous = getDotLine().previous();
1207:                if (previous != null) {
1208:                    dot.moveTo(previous, previous.length());
1209:                    return true;
1210:                }
1211:                return false;
1212:            }
1213:
1214:            public char getDotChar() {
1215:                Debug.assertTrue(dot != null);
1216:                return dot.getChar();
1217:            }
1218:
1219:            public void cppFindMatch() {
1220:                if (getDotLine().trim().startsWith("#")) {
1221:                    Line line = CMode.findMatchPreprocessor(getDotLine());
1222:                    if (line != null)
1223:                        moveDotTo(line, 0);
1224:                    else
1225:                        status("No match");
1226:                } else
1227:                    findMatchingChar();
1228:            }
1229:
1230:            // If numLines is non-zero, limit the search to that many lines either
1231:            // forward or backward in the buffer.
1232:            public Position findMatchInternal(Position start, int numLines) {
1233:                if (start == null)
1234:                    return null;
1235:                final String s1 = new String("{([})]");
1236:                final char origChar = start.getChar();
1237:                int index = s1.indexOf(origChar);
1238:                if (index < 0)
1239:                    return null;
1240:                final Mode mode = getMode();
1241:                if (mode.isInComment(getBuffer(), start))
1242:                    return null;
1243:                boolean inQuote = mode.isInQuote(buffer, start);
1244:                if (inQuote)
1245:                    return null;
1246:                final String s2 = new String("})]{([");
1247:                final char match = s2.charAt(index);
1248:                final boolean searchBackwards = index > 2;
1249:                int stopLineNumber = searchBackwards ? 0 : buffer
1250:                        .getLineCount();
1251:                if (numLines != 0)
1252:                    stopLineNumber = searchBackwards ? start.lineNumber()
1253:                            - numLines : start.lineNumber() + numLines;
1254:                int count = 1;
1255:                final SyntaxIterator it = mode.getSyntaxIterator(start);
1256:                while (true) {
1257:                    char c;
1258:                    Position pos = it.getPosition();
1259:                    if (searchBackwards) {
1260:                        if (pos.lineNumber() < stopLineNumber)
1261:                            return null;
1262:                        else
1263:                            c = it.prevChar();
1264:                    } else {
1265:                        if (pos.lineNumber() > stopLineNumber)
1266:                            return null;
1267:                        else
1268:                            c = it.nextChar();
1269:                    }
1270:                    if (c == SyntaxIterator.DONE)
1271:                        return null;
1272:                    if (inQuote && c == '"')
1273:                        return null;
1274:                    if (c == origChar)
1275:                        ++count;
1276:                    else if (c == match)
1277:                        --count;
1278:                    if (count == 0) {
1279:                        // Found it!
1280:                        return it.getPosition();
1281:                    }
1282:                }
1283:            }
1284:
1285:            public void findMatchingChar() {
1286:                setWaitCursor();
1287:                Position pos = findDelimiterNearDot();
1288:                if (pos != null) {
1289:                    Position match = findMatchInternal(pos, 0);
1290:                    if (match != null) {
1291:                        // If the match is a right delimiter, we want to put the caret
1292:                        // beyond it.
1293:                        if ("})]".indexOf(match.getChar()) >= 0)
1294:                            match.next();
1295:                        addUndo(SimpleEdit.MOVE);
1296:                        unmark();
1297:                        updateDotLine();
1298:                        dot.moveTo(match);
1299:                        updateDotLine();
1300:                        moveCaretToDotCol();
1301:                    } else
1302:                        status("No match");
1303:                }
1304:                setDefaultCursor();
1305:            }
1306:
1307:            public void selectSyntax() {
1308:                setWaitCursor();
1309:                Position pos = findDelimiterNearDot();
1310:                if (pos != null) {
1311:                    Position match = findMatchInternal(pos, 0);
1312:                    if (match != null) {
1313:                        if ("})]".indexOf(pos.getChar()) >= 0)
1314:                            pos.next();
1315:                        else if ("})]".indexOf(match.getChar()) >= 0)
1316:                            match.next();
1317:                        if (pos.getLine() != match.getLine()) {
1318:                            // Extend selection to full lines if possible.
1319:                            Region r = new Region(buffer, pos, match);
1320:                            Position begin = r.getBegin();
1321:                            String trim = begin.getLine().substring(0,
1322:                                    begin.getOffset()).trim();
1323:                            if (trim.length() == 0) {
1324:                                Position end = r.getEnd();
1325:                                trim = end.getLine().substring(end.getOffset())
1326:                                        .trim();
1327:                                if (trim.length() == 0) {
1328:                                    // Extend selection to complete lines.
1329:                                    begin.setOffset(0);
1330:                                    if (end.getNextLine() != null)
1331:                                        end.moveTo(end.getNextLine(), 0);
1332:                                    else
1333:                                        end.setOffset(end.getLineLength());
1334:                                    if (pos.isBefore(match)) {
1335:                                        pos = begin;
1336:                                        match = end;
1337:                                    } else {
1338:                                        match = begin;
1339:                                        pos = end;
1340:                                    }
1341:                                }
1342:                            }
1343:                        }
1344:                        addUndo(SimpleEdit.MOVE);
1345:                        unmark();
1346:                        dot.moveTo(pos);
1347:                        setMarkAtDot();
1348:                        updateDotLine();
1349:                        dot.moveTo(match);
1350:                        updateDotLine();
1351:                        moveCaretToDotCol();
1352:                        if (dot.getLine() != mark.getLine())
1353:                            setUpdateFlag(REPAINT);
1354:                    } else
1355:                        status("No match");
1356:                }
1357:                setDefaultCursor();
1358:            }
1359:
1360:            private Position findDelimiterNearDot() {
1361:                Position pos = dot.copy();
1362:                if ("{([".indexOf(pos.getChar()) >= 0) {
1363:                    // The character to the right of the caret is a left delimiter.
1364:                    return pos;
1365:                }
1366:                Position saved = dot.copy();
1367:                if (pos.getOffset() > 0) {
1368:                    pos.prev();
1369:                    if ("})]".indexOf(pos.getChar()) >= 0) {
1370:                        // The character to the left of the caret is a right delimiter.
1371:                        return pos;
1372:                    }
1373:                }
1374:                // There's no delimiter at the exact location of the caret.
1375:                final String delimiters = "{([})]";
1376:                pos.moveTo(saved);
1377:                while (pos.getOffset() > 0) {
1378:                    // Look at previous char.
1379:                    pos.prev();
1380:                    char c = pos.getChar();
1381:                    if (delimiters.indexOf(c) >= 0)
1382:                        return pos;
1383:                    if (!Character.isWhitespace(c) && c != ';')
1384:                        break;
1385:                }
1386:                pos.moveTo(saved);
1387:                final int limit = pos.getLineLength();
1388:                while (pos.getOffset() < limit) {
1389:                    char c = pos.getChar();
1390:                    if (delimiters.indexOf(c) >= 0)
1391:                        return pos;
1392:                    if (!Character.isWhitespace(c))
1393:                        return null;
1394:                    // Look at next char.
1395:                    pos.next();
1396:                }
1397:                return null;
1398:            }
1399:
1400:            public void closeParen() {
1401:                insertNormalChar(')');
1402:                if (prefs
1403:                        .getBooleanProperty(Property.HIGHLIGHT_MATCHING_BRACKET)
1404:                        || prefs
1405:                                .getBooleanProperty(Property.HIGHLIGHT_BRACKETS))
1406:                    return;
1407:                // Limit search to 50 lines.
1408:                Position match = findMatchInternal(new Position(getDotLine(),
1409:                        getDotOffset() - 1), 50);
1410:                if (match == null)
1411:                    return;
1412:                // We don't want to reframe.
1413:                if (match.lineNumber() < display.getTopLineNumber())
1414:                    return;
1415:                if (buffer.getCol(match) < display.getShift())
1416:                    return;
1417:                // Move caret to match momentarily and then return.
1418:                Position saved = new Position(dot);
1419:                updateDotLine();
1420:                dot.moveTo(match);
1421:                updateDotLine();
1422:                moveCaretToDotCol();
1423:                display.repaintChangedLines();
1424:                try {
1425:                    Thread.sleep(300);
1426:                } catch (InterruptedException e) {
1427:                }
1428:                updateDotLine();
1429:                dot.moveTo(saved);
1430:                moveCaretToDotCol();
1431:                updateDotLine();
1432:            }
1433:
1434:            // No undo.
1435:            public void insertLineSeparator() {
1436:                Debug.assertTrue(mark == null);
1437:                try {
1438:                    buffer.lockWrite();
1439:                } catch (InterruptedException e) {
1440:                    Log.error(e);
1441:                    return;
1442:                }
1443:                try {
1444:                    buffer.insertLineSeparator(dot);
1445:                } finally {
1446:                    buffer.unlockWrite();
1447:                }
1448:                final Line dotLine = getDotLine();
1449:                for (int i = 0; i < getEditorCount(); i++) {
1450:                    Editor ed = getEditor(i);
1451:                    if (ed.getTopLine() == dotLine)
1452:                        ed.setTopLine(dotLine.previous());
1453:                }
1454:            }
1455:
1456:            public void newline() {
1457:                if (!checkReadOnly())
1458:                    return;
1459:                CompoundEdit compoundEdit = beginCompoundEdit();
1460:                if (mark != null)
1461:                    deleteRegion();
1462:                addUndo(SimpleEdit.INSERT_LINE_SEP);
1463:                insertLineSeparator();
1464:                moveCaretToDotCol();
1465:                endCompoundEdit(compoundEdit);
1466:            }
1467:
1468:            public void newlineAndIndent() {
1469:                if (isColumnSelection()) {
1470:                    notSupportedForColumnSelections();
1471:                    return;
1472:                }
1473:                if (!checkReadOnly())
1474:                    return;
1475:                try {
1476:                    buffer.lockWrite();
1477:                } catch (InterruptedException e) {
1478:                    Log.error(e);
1479:                    return;
1480:                }
1481:                try {
1482:                    CompoundEdit compoundEdit = beginCompoundEdit();
1483:                    if (mark != null)
1484:                        deleteRegion();
1485:                    addUndo(SimpleEdit.INSERT_LINE_SEP);
1486:                    insertLineSeparator();
1487:                    final Mode mode = getMode();
1488:                    final Line dotLine = getDotLine();
1489:                    int indent;
1490:                    if (mode.canIndent()) {
1491:                        if (buffer.needsRenumbering())
1492:                            buffer.renumber();
1493:                        getFormatter().parseBuffer();
1494:                        indent = mode.getCorrectIndentation(dotLine, buffer);
1495:                    } else {
1496:                        // Can't indent according to context. Match indentation of previous line.
1497:                        indent = buffer.getIndentation(dotLine.previous());
1498:                    }
1499:                    if (indent != buffer.getIndentation(dotLine)) {
1500:                        addUndo(SimpleEdit.LINE_EDIT);
1501:                        buffer.setIndentation(dotLine, indent);
1502:                    }
1503:                    if (dotLine.length() > 0) {
1504:                        moveDotToIndentation();
1505:                        moveCaretToDotCol();
1506:                    } else {
1507:                        display.setCaretCol(indent - display.getShift());
1508:                        if (buffer.getBooleanProperty(Property.RESTRICT_CARET))
1509:                            fillToCaret();
1510:                    }
1511:                    endCompoundEdit(compoundEdit);
1512:                } finally {
1513:                    buffer.unlockWrite();
1514:                }
1515:                setUpdateFlag(REFRAME);
1516:            }
1517:
1518:            public void insertNormalChar(char c) {
1519:                if (isColumnSelection()) {
1520:                    notSupportedForColumnSelections();
1521:                    return;
1522:                }
1523:                if (!checkReadOnly())
1524:                    return;
1525:                try {
1526:                    buffer.lockWrite();
1527:                } catch (InterruptedException e) {
1528:                    Log.error(e);
1529:                    return;
1530:                }
1531:                try {
1532:                    c = getMode().fixCase(this , c);
1533:                    if (mark != null) {
1534:                        CompoundEdit compoundEdit = beginCompoundEdit();
1535:                        deleteRegion();
1536:                        insertChar(c);
1537:                        endCompoundEdit(compoundEdit);
1538:                    } else {
1539:                        // No selection.
1540:                        if (buffer.getBooleanProperty(Property.WRAP)
1541:                                && getDotCol() >= buffer
1542:                                        .getIntegerProperty(Property.WRAP_COL)) {
1543:                            CompoundEdit compoundEdit = beginCompoundEdit();
1544:                            insertChar(c);
1545:                            new WrapText(this ).wrapLine();
1546:                            endCompoundEdit(compoundEdit);
1547:                        } else
1548:                            insertChar(c);
1549:                    }
1550:                } finally {
1551:                    buffer.unlockWrite();
1552:                }
1553:                moveCaretToDotCol();
1554:            }
1555:
1556:            public void tab() {
1557:                if (isColumnSelection()) {
1558:                    notSupportedForColumnSelections();
1559:                    return;
1560:                }
1561:                if (buffer.getBooleanProperty(Property.TAB_ALWAYS_INDENT)) {
1562:                    indentLineOrRegion();
1563:                    return;
1564:                }
1565:                if (mark == null) {
1566:                    // No selection.
1567:                    if (dot.getOffset() <= dot.getLine().getIndentation())
1568:                        indentLine();
1569:                    else
1570:                        insertTab();
1571:                    return;
1572:                }
1573:                if (getMarkLine() != getDotLine()) {
1574:                    // Multi-line selection.
1575:                    indentRegion();
1576:                    return;
1577:                }
1578:                // Single-line selection.
1579:                Region r = new Region(this );
1580:                if (r.getBeginOffset() <= getDotLine().getIndentation())
1581:                    indentLine();
1582:                else
1583:                    insertTab();
1584:            }
1585:
1586:            public void insertTab() {
1587:                if (isColumnSelection()) {
1588:                    notSupportedForColumnSelections();
1589:                    return;
1590:                }
1591:
1592:                if (!checkReadOnly())
1593:                    return;
1594:
1595:                try {
1596:                    buffer.lockWrite();
1597:                } catch (InterruptedException e) {
1598:                    Log.error(e);
1599:                    return;
1600:                }
1601:                try {
1602:                    CompoundEdit compoundEdit = beginCompoundEdit();
1603:                    if (mark != null)
1604:                        deleteRegion();
1605:                    if (buffer.getUseTabs())
1606:                        insertChar('\t');
1607:                    else {
1608:                        fillToCaret();
1609:                        int tabWidth = buffer.getTabWidth();
1610:                        addUndo(SimpleEdit.LINE_EDIT);
1611:                        buffer.insertChars(dot, Utilities.spaces(tabWidth
1612:                                - getDotCol() % tabWidth));
1613:                        updateInAllEditors(getDotLine());
1614:                    }
1615:                    moveCaretToDotCol();
1616:                    endCompoundEdit(compoundEdit);
1617:                } finally {
1618:                    buffer.unlockWrite();
1619:                }
1620:            }
1621:
1622:            public void moveDotToIndentation() {
1623:                final Line dotLine = getDotLine();
1624:                final int limit = dotLine.length();
1625:                int i;
1626:                for (i = 0; i < limit; i++) {
1627:                    if (!Character.isWhitespace(dotLine.charAt(i)))
1628:                        break;
1629:                }
1630:                dot.setOffset(i);
1631:            }
1632:
1633:            public void indentLineOrRegion() {
1634:                if (isColumnSelection()) {
1635:                    notSupportedForColumnSelections();
1636:                    return;
1637:                }
1638:                if (getMode().canIndent()) {
1639:                    if (mark != null && getMarkLine() != getDotLine()) {
1640:                        indentRegion();
1641:                    } else {
1642:                        unmark();
1643:                        indentLine();
1644:                    }
1645:                }
1646:            }
1647:
1648:            public void indentRegion() {
1649:                if (isColumnSelection()) {
1650:                    notSupportedForColumnSelections();
1651:                    return;
1652:                }
1653:                if (getMode().canIndent() && mark != null) {
1654:                    Region r = new Region(this );
1655:                    if (r.getBeginLine() == r.getEndLine()) {
1656:                        indentLine();
1657:                    } else {
1658:                        setWaitCursor();
1659:                        Position savedDot = new Position(dot);
1660:                        try {
1661:                            buffer.lockWrite();
1662:                        } catch (InterruptedException e) {
1663:                            Log.error(e);
1664:                            return;
1665:                        }
1666:                        try {
1667:                            if (buffer.needsParsing()) {
1668:                                if (getFormatter().parseBuffer())
1669:                                    buffer.repaint();
1670:                            }
1671:                            CompoundEdit compoundEdit = beginCompoundEdit();
1672:                            addUndo(SimpleEdit.MOVE);
1673:                            dot.moveTo(r.getBeginLine(), 0);
1674:                            do {
1675:                                if (!dot.getLine().isBlank())
1676:                                    indentLineInternal();
1677:                                dot.moveTo(dot.getNextLine(), 0);
1678:                            } while (dot.getLine() != r.getEndLine());
1679:                            addUndo(SimpleEdit.MOVE);
1680:                            dot = savedDot;
1681:                            if (dot.getOffset() > getDotLine().length())
1682:                                dot.setOffset(getDotLine().length());
1683:                            if (mark.getOffset() > getMarkLine().length())
1684:                                mark.setOffset(getMarkLine().length());
1685:                            moveCaretToDotCol();
1686:                            endCompoundEdit(compoundEdit);
1687:                        } finally {
1688:                            buffer.unlockWrite();
1689:                        }
1690:                        setUpdateFlag(REFRAME);
1691:                        setDefaultCursor();
1692:                    }
1693:                }
1694:            }
1695:
1696:            public void commentRegion() {
1697:                if (isColumnSelection()) {
1698:                    notSupportedForColumnSelections();
1699:                    return;
1700:                }
1701:                commentRegion(true);
1702:            }
1703:
1704:            public void uncommentRegion() {
1705:                if (isColumnSelection()) {
1706:                    notSupportedForColumnSelections();
1707:                    return;
1708:                }
1709:                commentRegion(false);
1710:            }
1711:
1712:            // If argument is false, uncomment the region.
1713:            private void commentRegion(boolean comment) {
1714:                if (!checkReadOnly())
1715:                    return;
1716:                if (dot == null)
1717:                    return;
1718:                try {
1719:                    buffer.lockWrite();
1720:                } catch (InterruptedException e) {
1721:                    Log.error(e);
1722:                    return;
1723:                }
1724:                try {
1725:                    commentRegionInternal(comment);
1726:                } finally {
1727:                    buffer.unlockWrite();
1728:                }
1729:            }
1730:
1731:            // If argument is false, uncomment the region.
1732:            private void commentRegionInternal(boolean comment) {
1733:                String commentStart = buffer.getCommentStart();
1734:                if (commentStart == null)
1735:                    return;
1736:                String commentEnd = buffer.getCommentEnd();
1737:                Position savedDot = new Position(dot);
1738:                Line beginLine, endLine;
1739:                if (mark != null) {
1740:                    Region r = new Region(buffer, dot, mark);
1741:                    beginLine = r.getBeginLine();
1742:                    endLine = r.getEndLine();
1743:                } else {
1744:                    beginLine = getDotLine();
1745:                    endLine = getDotLine().next();
1746:                }
1747:                if (endLine == beginLine)
1748:                    endLine = beginLine.next();
1749:
1750:                CompoundEdit compoundEdit = beginCompoundEdit();
1751:
1752:                if (mark != null) {
1753:                    addUndo(SimpleEdit.MOVE);
1754:                    setMark(null);
1755:                    setUpdateFlag(REPAINT);
1756:                }
1757:
1758:                if (getDotLine() != beginLine) {
1759:                    addUndo(SimpleEdit.MOVE);
1760:                    dot.moveTo(beginLine, 0);
1761:                }
1762:
1763:                boolean modified = false;
1764:
1765:                while (true) {
1766:                    Line dotLine = getDotLine();
1767:                    String trim = dotLine.trim();
1768:                    if (comment) {
1769:                        if (trim.length() != 0) {
1770:                            addUndo(SimpleEdit.LINE_EDIT);
1771:                            if (commentEnd != null)
1772:                                dotLine.setText(commentStart
1773:                                        + dotLine.getText() + commentEnd);
1774:                            else
1775:                                dotLine.setText(commentStart
1776:                                        + dotLine.getText());
1777:                            modified = true;
1778:                            if (dotLine == savedDot.getLine())
1779:                                savedDot.setOffset(savedDot.getOffset()
1780:                                        + commentStart.length());
1781:                            updateInAllEditors(dotLine);
1782:                        }
1783:                    } else {
1784:                        // Uncomment.
1785:                        if (trim.startsWith(commentStart)) {
1786:                            if (commentEnd == null || trim.endsWith(commentEnd)) {
1787:                                addUndo(SimpleEdit.LINE_EDIT);
1788:                                int index = dotLine.getText().indexOf(
1789:                                        commentStart)
1790:                                        + commentStart.length();
1791:                                dotLine.setText(dotLine.substring(index));
1792:                                if (commentEnd != null)
1793:                                    dotLine.setText(dotLine.substring(0,
1794:                                            dotLine.length()
1795:                                                    - commentEnd.length()));
1796:                                modified = true;
1797:                                int dotCol = 0;
1798:                                if (dotLine == savedDot.getLine()) {
1799:                                    // Adjust saved position.
1800:                                    savedDot.setOffset(savedDot.getOffset()
1801:                                            - index);
1802:                                    if (savedDot.getOffset() < 0)
1803:                                        savedDot.setOffset(0);
1804:                                    dotCol = buffer.getCol(dotLine, savedDot
1805:                                            .getOffset());
1806:                                }
1807:
1808:                                int oldIndent = buffer.getIndentation(dotLine);
1809:                                int indent = getMode().getCorrectIndentation(
1810:                                        dotLine, buffer);
1811:                                if (indent != oldIndent) {
1812:                                    buffer.setIndentation(dotLine, indent);
1813:                                    if (dotLine == savedDot.getLine()) {
1814:                                        // Adjust saved position.
1815:                                        if (dotCol >= oldIndent) {
1816:                                            dotCol += indent - oldIndent;
1817:                                            dot.moveToCol(dotCol, buffer
1818:                                                    .getTabWidth());
1819:                                            savedDot.setOffset(dot.getOffset());
1820:                                        }
1821:                                    }
1822:                                }
1823:                                updateInAllEditors(dotLine);
1824:                            }
1825:                        }
1826:                    }
1827:
1828:                    if (dotLine.next() == endLine)
1829:                        break;
1830:
1831:                    addUndo(SimpleEdit.MOVE);
1832:                    dot.moveTo(dotLine.next(), 0);
1833:                }
1834:
1835:                addUndo(SimpleEdit.MOVE);
1836:                setDot(savedDot);
1837:                moveCaretToDotCol();
1838:
1839:                if (modified)
1840:                    buffer.modified();
1841:
1842:                endCompoundEdit(compoundEdit);
1843:            }
1844:
1845:            public final void moveDotTo(Position pos) {
1846:                if (pos != null)
1847:                    moveDotTo(pos.getLine(), pos.getOffset());
1848:            }
1849:
1850:            public void moveDotTo(Line line, int offset) {
1851:                if (dot == null)
1852:                    return;
1853:                addUndo(SimpleEdit.MOVE);
1854:                if (mark != null) {
1855:                    setMark(null);
1856:                    dot.moveTo(line, offset);
1857:                    setUpdateFlag(REPAINT);
1858:                } else {
1859:                    updateDotLine();
1860:                    dot.moveTo(line, offset);
1861:                    updateDotLine();
1862:                }
1863:                moveCaretToDotCol();
1864:            }
1865:
1866:            public void indentLine() {
1867:                if (isColumnSelection()) {
1868:                    notSupportedForColumnSelections();
1869:                    return;
1870:                }
1871:                if (!checkReadOnly())
1872:                    return;
1873:                if (!getMode().canIndent())
1874:                    return; // No change.
1875:                try {
1876:                    buffer.lockWrite();
1877:                } catch (InterruptedException e) {
1878:                    Log.error(e);
1879:                    return;
1880:                }
1881:                try {
1882:                    if (buffer.needsParsing()) {
1883:                        if (getFormatter().parseBuffer())
1884:                            buffer.repaint();
1885:                    }
1886:                    indentLineInternal();
1887:                } finally {
1888:                    buffer.unlockWrite();
1889:                }
1890:                setUpdateFlag(REFRAME);
1891:            }
1892:
1893:            private void indentLineInternal() {
1894:                final Line dotLine = getDotLine();
1895:                final int indent = getMode().getCorrectIndentation(dotLine,
1896:                        buffer);
1897:                final int shift = display.getShift();
1898:
1899:                if (dotLine.isBlank()) {
1900:                    // Put the caret where it needs to go...
1901:                    addUndo(SimpleEdit.LINE_EDIT);
1902:                    dotLine.setText("");
1903:                    dot.setOffset(0);
1904:                    display.setCaretCol(indent - shift);
1905:                    // Fill if necessary.
1906:                    if (buffer.getBooleanProperty(Property.RESTRICT_CARET))
1907:                        fillToCaret();
1908:                    updateInAllEditors(dotLine);
1909:                    return;
1910:                }
1911:
1912:                // Line is not blank. Figure out current indentation.
1913:                final int oldIndent = buffer.getIndentation(dotLine);
1914:
1915:                FastStringBuffer sb = null;
1916:
1917:                if (indent == oldIndent) {
1918:                    boolean ok = false;
1919:                    if (buffer
1920:                            .getBooleanProperty(Property.INDENT_LINE_FIX_WHITESPACE)) {
1921:                        sb = buffer.getCorrectIndentationString(indent);
1922:                        if (dotLine.getText().startsWith(sb.toString()))
1923:                            ok = true;
1924:                    } else
1925:                        ok = true;
1926:
1927:                    if (ok) {
1928:                        // Current indentation is correct. If the caret is in the
1929:                        // indentation area, move it to the start of the non-blank
1930:                        // text.
1931:                        if (display.getCaretCol() + shift < indent) {
1932:                            addUndo(SimpleEdit.MOVE);
1933:                            display.setCaretCol(indent - shift);
1934:                            moveDotToCaretCol();
1935:                        }
1936:                        return;
1937:                    }
1938:                }
1939:
1940:                // We need to fix the indentation. Figure out where we want to put the
1941:                // caret when we're done. We want to maintain the existing offset from
1942:                // the start of the non-blank text.
1943:                final int existing = display.getCaretCol() + shift - oldIndent;
1944:                final int goal = existing < 0 ? indent : existing + indent;
1945:
1946:                // Strip existing indentation.
1947:                int i = 0;
1948:                while (i < dotLine.length()
1949:                        && Character.isWhitespace(dotLine.charAt(i)))
1950:                    ++i;
1951:                String nonBlank = dotLine.substring(i);
1952:
1953:                // Get the correct indentation string.
1954:                if (sb == null)
1955:                    sb = buffer.getCorrectIndentationString(indent);
1956:
1957:                // Add the rest of the line.
1958:                sb.append(nonBlank);
1959:
1960:                // Replace the existing text.
1961:                addUndo(SimpleEdit.LINE_EDIT);
1962:                dotLine.setText(sb.toString());
1963:                buffer.modified();
1964:                updateInAllEditors(dotLine);
1965:
1966:                // Put the caret where we want it.
1967:                display.setCaretCol(goal - shift);
1968:                moveDotToCaretCol();
1969:            }
1970:
1971:            public void save() {
1972:                save(buffer);
1973:            }
1974:
1975:            public void save(Buffer toBeSaved) {
1976:                if (toBeSaved.isLocked())
1977:                    return;
1978:                if (toBeSaved.getType() == Buffer.TYPE_NORMAL) {
1979:                    if (toBeSaved.isModified()) {
1980:                        if (toBeSaved.isUntitled()) {
1981:                            saveAs(toBeSaved);
1982:                        } else {
1983:                            setWaitCursor();
1984:                            status("Saving...");
1985:                            if (toBeSaved
1986:                                    .getBooleanProperty(Property.REMOVE_TRAILING_WHITESPACE))
1987:                                toBeSaved.removeTrailingWhitespace();
1988:                            if (toBeSaved.save())
1989:                                status("Saving...done");
1990:                            else
1991:                                status("Save failed");
1992:                            setDefaultCursor();
1993:                        }
1994:                    } else
1995:                        status("Not modified");
1996:                }
1997:            }
1998:
1999:            public void saveAs() {
2000:                saveAs(buffer);
2001:            }
2002:
2003:            private void saveAs(Buffer toBeSaved) {
2004:                if (toBeSaved.isLocked())
2005:                    return;
2006:                if (toBeSaved.getType() == Buffer.TYPE_NORMAL) {
2007:                    final String dialogTitle = "Save As";
2008:                    File destination = SaveFileDialog.getSaveFile(this ,
2009:                            dialogTitle);
2010:                    if (destination == null)
2011:                        return;
2012:
2013:                    // At this point, if the target file exists, the user has said
2014:                    // it's OK to overwrite it.
2015:                    repaintNow();
2016:
2017:                    // Do we have the target file in a buffer?
2018:                    Buffer buf = bufferList.findBuffer(destination);
2019:                    if (buf != null) {
2020:                        // We do. Can we just get rid of it?
2021:                        if (!buf.isModified()) {
2022:                            buf.deleteAutosaveFile();
2023:                            bufferList.remove(buf);
2024:                        } else {
2025:                            // Buffer is modified.  Make user deal with it.
2026:                            setDefaultCursor();
2027:                            String message = "Target file is in an active buffer.  Please take care of that first.";
2028:                            MessageDialog.showMessageDialog(this , message,
2029:                                    dialogTitle);
2030:                            return;
2031:                        }
2032:                    }
2033:
2034:                    toBeSaved.saveAs(destination);
2035:                }
2036:            }
2037:
2038:            public void saveCopy() {
2039:                if (buffer.isLocked())
2040:                    return;
2041:                if (buffer.getType() == Buffer.TYPE_NORMAL) {
2042:                    final String dialogTitle = "Save Copy";
2043:                    final File destination = SaveFileDialog.getSaveFile(this ,
2044:                            dialogTitle);
2045:                    if (destination == null)
2046:                        return;
2047:
2048:                    repaintNow();
2049:
2050:                    // Do we have the target file in a buffer?
2051:                    Buffer buf = bufferList.findBuffer(destination);
2052:                    if (buf != null) {
2053:                        // We do.  Do we care?
2054:                        if (buf.isModified()) {
2055:                            // Buffer is modified.  Make user deal with it.
2056:                            setDefaultCursor();
2057:                            String message = "Target file is in an active buffer.  Please take care of that first.";
2058:                            MessageDialog.showMessageDialog(this , message,
2059:                                    "Save Copy");
2060:                            return;
2061:                        }
2062:                    }
2063:
2064:                    buffer.saveCopy(destination);
2065:                    if (buf != null && buf.isLoaded())
2066:                        reload(buf);
2067:                }
2068:            }
2069:
2070:            public void saveAll() {
2071:                setWaitCursor();
2072:                int numModified = 0;
2073:                int numErrors = 0;
2074:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
2075:                    Buffer buf = it.nextBuffer();
2076:                    if (buf.getModeId() == CHECKIN_MODE)
2077:                        continue;
2078:                    if (buf.isUntitled()) {
2079:                        setDefaultCursor();
2080:                        makeNext(buf);
2081:                        activate(buf);
2082:                        saveAs();
2083:                        setWaitCursor();
2084:                    } else if (buf.isModified()) {
2085:                        status("Saving modified buffers...");
2086:                        ++numModified;
2087:                        if (buffer.getFile() != null)
2088:                            if (buffer
2089:                                    .getBooleanProperty(Property.REMOVE_TRAILING_WHITESPACE))
2090:                                buffer.removeTrailingWhitespace();
2091:                        if (!buf.save())
2092:                            ++numErrors;
2093:                    }
2094:                }
2095:                if (numModified == 0)
2096:                    status("No modified buffers");
2097:                else if (numErrors == 0)
2098:                    status("Saving modified buffers...done");
2099:                else {
2100:                    // User will already have seen detailed error information from Buffer.save().
2101:                    status("Unable to save all modified buffers");
2102:                }
2103:                setDefaultCursor();
2104:            }
2105:
2106:            public boolean okToClose(Buffer buf) {
2107:                if (buf.getType() != Buffer.TYPE_NORMAL)
2108:                    return true;
2109:                if (buf.isUntitled() || buf.isModified()) {
2110:                    makeNext(buf);
2111:                    activate(buf);
2112:                    repaintNow();
2113:                    if (!CloseBufferConfirmationDialog.confirmClose(this , buf))
2114:                        return false;
2115:                }
2116:                return true;
2117:            }
2118:
2119:            public void closeAll() {
2120:                repaintNow();
2121:
2122:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
2123:                    if (!okToClose(it.nextBuffer()))
2124:                        return;
2125:                }
2126:
2127:                Marker.invalidateAllMarkers();
2128:
2129:                Buffer toBeActivated = null;
2130:
2131:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
2132:                    Buffer buf = it.nextBuffer();
2133:                    if (buf instanceof  Directory
2134:                            && buf.getFile().equals(getCurrentDirectory())) {
2135:                        toBeActivated = buf;
2136:                        break;
2137:                    }
2138:                }
2139:
2140:                if (toBeActivated == null)
2141:                    toBeActivated = new Directory(getCurrentDirectory());
2142:
2143:                setWaitCursor();
2144:
2145:                for (int i = 0; i < getEditorCount(); i++) {
2146:                    Editor ed = getEditor(i);
2147:                    ed.activate(toBeActivated);
2148:                }
2149:
2150:                for (BufferIterator iter = new BufferIterator(); iter.hasNext();) {
2151:                    Buffer buf = iter.nextBuffer();
2152:                    if (buf != toBeActivated) {
2153:                        for (EditorIterator it = new EditorIterator(); it
2154:                                .hasNext();) {
2155:                            Editor ed = it.nextEditor();
2156:                            ed.views.remove(buf);
2157:                        }
2158:                        buf.deleteAutosaveFile();
2159:                        iter.remove();
2160:                        buf.dispose();
2161:                    }
2162:                }
2163:
2164:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_BUFFER_LIST_ALL);
2165:                Sidebar.refreshSidebarInAllFrames();
2166:                setDefaultCursor();
2167:            }
2168:
2169:            public void closeOthers() {
2170:                repaintNow();
2171:
2172:                Buffer toBeActivated = buffer;
2173:
2174:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
2175:                    Buffer buf = it.nextBuffer();
2176:                    if (buf != buffer && !okToClose(buf))
2177:                        return;
2178:                }
2179:
2180:                List markers = Marker.getAllMarkers();
2181:                for (int i = 0; i < markers.size(); i++) {
2182:                    Marker m = (Marker) markers.get(i);
2183:                    if (m != null && m.getBuffer() != buffer)
2184:                        m.invalidate();
2185:                }
2186:
2187:                setWaitCursor();
2188:
2189:                for (EditorIterator it = new EditorIterator(); it.hasNext();)
2190:                    it.nextEditor().activate(toBeActivated);
2191:
2192:                for (BufferIterator iter = new BufferIterator(); iter.hasNext();) {
2193:                    Buffer buf = iter.nextBuffer();
2194:                    if (buf != buffer) {
2195:                        for (EditorIterator it = new EditorIterator(); it
2196:                                .hasNext();) {
2197:                            Editor ed = it.nextEditor();
2198:                            ed.views.remove(buf);
2199:                        }
2200:                        buf.deleteAutosaveFile();
2201:                        iter.remove();
2202:                        buf.dispose();
2203:                    }
2204:                }
2205:
2206:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_BUFFER_LIST_ALL);
2207:                Sidebar.refreshSidebarInAllFrames();
2208:                setDefaultCursor();
2209:            }
2210:
2211:            public boolean execute(String command) throws NoSuchMethodException {
2212:                String[] array = parseCommand(command);
2213:                if (array == null)
2214:                    return false;
2215:                String methodName = array[0];
2216:                String parameters = array[1];
2217:                return execute(methodName, parameters);
2218:            }
2219:
2220:            public boolean execute(String commandName, String parameters)
2221:                    throws NoSuchMethodException {
2222:                if (commandName == null)
2223:                    return false;
2224:
2225:                try {
2226:                    String className = null;
2227:                    String methodName = null;
2228:                    Method method = null;
2229:
2230:                    Class[] parameterTypes;
2231:                    if (parameters == null)
2232:                        parameterTypes = new Class[0];
2233:                    else {
2234:                        parameterTypes = new Class[1];
2235:                        parameterTypes[0] = Class.forName("java.lang.String");
2236:                    }
2237:
2238:                    Command command = CommandTable.getCommand(commandName);
2239:                    if (command != null) {
2240:                        method = command.getMethod();
2241:                        if (method != null) {
2242:                            try {
2243:                                invoke(method, parameters);
2244:                                return true;
2245:                            } catch (IllegalArgumentException e) {
2246:                                // The cached method requires different arguments.
2247:                                // Fall through.
2248:                            }
2249:                        }
2250:                        // Method is not cached yet.
2251:                        className = command.getClassName();
2252:                        methodName = command.getMethodName();
2253:                        if (className == null) {
2254:                            // Special case. Command is implemented in org.armedbear.j.Editor.
2255:                            method = Editor.class.getMethod(methodName,
2256:                                    parameterTypes);
2257:                        } else {
2258:                            Class c = Class.forName("org.armedbear.j."
2259:                                    + className);
2260:                            if (c != null)
2261:                                method = c
2262:                                        .getMethod(methodName, parameterTypes);
2263:                        }
2264:                        if (method != null) {
2265:                            // Cache the method for nest time.
2266:                            command.setMethod(method);
2267:                            invoke(method, parameters);
2268:                            return true;
2269:                        }
2270:                    } else {
2271:                        // This is the old code path.
2272:                        Debug.assertTrue(className == null);
2273:                        Debug.assertTrue(methodName == null);
2274:                        int index = commandName.indexOf('.');
2275:                        if (index < 0) {
2276:                            // No class name.  Must be a method in the Editor class.
2277:                            method = Editor.class.getMethod(commandName,
2278:                                    parameterTypes);
2279:                        } else if (commandName.length() > index + 1) {
2280:                            // Class name was provided.
2281:                            className = commandName.substring(0, index);
2282:                            methodName = commandName.substring(index + 1);
2283:                            Class c = null;
2284:                            try {
2285:                                c = Class.forName("org.armedbear.j."
2286:                                        + className);
2287:                            } catch (ClassNotFoundException e) {
2288:                            }
2289:                            if (c == null) {
2290:                                // Check for extension class.
2291:                                c = loadExtensionClass(className);
2292:                            }
2293:                            if (c != null) {
2294:                                // Might throw NoSuchMethodException.
2295:                                method = c
2296:                                        .getMethod(methodName, parameterTypes);
2297:                            }
2298:                        }
2299:                        if (method != null) {
2300:                            invoke(method, parameters);
2301:                            return true;
2302:                        }
2303:                    }
2304:                } catch (NoSuchMethodException e) {
2305:                    throw e;
2306:                } catch (Throwable t) {
2307:                    Log.error(t);
2308:                }
2309:                return false;
2310:            }
2311:
2312:            private void invoke(Method method, String parameters)
2313:                    throws IllegalArgumentException {
2314:                Object[] args;
2315:                if (parameters == null)
2316:                    args = new Object[0]; // No arguments.
2317:                else {
2318:                    args = new Object[1];
2319:                    args[0] = parameters;
2320:                }
2321:                try {
2322:                    method.invoke(this , args);
2323:                } catch (IllegalArgumentException e) {
2324:                    throw e;
2325:                } catch (Throwable t) {
2326:                    Log.error(t);
2327:                }
2328:            }
2329:
2330:            public boolean handleKeyEvent(char keyChar, int keyCode,
2331:                    int modifiers) {
2332:                if (insertingKeyText) {
2333:                    insertKeyTextInternal(keyChar, keyCode, modifiers);
2334:                    return true;
2335:                }
2336:                KeyMapping mapping = getKeyMapping(keyChar, keyCode, modifiers);
2337:                if (mapping != null) {
2338:                    Object command = mapping.getCommand();
2339:                    if (isRecordingMacro()) {
2340:                        if (command != "recordMacro"
2341:                                && command != "playbackMacro")
2342:                            Macro.record(this , command);
2343:                    }
2344:                    if (command instanceof  String) {
2345:                        String commandString = (String) command;
2346:                        if (commandString.length() > 0
2347:                                && commandString.charAt(0) == '(') {
2348:                            // Lisp form.
2349:                            executeCommand(commandString);
2350:                            return true;
2351:                        }
2352:                        String[] array = parseCommand(commandString);
2353:                        if (array != null) {
2354:                            String methodName = array[0];
2355:                            String parameters = array[1];
2356:                            try {
2357:                                return execute(methodName, parameters);
2358:                            } catch (NoSuchMethodException e) {
2359:                            }
2360:                        }
2361:                    } else if (command instanceof  LispObject) {
2362:                        try {
2363:                            Lisp.funcall0(Lisp
2364:                                    .coerceToFunction((LispObject) command),
2365:                                    LispThread.currentThread());
2366:                        } catch (Throwable t) {
2367:                            Log.error(t);
2368:                        }
2369:                        return true;
2370:                    }
2371:                }
2372:                return false;
2373:            }
2374:
2375:            public KeyMapping getKeyMapping(char keyChar, int keyCode,
2376:                    int modifiers) {
2377:                // Look in mode-specific key map.
2378:                KeyMapping mapping = buffer.getMode().getKeyMap().lookup(
2379:                        keyChar, keyCode, modifiers);
2380:                if (mapping != null)
2381:                    return mapping;
2382:                // Look in global key map.
2383:                return KeyMap.getGlobalKeyMap().lookup(keyChar, keyCode,
2384:                        modifiers);
2385:            }
2386:
2387:            // Returns multiple values: mapping, mode.
2388:            // mode == null means it's a global mapping.
2389:            public Object[] getKeyMapping(String command) {
2390:                Mode mode = null;
2391:                // Look in buffer-local keymap first.
2392:                KeyMapping mapping = buffer.getKeyMapForMode().getKeyMapping(
2393:                        command);
2394:                // If not found there, try global keymap.
2395:                if (mapping == null) {
2396:                    mapping = KeyMap.getGlobalKeyMap().getKeyMapping(command);
2397:                    // Don't let a global mapping hide a different mapping of the same
2398:                    // keystroke in the buffer-local keymap!
2399:                    if (mapping != null) {
2400:                        javax.swing.KeyStroke keyStroke = javax.swing.KeyStroke
2401:                                .getKeyStroke(mapping.getKeyCode(), mapping
2402:                                        .getModifiers());
2403:                        if (buffer.getKeyMapForMode().lookup(keyStroke) != null)
2404:                            mapping = null;
2405:                    }
2406:                } else
2407:                    mode = getMode();
2408:                Object[] values = new Object[2];
2409:                values[0] = mapping;
2410:                values[1] = mode;
2411:                return values;
2412:            }
2413:
2414:            public void pageDown() {
2415:                if (dot == null)
2416:                    return;
2417:                maybeResetGoalColumn();
2418:                if (mark != null) {
2419:                    CompoundEdit compoundEdit = beginCompoundEdit();
2420:                    addUndo(SimpleEdit.MOVE);
2421:                    setMark(null);
2422:                    setUpdateFlag(REPAINT);
2423:                    pageDownInternal();
2424:                    endCompoundEdit(compoundEdit);
2425:                } else
2426:                    pageDownInternal();
2427:                setCurrentCommand(COMMAND_PAGE_DOWN);
2428:            }
2429:
2430:            public void pageDownOtherWindow() {
2431:                final Editor ed = frame.getOtherEditor();
2432:                if (ed != null) {
2433:                    ed.pageDown();
2434:                    ed.updateDisplay();
2435:                }
2436:            }
2437:
2438:            public void selectPageDown() {
2439:                if (dot == null)
2440:                    return;
2441:                maybeResetGoalColumn();
2442:                if (mark == null) {
2443:                    CompoundEdit compoundEdit = beginCompoundEdit();
2444:                    addUndo(SimpleEdit.MOVE);
2445:                    setMarkAtDot();
2446:                    pageDownInternal();
2447:                    endCompoundEdit(compoundEdit);
2448:                } else
2449:                    pageDownInternal();
2450:                setCurrentCommand(COMMAND_PAGE_DOWN);
2451:            }
2452:
2453:            public void pageUp() {
2454:                if (dot == null)
2455:                    return;
2456:                maybeResetGoalColumn();
2457:                if (mark != null) {
2458:                    CompoundEdit compoundEdit = beginCompoundEdit();
2459:                    addUndo(SimpleEdit.MOVE);
2460:                    setMark(null);
2461:                    setUpdateFlag(REPAINT);
2462:                    pageUpInternal();
2463:                    endCompoundEdit(compoundEdit);
2464:                } else
2465:                    pageUpInternal();
2466:                setCurrentCommand(COMMAND_PAGE_UP);
2467:            }
2468:
2469:            public void pageUpOtherWindow() {
2470:                final Editor ed = frame.getOtherEditor();
2471:                if (ed != null) {
2472:                    ed.pageUp();
2473:                    ed.updateDisplay();
2474:                }
2475:            }
2476:
2477:            public void selectPageUp() {
2478:                if (dot == null)
2479:                    return;
2480:                maybeResetGoalColumn();
2481:                if (mark == null) {
2482:                    CompoundEdit compoundEdit = beginCompoundEdit();
2483:                    addUndo(SimpleEdit.MOVE);
2484:                    setMarkAtDot();
2485:                    pageUpInternal();
2486:                    endCompoundEdit(compoundEdit);
2487:                } else
2488:                    pageUpInternal();
2489:                setCurrentCommand(COMMAND_PAGE_UP);
2490:            }
2491:
2492:            private void pageDownInternal() {
2493:                Debug.assertTrue(buffer.needsRenumbering == false);
2494:
2495:                int topLineNumber = display.getTopLineNumber();
2496:                Line dotLine = getDotLine();
2497:                int dotLineNumber = dot.lineNumber();
2498:                int numRows = display.getRows();
2499:
2500:                Line[] lines = new Line[numRows];
2501:                Line line = getTopLine();
2502:                int dotRow = -1;
2503:                for (int i = 0; i < numRows; i++) {
2504:                    lines[i] = line;
2505:                    if (line == dotLine)
2506:                        dotRow = i;
2507:                    if (line != null)
2508:                        line = line.nextVisible();
2509:                }
2510:                Line bottomLine = lines[numRows - 1];
2511:
2512:                if (bottomLine == null) {
2513:                    // We're on the last page already.
2514:                    if (dotRow >= 0) {
2515:                        Position eob = getEob();
2516:                        if (eob != null) {
2517:                            addUndo(SimpleEdit.MOVE);
2518:                            updateDotLine();
2519:                            dot.setLine(eob.getLine());
2520:                            moveDotToGoalCol();
2521:                            updateDotLine();
2522:                        }
2523:                    }
2524:                    return;
2525:                }
2526:
2527:                // Not on last page.
2528:                display.setTopLine(bottomLine);
2529:                setUpdateFlag(REPAINT);
2530:
2531:                if (dotRow >= 0) {
2532:                    line = getTopLine();
2533:                    for (int i = 0; i < dotRow; i++) {
2534:                        Line next = line.nextVisible();
2535:                        if (next == null)
2536:                            break;
2537:                        line = next;
2538:                    }
2539:                    addUndo(SimpleEdit.MOVE);
2540:                    dot.setLine(line);
2541:                    moveDotToGoalCol();
2542:                }
2543:            }
2544:
2545:            private void pageUpInternal() {
2546:                if (dot.getLine() == buffer.getFirstLine())
2547:                    return;
2548:                Debug.assertTrue(buffer.needsRenumbering == false);
2549:                int topLineNumber = display.getTopLineNumber();
2550:                int dotLineNumber = dot.lineNumber();
2551:                int linesToScroll = display.getRows() - 1;
2552:                boolean dotLineIsVisible = false;
2553:                if (dotLineNumber >= topLineNumber) {
2554:                    Line bottomLine = display.getBottomLine();
2555:                    if (bottomLine != null)
2556:                        if (dotLineNumber <= bottomLine.lineNumber())
2557:                            dotLineIsVisible = true;
2558:                }
2559:                addUndo(SimpleEdit.MOVE);
2560:                if (dotLineIsVisible) {
2561:                    for (int i = 0; i < linesToScroll; i++) {
2562:                        Line topLinePrevious = getTopLine().previousVisible();
2563:                        if (topLinePrevious != null)
2564:                            display.setTopLine(topLinePrevious);
2565:                        Line dotLinePrevious = dot.getLine().previousVisible();
2566:                        if (dotLinePrevious == null)
2567:                            break;
2568:                        dot.setLine(dotLinePrevious);
2569:                    }
2570:                } else {
2571:                    for (int i = 0; i < linesToScroll; i++) {
2572:                        Line dotLinePrevious = dot.getLine().previousVisible();
2573:                        if (dotLinePrevious == null)
2574:                            break;
2575:                        dot.setLine(dotLinePrevious);
2576:                    }
2577:                }
2578:                moveDotToGoalCol();
2579:                setUpdateFlag(REPAINT);
2580:            }
2581:
2582:            // Move dot to beginning of block, no undo.
2583:            public void beginningOfBlock() {
2584:                if (mark != null) {
2585:                    Region r = new Region(buffer, mark, dot);
2586:                    dot.moveTo(r.getBegin());
2587:                    setMark(null);
2588:                    moveCaretToDotCol();
2589:                    if (r.getBeginLine() != r.getEndLine())
2590:                        setUpdateFlag(REPAINT);
2591:                    else
2592:                        updateDotLine();
2593:                }
2594:            }
2595:
2596:            // Move dot to end of block, no undo.
2597:            public void endOfBlock() {
2598:                if (mark != null) {
2599:                    Region r = new Region(buffer, mark, dot);
2600:                    dot.moveTo(r.getEnd());
2601:                    setMark(null);
2602:                    moveCaretToDotCol();
2603:                    if (r.getBeginLine() != r.getEndLine())
2604:                        setUpdateFlag(REPAINT);
2605:                    else
2606:                        updateDotLine();
2607:                }
2608:            }
2609:
2610:            public void right() {
2611:                if (dot == null)
2612:                    return;
2613:                if (buffer.getBooleanProperty(Property.RESTRICT_CARET)) {
2614:                    if (mark == null && getDotOffset() >= getDotLine().length()) {
2615:                        // Caret is at end of line.
2616:                        if (getDotLine().next() != null) {
2617:                            moveDotTo(getDotLine().next(), 0);
2618:                            setCurrentCommand(COMMAND_RIGHT);
2619:                        }
2620:                        return;
2621:                    }
2622:                }
2623:                if (mark != null || lastCommand != COMMAND_RIGHT)
2624:                    addUndo(SimpleEdit.MOVE);
2625:                if (mark != null)
2626:                    endOfBlock();
2627:                else if (dot.getOffset() < dot.getLineLength()) {
2628:                    dot.skip(1);
2629:                    moveCaretToDotCol();
2630:                } else {
2631:                    ++display.caretCol;
2632:                }
2633:                updateDotLine();
2634:                setCurrentCommand(COMMAND_RIGHT);
2635:                setUpdateFlag(REFRAME);
2636:            }
2637:
2638:            public void selectRight() {
2639:                if (dot == null)
2640:                    return;
2641:                if (getDotOffset() < getDotLine().length()) {
2642:                    if (mark == null || lastCommand != COMMAND_RIGHT)
2643:                        addUndo(SimpleEdit.MOVE);
2644:                    if (mark == null)
2645:                        setMarkAtDot();
2646:                    dot.moveRight();
2647:                    moveCaretToDotCol();
2648:                } else {
2649:                    // We're at or beyond the end of the line.
2650:                    if (buffer.getBooleanProperty(Property.RESTRICT_CARET)) {
2651:                        if (getDotLine().next() == null)
2652:                            return;
2653:                        if (mark == null || lastCommand != COMMAND_RIGHT)
2654:                            addUndo(SimpleEdit.MOVE);
2655:                        if (mark == null)
2656:                            setMarkAtDot();
2657:                        updateDotLine();
2658:                        dot.moveTo(getDotLine().next(), 0);
2659:                        moveCaretToDotCol();
2660:                    } else {
2661:                        // Don't start a new selection, since there's no text there.
2662:                        if (lastCommand != COMMAND_RIGHT)
2663:                            addUndo(SimpleEdit.MOVE);
2664:                        ++display.caretCol;
2665:                    }
2666:                }
2667:                updateDotLine();
2668:                setCurrentCommand(COMMAND_RIGHT);
2669:                setUpdateFlag(REFRAME);
2670:            }
2671:
2672:            public void left() {
2673:                if (dot == null)
2674:                    return;
2675:                final Line dotLine = getDotLine();
2676:                final int dotOffset = getDotOffset();
2677:                final Line prevLine = dotLine.previous();
2678:                if (dotOffset == 0 && prevLine == null)
2679:                    return;
2680:                if (mark != null || lastCommand != COMMAND_LEFT)
2681:                    addUndo(SimpleEdit.MOVE);
2682:                if (mark != null)
2683:                    beginningOfBlock();
2684:                else {
2685:                    int absCaretCol = display.getCaretCol()
2686:                            + display.getShift();
2687:                    if (absCaretCol > 0
2688:                            && absCaretCol <= buffer.getCol(dotLine, dotLine
2689:                                    .length())) {
2690:                        // Back up one character.
2691:                        dot.setOffset(dotOffset - 1);
2692:                        moveCaretToDotCol();
2693:                    } else if (absCaretCol > 0) {
2694:                        // We're beyond the end of the text on the line.
2695:                        --display.caretCol;
2696:                    } else if (dot.getOffset() == 0) {
2697:                        // Back up to the end of the text on the previous line.
2698:                        update(dotLine);
2699:                        setDot(prevLine, prevLine.length());
2700:                        moveCaretToDotCol();
2701:                    } else {
2702:                        // There shouldn't be any other cases.
2703:                        Debug.assertTrue(false);
2704:                    }
2705:                }
2706:                updateDotLine();
2707:                setCurrentCommand(COMMAND_LEFT);
2708:                setUpdateFlag(REFRAME);
2709:            }
2710:
2711:            public void selectLeft() {
2712:                if (dot == null)
2713:                    return;
2714:                final Line dotLine = getDotLine();
2715:                final int dotOffset = getDotOffset();
2716:                final Line prevLine = dotLine.previous();
2717:                if (dotOffset == 0 && prevLine == null)
2718:                    return;
2719:                if (mark == null || lastCommand != COMMAND_LEFT)
2720:                    addUndo(SimpleEdit.MOVE);
2721:
2722:                // Only start a new selection if we're over some actual text.
2723:                final int absCaretCol = display.getAbsoluteCaretCol();
2724:                final int end = buffer.getCol(dotLine, dotLine.length());
2725:                if (mark == null && absCaretCol <= end)
2726:                    setMarkAtDot();
2727:
2728:                if (absCaretCol > 0 && absCaretCol <= end) {
2729:                    // Back up one character.
2730:                    dot.moveLeft();
2731:                    moveCaretToDotCol();
2732:                } else if (absCaretCol > 0) {
2733:                    // We're beyond the end of the text on the line.
2734:                    --display.caretCol;
2735:                } else if (dotOffset == 0) {
2736:                    // Back up to the end of the text on the previous line.
2737:                    updateDotLine();
2738:                    setDot(prevLine, prevLine.length());
2739:                    moveCaretToDotCol();
2740:                } else {
2741:                    // There shouldn't be any other cases.
2742:                    Debug.assertTrue(false);
2743:                }
2744:                updateDotLine();
2745:                setCurrentCommand(COMMAND_LEFT);
2746:                setUpdateFlag(REFRAME);
2747:            }
2748:
2749:            public final int getAbsoluteCaretCol() {
2750:                return display.getAbsoluteCaretCol();
2751:            }
2752:
2753:            public final void setAbsoluteCaretCol(int col) {
2754:                display.setAbsoluteCaretCol(col);
2755:            }
2756:
2757:            private int goalColumn;
2758:
2759:            public final void setGoalColumn(int col) {
2760:                goalColumn = col;
2761:            }
2762:
2763:            public void moveDotToGoalCol() {
2764:                if (buffer.getBooleanProperty(Property.RESTRICT_CARET)) {
2765:                    final int limit = buffer.getCol(getDotLine(), getDotLine()
2766:                            .length());
2767:                    moveDotToCol(goalColumn > limit ? limit : goalColumn);
2768:                    moveCaretToDotCol();
2769:                } else {
2770:                    setAbsoluteCaretCol(goalColumn);
2771:                    moveDotToCaretCol();
2772:                }
2773:            }
2774:
2775:            // Move caret down one line, keeping it in the same column if possible.
2776:            // Synchronize dot with caret.
2777:            public void down() {
2778:                maybeResetGoalColumn();
2779:                display.down(false);
2780:                setCurrentCommand(COMMAND_DOWN);
2781:            }
2782:
2783:            public void selectDown() {
2784:                maybeResetGoalColumn();
2785:                display.down(true);
2786:                setCurrentCommand(COMMAND_DOWN);
2787:            }
2788:
2789:            // Move caret up one line, keeping it in the same column if possible.
2790:            // Synchronize dot with caret.
2791:            public void up() {
2792:                maybeResetGoalColumn();
2793:                display.up(false);
2794:                setCurrentCommand(COMMAND_UP);
2795:            }
2796:
2797:            public void selectUp() {
2798:                maybeResetGoalColumn();
2799:                display.up(true);
2800:                setCurrentCommand(COMMAND_UP);
2801:            }
2802:
2803:            private void maybeResetGoalColumn() {
2804:                switch (lastCommand) {
2805:                case COMMAND_UP:
2806:                case COMMAND_DOWN:
2807:                case COMMAND_PAGE_UP:
2808:                case COMMAND_PAGE_DOWN:
2809:                case COMMAND_WINDOW_UP:
2810:                case COMMAND_WINDOW_DOWN:
2811:                    return;
2812:                default:
2813:                    goalColumn = getAbsoluteCaretCol();
2814:                    return;
2815:                }
2816:            }
2817:
2818:            public void windowUp() {
2819:                maybeResetGoalColumn();
2820:                display.windowUp();
2821:                maybeScrollCaret();
2822:                setCurrentCommand(COMMAND_WINDOW_UP);
2823:            }
2824:
2825:            public void windowDown() {
2826:                maybeResetGoalColumn();
2827:                display.windowDown();
2828:                maybeScrollCaret();
2829:                setCurrentCommand(COMMAND_WINDOW_DOWN);
2830:            }
2831:
2832:            public void maybeScrollCaret() {
2833:                if (dot == null)
2834:                    return;
2835:                // Don't scroll the caret if a region is selected!
2836:                if (mark != null)
2837:                    return;
2838:                if (buffer.getBooleanProperty(Property.SCROLL_CARET)) {
2839:                    final int dotLineNumber = dot.lineNumber();
2840:                    final Line topLine = display.getTopLine();
2841:                    if (dotLineNumber < topLine.lineNumber()) {
2842:                        // Caret is above window.
2843:                        addUndo(SimpleEdit.SCROLL_CARET);
2844:                        dot.moveTo(topLine, 0);
2845:                        updateDotLine();
2846:                        moveCaretToDotCol();
2847:                        goalColumn = 0;
2848:                        return;
2849:                    }
2850:                    final Line bottomLine = display.getBottomLine();
2851:                    if (dotLineNumber > bottomLine.lineNumber()) {
2852:                        // Caret is below window.
2853:                        addUndo(SimpleEdit.SCROLL_CARET);
2854:                        updateDotLine();
2855:                        dot.moveTo(bottomLine, 0);
2856:                        updateDotLine();
2857:                        moveCaretToDotCol();
2858:                        goalColumn = 0;
2859:                    }
2860:                }
2861:            }
2862:
2863:            public void toCenter() {
2864:                display.toCenter();
2865:            }
2866:
2867:            public void toTop() {
2868:                display.toTop();
2869:            }
2870:
2871:            private void selectToPosition(Position pos) {
2872:                if (!pos.equals(dot)
2873:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol()) {
2874:                    addUndo(SimpleEdit.MOVE);
2875:                    if (mark == null)
2876:                        setMarkAtDot();
2877:                    if (pos.getLine() != getDotLine())
2878:                        setUpdateFlag(REPAINT);
2879:                    else
2880:                        updateDotLine();
2881:                    dot.moveTo(pos);
2882:                    moveCaretToDotCol();
2883:                }
2884:            }
2885:
2886:            public void bol() {
2887:                if (dot != null)
2888:                    moveDotTo(dot.getLine(), 0);
2889:            }
2890:
2891:            public void home() {
2892:                if (dot == null)
2893:                    return;
2894:                final boolean extend = prefs
2895:                        .getBooleanProperty(Property.EXTEND_HOME);
2896:                Position pos;
2897:                if (mark != null)
2898:                    pos = new Position(new Region(this ).getBegin());
2899:                else
2900:                    pos = new Position(dot);
2901:                int indent = pos.getLine().getIndentation();
2902:                if (extend) {
2903:                    if (pos.getOffset() > indent)
2904:                        pos.setOffset(indent);
2905:                    else
2906:                        pos.setOffset(0);
2907:                } else {
2908:                    if (pos.getOffset() > indent)
2909:                        pos.setOffset(indent);
2910:                    else if (pos.getOffset() == indent)
2911:                        pos.setOffset(0);
2912:                    else
2913:                        pos.setOffset(indent);
2914:                }
2915:                if (mark != null || !pos.equals(dot)
2916:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol()) {
2917:                    moveDotTo(pos);
2918:                    setCurrentCommand(COMMAND_HOME);
2919:                    return;
2920:                }
2921:                // Reaching here, caret is already in column 0.
2922:                if (!extend)
2923:                    return;
2924:                if (System.currentTimeMillis()
2925:                        - dispatcher.getLastEventMillis() > 1000) {
2926:                    // Timed out.
2927:                    setUpdateFlag(REFRAME);
2928:                    setCurrentCommand(COMMAND_HOME);
2929:                    return;
2930:                }
2931:                if (lastCommand == COMMAND_HOME_HOME)
2932:                    pos = new Position(buffer.getFirstLine(), 0);
2933:                else if (lastCommand == COMMAND_HOME) {
2934:                    pos = new Position(getTopLine(), 0);
2935:                    setUpdateFlag(REFRAME);
2936:                    setCurrentCommand(COMMAND_HOME_HOME);
2937:                } else {
2938:                    setUpdateFlag(REFRAME);
2939:                    setCurrentCommand(COMMAND_HOME);
2940:                    return;
2941:                }
2942:                if (!pos.equals(dot)
2943:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol())
2944:                    moveDotTo(pos);
2945:            }
2946:
2947:            public void selectHome() {
2948:                if (dot == null)
2949:                    return;
2950:                final boolean extend = prefs
2951:                        .getBooleanProperty(Property.EXTEND_HOME);
2952:                Position pos;
2953:                if (mark != null)
2954:                    pos = new Position(new Region(buffer, mark, dot).getBegin());
2955:                else
2956:                    pos = new Position(dot);
2957:                int indent = pos.getLine().getIndentation();
2958:                if (extend) {
2959:                    if (pos.getOffset() > indent)
2960:                        pos.setOffset(indent);
2961:                    else
2962:                        pos.setOffset(0);
2963:                } else {
2964:                    if (pos.getOffset() > indent)
2965:                        pos.setOffset(indent);
2966:                    else if (pos.getOffset() == indent)
2967:                        pos.setOffset(0);
2968:                    else
2969:                        pos.setOffset(indent);
2970:                }
2971:                if (mark != null || !pos.equals(dot)
2972:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol()) {
2973:                    selectToPosition(pos);
2974:                    setUpdateFlag(REFRAME);
2975:                    setCurrentCommand(COMMAND_SELECT_HOME);
2976:                    return;
2977:                }
2978:                // Reaching here, caret is already in column 0.
2979:                if (!prefs.getBooleanProperty(Property.EXTEND_HOME))
2980:                    return;
2981:                if (System.currentTimeMillis()
2982:                        - dispatcher.getLastEventMillis() > 1000) {
2983:                    // Timed out.
2984:                    setUpdateFlag(REFRAME);
2985:                    setCurrentCommand(COMMAND_SELECT_HOME);
2986:                    return;
2987:                }
2988:                if (lastCommand == COMMAND_SELECT_HOME_HOME)
2989:                    pos = new Position(buffer.getFirstLine(), 0);
2990:                else if (lastCommand == COMMAND_SELECT_HOME) {
2991:                    pos = new Position(getTopLine(), 0);
2992:                    setUpdateFlag(REFRAME);
2993:                    setCurrentCommand(COMMAND_SELECT_HOME_HOME);
2994:                } else {
2995:                    setUpdateFlag(REFRAME);
2996:                    setCurrentCommand(COMMAND_SELECT_HOME);
2997:                    return;
2998:                }
2999:                if (!pos.equals(dot)
3000:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol())
3001:                    selectToPosition(pos);
3002:            }
3003:
3004:            public void eol() {
3005:                if (dot == null)
3006:                    return;
3007:                if (mark != null
3008:                        || dot.getOffset() != dot.getLineLength()
3009:                        || buffer.getCol(dot) != display.getCaretCol()
3010:                                + display.getShift())
3011:                    moveDotTo(dot.getLine(), dot.getLineLength());
3012:            }
3013:
3014:            public void end() {
3015:                if (dot == null)
3016:                    return;
3017:                Position pos;
3018:                if (mark != null)
3019:                    pos = new Position(new Region(buffer, mark, dot).getEnd());
3020:                else
3021:                    pos = new Position(dot);
3022:                pos.setOffset(pos.getLineLength());
3023:                if (mark != null || !pos.equals(dot)
3024:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol()) {
3025:                    moveDotTo(pos);
3026:                    setUpdateFlag(REFRAME);
3027:                    setCurrentCommand(COMMAND_END);
3028:                    return;
3029:                }
3030:                // Reaching here, caret is already at end of line.
3031:                if (!prefs.getBooleanProperty(Property.EXTEND_END))
3032:                    return;
3033:                if (System.currentTimeMillis()
3034:                        - dispatcher.getLastEventMillis() > 1000) {
3035:                    // Timed out.
3036:                    setUpdateFlag(REFRAME);
3037:                    setCurrentCommand(COMMAND_END);
3038:                    return;
3039:                }
3040:                if (lastCommand == COMMAND_END_END)
3041:                    pos = getEob();
3042:                else if (lastCommand == COMMAND_END) {
3043:                    Line bottomLine = display.getBottomLine();
3044:                    if (bottomLine != null)
3045:                        pos = new Position(bottomLine, bottomLine.length());
3046:                    else
3047:                        pos = getEob();
3048:                    setUpdateFlag(REFRAME);
3049:                    setCurrentCommand(COMMAND_END_END);
3050:                } else {
3051:                    setUpdateFlag(REFRAME);
3052:                    setCurrentCommand(COMMAND_END);
3053:                    return;
3054:                }
3055:                if (!pos.equals(dot)
3056:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol())
3057:                    moveDotTo(pos);
3058:            }
3059:
3060:            public void selectEnd() {
3061:                if (dot == null)
3062:                    return;
3063:                Position pos;
3064:                if (mark != null)
3065:                    pos = new Position(new Region(buffer, mark, dot).getEnd());
3066:                else
3067:                    pos = new Position(dot);
3068:                pos.setOffset(pos.getLineLength());
3069:                if (!pos.equals(dot)
3070:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol()) {
3071:                    selectToPosition(pos);
3072:                    setUpdateFlag(REFRAME);
3073:                    setCurrentCommand(COMMAND_END);
3074:                    return;
3075:                }
3076:                // Reaching here, caret is already at end of line.
3077:                if (!prefs.getBooleanProperty(Property.EXTEND_END))
3078:                    return;
3079:                if (System.currentTimeMillis()
3080:                        - dispatcher.getLastEventMillis() > 1000) {
3081:                    // Timed out.
3082:                    setUpdateFlag(REFRAME);
3083:                    setCurrentCommand(COMMAND_END);
3084:                    return;
3085:                }
3086:                if (lastCommand == COMMAND_END_END)
3087:                    pos = getEob();
3088:                else if (lastCommand == COMMAND_END) {
3089:                    Line bottomLine = display.getBottomLine();
3090:                    if (bottomLine != null)
3091:                        pos = new Position(bottomLine, bottomLine.length());
3092:                    else
3093:                        pos = getEob();
3094:                    setUpdateFlag(REFRAME);
3095:                    setCurrentCommand(COMMAND_END_END);
3096:                } else {
3097:                    setCurrentCommand(COMMAND_END);
3098:                    return;
3099:                }
3100:                if (!pos.equals(dot)
3101:                        || buffer.getCol(pos) != display.getAbsoluteCaretCol())
3102:                    selectToPosition(pos);
3103:            }
3104:
3105:            public void bob() {
3106:                if (buffer.getFirstLine() != null)
3107:                    moveDotTo(buffer.getFirstLine(), 0);
3108:            }
3109:
3110:            public void selectBob() {
3111:                if (dot == null)
3112:                    return;
3113:                if (buffer.getFirstLine() == null)
3114:                    return;
3115:                addUndo(SimpleEdit.MOVE);
3116:                if (mark == null)
3117:                    setMarkAtDot();
3118:                dot.moveTo(buffer.getFirstLine(), 0);
3119:                moveCaretToDotCol();
3120:                setUpdateFlag(REPAINT);
3121:            }
3122:
3123:            private final Position getEob() {
3124:                return buffer.getEnd();
3125:            }
3126:
3127:            public void eob() {
3128:                moveDotTo(getEob());
3129:            }
3130:
3131:            public void selectEob() {
3132:                if (buffer.getFirstLine() == null)
3133:                    return;
3134:                Line line = buffer.getFirstLine();
3135:                while (line.next() != null)
3136:                    line = line.next();
3137:                addUndo(SimpleEdit.MOVE);
3138:                if (mark == null)
3139:                    setMarkAtDot();
3140:                dot.moveTo(line, line.length());
3141:                moveCaretToDotCol();
3142:                setUpdateFlag(REPAINT);
3143:            }
3144:
3145:            public void top() {
3146:                if (dot == null)
3147:                    return;
3148:                if (getDotLine() != getTopLine()) {
3149:                    addUndo(SimpleEdit.MOVE);
3150:                    updateDotLine();
3151:                    dot.setLine(getTopLine());
3152:                    moveDotToCaretCol();
3153:                }
3154:            }
3155:
3156:            public void bottom() {
3157:                if (dot == null)
3158:                    return;
3159:                Line line = display.getBottomLine();
3160:                if (line != getDotLine()) {
3161:                    addUndo(SimpleEdit.MOVE);
3162:                    updateDotLine();
3163:                    dot.setLine(line);
3164:                    updateDotLine();
3165:                    moveDotToCaretCol();
3166:                }
3167:            }
3168:
3169:            public void selectWord() {
3170:                if (dot == null)
3171:                    return;
3172:                AWTEvent e = dispatcher.getLastEvent();
3173:                CompoundEdit compoundEdit = null;
3174:                if (e instanceof  MouseEvent) {
3175:                    compoundEdit = beginCompoundEdit();
3176:                    mouseMoveDotToPoint((MouseEvent) e);
3177:                }
3178:                if (inWord()) {
3179:                    addUndo(SimpleEdit.MOVE);
3180:                    while (getDotOffset() > 0) {
3181:                        dot.moveLeft();
3182:                        if (!inWord()) {
3183:                            dot.moveRight();
3184:                            break;
3185:                        }
3186:                    }
3187:                    setMarkAtDot();
3188:                    final int limit = getDotLine().length();
3189:                    while (inWord() && getDotOffset() < limit)
3190:                        dot.moveRight();
3191:                    moveCaretToDotCol();
3192:                }
3193:                if (compoundEdit != null)
3194:                    endCompoundEdit(compoundEdit);
3195:            }
3196:
3197:            public void mouseMoveDotToPoint() {
3198:                AWTEvent e = dispatcher.getLastEvent();
3199:                if (e instanceof  MouseEvent)
3200:                    mouseMoveDotToPoint((MouseEvent) e);
3201:            }
3202:
3203:            public void mouseMoveDotToPoint(MouseEvent e) {
3204:                addUndo(SimpleEdit.MOVE);
3205:                if (mark != null)
3206:                    unmark();
3207:                display.moveCaretToPoint(e.getPoint());
3208:                if (buffer.getBooleanProperty(Property.RESTRICT_CARET))
3209:                    moveCaretToDotCol();
3210:
3211:                // Dec 13 2002 6:30 PM
3212:                // Without this, focus ends up in the location bar textfield if you
3213:                // click in the edit window after using the openFile completion list
3214:                // to open a file. Weird.
3215:                Editor.restoreFocus();
3216:            }
3217:
3218:            public void mouseSelect() {
3219:                if (dot != null) {
3220:                    AWTEvent e = dispatcher.getLastEvent();
3221:                    if (e instanceof  MouseEvent) {
3222:                        MouseEvent mouseEvent = (MouseEvent) e;
3223:                        Position pos = display.positionFromPoint(mouseEvent
3224:                                .getPoint());
3225:                        addUndo(SimpleEdit.MOVE);
3226:                        Position min, max;
3227:                        if (mark == null) {
3228:                            // New selection.
3229:                            setMarkAtDot();
3230:                            dot = pos;
3231:                            moveCaretToDotCol();
3232:                            Region r = new Region(this );
3233:                            min = r.getBegin();
3234:                            max = r.getEnd();
3235:                        } else {
3236:                            // Adjust existing selection.
3237:                            Region r = new Region(this );
3238:                            min = r.getBegin();
3239:                            max = r.getEnd();
3240:                            if (pos.isBefore(r.getBegin())) {
3241:                                min = pos;
3242:                                mark = r.getEnd();
3243:                            } else if (pos.isAfter(r.getEnd())) {
3244:                                max = pos;
3245:                                mark = r.getBegin();
3246:                            } else {
3247:                                // Click was inside selected region.
3248:                                if (Position.getDistance(r.getBegin(), pos) < Position
3249:                                        .getDistance(r.getEnd(), pos)) {
3250:                                    // Click was closer to beginning of region.
3251:                                    mark = r.getEnd();
3252:                                } else
3253:                                    mark = r.getBegin();
3254:                            }
3255:                            dot = pos;
3256:                            moveCaretToDotCol();
3257:                        }
3258:                        // Minimize repaint.
3259:                        if (max.lineNumber() - min.lineNumber() < display
3260:                                .getRows()) {
3261:                            Line line = min.getLine();
3262:                            Line endLine = max.getLine();
3263:                            while (line != null && line != endLine) {
3264:                                update(line);
3265:                                line = line.next();
3266:                            }
3267:                            update(endLine);
3268:                        } else
3269:                            setUpdateFlag(REPAINT);
3270:                    }
3271:                }
3272:            }
3273:
3274:            public void mouseSelectColumn() {
3275:                if (dot != null) {
3276:                    AWTEvent e = dispatcher.getLastEvent();
3277:                    if (e instanceof  MouseEvent) {
3278:                        MouseEvent mouseEvent = (MouseEvent) e;
3279:                        if (getMark() == null)
3280:                            setMarkAtDot();
3281:                        display.moveCaretToPoint(mouseEvent.getPoint());
3282:                        setColumnSelection(true);
3283:                        display.setUpdateFlag(REPAINT);
3284:                    }
3285:                }
3286:            }
3287:
3288:            private JPopupMenu popup;
3289:
3290:            public void mouseShowContextMenu() {
3291:                AWTEvent e = dispatcher.getLastEvent();
3292:                if (e instanceof  MouseEvent) {
3293:                    MouseEvent mouseEvent = (MouseEvent) e;
3294:                    int x = mouseEvent.getX();
3295:                    int y = mouseEvent.getY();
3296:                    popup = buffer.getMode().getContextMenu(this );
3297:                    if (popup != null) {
3298:                        Dimension dimPopup = popup.getPreferredSize();
3299:                        Dimension dimDisplay = display.getSize();
3300:                        int xMax = dimDisplay.width - dimPopup.width - 5;
3301:                        int yMax = dimDisplay.height - dimPopup.height - 5;
3302:                        if (x > xMax)
3303:                            x = xMax;
3304:                        else
3305:                            ++x;
3306:                        if (y > yMax)
3307:                            y = yMax;
3308:                        else
3309:                            ++y;
3310:                        popup.show(mouseEvent.getComponent(), x, y);
3311:                    }
3312:                }
3313:            }
3314:
3315:            public final JPopupMenu getPopup() {
3316:                return popup;
3317:            }
3318:
3319:            public final void setPopup(JPopupMenu popup) {
3320:                this .popup = popup;
3321:            }
3322:
3323:            public void killPopup() {
3324:                if (popup != null) {
3325:                    popup.setVisible(false);
3326:                    popup = null;
3327:                    restoreFocus();
3328:                }
3329:            }
3330:
3331:            private boolean inWord() {
3332:                return getMode().isIdentifierPart(getDotChar());
3333:            }
3334:
3335:            private boolean inWhitespace() {
3336:                return Character.isWhitespace(getDotChar());
3337:            }
3338:
3339:            private void skipWhitespace() {
3340:                while (inWhitespace())
3341:                    if (!nextChar())
3342:                        break;
3343:            }
3344:
3345:            private void nextWord() {
3346:                if (dot == null)
3347:                    return;
3348:                if (inWord()) {
3349:                    while (nextChar())
3350:                        if (!inWord())
3351:                            break;
3352:                    skipWhitespace();
3353:                } else if (inWhitespace()) {
3354:                    skipWhitespace();
3355:                } else {
3356:                    // Not in word or whitespace.
3357:                    while (nextChar() && !inWord() && !inWhitespace())
3358:                        ;
3359:                    skipWhitespace();
3360:                }
3361:            }
3362:
3363:            private void prevWord() {
3364:                if (dot == null)
3365:                    return;
3366:                if (!prevChar())
3367:                    return;
3368:                if (inWord()) {
3369:                    while (prevChar() && inWord())
3370:                        ;
3371:                    if (!inWord())
3372:                        nextChar();
3373:                } else if (inWhitespace()) {
3374:                    while (prevChar() && inWhitespace())
3375:                        ;
3376:                    if (inWord()) {
3377:                        while (prevChar() && inWord())
3378:                            ;
3379:                        if (!inWord())
3380:                            nextChar();
3381:                    } else {
3382:                        while (prevChar() && !inWord() && !inWhitespace())
3383:                            ;
3384:                        if (inWord() || inWhitespace())
3385:                            nextChar();
3386:                    }
3387:                } else {
3388:                    // Not in word or whitespace.
3389:                    while (prevChar()) {
3390:                        if (inWord())
3391:                            break;
3392:                        if (inWhitespace())
3393:                            break;
3394:                    }
3395:                    if (inWord() || inWhitespace())
3396:                        nextChar();
3397:                }
3398:            }
3399:
3400:            public void wordRight() {
3401:                if (dot == null)
3402:                    return;
3403:                updateDotLine();
3404:                addUndo(SimpleEdit.MOVE);
3405:                endOfBlock();
3406:                nextWord();
3407:                moveCaretToDotCol();
3408:                updateDotLine();
3409:            }
3410:
3411:            public void wordLeft() {
3412:                if (dot == null)
3413:                    return;
3414:                updateDotLine();
3415:                addUndo(SimpleEdit.MOVE);
3416:                beginningOfBlock();
3417:                prevWord();
3418:                moveCaretToDotCol();
3419:                updateDotLine();
3420:            }
3421:
3422:            public void selectWordRight() {
3423:                if (dot == null)
3424:                    return;
3425:                addUndo(SimpleEdit.MOVE);
3426:                if (mark == null)
3427:                    setMarkAtDot();
3428:                updateDotLine();
3429:                nextWord();
3430:                moveCaretToDotCol();
3431:                updateDotLine();
3432:            }
3433:
3434:            public void selectWordLeft() {
3435:                if (dot == null)
3436:                    return;
3437:                addUndo(SimpleEdit.MOVE);
3438:                if (mark == null)
3439:                    setMarkAtDot();
3440:                updateDotLine();
3441:                prevWord();
3442:                moveCaretToDotCol();
3443:                updateDotLine();
3444:            }
3445:
3446:            public void selectAll() {
3447:                if (dot == null)
3448:                    return;
3449:                pushPosition();
3450:                addUndo(SimpleEdit.MOVE);
3451:                unmark();
3452:                Line line = buffer.getFirstLine();
3453:                dot.moveTo(line, 0);
3454:                display.setCaretCol(0);
3455:                display.setShift(0);
3456:                setMarkAtDot();
3457:                while (line.next() != null)
3458:                    line = line.next();
3459:                dot.moveTo(line, line.length());
3460:                moveCaretToDotCol();
3461:                display.setUpdateFlag(REPAINT);
3462:            }
3463:
3464:            // Moves dot to the requested absolute column, based on the tab size of
3465:            // the buffer. If the requested column is past the end of the line, dot is
3466:            // moved to the end of the line.
3467:            public void moveDotToCol(int goal) {
3468:                if (dot == null)
3469:                    return;
3470:
3471:                dot.moveToCol(goal, buffer.getTabWidth());
3472:                updateDotLine();
3473:
3474:                // Support tab chars in buffer. If we're not beyond the end of the
3475:                // line, make sure we're on an actual character.
3476:                if (dot.getOffset() < dot.getLineLength())
3477:                    moveCaretToDotCol();
3478:            }
3479:
3480:            public final void moveDotToCaretCol() {
3481:                moveDotToCol(display.getAbsoluteCaretCol());
3482:            }
3483:
3484:            public final void moveCaretToDotCol() {
3485:                display.moveCaretToDotCol();
3486:            }
3487:
3488:            public final void repaintDisplay() {
3489:                display.setUpdateFlag(REPAINT);
3490:                display.repaint();
3491:            }
3492:
3493:            public final void repaintNow() {
3494:                display.repaintNow();
3495:            }
3496:
3497:            // Adds whitespace to fill the area between the end of the actual text on
3498:            // a line and the location of the caret, if it's beyond the end of the
3499:            // text. Dot is moved to the end of the appended whitespace. Does nothing
3500:            // if caret is not past end of text.
3501:            public void fillToCaret() {
3502:                final int where = display.getAbsoluteCaretCol();
3503:                final Line dotLine = getDotLine();
3504:                String s = getFillString(dotLine, where);
3505:                if (s != null) {
3506:                    try {
3507:                        buffer.lockWrite();
3508:                    } catch (InterruptedException e) {
3509:                        Log.error(e);
3510:                        return;
3511:                    }
3512:                    try {
3513:                        addUndo(SimpleEdit.LINE_EDIT);
3514:                        dotLine.setText(dotLine.getText().concat(s));
3515:                        buffer.modified();
3516:                        dot.setOffset(dotLine.length());
3517:                    } finally {
3518:                        buffer.unlockWrite();
3519:                    }
3520:                }
3521:            }
3522:
3523:            private String getFillString(Line line, int where) {
3524:                int end = buffer.getCol(line, line.length());
3525:                if (where <= end)
3526:                    return null;
3527:                final int width = where - end;
3528:
3529:                // For sanity, only use actual tab chars at beginning of line!
3530:                if (buffer.getUseTabs() && line.length() == 0) {
3531:                    FastStringBuffer sb = new FastStringBuffer(width);
3532:                    int col = 0;
3533:                    final int tabWidth = buffer.getTabWidth();
3534:                    while (col + tabWidth <= width) {
3535:                        sb.append('\t');
3536:                        col += tabWidth;
3537:                    }
3538:                    while (col < width) {
3539:                        sb.append(' ');
3540:                        ++col;
3541:                    }
3542:                    return sb.toString();
3543:                } else
3544:                    return Utilities.spaces(width);
3545:            }
3546:
3547:            public final int getDotCol() {
3548:                return buffer.getCol(dot);
3549:            }
3550:
3551:            // Insert string at dot, put dot at end of inserted string.
3552:            // No undo.
3553:            public void insertStringInternal(String s) {
3554:                updateInAllEditors(getDotLine());
3555:                buffer.insertString(dot, s);
3556:            }
3557:
3558:            // Fills the space (if any) between dot and caret and inserts
3559:            // the char in question.
3560:            public void insertChar(char c) {
3561:                final Line dotLine = getDotLine();
3562:                if (getDotOffset() > dotLine.length()) {
3563:                    // Shouldn't happen.
3564:                    Debug.bug();
3565:                    Log.error("insertChar dot offset = " + getDotOffset()
3566:                            + " dotLine length = " + dotLine.length());
3567:                    // Enforce sanity and carry on.
3568:                    dot.setOffset(dotLine.length());
3569:                }
3570:                try {
3571:                    buffer.lockWrite();
3572:                } catch (InterruptedException e) {
3573:                    Log.error(e);
3574:                    return;
3575:                }
3576:                try {
3577:                    addUndo(SimpleEdit.LINE_EDIT);
3578:                    fillToCaret();
3579:                    FastStringBuffer sb = new FastStringBuffer(dotLine
3580:                            .substring(0, getDotOffset()));
3581:                    sb.append(c);
3582:                    sb.append(dotLine.substring(getDotOffset()));
3583:                    dotLine.setText(sb.toString());
3584:                    dot.moveRight();
3585:                    moveCaretToDotCol();
3586:                    buffer.modified();
3587:                } finally {
3588:                    buffer.unlockWrite();
3589:                }
3590:                updateInAllEditors(dotLine);
3591:            }
3592:
3593:            public void insertChar() {
3594:                if (!checkReadOnly())
3595:                    return;
3596:                String input = InputDialog.showInputDialog(this , "Character:",
3597:                        "Insert Character");
3598:                if (input == null || input.length() == 0)
3599:                    return;
3600:                repaintNow();
3601:                int c = parseNumericInput(input);
3602:                if (c >= 0 && c < 0xfffe)
3603:                    insertChar((char) c);
3604:                else
3605:                    MessageDialog.showMessageDialog(this , "Invalid character",
3606:                            "Insert Character");
3607:            }
3608:
3609:            public void insertByte() {
3610:                if (!checkReadOnly())
3611:                    return;
3612:                String input = InputDialog.showInputDialog(this , "Byte:",
3613:                        "Insert Byte");
3614:                if (input == null || input.length() == 0)
3615:                    return;
3616:                repaintNow();
3617:                int c = parseNumericInput(input);
3618:                if (c >= 0 && c <= 255) {
3619:                    byte[] bytes = new byte[1];
3620:                    bytes[0] = (byte) c;
3621:                    String encoding = prefs
3622:                            .getStringProperty(Property.DEFAULT_ENCODING);
3623:                    try {
3624:                        String s = new String(bytes, encoding);
3625:                        insertChar(s.charAt(0));
3626:                    } catch (UnsupportedEncodingException e) {
3627:                        Log.error(e);
3628:                        MessageDialog.showMessageDialog(this ,
3629:                                "Unsupported encoding \"" + encoding + "\"",
3630:                                "Insert Byte");
3631:                    }
3632:                } else
3633:                    MessageDialog.showMessageDialog(this , "Invalid byte \""
3634:                            + input + "\"", "Insert Byte");
3635:            }
3636:
3637:            // Used only by insertChar and insertByte. Doesn't understand a leading
3638:            // minus sign.
3639:            private static int parseNumericInput(String input) {
3640:                int n = -1;
3641:                input = input.trim();
3642:                try {
3643:                    if (input.startsWith("0x") || input.startsWith("0X"))
3644:                        n = Integer.parseInt(input.substring(2), 16);
3645:                    else if (input.startsWith("0"))
3646:                        n = Integer.parseInt(input, 8);
3647:                    else
3648:                        n = Integer.parseInt(input, 10);
3649:                } catch (NumberFormatException e) {
3650:                    Log.error(e);
3651:                }
3652:                return n;
3653:            }
3654:
3655:            public void electricSemi() {
3656:                if (!checkReadOnly())
3657:                    return;
3658:                if (mark != null || getDotLine().flags() == STATE_COMMENT
3659:                        || getMode().isInQuote(buffer, dot)) {
3660:                    insertNormalChar(';');
3661:                } else {
3662:                    CompoundEdit compoundEdit = beginCompoundEdit();
3663:                    insertChar(';');
3664:                    moveCaretToDotCol();
3665:                    indentLine();
3666:                    if (buffer.getBooleanProperty(Property.AUTO_NEWLINE)) {
3667:                        boolean b = true;
3668:                        String s = dot.getLine().trim();
3669:                        if (s.startsWith("for")) {
3670:                            char c = s.charAt(3);
3671:                            if (c == ' ' || c == '\t' || c == '(')
3672:                                b = false;
3673:                        }
3674:                        if (b)
3675:                            newlineAndIndent();
3676:                    }
3677:                    endCompoundEdit(compoundEdit);
3678:                }
3679:            }
3680:
3681:            public void electricColon() {
3682:                if (!checkReadOnly())
3683:                    return;
3684:                try {
3685:                    buffer.lockWrite();
3686:                } catch (InterruptedException e) {
3687:                    Log.error(e);
3688:                    return;
3689:                }
3690:                try {
3691:                    electricColonInternal();
3692:                } finally {
3693:                    buffer.unlockWrite();
3694:                }
3695:            }
3696:
3697:            private void electricColonInternal() {
3698:                final Line dotLine = getDotLine();
3699:                final int dotOffset = getDotOffset();
3700:                if (mark != null || dotOffset != dotLine.length()) {
3701:                    insertNormalChar(':');
3702:                    return;
3703:                }
3704:                if (dotLine.flags() == STATE_COMMENT
3705:                        || getMode().isInQuote(buffer, dot)) {
3706:                    insertNormalChar(':');
3707:                    return;
3708:                }
3709:                CompoundEdit compoundEdit = beginCompoundEdit();
3710:                insertChar(':');
3711:                moveCaretToDotCol();
3712:                indentLine();
3713:                if (buffer.getBooleanProperty(Property.AUTO_NEWLINE))
3714:                    newlineAndIndent();
3715:                endCompoundEdit(compoundEdit);
3716:            }
3717:
3718:            public void electricStar() {
3719:                if (!checkReadOnly())
3720:                    return;
3721:
3722:                // The intention here is to line up the '*' under the '*' of
3723:                // the previous line if the current line is blank and if the
3724:                // previous line begins with "/*".
3725:                if (getDotLine().isBlank()) {
3726:                    if (buffer.needsParsing()) {
3727:                        if (getFormatter().parseBuffer())
3728:                            buffer.repaint();
3729:                    }
3730:                    CompoundEdit compoundEdit = beginCompoundEdit();
3731:                    insertNormalChar('*');
3732:                    indentLine();
3733:                    endCompoundEdit(compoundEdit);
3734:                } else
3735:                    insertNormalChar('*');
3736:            }
3737:
3738:            public void electricPound() {
3739:                if (!checkReadOnly())
3740:                    return;
3741:                if (mark == null && getDotLine().isBlank()) {
3742:                    try {
3743:                        buffer.lockWrite();
3744:                    } catch (InterruptedException e) {
3745:                        Log.error(e);
3746:                        return;
3747:                    }
3748:                    try {
3749:                        addUndo(SimpleEdit.LINE_EDIT);
3750:                        getDotLine().setText("#");
3751:                        dot.setOffset(1);
3752:                        buffer.modified();
3753:                    } finally {
3754:                        buffer.unlockWrite();
3755:                    }
3756:                    updateInAllEditors(getDotLine());
3757:                    moveCaretToDotCol();
3758:                } else
3759:                    insertNormalChar('#');
3760:            }
3761:
3762:            public void electricOpenBrace() {
3763:                electricBraceInternal('{');
3764:            }
3765:
3766:            public void electricCloseBrace() {
3767:                electricBraceInternal('}');
3768:            }
3769:
3770:            private void electricBraceInternal(char c) {
3771:                if (!checkReadOnly())
3772:                    return;
3773:                CompoundEdit compoundEdit = beginCompoundEdit();
3774:                if (mark == null && getDotLine().isBlank()) {
3775:                    addUndo(SimpleEdit.LINE_EDIT);
3776:                    getDotLine().setText("");
3777:                    dot.setOffset(0);
3778:                    insertChar(c);
3779:                    indentLine();
3780:                    eol();
3781:                    if (buffer.getBooleanProperty(Property.AUTO_NEWLINE))
3782:                        newlineAndIndent();
3783:                } else {
3784:                    insertNormalChar(c);
3785:                    indentLine();
3786:                }
3787:                endCompoundEdit(compoundEdit);
3788:            }
3789:
3790:            public void electricCloseAngleBracket() {
3791:                if (!checkReadOnly())
3792:                    return;
3793:                if (mark == null) {
3794:                    int modeId = getModeId();
3795:                    if (modeId == XML_MODE || modeId == HTML_MODE) {
3796:                        CompoundEdit compoundEdit = beginCompoundEdit();
3797:                        insertChar('>');
3798:                        moveCaretToDotCol();
3799:                        if (buffer.getBooleanProperty(Property.AUTO_INDENT)) {
3800:                            if (modeId == HTML_MODE
3801:                                    && getDotLine()
3802:                                            .substring(0, getDotOffset())
3803:                                            .endsWith("</pre>")) {
3804:                                ; // No autoindent after "</pre>" in HTML mode.
3805:                            } else {
3806:                                indentLine();
3807:                            }
3808:                        }
3809:                        endCompoundEdit(compoundEdit);
3810:                        return;
3811:                    }
3812:                }
3813:                // Otherwise...
3814:                insertNormalChar('>');
3815:            }
3816:
3817:            public void gotoline(int lineNumber) {
3818:                Line line = buffer.getLine(lineNumber);
3819:                if (line != null)
3820:                    setDot(line, 0);
3821:            }
3822:
3823:            public void saveState() {
3824:                if (saveSession) {
3825:                    // Make sure information about current buffer is up-to-date.
3826:                    saveView();
3827:
3828:                    Session.saveDefaultSession();
3829:                    if (sessionName != null)
3830:                        if (prefs
3831:                                .getBooleanProperty(Property.AUTOSAVE_NAMED_SESSIONS))
3832:                            Session.saveCurrentSession();
3833:                    sessionProperties.saveWindowPlacement();
3834:                    sessionProperties.save();
3835:                }
3836:            }
3837:
3838:            // It might make sense to move this code into the Buffer class.
3839:            public void reload(Buffer buf) {
3840:                setWaitCursor();
3841:                if (buf.getFile() instanceof  SshFile)
3842:                    return; // Not supported.
3843:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
3844:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
3845:                    Editor ed = it.nextEditor();
3846:                    if (ed.getBuffer() == buf)
3847:                        ed.saveView();
3848:                }
3849:
3850:                // May be asynchronous.
3851:                buf.reload();
3852:                setDefaultCursor();
3853:            }
3854:
3855:            public void revertBuffer() {
3856:                final File file = buffer.getFile();
3857:                if (file instanceof  SshFile)
3858:                    return; // Not supported.
3859:                if (buffer.isModified()) {
3860:                    String prompt = "Discard changes to "
3861:                            + file.canonicalPath() + "?";
3862:                    if (!confirm("Revert Buffer", prompt))
3863:                        return;
3864:                    reload(buffer);
3865:                }
3866:            }
3867:
3868:            // Returns true if the buffer is active and there has been some change
3869:            // that requires us to redraw the menus, title bar or display, false
3870:            // otherwise.
3871:            public boolean reactivate(Buffer buf) {
3872:                if (buf instanceof  ImageBuffer)
3873:                    return ((ImageBuffer) buf).reactivate();
3874:
3875:                if (buf.getType() != Buffer.TYPE_NORMAL)
3876:                    return false;
3877:                if (buf.isUntitled())
3878:                    return false;
3879:
3880:                // BUG! Why don't we reload binary mode buffers?
3881:                if (buf.getModeId() == BINARY_MODE)
3882:                    return false;
3883:
3884:                final File file = buf.getFile();
3885:                if (file == null || file.isRemote() || !file.isFile())
3886:                    return false;
3887:
3888:                boolean changed = false;
3889:
3890:                // Check read-only status even if buffer is not loaded so buffer list
3891:                // will be correct.
3892:                if (buf.readOnly == file.canWrite()) {
3893:                    // Read-only status has changed.
3894:                    buf.readOnly = !buf.readOnly;
3895:                    changed = true;
3896:                    // Let the user know if the file associated with a modified buffer
3897:                    // is no longer writable.
3898:                    if (buf.readOnly && buf.isLoaded() && buf.isModified())
3899:                        MessageDialog.showMessageDialog(file.canonicalPath()
3900:                                .concat(" is no longer writable"), "Warning");
3901:                }
3902:
3903:                if (buf.isLoaded()) {
3904:                    if (file.lastModified() != buf.getLastModified()) {
3905:                        if (buf.isModified()) {
3906:                            String prompt = file.canonicalPath()
3907:                                    + " has changed on disk. Reload and lose current changes?";
3908:                            if (confirm("Reload File From Disk", prompt)) {
3909:                                reload(buf);
3910:                                changed = true;
3911:                            } else
3912:                                buf.setLastModified(file.lastModified());
3913:                        } else {
3914:                            // No need for confirmation.
3915:                            reload(buf);
3916:                            changed = true;
3917:                        }
3918:                    }
3919:                }
3920:
3921:                return changed;
3922:            }
3923:
3924:            public void setFocus(JComponent c) {
3925:                frame.setFocus(c);
3926:            }
3927:
3928:            public JComponent getFocusedComponent() {
3929:                return frame.getFocusedComponent();
3930:            }
3931:
3932:            public void setFocusToDisplay() {
3933:                frame.setFocus(display);
3934:            }
3935:
3936:            public static final void restoreFocus() {
3937:                Runnable r = new Runnable() {
3938:                    public void run() {
3939:                        if (currentEditor != null)
3940:                            currentEditor.setFocusToDisplay();
3941:                    }
3942:                };
3943:                SwingUtilities.invokeLater(r);
3944:            }
3945:
3946:            public void componentHidden(ComponentEvent e) {
3947:            }
3948:
3949:            public void componentMoved(ComponentEvent e) {
3950:            }
3951:
3952:            public void componentResized(ComponentEvent e) {
3953:                updateScrollBars();
3954:            }
3955:
3956:            public void componentShown(ComponentEvent e) {
3957:            }
3958:
3959:            public void mouseWheelMoved(MouseWheelEvent e) {
3960:                // Without this, focus ends up in the location bar textfield if you use
3961:                // the mouse wheel in the edit window after using the openFile
3962:                // completion list to open a file (Blackdown 1.4.1-01).
3963:                // See also mouseMoveDotToPoint(MouseEvent).
3964:                setFocusToDisplay();
3965:
3966:                if (e.getWheelRotation() < 0)
3967:                    display.windowUp(5);
3968:                else
3969:                    display.windowDown(5);
3970:            }
3971:
3972:            public void ensureActive() {
3973:                if (!frame.isActive()) {
3974:                    for (int i = 0; i < getFrameCount(); i++) {
3975:                        Frame f = getFrame(i);
3976:                        if (f.isActive()) {
3977:                            f.dispatchEvent(new WindowEvent(f,
3978:                                    WindowEvent.WINDOW_DEACTIVATED));
3979:                            break;
3980:                        }
3981:                    }
3982:                    frame.dispatchEvent(new WindowEvent(frame,
3983:                            WindowEvent.WINDOW_ACTIVATED));
3984:                }
3985:            }
3986:
3987:            public void quit() {
3988:                maybeExit();
3989:            }
3990:
3991:            public void saveAllExit() {
3992:                tagFileManager.setEnabled(false);
3993:                saveAll();
3994:                maybeExit(); // May never return.
3995:                tagFileManager.setEnabled(true);
3996:            }
3997:
3998:            private void maybeExit() {
3999:                int numModifiedBuffers = 0;
4000:
4001:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
4002:                    if (it.nextBuffer().isModified())
4003:                        ++numModifiedBuffers;
4004:                }
4005:
4006:                if (numModifiedBuffers > 0) {
4007:                    FastStringBuffer sb = new FastStringBuffer(
4008:                            "Really exit with ");
4009:                    sb.append(numModifiedBuffers);
4010:                    sb.append(" modifed buffer");
4011:                    if (numModifiedBuffers > 1)
4012:                        sb.append('s');
4013:                    sb.append('?');
4014:                    if (!confirm("Really exit?", sb.toString()))
4015:                        return;
4016:                }
4017:
4018:                setWaitCursor();
4019:
4020:                saveState();
4021:                RecentFiles.getInstance().save();
4022:
4023:                // Delete all autosave files.
4024:                for (BufferIterator iter = new BufferIterator(); iter.hasNext();)
4025:                    iter.nextBuffer().deleteAutosaveFile();
4026:
4027:                Autosave.deleteCatalogFile();
4028:
4029:                // Call dispose on all buffers.
4030:                for (BufferIterator it = new BufferIterator(); it.hasNext();)
4031:                    it.nextBuffer().dispose();
4032:
4033:                // Clean up temporary directory.
4034:                Directories.cleanTempDirectory();
4035:
4036:                // Clean up cache  directory.
4037:                Cache.cleanup();
4038:
4039:                Server.stopServer();
4040:                pendingOperations.run();
4041:                setDefaultCursor();
4042:                System.exit(0);
4043:            }
4044:
4045:            public void killFrame() {
4046:                if (getFrameCount() == 1) {
4047:                    // Does not return if OK to exit.
4048:                    maybeExit();
4049:                } else {
4050:                    // Move frame being closed to end of list.
4051:                    if (indexOf(frame) != getFrameCount() - 1) {
4052:                        frames.remove(frame);
4053:                        frames.add(frame);
4054:                    }
4055:                    sessionProperties.saveWindowPlacement();
4056:                    frames.remove(frame);
4057:                    frame.dispose();
4058:
4059:                    Editor ed = frame.getSecondaryEditor();
4060:                    if (ed != null)
4061:                        removeEditor(ed);
4062:                    removeEditor(this );
4063:                    setCurrentEditor(getEditor(0));
4064:                }
4065:            }
4066:
4067:            // See if we have the requested file in a buffer. If not, and if the file
4068:            // actually exists, make a new buffer for it.
4069:            public static Buffer getBuffer(File file) {
4070:                if (file == null)
4071:                    return null;
4072:                Buffer buf = bufferList.findBuffer(file);
4073:                if (buf != null)
4074:                    return buf;
4075:                if (file.isRemote())
4076:                    return Buffer.createBuffer(file);
4077:                if (file.isDirectory())
4078:                    return new Directory(file);
4079:                if (file.isFile()) {
4080:                    if (!file.canRead()) {
4081:                        MessageDialog.showMessageDialog("File is not readable",
4082:                                "Error");
4083:                        return null;
4084:                    }
4085:                    return Buffer.createBuffer(file);
4086:                }
4087:                if (file.exists()) {
4088:                    // The file exists, but it's neither a directory nor a "normal"
4089:                    // file. This can occur on Linux if an SMB mount goes south.
4090:
4091:                    // Not a very informative error message, but this is what bash says
4092:                    // in the SMB mount case.
4093:                    currentEditor.status("I/O error");
4094:                }
4095:                return null;
4096:            }
4097:
4098:            public void nextBuffer() {
4099:                Buffer buf = bufferList.getNextPrimaryBuffer(buffer);
4100:                if (buf == null)
4101:                    return;
4102:                if (buf.isPaired()) {
4103:                    Buffer secondary = buf.getSecondary();
4104:                    if (secondary != null) {
4105:                        if (secondary.getLastActivated() > buf
4106:                                .getLastActivated())
4107:                            buf = secondary;
4108:                    }
4109:                }
4110:                if (buf != buffer)
4111:                    switchToBuffer(buf);
4112:            }
4113:
4114:            public void prevBuffer() {
4115:                Buffer buf = bufferList.getPreviousPrimaryBuffer(buffer);
4116:                if (buf == null)
4117:                    return;
4118:                if (buf.isPaired()) {
4119:                    Buffer secondary = buf.getSecondary();
4120:                    if (secondary != null) {
4121:                        if (secondary.getLastActivated() > buf
4122:                                .getLastActivated())
4123:                            buf = secondary;
4124:                    }
4125:                }
4126:                if (buf != buffer)
4127:                    switchToBuffer(buf);
4128:            }
4129:
4130:            public void switchToBuffer(Buffer buf) {
4131:                if (buf != null) {
4132:                    if (!buf.isPaired()
4133:                            && (buffer == null || !buffer.isPaired())) {
4134:                        // This is the easy case. Both the buffer we're switching in
4135:                        // and the buffer we're switching out are unpaired.
4136:                        activate(buf);
4137:                    } else {
4138:                        // We're either switching in a paired buffer or switching out
4139:                        // a paired buffer (or both). Delegate to our frame, since we
4140:                        // may end up closing this editor.
4141:                        frame.switchToBuffer(buf);
4142:                    }
4143:                    Sidebar sidebar = getSidebar();
4144:                    if (sidebar != null)
4145:                        sidebar.setBuffer();
4146:                } else
4147:                    Debug.bug();
4148:            }
4149:
4150:            public void makeNext(final Buffer buf) {
4151:                bufferList.makeNext(buf, buffer);
4152:            }
4153:
4154:            public void newBuffer() {
4155:                Buffer buf = new Buffer(0);
4156:                makeNext(buf);
4157:                switchToBuffer(buf);
4158:            }
4159:
4160:            public final void openFile() {
4161:                AWTEvent e = dispatcher.getLastEvent();
4162:                if (e != null && e.getSource() instanceof  MenuItem) {
4163:                    Runnable r = new Runnable() {
4164:                        public void run() {
4165:                            setFocusToTextField();
4166:                        }
4167:                    };
4168:                    SwingUtilities.invokeLater(r);
4169:                } else
4170:                    setFocusToTextField();
4171:            }
4172:
4173:            public void openFileInOtherWindow() {
4174:                Debug.assertTrue(locationBar != null);
4175:                saveView();
4176:                boolean alreadySplit = (getOtherEditor() != null);
4177:                if (!alreadySplit)
4178:                    splitWindow();
4179:                final Editor ed = getOtherEditor();
4180:                if (ed.getLocationBar() != null) {
4181:                    Runnable r = new Runnable() {
4182:                        public void run() {
4183:                            frame.setFocus(ed.getLocationBar().getTextField());
4184:                        }
4185:                    };
4186:                    SwingUtilities.invokeLater(r);
4187:                }
4188:                setCurrentEditor(ed);
4189:                if (alreadySplit) {
4190:                    // Current editor has changed.
4191:                    repaint();
4192:                    ed.repaint();
4193:                }
4194:            }
4195:
4196:            public Buffer openFile(File file) {
4197:                Buffer buf = getBuffer(file);
4198:                if (buf != null) {
4199:                    Debug.assertTrue(bufferList.contains(buf));
4200:                    return buf;
4201:                }
4202:                if (file.isRemote())
4203:                    return null;
4204:                // File is local.
4205:                if (!file.exists()) {
4206:                    if (confirm("Create file?", file.canonicalPath()
4207:                            + " does not exist. Create?"))
4208:                        return Buffer.createBuffer(file);
4209:                }
4210:                return null;
4211:            }
4212:
4213:            public Buffer openFiles(List list) {
4214:                if (list == null)
4215:                    return null;
4216:                final int listSize = list.size();
4217:                if (listSize < 2)
4218:                    return null;
4219:                Buffer toBeActivated = null;
4220:                // First string is directory.
4221:                String dirname = (String) list.get(0);
4222:                File directory = File.getInstance(dirname);
4223:                History openFileHistory = new History("openFile.file");
4224:                int lineNumber = -1;
4225:                for (int i = 1; i < listSize; i++) {
4226:                    String s = (String) list.get(i);
4227:                    if (s == null || s.length() == 0)
4228:                        continue;
4229:                    if (s.charAt(0) == '+') {
4230:                        try {
4231:                            lineNumber = Integer.parseInt(s.substring(1)) - 1;
4232:                        } catch (NumberFormatException e) {
4233:                        }
4234:                        continue;
4235:                    }
4236:                    // Aliases.
4237:                    String value = getAlias(s);
4238:                    if (value != null)
4239:                        s = value;
4240:                    if (s.startsWith("pop://") || s.startsWith("{")) {
4241:                        MailboxURL url = MailboxURL.parse(s);
4242:                        if (url != null) {
4243:                            Buffer buf = MailCommands.getMailboxBuffer(this ,
4244:                                    url);
4245:                            if (buf != null) {
4246:                                makeNext(buf);
4247:                                toBeActivated = buf;
4248:                            }
4249:                        }
4250:                        continue;
4251:                    }
4252:                    File file = File.getInstance(directory, s);
4253:                    if (file == null) {
4254:                        MessageDialog.showMessageDialog(this , "Invalid path "
4255:                                .concat(s), "Invalid Path");
4256:                        continue;
4257:                    }
4258:                    if (Utilities.isFilenameAbsolute(s) || s.startsWith("./")
4259:                            || s.startsWith(".\\"))
4260:                        ; // No tricks.
4261:                    else if (!file.exists()) {
4262:                        // Look in source and include paths as appropriate.
4263:                        File f = Utilities.findFile(this , s);
4264:                        if (f != null)
4265:                            file = f;
4266:                        else {
4267:                            // Not found in source or include path.
4268:                            if (s.startsWith("www."))
4269:                                file = File.getInstance("http://".concat(s));
4270:                            else if (s.startsWith("ftp."))
4271:                                file = File.getInstance("ftp://".concat(s));
4272:                        }
4273:                    }
4274:                    if (file.isLocal() && !file.exists()) {
4275:                        if (!Utilities.checkParentDirectory(file, "Open File"))
4276:                            continue;
4277:                    }
4278:                    Buffer buf = openFile(file);
4279:                    if (buf != null) {
4280:                        Debug.assertTrue(bufferList.contains(buf));
4281:                        openFileHistory.append(file.netPath());
4282:                        if (lineNumber >= 0) {
4283:                            // Line number was specified on command line.
4284:                            if (buf.isLoaded()) {
4285:                                if (buf == buffer) {
4286:                                    // Current buffer.
4287:                                    Line line = buffer.getLine(lineNumber);
4288:                                    if (line == null)
4289:                                        eob();
4290:                                    else {
4291:                                        addUndo(SimpleEdit.MOVE);
4292:                                        updateDotLine();
4293:                                        dot.moveTo(line, 0);
4294:                                        updateDotLine();
4295:                                        moveCaretToDotCol();
4296:                                    }
4297:                                } else {
4298:                                    // Not current buffer.
4299:                                    Buffer oldBuffer = buffer;
4300:                                    if (buffer != null)
4301:                                        saveView();
4302:                                    buffer = buf;
4303:                                    findOrCreateView(buffer);
4304:                                    restoreView();
4305:                                    addUndo(SimpleEdit.MOVE);
4306:                                    Line line = buffer.getLine(lineNumber);
4307:                                    if (line == null) {
4308:                                        line = buffer.getFirstLine();
4309:                                        while (line.next() != null)
4310:                                            line = line.next();
4311:                                        dot.moveTo(line, line.length());
4312:                                    } else
4313:                                        dot.moveTo(line, 0);
4314:                                    saveView();
4315:                                    View view = (View) views.get(buffer);
4316:                                    if (view != null) {
4317:                                        view.shift = 0;
4318:                                        view.caretCol = getDotCol();
4319:                                    }
4320:                                    buffer = oldBuffer;
4321:                                    if (buffer != null)
4322:                                        restoreView();
4323:                                }
4324:                            } else {
4325:                                // Not yet loaded.
4326:                                View view = findOrCreateView(buf);
4327:                                view.lineNumber = lineNumber;
4328:                                view.offs = 0;
4329:                            }
4330:                        }
4331:                        Debug.assertTrue(bufferList.contains(buf));
4332:                        makeNext(buf);
4333:                        Debug.assertTrue(bufferList.contains(buf));
4334:                        toBeActivated = buf;
4335:                    }
4336:                }
4337:                openFileHistory.save();
4338:                return toBeActivated;
4339:            }
4340:
4341:            public void unmark() {
4342:                if (mark != null) {
4343:                    setMark(null);
4344:                    display.setUpdateFlag(REPAINT); // BUG! Not always necessary!
4345:                }
4346:            }
4347:
4348:            public void cancelBackgroundProcess() {
4349:                BackgroundProcess backgroundProcess = buffer
4350:                        .getBackgroundProcess();
4351:                if (backgroundProcess != null)
4352:                    backgroundProcess.cancel();
4353:            }
4354:
4355:            // Returns after doing exactly one thing.
4356:            public void escape() {
4357:                // Cancel background process (if any).
4358:                BackgroundProcess backgroundProcess = buffer
4359:                        .getBackgroundProcess();
4360:                if (backgroundProcess != null) {
4361:                    backgroundProcess.cancel();
4362:                    return;
4363:                }
4364:
4365:                if (popup != null) {
4366:                    if (popup.isVisible()) {
4367:                        killPopup();
4368:                        return;
4369:                    }
4370:                    popup = null;
4371:                    // We haven't really done anything yet. Fall through...
4372:                }
4373:
4374:                if (lastCommand == COMMAND_EXPAND) {
4375:                    Expansion expansion = Expansion.getLastExpansion();
4376:                    if (expansion != null) {
4377:                        expansion.undo(this );
4378:                        return;
4379:                    }
4380:                }
4381:
4382:                if (buffer instanceof  RemoteBuffer && buffer.isEmpty()) {
4383:                    killBuffer();
4384:                    return;
4385:                }
4386:
4387:                if (escapeInternal())
4388:                    return;
4389:
4390:                if (selection != null && selection.getSavedDot() != null)
4391:                    moveDotTo(selection.getSavedDot());
4392:                else if (mark != null)
4393:                    moveDotTo(mark);
4394:            }
4395:
4396:            public boolean escapeInternal() {
4397:                if (buffer instanceof  CompilationBuffer) {
4398:                    if (buffer.unsplitOnClose()) {
4399:                        buffer.windowClosing();
4400:                        otherWindow();
4401:                        unsplitWindow();
4402:                    }
4403:                    maybeKillBuffer(buffer);
4404:                    restoreFocus();
4405:                    Sidebar.refreshSidebarInAllFrames();
4406:                    return true;
4407:                }
4408:                if (buffer.isTransient()) {
4409:                    if (buffer.unsplitOnClose()) {
4410:                        buffer.windowClosing();
4411:                        otherWindow();
4412:                        unsplitWindow();
4413:                    }
4414:                    maybeKillBuffer(buffer);
4415:                    restoreFocus();
4416:                    Sidebar.refreshSidebarInAllFrames();
4417:                    return true;
4418:                }
4419:                if (buffer.getModeId() == CHECKIN_MODE) {
4420:                    otherWindow();
4421:                    unsplitWindow();
4422:                    if (!buffer.isModified())
4423:                        maybeKillBuffer(buffer);
4424:                    restoreFocus();
4425:                    return true;
4426:                }
4427:                // Check for transient buffer in other editor in current frame.
4428:                Editor ed = getOtherEditor();
4429:                if (ed != null) {
4430:                    Buffer buf = ed.getBuffer();
4431:                    if (buf instanceof  CompilationBuffer || buf.isTransient()) {
4432:                        if (buf.unsplitOnClose())
4433:                            unsplitWindow();
4434:                        maybeKillBuffer(buf);
4435:                        if (!buf.unsplitOnClose())
4436:                            ed.updateDisplay();
4437:                        Sidebar.refreshSidebarInAllFrames();
4438:                        return true;
4439:                    }
4440:                    if (buf.getModeId() == CHECKIN_MODE) {
4441:                        unsplitWindow();
4442:                        if (!buf.isModified())
4443:                            maybeKillBuffer(buf);
4444:                        return true;
4445:                    }
4446:                }
4447:                return false;
4448:            }
4449:
4450:            public void stamp() {
4451:                if (!checkReadOnly())
4452:                    return;
4453:                Date now = new Date(System.currentTimeMillis());
4454:                String dateString = null;
4455:                String stampFormat = buffer
4456:                        .getStringProperty(Property.STAMP_FORMAT);
4457:                if (stampFormat != null) {
4458:                    try {
4459:                        SimpleDateFormat df = new SimpleDateFormat(stampFormat);
4460:                        dateString = df.format(now);
4461:                    } catch (Throwable t) {
4462:                        // Fall through...
4463:                    }
4464:                }
4465:                if (dateString == null) {
4466:                    SimpleDateFormat df = new SimpleDateFormat(
4467:                            "MMM d yyyy h:mm a");
4468:                    dateString = df.format(now);
4469:                }
4470:                try {
4471:                    buffer.lockWrite();
4472:                } catch (InterruptedException e) {
4473:                    Log.error(e);
4474:                    return;
4475:                }
4476:                try {
4477:                    CompoundEdit compoundEdit = beginCompoundEdit();
4478:                    if (mark != null)
4479:                        delete();
4480:                    fillToCaret();
4481:                    addUndo(SimpleEdit.INSERT_STRING);
4482:                    insertStringInternal(dateString);
4483:                    buffer.modified();
4484:                    endCompoundEdit(compoundEdit);
4485:                    moveCaretToDotCol();
4486:                    updateInAllEditors(getDotLine());
4487:                } finally {
4488:                    buffer.unlockWrite();
4489:                }
4490:            }
4491:
4492:            public Search getSearchAtDot() {
4493:                if (dot == null)
4494:                    return null;
4495:                String pattern = null;
4496:                boolean wholeWordsOnly = false;
4497:                if (mark != null) {
4498:                    // No action if there's a multi-line selection.
4499:                    if (getMarkLine() == getDotLine())
4500:                        pattern = (new Region(buffer, dot, mark)).toString();
4501:                } else {
4502:                    pattern = tokenAt(dot);
4503:                    wholeWordsOnly = true;
4504:                }
4505:                if (pattern != null && pattern.length() != 0)
4506:                    return new Search(pattern, false, wholeWordsOnly);
4507:                else
4508:                    return null;
4509:            }
4510:
4511:            // Assumes dot is on first char of found pattern.
4512:            public void markFoundPattern(Search search) {
4513:                if (search.isRegularExpression() && search.isMultilinePattern()) {
4514:                    REMatch match = search.getMatch();
4515:                    if (match != null) {
4516:                        setDot(buffer.getPosition(match.getStartIndex()));
4517:                        setMark(buffer.getPosition(match.getEndIndex()));
4518:                        final Line markLine = getMarkLine();
4519:                        for (Line line = getDotLine(); line != null; line = line
4520:                                .next()) {
4521:                            update(line);
4522:                            if (line == markLine)
4523:                                break;
4524:                        }
4525:                        moveCaretToDotCol();
4526:                    }
4527:                } else {
4528:                    final int context = 2; // This could be a preference.
4529:                    Position saved = dot.copy();
4530:
4531:                    // Move dot to end of found pattern.
4532:                    int length;
4533:                    if (search.getMatch() != null)
4534:                        length = search.getMatch().toString().length();
4535:                    else
4536:                        length = search.getPatternLength();
4537:
4538:                    // Found pattern might go beyond end of line.
4539:                    dot.setOffset(Math.min(dot.getOffset() + length,
4540:                            getDotLine().length()));
4541:
4542:                    // Set mark at end of pattern.
4543:                    moveCaretToDotCol();
4544:                    setMarkAtDot();
4545:
4546:                    // Make sure end of pattern is actually visible, with additional
4547:                    // context as appropriate.
4548:                    int absCol = getDotCol() + context;
4549:                    display.ensureColumnVisible(getDotLine(), absCol);
4550:
4551:                    // Restore dot to original position at start of pattern.
4552:                    dot = saved;
4553:
4554:                    // Make sure start of pattern is actually visible, with additional
4555:                    // context as appropriate.
4556:                    absCol = getDotCol() - context;
4557:                    if (absCol < 0)
4558:                        absCol = 0;
4559:                    display.ensureColumnVisible(getDotLine(), absCol);
4560:                    moveCaretToDotCol();
4561:                }
4562:            }
4563:
4564:            public void findNext() {
4565:                if (lastSearch != null) {
4566:                    Position start;
4567:                    if (mark != null) {
4568:                        Region r = new Region(this );
4569:                        start = new Position(r.getBegin());
4570:                    } else
4571:                        start = new Position(dot);
4572:                    if (!start.next())
4573:                        return;
4574:                    setWaitCursor();
4575:                    Position pos = lastSearch.find(buffer, start);
4576:                    setDefaultCursor();
4577:                    if (pos != null) {
4578:                        moveDotTo(pos);
4579:                        markFoundPattern(lastSearch);
4580:                        if (lastSearch instanceof  FindInFiles) {
4581:                            if (buffer.getFile() != null) {
4582:                                ListOccurrencesInFiles buf = ((FindInFiles) lastSearch)
4583:                                        .getOutputBuffer();
4584:                                if (buf != null)
4585:                                    buf.follow(buffer.getFile(), getDotLine());
4586:                            }
4587:                        }
4588:                        return;
4589:                    }
4590:                    if (lastSearch instanceof  FindInFiles) {
4591:                        Editor ed = getOtherEditor();
4592:                        if (ed != null) {
4593:                            ListOccurrencesInFiles buf = ((FindInFiles) lastSearch)
4594:                                    .getOutputBuffer();
4595:                            if (ed.getBuffer() == buf) {
4596:                                buf.findNextOccurrence(ed);
4597:                                return;
4598:                            }
4599:                        }
4600:                    }
4601:                    lastSearch.notFound(this );
4602:                }
4603:            }
4604:
4605:            public void findPrev() {
4606:                if (lastSearch != null) {
4607:                    Position start;
4608:                    if (mark != null) {
4609:                        Region r = new Region(this );
4610:                        start = new Position(r.getBegin());
4611:                    } else
4612:                        start = new Position(dot);
4613:                    if (!start.prev())
4614:                        return;
4615:                    setWaitCursor();
4616:                    Position pos = lastSearch.reverseFind(buffer, start);
4617:                    setDefaultCursor();
4618:                    if (pos != null) {
4619:                        moveDotTo(pos);
4620:                        markFoundPattern(lastSearch);
4621:                        if (lastSearch instanceof  FindInFiles) {
4622:                            if (buffer.getFile() != null) {
4623:                                ListOccurrencesInFiles buf = ((FindInFiles) lastSearch)
4624:                                        .getOutputBuffer();
4625:                                if (buf != null)
4626:                                    buf.follow(buffer.getFile(), getDotLine());
4627:                            }
4628:                        }
4629:                        return;
4630:                    }
4631:                    if (lastSearch instanceof  FindInFiles) {
4632:                        Editor ed = getOtherEditor();
4633:                        if (ed != null) {
4634:                            ListOccurrencesInFiles buf = ((FindInFiles) lastSearch)
4635:                                    .getOutputBuffer();
4636:                            if (ed.getBuffer() == buf) {
4637:                                buf.findPreviousOccurrence(ed);
4638:                                return;
4639:                            }
4640:                        }
4641:                    }
4642:                    lastSearch.notFound(this );
4643:                }
4644:            }
4645:
4646:            public void incrementalFind() {
4647:                if (dot == null)
4648:                    return;
4649:
4650:                // Use location bar.
4651:                locationBar.setLabelText(LocationBar.PROMPT_PATTERN);
4652:                HistoryTextField textField = locationBar.getTextField();
4653:                textField.setHandler(new IncrementalFindTextFieldHandler(this ,
4654:                        textField));
4655:                textField.setHistory(new History("incrementalFind.pattern"));
4656:                textField.setText("");
4657:                setFocusToTextField();
4658:            }
4659:
4660:            public String getCurrentText() {
4661:                String s = getSelectionOnCurrentLine();
4662:                if (s == null)
4663:                    s = getTokenAtDot();
4664:                return (s != null && s.length() > 0) ? s : null;
4665:            }
4666:
4667:            public String getSelectionOnCurrentLine() {
4668:                if (dot != null && mark != null
4669:                        && getMarkLine() == getDotLine())
4670:                    return new Region(this ).toString();
4671:                else
4672:                    return null;
4673:            }
4674:
4675:            public String getFilenameAtDot() {
4676:                if (dot == null)
4677:                    return null;
4678:                Position pos;
4679:                if (mark != null) {
4680:                    Region r = new Region(this );
4681:
4682:                    // Trust the user if there's a highlighted selection on a single
4683:                    // line.
4684:                    if (r.getBeginLine() == r.getEndLine())
4685:                        return r.toString();
4686:
4687:                    // Otherwise, we want the beginning of the marked region.
4688:                    pos = r.getBegin();
4689:                } else
4690:                    pos = new Position(dot);
4691:                final Line line = pos.getLine();
4692:                final int limit = line.length();
4693:                int offset = pos.getOffset();
4694:                if (offset == limit)
4695:                    --offset;
4696:                FastStringBuffer sb = new FastStringBuffer();
4697:                if (offset >= 0 && offset < limit) {
4698:                    char c = line.charAt(offset);
4699:                    if (Utilities.isFilenameChar(c)) {
4700:                        while (offset > 0) {
4701:                            c = line.charAt(--offset);
4702:                            if (!Utilities.isFilenameChar(c)) {
4703:                                ++offset;
4704:                                break;
4705:                            }
4706:                        }
4707:
4708:                        // Now we're looking at the first char of the filename.
4709:                        sb.append(line.charAt(offset));
4710:                        while (++offset < limit) {
4711:                            c = line.charAt(offset);
4712:                            if (Utilities.isFilenameChar(c)) {
4713:                                sb.append(c);
4714:                            } else if (sb.toString().startsWith("http://")) {
4715:                                // Be more permissive since there may be an appended
4716:                                // query.
4717:                                if (!Character.isWhitespace(c))
4718:                                    sb.append(c);
4719:                                else
4720:                                    break;
4721:                            } else
4722:                                break;
4723:                        }
4724:
4725:                        // Now we're looking at the first char past the end of the
4726:                        // filename. If the filename starts with "http://", make sure
4727:                        // it doesn't end with normal punctuation (as is often the
4728:                        // case with links embedded in text).
4729:                        int length = sb.length();
4730:                        while (length > 0) {
4731:                            c = sb.charAt(length - 1);
4732:                            if (".,:;)]>".indexOf(c) >= 0)
4733:                                --length;
4734:                            else
4735:                                break;
4736:                        }
4737:                        sb.setLength(length);
4738:
4739:                        RE re = new UncheckedRE(" line [0-9]+");
4740:                        REMatch match = re.getMatch(line.getText().substring(
4741:                                offset));
4742:                        if (match != null && match.getStartIndex() == 0)
4743:                            sb.append(match.toString());
4744:                    }
4745:                }
4746:                return sb.toString();
4747:            }
4748:
4749:            private String getTokenAtDot() {
4750:                // If a selection is marked, return the token at the beginning of the
4751:                // marked region.
4752:                if (mark != null) {
4753:                    Region r = new Region(this );
4754:                    return tokenAt(r.getBegin());
4755:                }
4756:                return tokenAt(dot);
4757:            }
4758:
4759:            private String tokenAt(Position pos) {
4760:                return getMode().getIdentifier(pos);
4761:            }
4762:
4763:            public void findNextWord() {
4764:                if (dot == null)
4765:                    return;
4766:                String pattern = getTokenAtDot();
4767:                if (pattern == null || pattern.length() == 0)
4768:                    return;
4769:                lastSearch = new Search(pattern, false, true);
4770:                Position start;
4771:                if (mark != null && dot.isBefore(mark))
4772:                    start = new Position(mark);
4773:                else
4774:                    start = new Position(dot);
4775:                Position pos = lastSearch.find(buffer.getMode(), start);
4776:                if (pos != null && pos.equals(start)) {
4777:                    if (pos.next())
4778:                        pos = lastSearch.find(buffer.getMode(), pos);
4779:                }
4780:                if (pos != null && !pos.equals(start)) {
4781:                    moveDotTo(pos);
4782:                    markFoundPattern(lastSearch);
4783:                } else
4784:                    lastSearch.notFound(this );
4785:            }
4786:
4787:            public void findPrevWord() {
4788:                if (dot == null)
4789:                    return;
4790:                String pattern = getTokenAtDot();
4791:                if (pattern == null || pattern.length() == 0)
4792:                    return;
4793:                lastSearch = new Search(pattern, false, true);
4794:                boolean found = false;
4795:                Position start = null;
4796:                if (mark != null)
4797:                    start = new Region(this ).getBegin();
4798:                else
4799:                    start = new Position(dot);
4800:                if (start.prev()) {
4801:                    Position pos = lastSearch.reverseFind(buffer, start);
4802:                    if (pos != null && pos.getLine() == start.getLine()) {
4803:                        if (pos.getOffset() + lastSearch.getPatternLength() > start
4804:                                .getOffset()) {
4805:                            // We've found the instance we started with. Keep looking.
4806:                            start = new Position(pos);
4807:                            if (start.prev())
4808:                                pos = lastSearch.reverseFind(buffer, start);
4809:                            else
4810:                                pos = null;
4811:                        }
4812:                    }
4813:                    if (pos != null) {
4814:                        found = true;
4815:                        moveDotTo(pos);
4816:                        markFoundPattern(lastSearch);
4817:                    }
4818:                }
4819:                if (!found)
4820:                    lastSearch.notFound(this );
4821:            }
4822:
4823:            public void findFirstOccurrence() {
4824:                if (dot == null)
4825:                    return;
4826:                String pattern = getTokenAtDot();
4827:                if (pattern == null || pattern.length() == 0)
4828:                    return;
4829:                lastSearch = new Search(pattern, false, true);
4830:                Position pos = lastSearch.find(buffer.getMode(), new Position(
4831:                        buffer.getFirstLine(), 0));
4832:                if (pos != null) {
4833:                    moveDotTo(pos);
4834:                    markFoundPattern(lastSearch);
4835:                } else
4836:                    lastSearch.notFound(this );
4837:            }
4838:
4839:            public void copyPath() {
4840:                if (buffer instanceof  Directory) {
4841:                    String path = ((Directory) buffer).getPathAtDot();
4842:                    if (path != null) {
4843:                        killRing.appendNew(path);
4844:                        killRing.copyLastKillToSystemClipboard();
4845:                        status("Path copied to clipboard");
4846:                    }
4847:                }
4848:            }
4849:
4850:            public void copyRegion() {
4851:                if (dot == null)
4852:                    return;
4853:
4854:                String message = null;
4855:
4856:                if (mark != null) {
4857:                    Region r = new Region(this );
4858:                    if (isColumnSelection()) {
4859:                        killedColumn = r.toString();
4860:                        message = "Column selection stored";
4861:                    } else {
4862:                        killRing.appendNew(r.toString());
4863:                        message = "Region copied to clipboard";
4864:                    }
4865:                } else if (!getDotLine().isBlank()) {
4866:                    killRing.appendNew(getDotLine().getText()
4867:                            + System.getProperty("line.separator"));
4868:                    message = "Line copied to clipboard";
4869:                } else
4870:                    return; // Nothing to do.
4871:
4872:                if (!isColumnSelection())
4873:                    killRing.copyLastKillToSystemClipboard();
4874:
4875:                if (message != null)
4876:                    status(message);
4877:            }
4878:
4879:            public void copyAppend() {
4880:                if (isColumnSelection()) {
4881:                    notSupportedForColumnSelections();
4882:                    return;
4883:                }
4884:
4885:                if (dot == null)
4886:                    return;
4887:
4888:                String message = null;
4889:
4890:                if (mark != null) {
4891:                    Region r = new Region(buffer, mark, dot);
4892:                    killRing.appendToCurrent(r.toString());
4893:                    message = "Region appended to clipboard";
4894:                } else if (!getDotLine().isBlank()) {
4895:                    killRing.appendToCurrent(getDotLine().getText()
4896:                            + System.getProperty("line.separator"));
4897:                    message = "Line appended to clipboard";
4898:                } else
4899:                    return; // Nothing to do.
4900:
4901:                killRing.copyLastKillToSystemClipboard();
4902:
4903:                if (message != null)
4904:                    status(message);
4905:            }
4906:
4907:            // Handles undo, updates display and marks buffer modified.
4908:            public void deleteRegion() {
4909:                if (mark == null)
4910:                    return;
4911:                if (getMarkLine() != getDotLine()
4912:                        || getMarkOffset() != getDotOffset()) {
4913:                    try {
4914:                        buffer.lockWrite();
4915:                    } catch (InterruptedException e) {
4916:                        Log.error(e);
4917:                        return;
4918:                    }
4919:                    try {
4920:                        Region r = new Region(this );
4921:                        if (isColumnSelection()) {
4922:                            deleteColumn(r);
4923:                        } else {
4924:                            // A hard update is only necessary if the region spans a
4925:                            // line boundary.
4926:                            boolean hard = getDotLine() != getMarkLine();
4927:
4928:                            // Save undo information before calling r.delete() so
4929:                            // the modified flag will be correct if we revert.
4930:                            CompoundEdit compoundEdit = beginCompoundEdit();
4931:                            addUndo(SimpleEdit.MOVE);
4932:                            dot.moveTo(r.getBegin());
4933:                            addUndoDeleteRegion(r);
4934:
4935:                            // Sets buffer modified flag.
4936:                            r.delete();
4937:
4938:                            endCompoundEdit(compoundEdit);
4939:
4940:                            if (hard)
4941:                                buffer.repaint();
4942:                            else
4943:                                updateInAllEditors(getDotLine());
4944:                        }
4945:                    } finally {
4946:                        buffer.unlockWrite();
4947:                    }
4948:                    moveCaretToDotCol();
4949:                }
4950:                setMark(null);
4951:            }
4952:
4953:            // Leaves dot at beginning of deleted region.
4954:            private void deleteColumn(Region r) {
4955:                Debug.assertTrue(r.isColumnRegion());
4956:                final int beginCol = r.getBeginCol();
4957:                final int endCol = r.getEndCol();
4958:                CompoundEdit compoundEdit = beginCompoundEdit();
4959:                addUndo(SimpleEdit.MOVE);
4960:                dot.moveTo(r.getBegin());
4961:                while (true) {
4962:                    addUndo(SimpleEdit.LINE_EDIT);
4963:                    Line line = getDotLine();
4964:                    deleteLineRegion(line, beginCol, endCol);
4965:                    updateInAllEditors(line);
4966:                    if (line == r.getEndLine())
4967:                        break;
4968:                    if (line.next() == null)
4969:                        break;
4970:                    dot.moveTo(line.next(), 0);
4971:                }
4972:                addUndo(SimpleEdit.MOVE);
4973:                dot.moveTo(r.getBegin());
4974:                endCompoundEdit(compoundEdit);
4975:                buffer.modified();
4976:            }
4977:
4978:            private void deleteLineRegion(Line line, int beginCol, int endCol) {
4979:                String text = Utilities.detab(line.getText(), buffer
4980:                        .getTabWidth());
4981:                if (text.length() < beginCol)
4982:                    return; // No change.
4983:                String head = text.substring(0, beginCol);
4984:                if (text.length() < endCol) {
4985:                    line.setText(head);
4986:                    return;
4987:                }
4988:                String tail = text.substring(endCol);
4989:                line.setText(head.concat(tail));
4990:            }
4991:
4992:            // This really is a kill!
4993:            public void killRegion() {
4994:                if (!checkReadOnly())
4995:                    return;
4996:                try {
4997:                    buffer.lockWrite();
4998:                } catch (InterruptedException e) {
4999:                    Log.error(e);
5000:                    return;
5001:                }
5002:                try {
5003:                    killRegionInternal();
5004:                } finally {
5005:                    buffer.unlockWrite();
5006:                }
5007:            }
5008:
5009:            private void killRegionInternal() {
5010:                if (mark != null) {
5011:                    if (getMarkLine() != getDotLine()
5012:                            || getMarkOffset() != getDotOffset()) {
5013:                        // A hard update is only necessary if the region spans a line
5014:                        // boundary.
5015:                        boolean hard = getDotLine() != getMarkLine();
5016:                        if (isColumnSelection()) {
5017:                            Region r = new Region(this );
5018:                            killedColumn = r.toString();
5019:                            deleteColumn(r);
5020:                        } else {
5021:                            Region r = new Region(this );
5022:                            String kill = r.toString();
5023:                            if (lastCommand == COMMAND_KILL)
5024:                                killRing.appendToCurrent(kill);
5025:                            else
5026:                                killRing.appendNew(kill);
5027:                            killRing.copyLastKillToSystemClipboard();
5028:
5029:                            // Save undo information before calling Region.delete so
5030:                            // modified flag will be correct if we revert.
5031:                            CompoundEdit compoundEdit = beginCompoundEdit();
5032:                            addUndo(SimpleEdit.MOVE);
5033:                            dot.moveTo(r.getBegin());
5034:                            addUndoDeleteRegion(r);
5035:
5036:                            // Sets buffer modified flag.
5037:                            r.delete();
5038:
5039:                            endCompoundEdit(compoundEdit);
5040:                        }
5041:                        moveCaretToDotCol();
5042:                        if (hard)
5043:                            buffer.repaint();
5044:                        else
5045:                            updateInAllEditors(getDotLine());
5046:                        setCurrentCommand(COMMAND_KILL);
5047:                    }
5048:                    setMark(null);
5049:                } else {
5050:                    // No selection.  Use current line.
5051:                    final Line dotLine = getDotLine();
5052:                    final Line nextLine = dotLine.next();
5053:
5054:                    // Last line is a special case.
5055:                    if (nextLine == null) {
5056:                        CompoundEdit compoundEdit = beginCompoundEdit();
5057:                        dot.setOffset(0);
5058:                        killLine();
5059:                        endCompoundEdit(compoundEdit);
5060:                        setCurrentCommand(COMMAND_KILL);
5061:                        return;
5062:                    }
5063:
5064:                    CompoundEdit compoundEdit = beginCompoundEdit();
5065:                    addUndo(SimpleEdit.MOVE);
5066:                    dot.moveTo(dotLine, 0);
5067:                    mark = new Position(nextLine, 0);
5068:
5069:                    Region r = new Region(this );
5070:                    String kill = r.toString();
5071:                    if (lastCommand == COMMAND_KILL)
5072:                        killRing.appendToCurrent(kill);
5073:                    else
5074:                        killRing.appendNew(kill);
5075:                    killRing.copyLastKillToSystemClipboard();
5076:
5077:                    // Save undo information before calling Region.delete so
5078:                    // modified flag will be correct if we revert.
5079:                    addUndo(SimpleEdit.MOVE);
5080:                    dot.moveTo(r.getBegin());
5081:                    addUndoDeleteRegion(r);
5082:
5083:                    // Sets buffer modified flag.
5084:                    r.delete();
5085:
5086:                    addUndo(SimpleEdit.MOVE);
5087:                    mark = null;
5088:                    endCompoundEdit(compoundEdit);
5089:                    moveCaretToDotCol();
5090:                    buffer.repaint();
5091:                    setCurrentCommand(COMMAND_KILL);
5092:                }
5093:            }
5094:
5095:            public void killAppend() {
5096:                if (isColumnSelection()) {
5097:                    notSupportedForColumnSelections();
5098:                    return;
5099:                }
5100:                setLastCommand(COMMAND_KILL); // Force append.
5101:                killRegion();
5102:            }
5103:
5104:            // Copies text from dot to end of line to kill ring and then deletes that
5105:            // text. If dot is already at end of line, deletes newline and copies it
5106:            // to kill ring.
5107:            public void killLine() {
5108:                if (!checkReadOnly())
5109:                    return;
5110:
5111:                if (dot.getOffset() == dot.getLineLength()
5112:                        && dot.getNextLine() == null)
5113:                    return;
5114:
5115:                CompoundEdit compoundEdit = beginCompoundEdit();
5116:
5117:                addUndo(SimpleEdit.MOVE);
5118:                unmark();
5119:
5120:                if (getDotOffset() < getDotLine().length()) {
5121:                    setMarkAtDot();
5122:                    if (dot.getLine().isBlank() && dot.getNextLine() != null)
5123:                        dot.moveTo(dot.getNextLine(), 0);
5124:                    else
5125:                        dot.setOffset(dot.getLineLength());
5126:                } else if (dot.getOffset() == dot.getLineLength()) {
5127:                    fillToCaret(); // We might be beyond the end of the actual text on the line.
5128:                    setMarkAtDot();
5129:                    dot.moveTo(dot.getNextLine(), 0);
5130:                }
5131:
5132:                killRegion();
5133:
5134:                endCompoundEdit(compoundEdit);
5135:            }
5136:
5137:            public void deleteWordRight() {
5138:                deleteOrKillWordRight(false);
5139:            }
5140:
5141:            public void killWordRight() {
5142:                deleteOrKillWordRight(true);
5143:            }
5144:
5145:            private void deleteOrKillWordRight(boolean isKill) {
5146:                if (!checkReadOnly())
5147:                    return;
5148:                CompoundEdit compoundEdit = beginCompoundEdit();
5149:                addUndo(SimpleEdit.MOVE);
5150:                unmark();
5151:                fillToCaret();
5152:                setMarkAtDot();
5153:                if (inWord()) {
5154:                    while (inWord() && nextChar())
5155:                        ;
5156:                    while (inWhitespace() && nextChar())
5157:                        ;
5158:                } else if (inWhitespace()) {
5159:                    while (inWhitespace() && nextChar())
5160:                        ;
5161:                } else {
5162:                    while (!inWhitespace() && !inWord() && nextChar())
5163:                        ;
5164:                    while (inWhitespace() && nextChar())
5165:                        ;
5166:                }
5167:                if (isKill)
5168:                    killRegion();
5169:                else
5170:                    deleteRegion();
5171:                endCompoundEdit(compoundEdit);
5172:            }
5173:
5174:            public void deleteWordLeft() {
5175:                deleteOrKillWordLeft(false);
5176:            }
5177:
5178:            public void killWordLeft() {
5179:                deleteOrKillWordLeft(true);
5180:            }
5181:
5182:            private void deleteOrKillWordLeft(boolean isKill) {
5183:                if (!checkReadOnly())
5184:                    return;
5185:                if (getDotOffset() == 0 && getDotLine().previous() == null)
5186:                    return;
5187:                CompoundEdit compoundEdit = beginCompoundEdit();
5188:                addUndo(SimpleEdit.MOVE);
5189:                unmark();
5190:                setMarkAtDot();
5191:                prevChar();
5192:                if (inWord()) {
5193:                    while (getDotOffset() > 0 && inWord() && prevChar())
5194:                        ;
5195:                    if (!inWord())
5196:                        nextChar();
5197:                } else if (inWhitespace()) {
5198:                    while (inWhitespace() && prevChar())
5199:                        ;
5200:                    if (!inWhitespace())
5201:                        nextChar();
5202:                } else {
5203:                    while (!inWhitespace() && !inWord() && prevChar())
5204:                        ;
5205:                    while (inWhitespace() && prevChar())
5206:                        ;
5207:                    nextChar();
5208:                }
5209:                if (isKill)
5210:                    killRegion();
5211:                else
5212:                    deleteRegion();
5213:                endCompoundEdit(compoundEdit);
5214:            }
5215:
5216:            public boolean canPaste() {
5217:                if (buffer.isReadOnly())
5218:                    return false;
5219:                if (killRing.size() > 0)
5220:                    return true;
5221:                String toBeInserted = null;
5222:                Transferable t = getToolkit().getSystemClipboard().getContents(
5223:                        this );
5224:                if (t != null) {
5225:                    try {
5226:                        toBeInserted = (String) t
5227:                                .getTransferData(DataFlavor.stringFlavor);
5228:                    } catch (Exception e) {
5229:                    }
5230:                }
5231:                return toBeInserted != null;
5232:            }
5233:
5234:            public void paste() {
5235:                if (!checkReadOnly())
5236:                    return;
5237:                setWaitCursor();
5238:                String toBeInserted = null;
5239:                Transferable t = getToolkit().getSystemClipboard().getContents(
5240:                        this );
5241:                if (t != null) {
5242:                    try {
5243:                        toBeInserted = (String) t
5244:                                .getTransferData(DataFlavor.stringFlavor);
5245:                    } catch (Exception e) {
5246:                    }
5247:                }
5248:                if (toBeInserted != null && toBeInserted.length() > 0)
5249:                    killRing.appendNew(toBeInserted);
5250:                // Even if we already have the text to be inserted, we MUST call
5251:                // killRing.pop() here so that killRing.indexOfNextPop and
5252:                // killRing.lastPaste are set correctly.
5253:                toBeInserted = killRing.pop();
5254:                if (toBeInserted != null) {
5255:                    paste(toBeInserted);
5256:                    setCurrentCommand(COMMAND_PASTE);
5257:                }
5258:                setDefaultCursor();
5259:            }
5260:
5261:            public void cyclePaste() {
5262:                if (lastCommand == COMMAND_PASTE) {
5263:                    setWaitCursor();
5264:                    String s = killRing.popNext();
5265:                    if (s != null) {
5266:                        undo();
5267:                        paste(s);
5268:                        setCurrentCommand(COMMAND_PASTE);
5269:                    }
5270:                    setDefaultCursor();
5271:                } else
5272:                    paste();
5273:            }
5274:
5275:            public void mousePaste() {
5276:                if (dot == null)
5277:                    return;
5278:                if (!checkReadOnly())
5279:                    return;
5280:                if (isColumnSelection()) {
5281:                    notSupportedForColumnSelections();
5282:                    return;
5283:                }
5284:                AWTEvent e = dispatcher.getLastEvent();
5285:                if (!(e instanceof  MouseEvent))
5286:                    return;
5287:                CompoundEdit compoundEdit = beginCompoundEdit();
5288:                if (mark != null) {
5289:                    Region r = new Region(this );
5290:                    killRing.appendNew(r.toString());
5291:                    killRing.copyLastKillToSystemClipboard();
5292:                    addUndo(SimpleEdit.MOVE);
5293:                    setMark(null);
5294:                }
5295:                mouseMoveDotToPoint((MouseEvent) e);
5296:                paste();
5297:                endCompoundEdit(compoundEdit);
5298:            }
5299:
5300:            public static void promoteLastPaste() {
5301:                killRing.promoteLastPaste();
5302:            }
5303:
5304:            public void paste(String toBeInserted) {
5305:                paste(toBeInserted, false);
5306:            }
5307:
5308:            public void paste(String toBeInserted, boolean leavePasteSelected) {
5309:                if (!checkReadOnly())
5310:                    return;
5311:                if (toBeInserted == null || toBeInserted.length() == 0)
5312:                    return;
5313:                try {
5314:                    buffer.lockWrite();
5315:                } catch (InterruptedException e) {
5316:                    Log.error(e);
5317:                    return;
5318:                }
5319:                try {
5320:                    pasteInternal(toBeInserted, leavePasteSelected);
5321:                } finally {
5322:                    buffer.unlockWrite();
5323:                }
5324:                setUpdateFlag(REFRAME);
5325:            }
5326:
5327:            private void pasteInternal(String toBeInserted,
5328:                    boolean leavePasteSelected) {
5329:                final Mode mode = buffer.getMode();
5330:                CompoundEdit compoundEdit = beginCompoundEdit();
5331:                if (mark == null && Utilities.isLinePaste(toBeInserted)
5332:                        && mode.acceptsLinePaste(this )
5333:                        && buffer.getBooleanProperty(Property.AUTO_PASTE_LINES)) {
5334:                    // We want to the caret to be in the same column when we're done.
5335:                    final int absCaretCol = display.getAbsoluteCaretCol();
5336:
5337:                    final Line prevLine = getDotLine().previous();
5338:
5339:                    addUndo(SimpleEdit.MOVE);
5340:                    dot.setOffset(0);
5341:                    Position begin = dot.copy();
5342:                    addUndo(SimpleEdit.INSERT_STRING);
5343:                    insertStringInternal(toBeInserted);
5344:
5345:                    if (prevLine != null && mode.canIndentPaste()) {
5346:                        // Indent inserted lines according to context.
5347:
5348:                        // Make sure line flags are correct.
5349:                        if (getFormatter().parseBuffer())
5350:                            buffer.repaint();
5351:
5352:                        // Dot is at the beginning of the line following the inserted
5353:                        // block.
5354:                        Position savedDot = dot.copy();
5355:
5356:                        // First move dot to start of inserted block.
5357:                        addUndo(SimpleEdit.MOVE);
5358:                        dot.moveTo(prevLine.next(), 0);
5359:
5360:                        while (dot.getLine() != null
5361:                                && dot.getLine() != savedDot.getLine()) {
5362:                            if (!dot.getLine().isBlank())
5363:                                indentLineInternal();
5364:                            addUndo(SimpleEdit.MOVE);
5365:                            dot.moveTo(dot.getNextLine(), 0);
5366:                        }
5367:
5368:                        // Restore dot.
5369:                        dot = savedDot;
5370:                    }
5371:
5372:                    if (leavePasteSelected) {
5373:                        setMark(begin);
5374:                        final Line dotLine = getDotLine();
5375:                        for (Line line = begin.getLine(); line != null; line = line
5376:                                .nextVisible()) {
5377:                            update(line);
5378:                            if (line == dotLine)
5379:                                break;
5380:                        }
5381:                    } else {
5382:                        // Restore caret column.
5383:                        addUndo(SimpleEdit.MOVE);
5384:                        display.setCaretCol(absCaretCol - display.getShift());
5385:                        moveDotToCaretCol();
5386:                    }
5387:                } else {
5388:                    if (mark != null)
5389:                        deleteRegion();
5390:                    fillToCaret();
5391:                    Position begin = dot.copy();
5392:                    addUndo(SimpleEdit.INSERT_STRING);
5393:                    insertStringInternal(toBeInserted);
5394:                    moveCaretToDotCol();
5395:                    if (leavePasteSelected) {
5396:                        setMark(begin);
5397:                        final Line dotLine = getDotLine();
5398:                        for (Line line = begin.getLine(); line != null; line = line
5399:                                .nextVisible()) {
5400:                            update(line);
5401:                            if (line == dotLine)
5402:                                break;
5403:                        }
5404:                    }
5405:                }
5406:                endCompoundEdit(compoundEdit);
5407:                buffer.modified();
5408:                if (getFormatter().parseBuffer())
5409:                    buffer.repaint();
5410:            }
5411:
5412:            public void pasteColumn() {
5413:                if (!checkReadOnly())
5414:                    return;
5415:                if (killedColumn == null || killedColumn.length() == 0)
5416:                    return;
5417:                try {
5418:                    buffer.lockWrite();
5419:                } catch (InterruptedException e) {
5420:                    Log.error(e);
5421:                    return;
5422:                }
5423:                try {
5424:                    pasteColumnInternal(killedColumn);
5425:                } finally {
5426:                    buffer.unlockWrite();
5427:                }
5428:            }
5429:
5430:            private void pasteColumnInternal(String toBeInserted) {
5431:                Position pos = new Position(dot);
5432:                final int col = display.getAbsoluteCaretCol();
5433:                CompoundEdit compoundEdit = beginCompoundEdit();
5434:                while (true) {
5435:                    final int index = toBeInserted.indexOf('\n');
5436:                    final String s = index >= 0 ? toBeInserted.substring(0,
5437:                            index) : toBeInserted;
5438:                    if (index >= 0)
5439:                        toBeInserted = toBeInserted.substring(index + 1);
5440:                    final Line dotLine = getDotLine();
5441:                    String text = Utilities.detab(dotLine.getText(), buffer
5442:                            .getTabWidth());
5443:                    if (text.length() < col)
5444:                        text = text.concat(Utilities
5445:                                .spaces(col - text.length()));
5446:                    Debug.assertTrue(text.length() >= col);
5447:                    final String head = text.substring(0, col);
5448:                    final String tail = text.substring(col);
5449:                    addUndo(SimpleEdit.LINE_EDIT);
5450:                    FastStringBuffer sb = new FastStringBuffer(head);
5451:                    sb.append(s);
5452:                    sb.append(tail);
5453:                    dotLine.setText(sb.toString());
5454:                    updateInAllEditors(dotLine);
5455:                    pos = new Position(dotLine, head.length() + s.length());
5456:                    if (toBeInserted.length() == 0)
5457:                        break;
5458:                    if (dotLine.next() == null) {
5459:                        addUndo(SimpleEdit.MOVE);
5460:                        dot.setOffset(dotLine.length());
5461:                        addUndo(SimpleEdit.INSERT_LINE_SEP);
5462:                        buffer.insertLineSeparator(dot);
5463:                    } else {
5464:                        addUndo(SimpleEdit.MOVE);
5465:                        dot.moveTo(dotLine.next(), 0);
5466:                    }
5467:                }
5468:                addUndo(SimpleEdit.MOVE);
5469:                dot.moveTo(pos);
5470:                moveCaretToDotCol();
5471:                endCompoundEdit(compoundEdit);
5472:            }
5473:
5474:            public void insertString(String toBeInserted) {
5475:                if (toBeInserted == null || toBeInserted.length() == 0)
5476:                    return;
5477:                CompoundEdit compoundEdit = beginCompoundEdit();
5478:                if (mark != null)
5479:                    delete();
5480:                fillToCaret();
5481:                addUndo(SimpleEdit.INSERT_STRING);
5482:                insertStringInternal(toBeInserted);
5483:                updateInAllEditors(dot.getLine());
5484:                moveCaretToDotCol();
5485:                endCompoundEdit(compoundEdit);
5486:                if (getFormatter().parseBuffer())
5487:                    buffer.repaint();
5488:            }
5489:
5490:            public void centerDialog(JDialog d) {
5491:                Dimension parent = frame.getSize();
5492:                Dimension window = d.getSize();
5493:                Point p = frame.getLocation();
5494:                p.translate((parent.width - window.width) / 2,
5495:                        (parent.height - window.height) / 2);
5496:                d.setLocation(p);
5497:            }
5498:
5499:            public boolean confirm(String title, String text) {
5500:                int response = ConfirmDialog.showConfirmDialog(this , text,
5501:                        title);
5502:                repaintNow();
5503:                return response == RESPONSE_YES;
5504:            }
5505:
5506:            public int confirmAll(String title, String text) {
5507:                int response = ConfirmDialog.showConfirmAllDialog(this , text,
5508:                        title);
5509:                repaintNow();
5510:                return response;
5511:            }
5512:
5513:            public void killBuffer() {
5514:                try {
5515:                    if (buffer.isSecondary()) {
5516:                        buffer.windowClosing();
5517:                        otherWindow();
5518:                        unsplitWindow();
5519:                        currentEditor.maybeKillBuffer(buffer);
5520:                        restoreFocus();
5521:                        return;
5522:                    }
5523:                    Buffer buf = buffer.getSecondary();
5524:                    if (buf != null) {
5525:                        unsplitWindow();
5526:                        maybeKillBuffer(buf);
5527:                        return;
5528:                    }
5529:                    // Normal buffer.
5530:                    maybeKillBuffer(buffer);
5531:                    // If we're left with two editors showing exactly the same thing,
5532:                    // unsplit the window.
5533:                    Frame frame = currentEditor.getFrame();
5534:                    if (frame.getEditorCount() == 2) {
5535:                        Editor p = frame.getPrimaryEditor();
5536:                        Editor s = frame.getSecondaryEditor();
5537:                        boolean unsplit = false;
5538:                        if (p.getDot() != null && p.getDot().equals(s.getDot())) {
5539:                            if (p.getMark() == null && s.getMark() == null)
5540:                                unsplit = true;
5541:                            else if (p.getMark() != null
5542:                                    && p.getMark().equals(s.getMark()))
5543:                                unsplit = true;
5544:                        }
5545:                        if (unsplit)
5546:                            unsplitWindow();
5547:                    }
5548:                } finally {
5549:                    Sidebar.refreshSidebarInAllFrames();
5550:                }
5551:            }
5552:
5553:            public void maybeKillBuffer(Buffer toBeKilled) {
5554:                if (!bufferList.contains(toBeKilled)) {
5555:                    Debug.bug("maybeKillBuffer buffer not in list "
5556:                            + toBeKilled);
5557:                    return;
5558:                }
5559:
5560:                // Don't kill the last buffer if it's a directory.
5561:                if (bufferList.size() == 1 && toBeKilled instanceof  Directory)
5562:                    return;
5563:
5564:                // Cancel background process if any.
5565:                BackgroundProcess backgroundProcess = toBeKilled
5566:                        .getBackgroundProcess();
5567:                if (backgroundProcess != null) {
5568:                    Log
5569:                            .debug("maybeKillBuffer calling backgroundProcess.cancel...");
5570:                    backgroundProcess.cancel();
5571:                    // backgroundProcess.cancel() may have killed the buffer, so
5572:                    // verify that it's still in the list.
5573:                    if (!bufferList.contains(toBeKilled)) {
5574:                        Log
5575:                                .debug("maybeKillBuffer buffer is no longer in list");
5576:                        return;
5577:                    }
5578:                }
5579:
5580:                Mode mode = toBeKilled.getMode();
5581:                if (mode == null || mode.confirmClose(this , toBeKilled))
5582:                    toBeKilled.kill();
5583:            }
5584:
5585:            public void clearStatusText() {
5586:                StatusBar statusBar = getStatusBar();
5587:                if (statusBar != null) {
5588:                    statusBar.setText(null);
5589:                    statusBar.repaint();
5590:                }
5591:            }
5592:
5593:            public void activate(Buffer buf) {
5594:                if (buf == null)
5595:                    return;
5596:                Debug.assertTrue(bufferList.contains(buf));
5597:                if (buf == buffer)
5598:                    return;
5599:                if (!buf.initialized())
5600:                    buf.initialize();
5601:                clearStatusText();
5602:                if (buffer != null && bufferList.contains(buffer)) {
5603:                    // Save information about buffer being deactivated.
5604:                    buffer.autosave();
5605:                    saveView();
5606:                    RecentFiles.getInstance().bufferDeactivated(buffer, dot);
5607:                }
5608:
5609:                // Read-only status may have changed. (We could be switching back from
5610:                // a shell buffer.)
5611:                reactivate(buf);
5612:
5613:                buf.setLastActivated(System.currentTimeMillis());
5614:                if (buf.isLoaded()) {
5615:                    buffer = buf;
5616:                    bufferActivated(false);
5617:                } else {
5618:                    setWaitCursor();
5619:                    int result = LOAD_FAILED;
5620:                    try {
5621:                        result = buf.load();
5622:                    } catch (OutOfMemoryError e) {
5623:                        buf.kill();
5624:                        Sidebar.setUpdateFlagInAllFrames(SIDEBAR_ALL);
5625:                        MessageDialog.showMessageDialog(this ,
5626:                                "Insufficient memory to load buffer", "Error");
5627:                        return;
5628:                    }
5629:                    switch (result) {
5630:                    case LOAD_COMPLETED:
5631:                        buffer = buf;
5632:                        bufferActivated(true);
5633:                        break;
5634:                    case LOAD_PENDING:
5635:                        buffer = buf;
5636:                        buffer.setBusy(true);
5637:                        bufferPending();
5638:                        break;
5639:                    case LOAD_FAILED:
5640:                        setDefaultCursor();
5641:                        buffer = buf;
5642:                        bufferActivated(true);
5643:                        MessageDialog.showMessageDialog(this ,
5644:                                "Unable to load buffer", "Error");
5645:                        break;
5646:                    default:
5647:                        Debug.assertTrue(false);
5648:                    }
5649:                }
5650:            }
5651:
5652:            public Editor activateInOtherWindow(Buffer buf) {
5653:                return frame.activateInOtherWindow(this , buf);
5654:            }
5655:
5656:            public Editor activateInOtherWindow(Buffer buf, float split) {
5657:                return frame.activateInOtherWindow(this , buf, split);
5658:            }
5659:
5660:            public Editor displayInOtherWindow(Buffer buf) {
5661:                return frame.displayInOtherWindow(this , buf);
5662:            }
5663:
5664:            public void bufferActivated(boolean firstTime) {
5665:                if (buffer.getModeId() == IMAGE_MODE) {
5666:                    setDot(null);
5667:                    setMark(null);
5668:                    display.setTopLine(null);
5669:                    display.setShift(0);
5670:                    display.setCaretCol(0);
5671:                } else {
5672:                    findOrCreateView(buffer);
5673:                    restoreView();
5674:
5675:                    // If the buffer has already been loaded, the caret position will
5676:                    // be restored correctly.
5677:                    if (firstTime)
5678:                        moveCaretToDotCol();
5679:                }
5680:
5681:                if (dot != null && dot.getOffset() > dot.getLineLength()) {
5682:                    dot.setOffset(dot.getLineLength());
5683:                    moveCaretToDotCol();
5684:                }
5685:
5686:                frame.updateTitle();
5687:                frame.setMenu();
5688:                frame.setToolbar();
5689:
5690:                if (buffer.isBusy())
5691:                    setWaitCursor();
5692:                else
5693:                    setDefaultCursor();
5694:
5695:                setUpdateFlag(REFRAME);
5696:                reframe();
5697:                setUpdateFlag(REPAINT);
5698:
5699:                RecentFiles.getInstance().bufferActivated(buffer);
5700:
5701:                if (buffer.isTaggable()) {
5702:                    tagFileManager.addToQueue(buffer.getCurrentDirectory(),
5703:                            buffer.getMode());
5704:                }
5705:
5706:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_ALL);
5707:
5708:                if (isLispInitialized()) {
5709:                    if (firstTime)
5710:                        LispAPI.invokeOpenFileHook(buffer);
5711:                    LispAPI.invokeBufferActivatedHook(buffer);
5712:                }
5713:            }
5714:
5715:            private void bufferPending() {
5716:                // Find or create a view of this buffer.
5717:                findOrCreateView(buffer);
5718:                restoreView();
5719:
5720:                frame.updateTitle();
5721:                frame.setMenu();
5722:                frame.setToolbar();
5723:
5724:                display.repaint();
5725:
5726:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_ALL);
5727:                Sidebar sidebar = getSidebar();
5728:                if (sidebar != null)
5729:                    sidebar.setBuffer();
5730:            }
5731:
5732:            // Find or create another frame in which to activate the specified buffer.
5733:            public Editor activateInOtherFrame(Buffer buf) {
5734:                Editor ed = null;
5735:                if (getEditorCount() == 1) {
5736:                    ed = createNewFrame();
5737:                    ed.activate(buf);
5738:                    ed.getFrame().setVisible(true);
5739:                    ed.updateDisplay();
5740:                } else {
5741:                    for (int i = 0; i < getEditorCount(); i++) {
5742:                        ed = getEditor(i);
5743:                        if (ed != this ) {
5744:                            ed.activate(buf);
5745:                            ed.getFrame().toFront();
5746:                            break;
5747:                        }
5748:                    }
5749:                }
5750:                return ed;
5751:            }
5752:
5753:            public void nextFrame() {
5754:                int count = getEditorCount();
5755:                if (count > 1) {
5756:                    Editor ed = null;
5757:                    for (int i = 0; i < count; i++) {
5758:                        ed = Editor.getEditor(i);
5759:                        if (ed == this ) {
5760:                            if (++i == count)
5761:                                i = 0;
5762:                            ed = Editor.getEditor(i);
5763:                            ed.getFrame().toFront();
5764:                            ed.requestFocusLater();
5765:                            break;
5766:                        }
5767:                    }
5768:                }
5769:            }
5770:
5771:            private void requestFocusLater() {
5772:                Runnable r = new Runnable() {
5773:                    public void run() {
5774:                        Editor.this .requestFocus();
5775:                    }
5776:                };
5777:                SwingUtilities.invokeLater(r);
5778:            }
5779:
5780:            public void toggleSidebar() {
5781:                frame.frameToggleSidebar();
5782:            }
5783:
5784:            public void sidebarListBuffers() {
5785:                ensureActive();
5786:
5787:                if (frame.getSidebar() == null)
5788:                    toggleSidebar();
5789:
5790:                if (frame.getSidebar() != null)
5791:                    frame.getSidebar().activateBufferList();
5792:            }
5793:
5794:            public void sidebarListTags() {
5795:                if (!frame.isActive())
5796:                    return;
5797:
5798:                if (getMode().getSidebarComponent(this ) != null) {
5799:                    if (frame.getSidebar() == null)
5800:                        toggleSidebar();
5801:                    if (frame.getSidebar() != null)
5802:                        frame.getSidebar().activateNavigationComponent();
5803:                }
5804:            }
5805:
5806:            public void toggleToolbar() {
5807:                frame.frameToggleToolbar();
5808:            }
5809:
5810:            public final boolean addUndo(int type) {
5811:                return SimpleEdit.addUndo(this , type);
5812:            }
5813:
5814:            public final boolean addUndoDeleteRegion(Region r) {
5815:                buffer.addEdit(new UndoDeleteRegion(this , r));
5816:                return true;
5817:            }
5818:
5819:            public final CompoundEdit beginCompoundEdit() {
5820:                return buffer.beginCompoundEdit();
5821:            }
5822:
5823:            public final void endCompoundEdit(CompoundEdit compoundEdit) {
5824:                buffer.endCompoundEdit(compoundEdit);
5825:            }
5826:
5827:            public void undo() {
5828:                setWaitCursor();
5829:                try {
5830:                    buffer.lockWrite();
5831:                } catch (InterruptedException e) {
5832:                    Log.error(e);
5833:                    return;
5834:                }
5835:                try {
5836:                    buffer.undo();
5837:                    checkDotInOtherFrames();
5838:                    setCurrentCommand(COMMAND_UNDO);
5839:                } catch (Throwable t) {
5840:                    Log.error(t);
5841:                } finally {
5842:                    buffer.unlockWrite();
5843:                    setDefaultCursor();
5844:                }
5845:            }
5846:
5847:            public void redo() {
5848:                setWaitCursor();
5849:                try {
5850:                    buffer.lockWrite();
5851:                } catch (InterruptedException e) {
5852:                    Log.error(e);
5853:                    return;
5854:                }
5855:                try {
5856:                    buffer.redo();
5857:                    checkDotInOtherFrames();
5858:                } catch (Throwable t) {
5859:                    Log.error(t);
5860:                } finally {
5861:                    buffer.unlockWrite();
5862:                    setDefaultCursor();
5863:                }
5864:            }
5865:
5866:            private void checkDotInOtherFrames() {
5867:                if (getEditorCount() > 1) {
5868:                    for (int i = 0; i < getEditorCount(); i++) {
5869:                        Editor ed = getEditor(i);
5870:                        if (ed != this  && ed.getBuffer() == buffer) {
5871:                            if (ed.getDotOffset() > ed.getDotLine().length()) {
5872:                                ed.getDot().setOffset(ed.getDotLine().length());
5873:                                ed.moveCaretToDotCol();
5874:                                ed.updateDotLine();
5875:                            }
5876:                        }
5877:                    }
5878:                }
5879:            }
5880:
5881:            public final void jumpToLine(int lineNumber) {
5882:                jumpToLine(lineNumber, 0);
5883:            }
5884:
5885:            public void jumpToLine(int lineNumber, int offset) {
5886:                Line line = buffer.getLine(lineNumber);
5887:                if (line != null) {
5888:                    if (offset < 0)
5889:                        offset = 0;
5890:                    else if (offset > line.length())
5891:                        offset = line.length();
5892:                    moveDotTo(line, offset);
5893:                    setUpdateFlag(REFRAME);
5894:                } else
5895:                    eob();
5896:            }
5897:
5898:            public void offset() {
5899:                status(String.valueOf(buffer.getAbsoluteOffset(dot)));
5900:            }
5901:
5902:            public void executeCommand() {
5903:                // Use location bar.
5904:                locationBar.setLabelText(LocationBar.PROMPT_COMMAND);
5905:                HistoryTextField textField = locationBar.getTextField();
5906:                textField.setHandler(new ExecuteCommandTextFieldHandler(this ,
5907:                        textField));
5908:                textField.setHistory(new History("executeCommand.input", 30));
5909:                textField.recallLast();
5910:                textField.selectAll();
5911:                AWTEvent e = dispatcher.getLastEvent();
5912:                if (e != null && e.getSource() instanceof  MenuItem) {
5913:                    Runnable r = new Runnable() {
5914:                        public void run() {
5915:                            setFocusToTextField();
5916:                        }
5917:                    };
5918:                    SwingUtilities.invokeLater(r);
5919:                } else
5920:                    setFocusToTextField();
5921:            }
5922:
5923:            public void executeCommand(String input) {
5924:                executeCommand(input, false);
5925:            }
5926:
5927:            public void executeCommand(String input, final boolean interactive) {
5928:                input = Utilities.trimLeading(input);
5929:                if (input.length() == 0)
5930:                    return;
5931:                if (input.charAt(0) == '(') {
5932:                    // Lisp form.
5933:                    try {
5934:                        String result = String.valueOf(Interpreter
5935:                                .evaluate(input));
5936:                        if (interactive)
5937:                            status(result);
5938:                    } catch (Throwable t) {
5939:                        String message = null;
5940:                        if (t instanceof  ConditionThrowable) {
5941:                            LispObject obj = ((ConditionThrowable) t)
5942:                                    .getCondition();
5943:                            if (obj instanceof  Condition) {
5944:                                try {
5945:                                    message = ((Condition) obj)
5946:                                            .getConditionReport();
5947:                                } catch (Throwable ignored) {
5948:                                    // At least we tried.
5949:                                }
5950:                            }
5951:                        }
5952:                        if (message == null || message.length() == 0)
5953:                            message = t.getMessage();
5954:                        if (message != null && message.length() > 0) {
5955:                            FastStringBuffer sb = new FastStringBuffer(message);
5956:                            sb
5957:                                    .setCharAt(0, Character.toUpperCase(sb
5958:                                            .charAt(0)));
5959:                            message = sb.toString();
5960:                        } else
5961:                            message = String.valueOf(t);
5962:                        MessageDialog.showMessageDialog(this , message, "Error");
5963:                    }
5964:                    return;
5965:                }
5966:                int index = input.indexOf('=');
5967:                if (index >= 0) {
5968:                    String key = input.substring(0, index).trim();
5969:                    if (key.indexOf(' ') < 0 && key.indexOf('\t') < 0) {
5970:                        String value = input.substring(index + 1).trim();
5971:                        setProperty(key, value);
5972:                        return;
5973:                    }
5974:                }
5975:                String[] array = parseCommand(input);
5976:                if (array != null) {
5977:                    final String command = array[0];
5978:                    final String parameters = array[1];
5979:                    Runnable r = new Runnable() {
5980:                        public void run() {
5981:                            try {
5982:                                StatusBar statusBar = getStatusBar();
5983:                                statusBar.setText("");
5984:                                execute(command, parameters);
5985:                                if (interactive && parameters == null) {
5986:                                    // Suggest key binding if one is available.
5987:                                    Object[] values = getKeyMapping(command);
5988:                                    Debug.assertTrue(values != null);
5989:                                    Debug.assertTrue(values.length == 2);
5990:                                    KeyMapping mapping = (KeyMapping) values[0];
5991:                                    Mode mode = (Mode) values[1];
5992:                                    if (mapping != null) {
5993:                                        String statusText = statusBar.getText();
5994:                                        boolean append = statusText != null
5995:                                                && statusText.length() > 0;
5996:                                        FastStringBuffer sb = new FastStringBuffer();
5997:                                        if (append) {
5998:                                            sb.append(statusText);
5999:                                            sb.append("          ");
6000:                                        }
6001:                                        sb.append(command);
6002:                                        sb.append(" is mapped to ");
6003:                                        sb.append(mapping.getKeyText());
6004:                                        if (mode != null) {
6005:                                            sb.append(" (");
6006:                                            sb.append(mode);
6007:                                            sb.append(" mode)");
6008:                                        } else
6009:                                            sb.append(" (global mapping)");
6010:                                        status(sb.toString());
6011:                                    }
6012:                                }
6013:                            } catch (NoSuchMethodException e) {
6014:                                FastStringBuffer sb = new FastStringBuffer(
6015:                                        "Unknown command \"");
6016:                                sb.append(command);
6017:                                sb.append('"');
6018:                                MessageDialog.showMessageDialog(Editor.this , sb
6019:                                        .toString(), "Error");
6020:                            }
6021:                        }
6022:                    };
6023:                    if (SwingUtilities.isEventDispatchThread()) {
6024:                        r.run();
6025:                    } else {
6026:                        try {
6027:                            SwingUtilities.invokeAndWait(r);
6028:                        } catch (Throwable t) {
6029:                            Log.debug(t);
6030:                        }
6031:                    }
6032:                }
6033:            }
6034:
6035:            private static String[] parseCommand(String command) {
6036:                command = Utilities.trimLeading(command);
6037:                // Command name is terminated by whitespace or '('.
6038:                char delimiter = '\0';
6039:                int index = -1;
6040:                int commandLength = command.length();
6041:                for (int i = 0; i < commandLength; i++) {
6042:                    char c = command.charAt(i);
6043:                    if (c == '(' || Character.isWhitespace(c)) {
6044:                        delimiter = c;
6045:                        index = i;
6046:                        break;
6047:                    }
6048:                }
6049:                String methodName, parameters;
6050:                if (index < 0) {
6051:                    methodName = command;
6052:                    parameters = null;
6053:                } else {
6054:                    methodName = command.substring(0, index);
6055:                    parameters = Utilities
6056:                            .trimLeading(command.substring(index));
6057:                    if (delimiter != '(') {
6058:                        if (parameters.startsWith("("))
6059:                            delimiter = '(';
6060:                    }
6061:                    if (delimiter == '(') {
6062:                        // Strip parens.
6063:                        int length = parameters.length();
6064:                        if (length < 2)
6065:                            return null; // Error.
6066:                        if (parameters.charAt(length - 1) != ')')
6067:                            return null; // Error.
6068:                        parameters = parameters.substring(1, length - 1).trim();
6069:                        length = parameters.length();
6070:                        if (length == 0)
6071:                            parameters = null;
6072:                        else {
6073:                            // Strip required quotes.
6074:                            if (length < 2)
6075:                                return null; // Error.
6076:                            if (parameters.charAt(0) != '"'
6077:                                    || parameters.charAt(length - 1) != '"')
6078:                                return null; // Error.
6079:                            parameters = parameters.substring(1, length - 1); // Done.
6080:                        }
6081:                    }
6082:                }
6083:                String[] array = new String[2];
6084:                array[0] = methodName;
6085:                array[1] = parameters;
6086:                return array;
6087:            }
6088:
6089:            // Set a buffer-specific property.
6090:            private void setProperty(String key, String value) {
6091:                Property property = Property.findProperty(key);
6092:                if (property == null) {
6093:                    MessageDialog.showMessageDialog("Property \"" + key
6094:                            + "\" not found", "Error");
6095:                    return;
6096:                }
6097:                final boolean succeeded;
6098:                if (value.length() == 0) {
6099:                    succeeded = buffer.removeProperty(property);
6100:                } else {
6101:                    succeeded = buffer.setPropertyFromString(property, value);
6102:                    if (!succeeded)
6103:                        invalidPropertyValue(property, value);
6104:                }
6105:                if (succeeded)
6106:                    buffer.saveProperties();
6107:            }
6108:
6109:            // No error checking.
6110:            public static void setGlobalProperty(String key, String value) {
6111:                if (value == null || value.length() == 0)
6112:                    prefs.removeProperty(key);
6113:                else
6114:                    prefs.setProperty(key, value);
6115:            }
6116:
6117:            private void invalidPropertyValue(Property property, String value) {
6118:                if (property.isIntegerProperty())
6119:                    status("Invalid integer value \"" + value + "\"");
6120:                else if (property.isBooleanProperty())
6121:                    status("Invalid boolean value \"" + value + "\"");
6122:            }
6123:
6124:            public void slideIn() {
6125:                slide(buffer.getIndentSize());
6126:            }
6127:
6128:            public void slideOut() {
6129:                slide(-buffer.getIndentSize());
6130:            }
6131:
6132:            private void slide(int amount) {
6133:                if (!checkReadOnly())
6134:                    return;
6135:                Region r = mark != null ? new Region(this ) : null;
6136:                if (r != null
6137:                        && (r.getBeginOffset() != 0 || r.getEndOffset() != 0))
6138:                    return; // If a block is marked, it must be a block of full lines.
6139:                try {
6140:                    buffer.lockWrite();
6141:                } catch (InterruptedException e) {
6142:                    Log.error(e);
6143:                    return;
6144:                }
6145:                try {
6146:                    if (r == null) {
6147:                        CompoundEdit compoundEdit = beginCompoundEdit();
6148:                        int dotCol = getDotCol();
6149:                        int oldIndent = buffer.getIndentation(getDotLine());
6150:                        int newIndent = oldIndent + amount;
6151:                        addUndo(SimpleEdit.LINE_EDIT);
6152:                        buffer.setIndentation(getDotLine(), newIndent);
6153:                        updateInAllEditors(getDotLine());
6154:                        if (dotCol < oldIndent) {
6155:                            // Caret was originally in indentation area. Move caret to
6156:                            // start of text. This ensures that the caret is on an
6157:                            // actual character, in case the indentation got entabbed.
6158:                            moveDotToCol(newIndent);
6159:                        } else {
6160:                            // Move caret with text.
6161:                            display.setCaretCol(display.getCaretCol() + amount);
6162:                            moveDotToCaretCol();
6163:                        }
6164:                        endCompoundEdit(compoundEdit);
6165:                        buffer.modified();
6166:                    } else {
6167:                        // If a block is marked, it must be a block of full lines.
6168:                        CompoundEdit compoundEdit = beginCompoundEdit();
6169:                        Position saved = new Position(dot);
6170:                        Line line = r.getBeginLine();
6171:                        while (line != r.getEndLine()) {
6172:                            addUndo(SimpleEdit.MOVE);
6173:                            dot.moveTo(line, 0);
6174:                            addUndo(SimpleEdit.LINE_EDIT);
6175:                            buffer.setIndentation(getDotLine(), buffer
6176:                                    .getIndentation(getDotLine())
6177:                                    + amount);
6178:                            updateInAllEditors(getDotLine());
6179:                            line = line.next();
6180:                        }
6181:                        addUndo(SimpleEdit.MOVE);
6182:                        dot = saved;
6183:                        endCompoundEdit(compoundEdit);
6184:                        buffer.modified();
6185:                    }
6186:                } finally {
6187:                    buffer.unlockWrite();
6188:                }
6189:            }
6190:
6191:            public void dirHome() {
6192:                if (buffer instanceof  Directory)
6193:                    ((Directory) buffer).home();
6194:            }
6195:
6196:            public void dirTagFile() {
6197:                if (buffer instanceof  Directory)
6198:                    ((Directory) buffer).tagFileAtDot();
6199:            }
6200:
6201:            public void dirBrowseFile() {
6202:                if (buffer instanceof  Directory && !buffer.getFile().isRemote()) {
6203:                    Directory d = (Directory) buffer;
6204:                    d.browseFileAtDot();
6205:                }
6206:            }
6207:
6208:            public void dirDeleteFiles() {
6209:                if (mark != null && getMarkLine() != getDotLine()) {
6210:                    MessageDialog
6211:                            .showMessageDialog(
6212:                                    this ,
6213:                                    "This operation is not supported with multi-line text selections.",
6214:                                    "Delete Files");
6215:                    return;
6216:                }
6217:                if (buffer instanceof  Directory) {
6218:                    if (buffer.getFile() instanceof  SshFile) {
6219:                        MessageDialog
6220:                                .showMessageDialog(
6221:                                        this ,
6222:                                        "Deletions are not yet supported in ssh directory buffers.",
6223:                                        "Error");
6224:                        return;
6225:                    }
6226:                    ((Directory) buffer).deleteFiles();
6227:                }
6228:            }
6229:
6230:            public void dirCopyFile() {
6231:                if (buffer instanceof  Directory && buffer.getFile().isLocal())
6232:                    ((Directory) buffer).copyFileAtDot();
6233:            }
6234:
6235:            public void dirGetFile() {
6236:                if (buffer instanceof  Directory
6237:                        && buffer.getFile() instanceof  FtpFile)
6238:                    ((Directory) buffer).getFileAtDot();
6239:            }
6240:
6241:            public void dirMoveFile() {
6242:                if (buffer instanceof  Directory && buffer.getFile().isLocal())
6243:                    ((Directory) buffer).moveFileAtDot();
6244:            }
6245:
6246:            public void dirRescan() {
6247:                if (buffer instanceof  Directory) {
6248:                    setWaitCursor();
6249:                    ((Directory) buffer).rescan();
6250:                    setDefaultCursor();
6251:                }
6252:            }
6253:
6254:            public void dirHomeDir() {
6255:                File homeDir = File.getInstance(Utilities.getUserHome());
6256:                if (buffer instanceof  Directory) {
6257:                    if (!buffer.getFile().equals(homeDir))
6258:                        ((Directory) buffer).changeDirectory(homeDir);
6259:                } else {
6260:                    Buffer buf = getBuffer(homeDir);
6261:                    if (buf != null) {
6262:                        makeNext(buf);
6263:                        activate(buf);
6264:                    }
6265:                }
6266:            }
6267:
6268:            public void dirUpDir() {
6269:                if (buffer instanceof  Directory)
6270:                    ((Directory) buffer).upDir();
6271:            }
6272:
6273:            public void setFocusToTextField() {
6274:                frame.setFocus(locationBar.getTextField());
6275:            }
6276:
6277:            public void wrapRegion() {
6278:                if (!checkReadOnly())
6279:                    return;
6280:                if (dot == null || mark == null)
6281:                    return;
6282:                // Must be line block.
6283:                if (dot.getOffset() != 0 || mark.getOffset() != 0)
6284:                    return;
6285:                new WrapText(this ).wrapRegion();
6286:            }
6287:
6288:            public void wrapParagraph() {
6289:                if (!checkReadOnly())
6290:                    return;
6291:                new WrapText(this ).wrapParagraph();
6292:            }
6293:
6294:            public void unwrapParagraph() {
6295:                if (!checkReadOnly())
6296:                    return;
6297:                new WrapText(this ).unwrapParagraph();
6298:            }
6299:
6300:            public void wrapParagraphsInRegion() {
6301:                if (!checkReadOnly())
6302:                    return;
6303:                new WrapText(this ).wrapParagraphsInRegion();
6304:            }
6305:
6306:            public void visibleTabs() {
6307:                tabsAreVisible = !tabsAreVisible;
6308:                if (tabsAreVisible)
6309:                    status("Tabs are visible");
6310:                else
6311:                    status("Tabs are not visible");
6312:                for (int i = 0; i < getEditorCount(); i++) {
6313:                    Editor ed = getEditor(i);
6314:                    ed.getDisplay().repaint();
6315:                }
6316:            }
6317:
6318:            public void insertBraces() {
6319:                CompoundEdit compoundEdit = beginCompoundEdit();
6320:                insertChar('{');
6321:                indentLine();
6322:                eol();
6323:                newlineAndIndent();
6324:                insertChar('}');
6325:                indentLine();
6326:                up();
6327:                eol();
6328:                newlineAndIndent();
6329:                endCompoundEdit(compoundEdit);
6330:            }
6331:
6332:            public void insertParentheses() {
6333:                if (!checkReadOnly())
6334:                    return;
6335:                boolean parensRequireSpaces = buffer
6336:                        .getBooleanProperty(Property.PARENS_REQUIRE_SPACES);
6337:                CompoundEdit compoundEdit = beginCompoundEdit();
6338:                if (mark != null) {
6339:                    Position begin, end;
6340:                    if (mark.isBefore(dot)) {
6341:                        begin = new Position(mark);
6342:                        end = new Position(dot);
6343:                    } else {
6344:                        begin = new Position(dot);
6345:                        end = new Position(mark);
6346:                    }
6347:                    addUndo(SimpleEdit.MOVE);
6348:                    setMark(null);
6349:                    dot.moveTo(end);
6350:                    if (parensRequireSpaces)
6351:                        insertChar(' ');
6352:                    insertChar(')');
6353:                    addUndo(SimpleEdit.MOVE);
6354:                    dot.moveTo(begin);
6355:                    insertChar('(');
6356:                    if (parensRequireSpaces)
6357:                        insertChar(' ');
6358:                } else {
6359:                    fillToCaret();
6360:                    addUndo(SimpleEdit.INSERT_STRING);
6361:                    insertStringInternal(parensRequireSpaces ? "(  )" : "()");
6362:                    addUndo(SimpleEdit.MOVE);
6363:                    dot.skip(parensRequireSpaces ? -2 : -1);
6364:                }
6365:                moveCaretToDotCol();
6366:                endCompoundEdit(compoundEdit);
6367:            }
6368:
6369:            public void movePastCloseAndReindent() {
6370:                Position pos = new Position(dot);
6371:                int count = 1;
6372:                while (pos.next()) {
6373:                    char c = pos.getChar();
6374:                    if (c == '(')
6375:                        ++count;
6376:                    else if (c == ')')
6377:                        --count;
6378:                    if (count == 0)
6379:                        break;
6380:                }
6381:                if (count == 0) {
6382:                    pos.next();
6383:                    updateDotLine();
6384:                    CompoundEdit compoundEdit = beginCompoundEdit();
6385:                    addUndo(SimpleEdit.MOVE);
6386:                    dot.moveTo(pos);
6387:                    updateDotLine();
6388:                    newlineAndIndent();
6389:                    endCompoundEdit(compoundEdit);
6390:                }
6391:            }
6392:
6393:            public final void updateDotLine() {
6394:                display.lineChanged(dot.getLine());
6395:            }
6396:
6397:            // Adds line to changed line list of current frame only.
6398:            public final void update(Line line) {
6399:                display.lineChanged(line);
6400:            }
6401:
6402:            /**
6403:             * Adds line to changed line list of all editors in which the current
6404:             * buffer is displayed.
6405:             *
6406:             * @param line      the line
6407:             */
6408:            public static void updateInAllEditors(Line line) {
6409:                if (line != null) {
6410:                    for (EditorIterator it = new EditorIterator(); it.hasNext();) {
6411:                        Editor ed = it.nextEditor();
6412:                        if (ed.getBuffer() == currentEditor.getBuffer())
6413:                            ed.getDisplay().lineChanged(line);
6414:                    }
6415:                }
6416:            }
6417:
6418:            /**
6419:             * Adds line to changed line list of all editors in which the specified
6420:             * buffer is displayed.
6421:             *
6422:             * @param buffer    the buffer
6423:             * @param line      the line
6424:             */
6425:            public static void updateInAllEditors(Buffer buffer, Line line) {
6426:                if (line != null) {
6427:                    for (EditorIterator it = new EditorIterator(); it.hasNext();) {
6428:                        Editor ed = it.nextEditor();
6429:                        if (ed.getBuffer() == buffer)
6430:                            ed.getDisplay().lineChanged(line);
6431:                    }
6432:                }
6433:            }
6434:
6435:            public void updateScrollBars() {
6436:                if (buffer == null)
6437:                    return; // Avoid NPE.
6438:                if (!displayReady)
6439:                    return;
6440:                updateVerticalScrollBar();
6441:                updateHorizontalScrollBar();
6442:            }
6443:
6444:            boolean inScrollBarUpdate = false;
6445:
6446:            public void updateVerticalScrollBar() {
6447:                if (verticalScrollBar != null) {
6448:                    inScrollBarUpdate = true;
6449:                    int y;
6450:                    if (getTopLine() != null)
6451:                        y = buffer.getY(getTopLine())
6452:                                + display.getPixelsAboveTopLine();
6453:                    else
6454:                        y = display.getPixelsAboveTopLine();
6455:                    verticalScrollBar.setValues(y, display.getHeight(), 0,
6456:                            buffer.getDisplayHeight());
6457:                    inScrollBarUpdate = false;
6458:                }
6459:            }
6460:
6461:            public void updateHorizontalScrollBar() {
6462:                if (horizontalScrollBar != null)
6463:                    horizontalScrollBar.setValues(display.getShift()
6464:                            * Display.getCharWidth(), display.getWidth(), 0,
6465:                            buffer.getDisplayWidth());
6466:            }
6467:
6468:            public void updateDisplay() {
6469:                if (dot != null) {
6470:                    if (dot.isHidden()) {
6471:                        buffer.appendUndoFold(this );
6472:                        show(getDotLine());
6473:                    }
6474:                    reframe();
6475:                }
6476:                display.repaintChangedLines();
6477:                updateScrollBars();
6478:                Sidebar sidebar = getSidebar();
6479:                if (sidebar != null)
6480:                    sidebar.setUpdateFlag(SIDEBAR_POSITION);
6481:                frame.repaintStatusBar();
6482:                if (buffer.isBusy())
6483:                    setWaitCursor();
6484:                else
6485:                    setDefaultCursor();
6486:            }
6487:
6488:            public void updateDisplayLater() {
6489:                Runnable r = new Runnable() {
6490:                    public void run() {
6491:                        updateDisplay();
6492:                    }
6493:                };
6494:                SwingUtilities.invokeLater(r);
6495:            }
6496:
6497:            // Update display of buf in all windows showing it.
6498:            public static void updateDisplayLater(final Buffer buf) {
6499:                Runnable r = new Runnable() {
6500:                    public void run() {
6501:                        for (int i = 0; i < getEditorCount(); i++) {
6502:                            Editor ed = getEditor(i);
6503:                            if (ed.getBuffer() == buf)
6504:                                ed.updateDisplay();
6505:                        }
6506:                    }
6507:                };
6508:                SwingUtilities.invokeLater(r);
6509:            }
6510:
6511:            public final Line getTopLine() {
6512:                return display.getTopLine();
6513:            }
6514:
6515:            public final void setTopLine(Line line) {
6516:                display.setTopLine(line);
6517:            }
6518:
6519:            public final void setUpdateFlag(int mask) {
6520:                display.setUpdateFlag(mask);
6521:            }
6522:
6523:            public final void reframe() {
6524:                display.reframe();
6525:            }
6526:
6527:            public boolean checkReadOnly() {
6528:                boolean readOnly = buffer.isReadOnly();
6529:                if (readOnly
6530:                        && buffer.getBooleanProperty(Property.P4_AUTO_EDIT)) {
6531:                    if (buffer.getType() == Buffer.TYPE_NORMAL) {
6532:                        File file = buffer.getFile();
6533:                        if (file != null && file.isLocal() && file.isFile())
6534:                            if (P4.autoEdit(this ))
6535:                                readOnly = buffer.isReadOnly();
6536:                    }
6537:                }
6538:                if (readOnly) {
6539:                    status("Buffer is read only");
6540:                    return false;
6541:                }
6542:                if (buffer.isLocked())
6543:                    return false;
6544:                if (dot == null)
6545:                    return false;
6546:                return true;
6547:            }
6548:
6549:            public static boolean checkExperimental() {
6550:                return prefs
6551:                        .getBooleanProperty(Property.ENABLE_EXPERIMENTAL_FEATURES);
6552:            }
6553:
6554:            public void status(String s) {
6555:                frame.setStatusText(s);
6556:            }
6557:
6558:            private static boolean displayReady;
6559:
6560:            public static final boolean displayReady() {
6561:                return displayReady;
6562:            }
6563:
6564:            public static final void setDisplayReady(boolean b) {
6565:                displayReady = b;
6566:            }
6567:
6568:            private static final Cursor waitCursor = Cursor
6569:                    .getPredefinedCursor(Cursor.WAIT_CURSOR);
6570:
6571:            public final void setWaitCursor() {
6572:                display.setCursor(waitCursor);
6573:            }
6574:
6575:            public final void setDefaultCursor() {
6576:                final Cursor cursor;
6577:                if (displayReady && buffer != null)
6578:                    cursor = buffer.getDefaultCursor();
6579:                else
6580:                    cursor = waitCursor;
6581:                display.setCursor(cursor);
6582:            }
6583:
6584:            public final void setCursor(Cursor cursor) {
6585:                display.setCursor(cursor);
6586:            }
6587:
6588:            public static void loadPreferences() {
6589:                prefs.reload();
6590:                debug = prefs.getBooleanProperty(Property.DEBUG);
6591:            }
6592:
6593:            private boolean insertingKeyText = false;
6594:
6595:            public void insertKeyText() {
6596:                if (!checkReadOnly())
6597:                    return;
6598:                insertingKeyText = true; // The real work is done in handleKeyEvent.
6599:            }
6600:
6601:            private void insertKeyTextInternal(char keyChar, int keyCode,
6602:                    int modifiers) {
6603:                Log.debug("keycode = 0x" + Integer.toString(keyCode, 16));
6604:                Log.debug("modifiers = 0x" + Integer.toString(modifiers, 16));
6605:                Log.debug("character = " + String.valueOf(keyChar));
6606:                Log.debug("character = 0x"
6607:                        + Integer.toString((int) keyChar, 16));
6608:
6609:                insertingKeyText = false;
6610:
6611:                try {
6612:                    buffer.lockWrite();
6613:                } catch (InterruptedException e) {
6614:                    Log.error(e);
6615:                    return;
6616:                }
6617:                try {
6618:                    KeyMapping km;
6619:                    if (keyCode != 0)
6620:                        km = new KeyMapping(keyCode, modifiers, null);
6621:                    else
6622:                        km = new KeyMapping(keyChar, null);
6623:
6624:                    CompoundEdit compoundEdit = beginCompoundEdit();
6625:                    if (mark != null)
6626:                        delete();
6627:                    fillToCaret();
6628:                    addUndo(SimpleEdit.INSERT_STRING);
6629:                    insertStringInternal(km.toString());
6630:                    buffer.modified();
6631:                    moveCaretToDotCol();
6632:                    endCompoundEdit(compoundEdit);
6633:                } finally {
6634:                    buffer.unlockWrite();
6635:                }
6636:            }
6637:
6638:            public void whatChar() {
6639:                if (dot.getOffset() < dot.getLineLength()) {
6640:                    char c = getDotChar();
6641:                    FastStringBuffer sb = new FastStringBuffer(Integer
6642:                            .toString(c));
6643:                    sb.append("  0x");
6644:                    sb.append(Integer.toHexString(c));
6645:                    if (c >= ' ' && c < 0x7f) {
6646:                        sb.append("  '");
6647:                        if (c == '\'')
6648:                            sb.append('\\');
6649:                        sb.append(c);
6650:                        sb.append('\'');
6651:                    }
6652:                    status(sb.toString());
6653:                }
6654:            }
6655:
6656:            public void jmips() {
6657:                setWaitCursor();
6658:                long loopsPerSecond = 0;
6659:                long loops = 1;
6660:                Thread thread = Thread.currentThread();
6661:                int oldPriority = thread.getPriority();
6662:                thread.setPriority(Thread.MAX_PRIORITY);
6663:                do {
6664:                    long start = System.currentTimeMillis();
6665:                    for (long i = loops; i >= 0; i--)
6666:                        ;
6667:                    long elapsed = System.currentTimeMillis() - start;
6668:                    if (elapsed >= 1000) {
6669:                        loopsPerSecond = (loops / elapsed) * 1000;
6670:                        break;
6671:                    }
6672:                    loops *= 2;
6673:                } while (true);
6674:                thread.setPriority(oldPriority);
6675:                String s = String.valueOf(((float) loopsPerSecond) / 500000);
6676:                currentEditor.status(s);
6677:                setDefaultCursor();
6678:            }
6679:
6680:            public void httpDeleteCookies() {
6681:                Cookie.deleteCookies();
6682:            }
6683:
6684:            private static Class extensionClass = null;
6685:
6686:            private static void loadExtensions() {
6687:                String extension = prefs.getStringProperty(Property.EXTENSION);
6688:                if (extension != null) {
6689:                    Log.debug("loading extension " + extension);
6690:                    try {
6691:                        ExtensionClassLoader loader = new ExtensionClassLoader();
6692:                        extensionClass = loader.loadClass(extension, true);
6693:                        if (extensionClass != null) {
6694:                            Method method = extensionClass.getMethod("run",
6695:                                    new Class[0]);
6696:                            if (method != null)
6697:                                method.invoke(extensionClass.newInstance(),
6698:                                        new Class[0]);
6699:                        } else
6700:                            Log.error("extension " + extension + " not found");
6701:                    } catch (Exception e) {
6702:                        Log.error(e);
6703:                    }
6704:                }
6705:            }
6706:
6707:            private static Class loadExtensionClass(String className) {
6708:                Class c = null;
6709:                try {
6710:                    ExtensionClassLoader loader = new ExtensionClassLoader();
6711:                    c = loader.loadClass(className, true);
6712:                } catch (Exception e) {
6713:                    Log.error(e);
6714:                }
6715:                return c;
6716:            }
6717:
6718:            private static void runStartupScript() {
6719:                File file = File.getInstance(Directories.getEditorDirectory(),
6720:                        "init.lisp");
6721:                if (file != null && file.isFile()) {
6722:                    try {
6723:                        long start = System.currentTimeMillis();
6724:                        JLisp.runStartupScript(file);
6725:                        long elapsed = System.currentTimeMillis() - start;
6726:                        FastStringBuffer sb = new FastStringBuffer("loaded ");
6727:                        sb.append(file.canonicalPath());
6728:                        sb.append(" (");
6729:                        sb.append(elapsed);
6730:                        sb.append(" ms)");
6731:                        Log.info(sb.toString());
6732:                    } catch (Throwable t) {
6733:                        Log.error(t);
6734:                        Log.error("error loading " + file.canonicalPath());
6735:                    }
6736:                }
6737:            }
6738:
6739:            public static void runLispCommand(String command) {
6740:                try {
6741:                    JLisp.runLispCommand(command);
6742:                } catch (Throwable t) {
6743:                    Log.error(t);
6744:                }
6745:            }
6746:
6747:            private static boolean isLispInitialized;
6748:
6749:            public static synchronized boolean isLispInitialized() {
6750:                return isLispInitialized;
6751:            }
6752:
6753:            public static synchronized void setLispInitialized(boolean b) {
6754:                isLispInitialized = b;
6755:            }
6756:
6757:            public static void invokeHook(String hook) {
6758:                invokeHook(hook, null);
6759:            }
6760:
6761:            public static void invokeHook(String hook, String args) {
6762:                FastStringBuffer sb = new FastStringBuffer("(invoke-hook '");
6763:                sb.append(hook);
6764:                if (args != null && args.length() > 0) {
6765:                    sb.append(' ');
6766:                    sb.append(args);
6767:                }
6768:                sb.append(')');
6769:                runLispCommand(sb.toString());
6770:            }
6771:
6772:            public void mode() {
6773:                String modeName = InputDialog.showInputDialog(this ,
6774:                        "New mode:", "Change Mode");
6775:                if (modeName != null) {
6776:                    modeName = modeName.trim();
6777:                    if (modeName.length() > 0) {
6778:                        repaintNow();
6779:                        mode(modeName);
6780:                    }
6781:                }
6782:            }
6783:
6784:            public void mode(String modeName) {
6785:                int modeId = getModeList().getModeIdFromModeName(modeName);
6786:                if (modeId < 0) {
6787:                    MessageDialog.showMessageDialog("Unknown mode \""
6788:                            + modeName + '"', "Error");
6789:                } else if (modeId != buffer.getMode().getId()) {
6790:                    if (buffer.isModified() && modeId == BINARY_MODE) {
6791:                        String prompt = "Buffer will be reloaded in binary mode; discard changes?";
6792:                        if (!confirm("Change Mode", prompt))
6793:                            return;
6794:                    }
6795:                    Mode mode = getModeList().getMode(modeId);
6796:                    if (mode != null) {
6797:                        setWaitCursor();
6798:                        buffer.changeMode(mode);
6799:                        buffer.saveProperties();
6800:                        setDefaultCursor();
6801:                    }
6802:                }
6803:            }
6804:
6805:            public void defaultMode() {
6806:                Mode mode = buffer.getDefaultMode();
6807:                if (mode != null && mode != buffer.getMode()) {
6808:                    if (buffer.isModified()) {
6809:                        FastStringBuffer sb = new FastStringBuffer(
6810:                                "Buffer will be reloaded in ");
6811:                        sb.append(mode.toString());
6812:                        sb.append(" mode; discard changes?");
6813:                        if (!confirm("Change Mode", sb.toString()))
6814:                            return;
6815:                    }
6816:                    setWaitCursor();
6817:                    buffer.changeMode(mode);
6818:                    setDefaultCursor();
6819:                }
6820:            }
6821:
6822:            public void textMode() {
6823:                if (buffer.getModeId() == BINARY_MODE) {
6824:                    if (buffer.isModified()) {
6825:                        String prompt = "Buffer will be reloaded in text mode; discard changes?";
6826:                        if (!confirm("Change Mode", prompt))
6827:                            return;
6828:                    }
6829:                    setWaitCursor();
6830:                    buffer.changeMode(modeList.getMode(PLAIN_TEXT_MODE));
6831:                    setDefaultCursor();
6832:                }
6833:            }
6834:
6835:            public void splitWindow() {
6836:                currentEditor.getFrame().splitWindow();
6837:            }
6838:
6839:            public void unsplitWindow() {
6840:                IdleThread.killFollowContextTask();
6841:                frame.unsplitWindow();
6842:            }
6843:
6844:            public void killWindow() {
6845:                frame.unsplitWindowKeepOther();
6846:                Sidebar sidebar = getSidebar();
6847:                if (sidebar != null) {
6848:                    sidebar.setUpdateFlag(SIDEBAR_ALL);
6849:                    sidebar.refreshSidebar();
6850:                }
6851:            }
6852:
6853:            public void otherWindow() {
6854:                final Editor ed = frame.getOtherEditor();
6855:                if (ed != null) {
6856:                    saveView();
6857:                    setCurrentEditor(ed);
6858:                    ed.getBuffer().setLastActivated(System.currentTimeMillis());
6859:                    ed.setFocusToDisplay();
6860:                    if (ed.getDot() != null) {
6861:                        ed.update(ed.getDotLine());
6862:                        ed.getDisplay().repaintChangedLines();
6863:                    }
6864:                    if (dot != null) {
6865:                        updateDotLine();
6866:                        display.repaintChangedLines();
6867:                    }
6868:                    frame.setMenu();
6869:                    frame.setToolbar();
6870:                    Sidebar sidebar = getSidebar();
6871:                    if (sidebar != null) {
6872:                        sidebar.setUpdateFlag(SIDEBAR_ALL);
6873:                        sidebar.refreshSidebar();
6874:                    }
6875:                }
6876:            }
6877:
6878:            public void fold() {
6879:                if (dot == null)
6880:                    return;
6881:                if (!foldRegionInternal() && !foldExplicit())
6882:                    foldNearLine(getDotLine());
6883:            }
6884:
6885:            public void foldRegion() {
6886:                if (dot == null)
6887:                    return;
6888:                foldRegionInternal();
6889:            }
6890:
6891:            private boolean foldRegionInternal() {
6892:                if (mark == null)
6893:                    return false;
6894:                if (dot.getLine() == mark.getLine())
6895:                    return false;
6896:                if (dot.getOffset() > 0)
6897:                    return false;
6898:                if (mark.getOffset() > 0)
6899:                    return false;
6900:                Region r = new Region(buffer, mark, dot);
6901:                Line begin = r.getBegin().getLine().next();
6902:                Line end = r.getEnd().getLine();
6903:                addUndo(SimpleEdit.FOLD);
6904:                setMark(null);
6905:                for (Line line = begin; line != end; line = line.next())
6906:                    line.hide();
6907:                buffer.renumber();
6908:                unhideDotInAllFrames(buffer);
6909:                return true;
6910:            }
6911:
6912:            private boolean foldExplicit() {
6913:                final Line dotLine = getDotLine();
6914:                String text = dotLine.getText();
6915:                Line begin = null;
6916:                Line end = null;
6917:                if (text.indexOf(EXPLICIT_FOLD_END) >= 0) {
6918:                    // Current line contains an end marker.
6919:                    int count = 1;
6920:                    end = dotLine.next();
6921:                    begin = dotLine.previous();
6922:                    while (begin != null) {
6923:                        text = begin.getText();
6924:                        if (text.indexOf(EXPLICIT_FOLD_START) >= 0) {
6925:                            --count;
6926:                            if (count == 0) {
6927:                                begin = begin.next();
6928:                                break;
6929:                            }
6930:                        } else if (text.indexOf(EXPLICIT_FOLD_END) >= 0) {
6931:                            ++count;
6932:                        }
6933:                        begin = begin.previous();
6934:                    }
6935:                } else if (text.indexOf(EXPLICIT_FOLD_START) >= 0) {
6936:                    int count = 1;
6937:                    begin = dotLine.next();
6938:                    if (begin == null)
6939:                        return false;
6940:                    end = begin.next();
6941:                    while (end != null) {
6942:                        text = end.getText();
6943:                        if (text.indexOf(EXPLICIT_FOLD_START) >= 0) {
6944:                            ++count;
6945:                        } else if (text.indexOf(EXPLICIT_FOLD_END) >= 0) {
6946:                            --count;
6947:                            if (count == 0) {
6948:                                end = end.next();
6949:                                break;
6950:                            }
6951:                        }
6952:                        end = end.next();
6953:                    }
6954:                }
6955:                if (begin == null)
6956:                    return false;
6957:                addUndo(SimpleEdit.FOLD);
6958:                for (Line line = begin; line != end; line = line.next())
6959:                    line.hide();
6960:                buffer.renumber();
6961:                unhideDotInAllFrames(buffer);
6962:                return true;
6963:            }
6964:
6965:            public void foldNearLine(Line line) {
6966:                while (line != null && line.isBlank())
6967:                    line = line.previous();
6968:                if (line == null)
6969:                    return;
6970:                setWaitCursor();
6971:                Line next = line.next();
6972:                while (next != null && next.isBlank())
6973:                    next = next.next();
6974:                if (next != null) {
6975:                    final String trim = line.trim();
6976:                    switch (getModeId()) {
6977:                    case JAVA_MODE:
6978:                    case JAVASCRIPT_MODE:
6979:                    case C_MODE:
6980:                    case CPP_MODE:
6981:                    case PERL_MODE:
6982:                    case PHP_MODE:
6983:                        if (trim.endsWith("{")) {
6984:                            if (!next.isHidden()) {
6985:                                fold(next);
6986:                                return;
6987:                            }
6988:                        }
6989:                        if (trim.startsWith("}")) {
6990:                            // We're at the end of a code block. Find the start of
6991:                            // the block and fold from there.
6992:                            Position end = new Position(line, line.getText()
6993:                                    .indexOf('}'));
6994:                            Position start = findMatchInternal(end, 0);
6995:                            if (start != null) {
6996:                                foldNearLine(start.getLine());
6997:                                return;
6998:                            }
6999:                        }
7000:                        if (next.trim().startsWith("}")) {
7001:                            // Fold block containing current line.
7002:                            Position end = new Position(next, next.getText()
7003:                                    .indexOf('}'));
7004:                            Position start = findMatchInternal(end, 0);
7005:                            if (start != null) {
7006:                                foldNearLine(start.getLine());
7007:                                return;
7008:                            }
7009:                        } else if (next.trim().endsWith("{")) {
7010:                            Line nextNext = next.next();
7011:                            while (nextNext != null && nextNext.isBlank())
7012:                                nextNext = nextNext.next();
7013:                            if (nextNext != null && !nextNext.isHidden()) {
7014:                                fold(nextNext);
7015:                                return;
7016:                            }
7017:                        }
7018:                        break;
7019:                    case XML_MODE: {
7020:                        if (trim.startsWith("/>") || trim.startsWith("</")) {
7021:                            Line prev = line.previous();
7022:                            while (prev != null && prev.isBlank())
7023:                                prev = prev.previous();
7024:                            if (prev != null) {
7025:                                int indent = buffer.getCol(line, line
7026:                                        .getIndentation());
7027:                                int prevIndent = buffer.getCol(prev, prev
7028:                                        .getIndentation());
7029:                                if (indent < prevIndent) {
7030:                                    fold(prev);
7031:                                    return;
7032:                                }
7033:                            }
7034:                        } else if (trim.startsWith("<")) {
7035:                            int indent = buffer.getCol(line, line
7036:                                    .getIndentation());
7037:                            int nextIndent = buffer.getCol(next, next
7038:                                    .getIndentation());
7039:                            if (indent < nextIndent) {
7040:                                fold(next);
7041:                                return;
7042:                            }
7043:                        }
7044:                    }
7045:                    default:
7046:                        break;
7047:                    }
7048:                }
7049:                fold(line);
7050:            }
7051:
7052:            private void fold(Line target) {
7053:                if (target == null)
7054:                    return;
7055:                int indent = buffer.getCol(target, target.getIndentation());
7056:                if (indent == 0)
7057:                    return;
7058:                Line begin = target;
7059:                while (true) {
7060:                    Line prev = begin.previous();
7061:                    if (prev == null)
7062:                        break;
7063:                    if (prev.isBlank() || getMode().isCommentLine(prev)
7064:                            || isLabelLine(prev) || isPreprocessorLine(prev)) {
7065:                        begin = prev;
7066:                        continue;
7067:                    }
7068:                    if (buffer.getCol(prev, prev.getIndentation()) < indent)
7069:                        break;
7070:                    if (prev.getText().endsWith("{"))
7071:                        break;
7072:                    begin = prev;
7073:                }
7074:                Line end = target.next();
7075:                while (end != null) {
7076:                    if (end.isBlank() || getMode().isCommentLine(end)
7077:                            || isLabelLine(end) || isPreprocessorLine(end)) {
7078:                        end = end.next();
7079:                        continue;
7080:                    }
7081:                    if (buffer.getCol(end, end.getIndentation()) < indent)
7082:                        break;
7083:                    end = end.next();
7084:                }
7085:                addUndo(SimpleEdit.FOLD);
7086:                for (Line line = begin; line != end; line = line.next())
7087:                    line.hide();
7088:                buffer.renumber();
7089:                unhideDotInAllFrames(buffer);
7090:            }
7091:
7092:            private static RE labelRE = new UncheckedRE("^\\s*\\w+:");
7093:
7094:            private boolean isLabelLine(Line line) {
7095:                Mode mode = getMode();
7096:                if (mode instanceof  JavaMode || mode instanceof  PerlMode)
7097:                    return labelRE.getMatch(line.getText()) != null;
7098:                return false;
7099:            }
7100:
7101:            private boolean isPreprocessorLine(Line line) {
7102:                if (getMode() instanceof  CMode)
7103:                    if (line.trim().startsWith("#"))
7104:                        return true;
7105:
7106:                return false;
7107:            }
7108:
7109:            // BUG! This method does more than its name suggests...
7110:            public static void unhideDotInAllFrames(Buffer buffer) {
7111:                for (int i = 0; i < Editor.getEditorCount(); i++) {
7112:                    Editor ed = Editor.getEditor(i);
7113:                    if (ed.getBuffer() == buffer) {
7114:                        // Make sure dot is visible.
7115:                        if (ed.getDot().isHidden()) {
7116:                            ed.setMark(null);
7117:                            Line line = ed.getDotLine().previousVisible();
7118:                            if (line != null) {
7119:                                ed.setDot(line, 0);
7120:                                ed.moveCaretToDotCol();
7121:                            }
7122:                        }
7123:                        ed.setUpdateFlag(REFRAME);
7124:                        ed.reframe();
7125:                        ed.getDisplay().repaint();
7126:                    }
7127:                }
7128:            }
7129:
7130:            public void unfold() {
7131:                if (dot == null)
7132:                    return;
7133:                Line dotLine = getDotLine();
7134:                Line begin = null;
7135:                if (dotLine.isHidden()) {
7136:                    begin = dotLine;
7137:                    while (begin.previous() != null
7138:                            && begin.previous().isHidden())
7139:                        begin = begin.previous();
7140:                } else {
7141:                    // Look for next fold.
7142:                    begin = dotLine.next();
7143:                    while (begin != null && !begin.isHidden())
7144:                        begin = begin.next();
7145:                }
7146:                if (begin == null)
7147:                    return;
7148:                if (!begin.isHidden())
7149:                    return;
7150:                Line end = begin;
7151:                while (true) {
7152:                    Line line = end.next();
7153:                    if (line == null)
7154:                        break;
7155:                    if (!line.isHidden())
7156:                        break;
7157:                    end = line;
7158:                }
7159:                if (begin != null && end != null) {
7160:                    addUndo(SimpleEdit.FOLD);
7161:                    for (Line line = begin; line != end.next(); line = line
7162:                            .next())
7163:                        line.unhide();
7164:                    buffer.renumber();
7165:                    for (int i = 0; i < Editor.getEditorCount(); i++) {
7166:                        Editor ed = Editor.getEditor(i);
7167:                        if (ed.getBuffer() == buffer)
7168:                            ed.getDisplay().repaint();
7169:                    }
7170:                }
7171:            }
7172:
7173:            public void unfold(Line line) {
7174:                if (line == null)
7175:                    return;
7176:                if (!line.isHidden())
7177:                    return;
7178:                Line begin = line;
7179:                while (begin.previous() != null && begin.previous().isHidden())
7180:                    begin = begin.previous();
7181:                Line end = line.next();
7182:                while (end != null && end.isHidden())
7183:                    end = end.next();
7184:                addUndo(SimpleEdit.FOLD);
7185:                for (Line l = begin; l != end; l = l.next())
7186:                    l.unhide();
7187:                buffer.renumber();
7188:                for (int i = 0; i < Editor.getEditorCount(); i++) {
7189:                    Editor ed = Editor.getEditor(i);
7190:                    if (ed.getBuffer() == buffer)
7191:                        ed.getDisplay().repaint();
7192:                }
7193:            }
7194:
7195:            private void show(Line target) {
7196:                if (target == null)
7197:                    return;
7198:                if (!target.isHidden())
7199:                    return;
7200:                Line begin = target;
7201:                while (begin.previous() != null && begin.previous().isHidden())
7202:                    begin = begin.previous();
7203:                Line end = target.next();
7204:                while (end != null && end.isHidden())
7205:                    end = end.next();
7206:                for (Line line = begin; line != end; line = line.next())
7207:                    line.show();
7208:                buffer.renumber();
7209:                for (int i = 0; i < Editor.getEditorCount(); i++) {
7210:                    Editor ed = Editor.getEditor(i);
7211:                    if (ed.getBuffer() == buffer)
7212:                        ed.getDisplay().repaint();
7213:                }
7214:            }
7215:
7216:            public void unfoldAll() {
7217:                addUndo(SimpleEdit.FOLD);
7218:                for (Line line = buffer.getFirstLine(); line != null; line = line
7219:                        .next())
7220:                    line.show();
7221:                buffer.renumber();
7222:                for (int i = 0; i < Editor.getEditorCount(); i++) {
7223:                    Editor ed = Editor.getEditor(i);
7224:                    if (ed.getBuffer() == buffer)
7225:                        ed.getDisplay().repaint();
7226:                }
7227:            }
7228:
7229:            public void foldMethods() {
7230:                Mode mode = getMode();
7231:                if (mode instanceof  JavaMode || mode instanceof  PerlMode) {
7232:                    setWaitCursor();
7233:                    List tags = buffer.getTags();
7234:                    if (tags != null) {
7235:                        addUndo(SimpleEdit.FOLD);
7236:                        for (Line line = buffer.getFirstLine(); line != null; line = line
7237:                                .next())
7238:                            line.show();
7239:                        for (int i = 0; i < tags.size(); i++) {
7240:                            LocalTag tag = (LocalTag) tags.get(i);
7241:                            if (tag.getType() == TAG_METHOD)
7242:                                foldMethod(tag.getLine());
7243:                        }
7244:                        unhideDotInAllFrames(buffer);
7245:                    }
7246:                }
7247:            }
7248:
7249:            private final void foldMethod(Line line) {
7250:                foldOrUnfoldMethod(line, true);
7251:            }
7252:
7253:            public final void unfoldMethod(Line line) {
7254:                foldOrUnfoldMethod(line, false);
7255:            }
7256:
7257:            private void foldOrUnfoldMethod(Line line, boolean fold) {
7258:                Mode mode = getMode();
7259:                while (line != null) {
7260:                    String s = line.trim();
7261:                    if (mode instanceof  PerlMode)
7262:                        s = PerlMode.trimSyntacticWhitespace(s);
7263:                    else if (mode instanceof  JavaMode)
7264:                        s = JavaMode.trimSyntacticWhitespace(s);
7265:                    if (s.endsWith("{"))
7266:                        break;
7267:                    line = line.next();
7268:                }
7269:                if (line == null)
7270:                    return;
7271:                if (line.next() == null)
7272:                    return; // Nothing to fold.
7273:                Position start = new Position(line, line.length());
7274:                Line begin = line.next();
7275:                final SyntaxIterator it = mode.getSyntaxIterator(start);
7276:                Position match = null;
7277:                int count = 1;
7278:                while (true) {
7279:                    char c = it.nextChar();
7280:                    if (c == SyntaxIterator.DONE)
7281:                        break;
7282:                    if (c == '{')
7283:                        ++count;
7284:                    else if (c == '}')
7285:                        --count;
7286:                    if (count == 0) {
7287:                        // Found it!
7288:                        match = it.getPosition();
7289:                        break;
7290:                    }
7291:                }
7292:                if (match == null)
7293:                    return;
7294:                Line end = match.getLine();
7295:                if (fold) {
7296:                    for (Line toBeHidden = begin; toBeHidden != end
7297:                            && toBeHidden != null; toBeHidden = toBeHidden
7298:                            .next())
7299:                        toBeHidden.hide();
7300:                } else {
7301:                    for (Line toBeShown = begin; toBeShown != end
7302:                            && toBeShown != null; toBeShown = toBeShown.next())
7303:                        toBeShown.show();
7304:                }
7305:                buffer.needsRenumbering = true;
7306:            }
7307:
7308:            private static Aliases aliases;
7309:
7310:            private static final Aliases getAliases() {
7311:                if (aliases == null)
7312:                    aliases = new Aliases();
7313:                return aliases;
7314:            }
7315:
7316:            public static final File getAliasesFile() {
7317:                return aliases != null ? aliases.getFile() : null;
7318:            }
7319:
7320:            public static final void reloadAliases() {
7321:                if (aliases != null)
7322:                    aliases.reload();
7323:            }
7324:
7325:            public final String getAlias(String alias) {
7326:                return getAliases().get(alias);
7327:            }
7328:
7329:            public final void setAlias(String alias, String value) {
7330:                getAliases().setAlias(alias, value);
7331:            }
7332:
7333:            public final void setAliasForBuffer(String alias, Buffer buf) {
7334:                getAliases().setAliasForBuffer(alias, buf);
7335:            }
7336:
7337:            public final void removeAlias(String alias) {
7338:                getAliases().remove(alias);
7339:            }
7340:
7341:            public void setEncoding() {
7342:                File file = buffer.getFile();
7343:                if (file != null) {
7344:                    InputDialog d = new InputDialog(this , "Encoding:",
7345:                            "Set Encoding", buffer.getSaveEncoding());
7346:                    d.setHistory(new History("setEncoding"));
7347:                    centerDialog(d);
7348:                    d.show();
7349:                    String encoding = d.getInput();
7350:                    if (encoding != null)
7351:                        setEncoding(encoding);
7352:                }
7353:            }
7354:
7355:            public void setEncoding(String encoding) {
7356:                File file = buffer.getFile();
7357:                if (file != null) {
7358:                    if (Utilities.isSupportedEncoding(encoding)) {
7359:                        file.setEncoding(encoding);
7360:                        buffer.saveProperties();
7361:                    } else {
7362:                        FastStringBuffer sb = new FastStringBuffer(
7363:                                "Unsupported encoding \"");
7364:                        sb.append(encoding);
7365:                        sb.append('"');
7366:                        MessageDialog.showMessageDialog(this , sb.toString(),
7367:                                "Error");
7368:                    }
7369:                }
7370:            }
7371:
7372:            private static final ArrayList protectList = new ArrayList();
7373:
7374:            // Add reference to global list to protect obj from garbage collection.
7375:            public static synchronized void protect(Object obj) {
7376:                protectList.add(obj);
7377:            }
7378:
7379:            private static String sessionName;
7380:
7381:            /**
7382:             * Returns the name of the active named session (if any).
7383:             *
7384:             * @return  the name of the active named session, or <code>null</code> if
7385:             *          there is no named session.
7386:             */
7387:            public static String getSessionName() {
7388:                return sessionName;
7389:            }
7390:
7391:            /**
7392:             * Sets the name of the active named session.
7393:             *
7394:             * @param name      the name of the session
7395:             * @see             Session#loadSession
7396:             * @see             Session#saveSession
7397:             */
7398:            public static void setSessionName(String name) {
7399:                sessionName = name;
7400:                // The session name is displayed in the frame's title bar.
7401:                for (int i = 0; i < getFrameCount(); i++) {
7402:                    Frame frame = getFrame(i);
7403:                    if (frame != null)
7404:                        frame.titleChanged();
7405:                }
7406:            }
7407:
7408:            // Position stack.
7409:            private static Stack positionStack = new Stack();
7410:
7411:            public static List getPositionStack() {
7412:                return positionStack;
7413:            }
7414:
7415:            public void pushPosition() {
7416:                if (buffer.getFile() != null) {
7417:                    pushMarker(new Marker(buffer, dot));
7418:                    status("Position saved");
7419:                }
7420:            }
7421:
7422:            public void popPosition() {
7423:                if (positionStack.empty()) {
7424:                    status("Position stack is empty");
7425:                } else {
7426:                    Marker m = (Marker) positionStack.pop();
7427:                    if (m != null)
7428:                        m.gotoMarker(this );
7429:                }
7430:            }
7431:
7432:            public static void pushMarker(Marker m) {
7433:                while (positionStack.size() >= 30)
7434:                    positionStack.removeElementAt(0);
7435:                positionStack.push(m);
7436:            }
7437:
7438:            public static void resetDisplay() {
7439:                if (!displayReady())
7440:                    return;
7441:                // Force formatters to be re-initialized.
7442:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
7443:                    Buffer buf = it.nextBuffer();
7444:                    if (buf.getFormatter() != null)
7445:                        buf.getFormatter().reset();
7446:                }
7447:                Display.initializeStaticValues();
7448:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
7449:                    Display display = it.nextEditor().getDisplay();
7450:                    display.initialize();
7451:                    display.repaint();
7452:                }
7453:                Editor.restoreFocus();
7454:            }
7455:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.