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

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


0001:        // Copyright (c) 2000, 2005 BlueJ Group, Deakin University
0002:        //
0003:        // This software is made available under the terms of the "MIT License"
0004:        // A copy of this license is included with this source distribution
0005:        // in "license.txt" and is also available at:
0006:        // http://www.opensource.org/licenses/mit-license.html 
0007:        // Any queries should be directed to Michael Kolling mik@bluej.org
0008:
0009:        package bluej.editor.moe;
0010:
0011:        import java.awt.*;
0012:        import java.awt.event.ActionEvent;
0013:        import java.awt.event.WindowAdapter;
0014:        import java.awt.event.WindowEvent;
0015:        import java.awt.print.PageFormat;
0016:        import java.awt.print.PrinterJob;
0017:        import java.beans.PropertyChangeEvent;
0018:        import java.beans.PropertyChangeListener;
0019:        import java.io.*;
0020:        import java.net.URL;
0021:        import java.util.ArrayList;
0022:        import java.util.HashMap;
0023:        import java.util.List;
0024:        import java.util.Properties;
0025:        import java.util.StringTokenizer;
0026:
0027:        import javax.swing.*;
0028:        import javax.swing.border.EmptyBorder;
0029:        import javax.swing.event.*;
0030:        import javax.swing.text.AbstractDocument;
0031:        import javax.swing.text.BadLocationException;
0032:        import javax.swing.text.Caret;
0033:        import javax.swing.text.Element;
0034:        import javax.swing.text.SimpleAttributeSet;
0035:        import javax.swing.text.html.HTMLDocument;
0036:        import javax.swing.text.html.HTMLEditorKit;
0037:        import javax.swing.text.html.HTMLFrameHyperlinkEvent;
0038:
0039:        import org.syntax.jedit.tokenmarker.JavaTokenMarker;
0040:
0041:        import bluej.BlueJEvent;
0042:        import bluej.BlueJEventListener;
0043:        import bluej.Config;
0044:        import bluej.editor.EditorWatcher;
0045:        import bluej.editor.LineColumn;
0046:        import bluej.pkgmgr.PkgMgrFrame;
0047:        import bluej.prefmgr.PrefMgr;
0048:        import bluej.utility.Debug;
0049:        import bluej.utility.DialogManager;
0050:        import bluej.utility.FileUtility;
0051:        import bluej.utility.Utility;
0052:
0053:        /**
0054:         * Moe is the editor of the BlueJ environment. This class is the main class of
0055:         * this editor and implements the top-level functionality.
0056:         * 
0057:         * MoeEditor implements the Editor interface, which defines the interface to the
0058:         * rest of the BlueJ system.
0059:         * 
0060:         * @author Michael Kolling
0061:         * @author Bruce Quig
0062:         * @author Damiano Bolla
0063:         */
0064:
0065:        public final class MoeEditor extends JFrame implements 
0066:                bluej.editor.Editor, BlueJEventListener, HyperlinkListener,
0067:                DocumentListener {
0068:            // -------- CONSTANTS --------
0069:
0070:            // version number
0071:            final static int version = 200;
0072:            final static String versionString = "2.0";
0073:
0074:            // colours
0075:            final static Color cursorColor = new Color(255, 0, 100); // cursor
0076:
0077:            final static Color frameBgColor = new Color(196, 196, 196);
0078:            final static Color infoColor = new Color(240, 240, 240);
0079:            final static Color lightGrey = new Color(224, 224, 224);
0080:            final static Color selectionColour = Config.getSelectionColour();
0081:            final static Color titleCol = Config
0082:                    .getItemColour("colour.text.fg");
0083:            final static Color envOpColour = Config
0084:                    .getItemColour("colour.menu.environOp");
0085:
0086:            // Icons
0087:            final static Image iconImage = Config.getImageAsIcon(
0088:                    "image.icon.editor").getImage();
0089:
0090:            // Fonts
0091:            public static int printFontSize = Config.getPropInteger(
0092:                    "bluej.fontsize.printText", 10);
0093:            public static Font printFont = new Font("Monospaced", Font.PLAIN,
0094:                    printFontSize);
0095:
0096:            // Strings
0097:            String implementationString = Config
0098:                    .getString("editor.implementationLabel");
0099:            String interfaceString = Config.getString("editor.interfaceLabel");
0100:
0101:            // suffixes for resources
0102:            final static String LabelSuffix = "Label";
0103:            final static String ActionSuffix = "Action";
0104:            final static String TooltipSuffix = "Tooltip";
0105:            final static String AcceleratorSuffix = "Accelerator";
0106:
0107:            // file suffixes
0108:            final static String CRASHFILE_SUFFIX = "#";
0109:            final static String BACKUP_SUFFIX = "~";
0110:
0111:            final static String spaces = "    ";
0112:
0113:            final static String COMPILED = "compiled";
0114:
0115:            private static boolean matchBrackets = false;
0116:
0117:            // -------- INSTANCE VARIABLES --------
0118:
0119:            private EditorWatcher watcher;
0120:            private Properties resources;
0121:
0122:            private AbstractDocument document;
0123:            private MoeSyntaxDocument sourceDocument;
0124:            private HTMLDocument htmlDocument;
0125:
0126:            private MoeActions actions;
0127:            public MoeUndoManager undoManager;
0128:
0129:            JEditorPane currentTextPane; // text component currently dislayed
0130:            private JEditorPane sourcePane; // the component holding the source text
0131:
0132:            private JEditorPane htmlPane; // the component holding the javadoc html
0133:            private MoeCaret moeCaret;
0134:
0135:            private Info info; // the info number label
0136:            private JPanel statusArea; // the status area
0137:            private StatusLabel saveState; // the status label
0138:            private JComboBox interfaceToggle;
0139:            private GoToLineDialog goToLineDialog;
0140:
0141:            private JScrollPane scrollPane;
0142:            private JComponent toolbar; // The toolbar
0143:
0144:            private String filename; // name of file or null
0145:            private long lastModified; // time of last modification of file
0146:            private String windowTitle; // title of editor window
0147:            private String docFilename; // path to javadoc html file
0148:
0149:            private boolean sourceIsCode; // true if current buffer is code
0150:            private boolean viewingHTML;
0151:
0152:            private int currentStepPos; // position of step mark (or -1)
0153:            private boolean mayHaveBreakpoints; // true if there were BP here
0154:            private boolean ignoreChanges = false;
0155:            private boolean tabsAreExpanded = false;
0156:
0157:            private MoePrinter printer;
0158:
0159:            private TextInsertNotifier doTextInsert = new TextInsertNotifier();
0160:
0161:            /**
0162:             * Property map, allows BlueJ extensions to assosciate property values with
0163:             * this editor instance; otherwise unused.
0164:             */
0165:            private HashMap propertyMap = new HashMap();
0166:
0167:            /**
0168:             * Constructor. Title may be null
0169:             */
0170:            public MoeEditor(String title, boolean isCode,
0171:                    EditorWatcher watcher, boolean showToolbar,
0172:                    boolean showLineNum, Properties resources) {
0173:                super ("Moe");
0174:                this .watcher = watcher;
0175:                this .resources = resources;
0176:
0177:                filename = null;
0178:                windowTitle = title;
0179:                sourceIsCode = isCode;
0180:                viewingHTML = false;
0181:                currentStepPos = -1;
0182:                mayHaveBreakpoints = false;
0183:                matchBrackets = PrefMgr.getFlag(PrefMgr.MATCH_BRACKETS);
0184:                undoManager = new MoeUndoManager(this );
0185:
0186:                initWindow();
0187:            }
0188:
0189:            // --------------------------------------------------------------------
0190:
0191:            /**
0192:             * Update the state of controls bound to "undo".
0193:             */
0194:            public void updateUndoControls() {
0195:                actions.setUndoEnabled(undoManager.canUndo());
0196:            }
0197:
0198:            /**
0199:             * Update the state of controls bound to "redo".
0200:             */
0201:            public void updateRedoControls() {
0202:                actions.setRedoEnabled(undoManager.canRedo());
0203:            }
0204:
0205:            /**
0206:             * Load the file "filename" and show the editor window.
0207:             */
0208:            public boolean showFile(String filename, boolean compiled, // inherited from Editor, redefined
0209:                    String docFilename, Rectangle bounds) {
0210:                this .filename = filename;
0211:                this .docFilename = docFilename;
0212:
0213:                if (bounds != null) {
0214:                    setBounds(bounds);
0215:                }
0216:
0217:                boolean loaded = false;
0218:                boolean readError = false;
0219:
0220:                if (filename != null) {
0221:
0222:                    try {
0223:                        // check for crash file
0224:                        String crashFilename = filename + CRASHFILE_SUFFIX;
0225:                        String backupFilename = crashFilename + "backup";
0226:                        File crashFile = new File(crashFilename);
0227:                        if (crashFile.exists()) {
0228:                            File backupFile = new File(backupFilename);
0229:                            backupFile.delete();
0230:                            crashFile.renameTo(backupFile);
0231:                            DialogManager.showMessage(this , "editor-crashed");
0232:                        }
0233:
0234:                        FileReader reader = new FileReader(filename);
0235:                        sourcePane.read(reader, null);
0236:                        reader.close();
0237:                        File file = new File(filename);
0238:                        lastModified = file.lastModified();
0239:
0240:                        sourceDocument = (MoeSyntaxDocument) sourcePane
0241:                                .getDocument();
0242:
0243:                        // set TokenMarker for syntax highlighting if desired
0244:                        checkSyntaxStatus();
0245:
0246:                        sourceDocument.addDocumentListener(this );
0247:                        sourceDocument.addUndoableEditListener(undoManager);
0248:                        document = sourceDocument;
0249:                        loaded = true;
0250:                    } catch (FileNotFoundException ex) {
0251:                        clear();
0252:                    } catch (IOException ex) {
0253:                        readError = true;
0254:                    }
0255:                }
0256:
0257:                if (!loaded) // should exist, but didn't
0258:                    return false;
0259:
0260:                //     if (loaded) ## NYI
0261:                //       if (newFile.canWrite()) { // have write permission
0262:                // 	  save_state = Saved;
0263:                // 	  statusLabel.setText("saved");
0264:                //       }
0265:                //       else {
0266:                // 	  save_state = ReadOnly;
0267:                // 	  statusLabel.setText("read only");
0268:                //       }
0269:                //     else
0270:                //       save_state = Saved;
0271:
0272:                if (loaded)
0273:                    info.message(Config.getString("editor.info.version") + " "
0274:                            + versionString);
0275:                else if (readError)
0276:                    info.warning(
0277:                            Config.getString("editor.info.readingProblem"),
0278:                            Config.getString("editor.info.regularFile"));
0279:                else
0280:                    info.message(Config.getString("editor.info.version"
0281:                            + versionString), Config
0282:                            .getString("editor.info.newFile"));
0283:
0284:                setWindowTitle();
0285:                sourcePane.setFont(PrefMgr.getStandardEditorFont());
0286:                sourcePane.setSelectionColor(selectionColour);
0287:
0288:                setCompileStatus(compiled);
0289:
0290:                return true;
0291:            }
0292:
0293:            /**
0294:             * Reload the editor content from the associated file, discarding unsaved
0295:             * edits.
0296:             */
0297:            public void reloadFile() // inherited from Editor, redefined
0298:            {
0299:                doReload();
0300:            }
0301:
0302:            /**
0303:             * Wipe out contents of the editor.
0304:             */
0305:            public void clear() // inherited from Editor, redefined
0306:            {
0307:                ignoreChanges = true;
0308:                sourcePane.setText("");
0309:                ignoreChanges = false;
0310:            }
0311:
0312:            /**
0313:             * Insert a string into the buffer. The editor is not immediately
0314:             * redisplayed. This function is typically used in a sequence "clear;
0315:             * [insertText]*; setVisible(true)". If the selection is on, it is replaced
0316:             * by the new text.
0317:             * 
0318:             * @param text  the text to be inserted
0319:             * @param caretBack  move the caret to the beginning of the inserted text
0320:             */
0321:            public void insertText(String text, boolean caretBack) // inherited from Editor, redefined
0322:            {
0323:                sourcePane.replaceSelection(text);
0324:                if (caretBack) {
0325:                    sourcePane.setCaretPosition(sourcePane.getCaretPosition()
0326:                            - text.length());
0327:                }
0328:            }
0329:
0330:            /**
0331:             * Show the editor window. This includes whatever is necessary of the
0332:             * following: make visible, de-iconify, bring to front of window stack.
0333:             * 
0334:             * @param vis  The new visible value
0335:             */
0336:            public void setVisible(boolean vis) // inherited from Editor, redefined
0337:            {
0338:                if (vis) {
0339:                    sourcePane.setFont(PrefMgr.getStandardEditorFont());
0340:                    checkSyntaxStatus();
0341:                    checkBracketStatus();
0342:                    setState(Frame.NORMAL); // de-iconify
0343:                    toFront(); // window to front
0344:                }
0345:                Utility.bringToFront();
0346:                super .setVisible(vis); // show the window
0347:            }
0348:
0349:            /**
0350:             * Refresh the editor window.
0351:             */
0352:            public void refresh() // inherited from Editor, redefined
0353:            {
0354:                sourcePane.setFont(PrefMgr.getStandardEditorFont());
0355:                checkBracketStatus();
0356:                checkSyntaxStatus();
0357:                currentTextPane.repaint();
0358:            }
0359:
0360:            /**
0361:             * True is the editor is on screen.
0362:             * 
0363:             * @return The showing value
0364:             */
0365:            public boolean isShowing() // inherited from Editor, redefined
0366:            {
0367:                if (isVisible() != super .isShowing()) {
0368:                    Debug.message("isVisible is not isShowing!");
0369:                }
0370:                return super .isShowing();
0371:            }
0372:
0373:            /**
0374:             * Save the buffer to disk under current filename. This is often called from
0375:             * the outside - just in case. Save only if really necessary, otherwise we
0376:             * save much too often. PRE: filename != null
0377:             */
0378:            public void save() // inherited from Editor, redefined
0379:                    throws IOException {
0380:                IOException failureException = null;
0381:                if (saveState.isChanged()) {
0382:                    BufferedWriter writer = null;
0383:                    try {
0384:                        // The crash file is used during writing and will remain in
0385:                        // case of a crash during the write operation. The backup
0386:                        // file always contains the last version.
0387:                        String crashFilename = filename + CRASHFILE_SUFFIX;
0388:                        String backupFilename = filename + BACKUP_SUFFIX;
0389:
0390:                        // make a backup to the crash file
0391:                        FileUtility.copyFile(filename, crashFilename);
0392:
0393:                        writer = new BufferedWriter(new FileWriter(filename));
0394:                        sourcePane.write(writer);
0395:                        writer.close();
0396:                        setSaved();
0397:                        File file = new File(filename);
0398:                        lastModified = file.lastModified();
0399:
0400:                        if (PrefMgr.getFlag(PrefMgr.MAKE_BACKUP)) {
0401:                            // if all went well, rename the crash file as a normal
0402:                            // backup
0403:                            File crashFile = new File(crashFilename);
0404:                            File backupFile = new File(backupFilename);
0405:                            backupFile.delete();
0406:                            crashFile.renameTo(backupFile);
0407:                        } else {
0408:                            File crashFile = new File(crashFilename);
0409:                            crashFile.delete();
0410:                        }
0411:                    } catch (IOException ex) {
0412:                        failureException = ex;
0413:                        info.warning(Config
0414:                                .getString("editor.info.errorSaving")
0415:                                + " - " + ex.getLocalizedMessage());
0416:                    } finally {
0417:                        try {
0418:                            if (writer != null)
0419:                                writer.close();
0420:                        } catch (IOException ex) {
0421:                            failureException = ex;
0422:                        }
0423:                    }
0424:                }
0425:
0426:                // If an error occurred, set a message in the editor status bar, and
0427:                // re-throw the exception.
0428:                if (failureException != null) {
0429:                    info.warning(Config.getString("editor.info.errorSaving")
0430:                            + " - " + failureException.getLocalizedMessage());
0431:                    throw failureException;
0432:                }
0433:            }
0434:
0435:            /**
0436:             * The editor wants to close. Do this through the EditorManager so that we
0437:             * can be removed from the list of open editors.
0438:             */
0439:            public void close() // inherited from Editor, redefined
0440:            {
0441:                try {
0442:                    save();
0443:                } catch (IOException ioe) {
0444:                }
0445:                // temporary - should really be done by watcher from outside
0446:                doClose();
0447:            }
0448:
0449:            /**
0450:             * Display a message (used for compile/runtime errors). An editor must
0451:             * support at least two lines of message text, so the message can contain a
0452:             * newline character.
0453:             * 
0454:             * @param message  the message to be displayed
0455:             * @param lineNumber  The line to highlight
0456:             * @param column   the column to move the cursor to
0457:             * @param beep   if true, do a system beep
0458:             * @param setStepMark  if true, set step mark (for single stepping)
0459:             * @param help  name of help group (may be null)
0460:             */
0461:            public void displayMessage(String message, int lineNumber,
0462:                    int column, boolean beep, boolean setStepMark, String help) // inherited from Editor
0463:            {
0464:                switchToSourceView();
0465:
0466:                Element line = getLine(lineNumber);
0467:                int pos = line.getStartOffset();
0468:
0469:                if (setStepMark) {
0470:                    setStepMark(pos);
0471:                }
0472:
0473:                // highlight the line
0474:
0475:                sourcePane.setCaretPosition(pos);
0476:                sourcePane.moveCaretPosition(line.getEndOffset() - 1);
0477:                moeCaret.setPersistentHighlight();
0478:                // w/o line break
0479:
0480:                // display the message
0481:
0482:                if (beep)
0483:                    info.warning(message);
0484:                else
0485:                    info.message(message);
0486:
0487:                if (help != null)
0488:                    info.setHelp(help);
0489:            }
0490:
0491:            /**
0492:             * Set the selection of the editor to be a len characters on the line
0493:             * lineNumber, starting with column columnNumber
0494:             * 
0495:             * @param lineNumber  the line to select characters on
0496:             * @param columnNumber  the column to start selection at (1st column is 1 - not 0)
0497:             * @param len         the number of characters to select
0498:             */
0499:            public void setSelection(int lineNumber, int columnNumber, int len) {
0500:                Element line = getLine(lineNumber);
0501:
0502:                sourcePane.select(line.getStartOffset() + columnNumber - 1,
0503:                        line.getStartOffset() + columnNumber + len - 1);
0504:            }
0505:
0506:            /**
0507:             * Select a specified area of text.
0508:             * 
0509:             * @param lineNumber1  The new selection value
0510:             * @param columnNumber1  The new selection value
0511:             * @param lineNumber2  The new selection value
0512:             * @param columnNumber2  The new selection value
0513:             */
0514:            public void setSelection(int lineNumber1, int columnNumber1,
0515:                    int lineNumber2, int columnNumber2) {
0516:                /*
0517:                 * if (lineNumber2 < lineNumber1) return; if (lineNumber2 == lineNumber1 &&
0518:                 * (columnNumber2 < columnNumber1)) return;
0519:                 */
0520:                Element line1 = getLine(lineNumber1);
0521:                Element line2 = getLine(lineNumber2);
0522:
0523:                sourcePane.select(line1.getStartOffset() + columnNumber1 - 1,
0524:                        line2.getStartOffset() + columnNumber2 - 1);
0525:            }
0526:
0527:            /**
0528:             * Get the text currently selected.
0529:             * 
0530:             * @return The selected text.
0531:             */
0532:            public String getSelectedText() {
0533:                return sourcePane.getSelectedText();
0534:            }
0535:
0536:            /**
0537:             * Remove the step mark (the mark that shows the current line when
0538:             * single-stepping through code). If it is not currently displayed, do
0539:             * nothing.
0540:             */
0541:            public void removeStepMark() // inherited from Editor
0542:            {
0543:                if (currentStepPos != -1) {
0544:                    SimpleAttributeSet a = new SimpleAttributeSet();
0545:                    a.addAttribute(MoeSyntaxView.STEPMARK, Boolean.FALSE);
0546:                    sourceDocument.setParagraphAttributes(currentStepPos, a);
0547:                    currentStepPos = -1;
0548:                    // remove highlight as well
0549:                    sourcePane.setCaretPosition(sourcePane.getCaretPosition());
0550:                    // force an update of UI
0551:                    repaint();
0552:                }
0553:            }
0554:
0555:            /**
0556:             * Change class name.
0557:             * 
0558:             * @param title  new window title
0559:             * @param filename  new file name
0560:             */
0561:            public void changeName(String title, String filename,
0562:                    String docFilename) {
0563:                this .filename = filename;
0564:                this .docFilename = docFilename;
0565:                // error ## - need to add full path
0566:                windowTitle = title;
0567:                setWindowTitle();
0568:            }
0569:
0570:            /**
0571:             * Set the "compiled" status
0572:             * 
0573:             * @param compiled  True if the class has been compiled.
0574:             */
0575:            public void setCompiled(boolean compiled) {
0576:                setCompileStatus(compiled);
0577:                if (compiled) {
0578:                    info.message(Config.getString("editor.info.compiled"));
0579:                }
0580:            }
0581:
0582:            /**
0583:             * Called when all the breakpoints have been cleared. The editor should
0584:             * update its display to show that no breakpoints are set.
0585:             */
0586:            public void removeBreakpoints() {
0587:                // This may be a callback in response to a modification event.
0588:                // If we try to remove breakpoints during the modification notification,
0589:                // AbstractDocument throws an exception.
0590:                EventQueue.invokeLater(new Runnable() {
0591:                    public void run() {
0592:                        clearAllBreakpoints();
0593:                    }
0594:                });
0595:            }
0596:
0597:            /**
0598:             * The editor must re-set all its breakpoints via the EditorWatcher
0599:             * interface.
0600:             */
0601:            public void reInitBreakpoints() {
0602:                if (mayHaveBreakpoints) {
0603:                    mayHaveBreakpoints = false;
0604:                    for (int i = 1; i <= numberOfLines(); i++) {
0605:                        if (lineHasBreakpoint(i)) {
0606:                            watcher.breakpointToggleEvent(this , i, true);
0607:                            mayHaveBreakpoints = true;
0608:                        }
0609:                    }
0610:                }
0611:            }
0612:
0613:            /**
0614:             *  Determine whether this buffer has been modified.
0615:             *
0616:             * @return    a boolean indicating whether the file is modified
0617:             */
0618:            public boolean isModified() // inherited from Editor
0619:            {
0620:                return (saveState.isChanged());
0621:            }
0622:
0623:            /**
0624:             * Set this editor to read-only.
0625:             * 
0626:             * @param readOnly  The new readOnly value
0627:             */
0628:            public void setReadOnly(boolean readOnly) {
0629:                if (readOnly) {
0630:                    saveState.setState(StatusLabel.READONLY);
0631:                    updateUndoControls();
0632:                    updateRedoControls();
0633:                }
0634:                sourcePane.setEditable(!readOnly);
0635:            }
0636:
0637:            /**
0638:             * Returns if this editor is read-only. Accessor for the setReadOnly
0639:             * property.
0640:             * 
0641:             * @return a boolean indicating whether the editor is read-only.
0642:             */
0643:            public boolean isReadOnly() {
0644:                return !sourcePane.isEditable();
0645:            }
0646:
0647:            /**
0648:             * Set this editor to display either the interface or the source code of
0649:             * this class
0650:             * 
0651:             * @param interfaceStatus  If true, display class interface, otherwise source.
0652:             */
0653:            public void showInterface(boolean interfaceStatus) {
0654:                interfaceToggle.setSelectedIndex(interfaceStatus ? 1 : 0);
0655:            }
0656:
0657:            /**
0658:             * Tell whether the editor is currently displaying the interface or the
0659:             * source of the class.
0660:             * 
0661:             * @return True, if interface is currently shown, false otherwise.
0662:             */
0663:            public boolean isShowingInterface() {
0664:                return viewingHTML;
0665:            }
0666:
0667:            /**
0668:             * Check whether the source file has changed on disk. If it has, reload.
0669:             */
0670:            private void checkForChangeOnDisk() {
0671:                File file = new File(filename);
0672:                long modified = file.lastModified();
0673:                if (modified != lastModified) {
0674:                    if (saveState.isChanged()) {
0675:                        int answer = DialogManager.askQuestion(this ,
0676:                                "changed-on-disk");
0677:                        if (answer == 0)
0678:                            doReload();
0679:                        else
0680:                            lastModified = modified; // don't ask again for this change
0681:                    } else {
0682:                        doReload();
0683:                    }
0684:                }
0685:            }
0686:
0687:            /**
0688:             * Returns the current caret location within the edited text.
0689:             * 
0690:             * @return An object describing the current caret location.
0691:             */
0692:            public LineColumn getCaretLocation() {
0693:                int caretOffset = sourcePane.getCaretPosition();
0694:                return getLineColumnFromOffset(caretOffset);
0695:            }
0696:
0697:            /**
0698:             * Returns the LineColumn object from the given offset in the text.
0699:             * 
0700:             * @param offset  The number of characters from the beginning of text (startng
0701:             *                from zero)
0702:             * @return the LineColumn object or null if the offset points outside the
0703:             *         text.
0704:             */
0705:            public LineColumn getLineColumnFromOffset(int offset) {
0706:                int lineNumber = sourceDocument.getDefaultRootElement()
0707:                        .getElementIndex(offset);
0708:
0709:                if (lineNumber < 0) {
0710:                    return null;
0711:                }
0712:
0713:                Element lineElement = getLineAt(offset);
0714:                int column = offset - lineElement.getStartOffset();
0715:
0716:                if (column < 0) {
0717:                    return null;
0718:                }
0719:
0720:                return new LineColumn(lineNumber, column);
0721:            }
0722:
0723:            /**
0724:             * Sets the current Caret location within the edited text.
0725:             * 
0726:             * @param location  The location in the text to set the Caret to.
0727:             * @throws IllegalArgumentException
0728:             *             if the specified TextLocation represents a position which
0729:             *             does not exist in the text.
0730:             */
0731:            public void setCaretLocation(LineColumn location) {
0732:                sourcePane.setCaretPosition(getOffsetFromLineColumn(location));
0733:            }
0734:
0735:            /**
0736:             * Returns the location where the current selection begins.
0737:             * 
0738:             * @return the current beginning of the selection or null if no text is
0739:             *         selected.
0740:             */
0741:            public LineColumn getSelectionBegin() {
0742:                Caret aCaret = sourcePane.getCaret();
0743:
0744:                // If the dot is == as the mark then there is no selection.
0745:                if (aCaret.getDot() == aCaret.getMark()) {
0746:                    return null;
0747:                }
0748:
0749:                int beginOffset = Math.min(aCaret.getDot(), aCaret.getMark());
0750:
0751:                return getLineColumnFromOffset(beginOffset);
0752:            }
0753:
0754:            /**
0755:             * Returns the location where the current selection ends.
0756:             * 
0757:             * @return the current end of the selection or null if no text is selected.
0758:             */
0759:            public LineColumn getSelectionEnd() {
0760:                Caret aCaret = sourcePane.getCaret();
0761:
0762:                // If the dot is == as the mark then there is no selection.
0763:                if (aCaret.getDot() == aCaret.getMark()) {
0764:                    return null;
0765:                }
0766:
0767:                int endOffset = Math.max(aCaret.getDot(), aCaret.getMark());
0768:
0769:                return getLineColumnFromOffset(endOffset);
0770:            }
0771:
0772:            /**
0773:             * Returns the text which lies between the two LineColumn.
0774:             * 
0775:             * @param begin  The beginning of the text to get
0776:             * @param end    The end of the text to get
0777:             * @return  The text between the 'begin' and 'end' positions.
0778:             * @throws IllegalArgumentException
0779:             *             if either of the specified TextLocations represent a position
0780:             *             which does not exist in the text.
0781:             */
0782:            public String getText(LineColumn begin, LineColumn end) {
0783:                int first = getOffsetFromLineColumn(begin);
0784:                int last = getOffsetFromLineColumn(end);
0785:                int beginOffset = Math.min(first, last);
0786:                int endOffset = Math.max(first, last);
0787:
0788:                try {
0789:                    return sourceDocument.getText(beginOffset, endOffset
0790:                            - beginOffset);
0791:                } catch (BadLocationException exc) {
0792:                    throw new IllegalArgumentException(exc.getMessage());
0793:                }
0794:            }
0795:
0796:            /**
0797:             * Request to the editor to replace the text between 'begin' and 'end' with
0798:             * the given newText. If begin and end point to the same location, the text
0799:             * is inserted.
0800:             * 
0801:             * @param begin  The start position of text to replace
0802:             * @param end    The end position of text to replace
0803:             * @param newText  The text to insert
0804:             * @throws IllegalArgumentException
0805:             *             if either of the specified LineColumn represent a position
0806:             *             which does not exist in the text.
0807:             * @throws BadLocationException
0808:             *             if internally the text points outside a location in the text.
0809:             */
0810:            public void setText(LineColumn begin, LineColumn end, String newText)
0811:                    throws BadLocationException {
0812:                int start = getOffsetFromLineColumn(begin);
0813:                int finish = getOffsetFromLineColumn(end);
0814:
0815:                int beginOffset = Math.min(start, finish);
0816:                int endOffset = Math.max(start, finish);
0817:
0818:                if (beginOffset != endOffset) {
0819:                    sourceDocument.remove(beginOffset, endOffset - beginOffset);
0820:                }
0821:
0822:                sourceDocument.insertString(beginOffset, newText, null);
0823:            }
0824:
0825:            /**
0826:             * Request to the editor to mark the text between begin and end as selected.
0827:             * 
0828:             * @param begin  The start position of the selection
0829:             * @param end  The end position of the selection
0830:             * @throws IllegalArgumentException
0831:             *             if either of the specified TextLocations represent a position
0832:             *             which does not exist in the text.
0833:             */
0834:            public void setSelection(LineColumn begin, LineColumn end) {
0835:                int start = getOffsetFromLineColumn(begin);
0836:                int finish = getOffsetFromLineColumn(end);
0837:
0838:                int selectionStart = Math.min(start, finish);
0839:                int selectionEnd = Math.max(start, finish);
0840:
0841:                sourcePane.setCaretPosition(selectionStart);
0842:                sourcePane.moveCaretPosition(selectionEnd);
0843:            }
0844:
0845:            /**
0846:             * Translates a LineColumn into an offset into the text held by the editor.
0847:             * 
0848:             * @param location  position to be translated
0849:             * @return the offset into the content of this editor
0850:             * @throws IllegalArgumentException
0851:             *             if the specified LineColumn represent a position which does
0852:             *             not exist in the text.
0853:             */
0854:            public int getOffsetFromLineColumn(LineColumn location) {
0855:                if (location.getLine() < 0) {
0856:                    throw new IllegalArgumentException("line < 0");
0857:                }
0858:
0859:                Element lineElement = sourceDocument.getDefaultRootElement()
0860:                        .getElement(location.getLine());
0861:                if (lineElement == null) {
0862:                    throw new IllegalArgumentException("line="
0863:                            + location.getLine() + " is out of bound");
0864:                }
0865:
0866:                int lineOffset = lineElement.getStartOffset();
0867:
0868:                if (location.getColumn() < 0) {
0869:                    throw new IllegalArgumentException("column < 0 ");
0870:                }
0871:
0872:                int lineLen = lineElement.getEndOffset() - lineOffset;
0873:
0874:                if (location.getColumn() >= lineLen) {
0875:                    throw new IllegalArgumentException("column="
0876:                            + location.getColumn() + " greater than line len="
0877:                            + lineLen);
0878:                }
0879:
0880:                return lineOffset + location.getColumn();
0881:            }
0882:
0883:            /**
0884:             * Returns a property of the current editor.
0885:             *
0886:             * @param  propertyKey  The propertyKey of the property to retrieve.
0887:             * @return              the property value or null if it is not found
0888:             */
0889:            public Object getProperty(String propertyKey) {
0890:                return propertyMap.get(propertyKey);
0891:            }
0892:
0893:            /**
0894:             * Set a property for the current editor. Any existing property with
0895:             * this key will be overwritten.
0896:             *
0897:             * @param  propertyKey  The property key of the new property
0898:             * @param  value        The new property value
0899:             */
0900:            public void setProperty(String propertyKey, Object value) {
0901:                if (propertyKey == null) {
0902:                    return;
0903:                }
0904:
0905:                propertyMap.put(propertyKey, value);
0906:            }
0907:
0908:            /**
0909:             * Returns the length of the line indicated in the edited text.
0910:             * Zero is a valid value if the given line has no characters in it.
0911:             *
0912:             * @param  line  the line in the text for which the length should be calculated, starting from 0
0913:             * @return       the length of the line, -1 if line is invalid
0914:             */
0915:            public int getLineLength(int line) {
0916:                if (line < 0) {
0917:                    return -1;
0918:                }
0919:
0920:                Element lineElement = sourceDocument.getDefaultRootElement()
0921:                        .getElement(line);
0922:                if (lineElement == null) {
0923:                    return -1;
0924:                }
0925:
0926:                int startOffset = lineElement.getStartOffset();
0927:
0928:                return lineElement.getEndOffset() - startOffset;
0929:            }
0930:
0931:            /**
0932:             * Returns the length of the data.  This is the number of
0933:             * characters of content that represents the users data.
0934:             *
0935:             * It is possible to obtain the line and column of the last character of text by using
0936:             * the getLineColumnFromOffset() method.
0937:             *
0938:             * @return the length >= 0
0939:             */
0940:            public int getTextLength() {
0941:                return sourceDocument.getLength();
0942:            }
0943:
0944:            /**
0945:             * Return the number of lines in the documant.
0946:             */
0947:            public int numberOfLines() {
0948:                return sourceDocument.getDefaultRootElement().getElementCount();
0949:            }
0950:
0951:            // --------------------------------------------------------------------
0952:            // ------------ end of interface inherited from Editor ----------------
0953:            // --------------------------------------------------------------------
0954:
0955:            // ---- BlueJEventListener interface ----
0956:
0957:            /**
0958:             * A BlueJEvent was raised. Check whether it is one that we're interested
0959:             * in.
0960:             */
0961:            public void blueJEvent(int eventId, Object arg) {
0962:                switch (eventId) {
0963:                case BlueJEvent.DOCU_GENERATED:
0964:                    BlueJEvent.removeListener(this );
0965:                    refreshHtmlDisplay();
0966:                    break;
0967:                case BlueJEvent.DOCU_ABORTED:
0968:                    BlueJEvent.removeListener(this );
0969:                    info.warning(Config.getString("editor.info.docAborted"));
0970:                    break;
0971:                }
0972:            }
0973:
0974:            // -------- DocumentListener interface --------
0975:
0976:            /**
0977:             * A text insertion has taken place.
0978:             */
0979:            public void insertUpdate(DocumentEvent e) {
0980:                if (!saveState.isChanged()) {
0981:                    saveState.setState(StatusLabel.CHANGED);
0982:                    setChanged();
0983:                }
0984:                actions.userAction();
0985:                doTextInsert.setEvent(e, sourcePane);
0986:                SwingUtilities.invokeLater(doTextInsert);
0987:            }
0988:
0989:            /**
0990:             * A text removal has taken place.
0991:             */
0992:            public void removeUpdate(DocumentEvent e) {
0993:                if (!saveState.isChanged()) {
0994:                    saveState.setState(StatusLabel.CHANGED);
0995:                    setChanged();
0996:                }
0997:                actions.userAction();
0998:            }
0999:
1000:            /**
1001:             * Document properties have changed - ignore
1002:             */
1003:            public void changedUpdate(DocumentEvent e) {
1004:            }
1005:
1006:            // --------------------------------------------------------------------
1007:            /**
1008:             * Clear the message in the info area.
1009:             */
1010:            public void clearMessage() {
1011:                info.clear();
1012:            }
1013:
1014:            /**
1015:             * Display a message into the info area.
1016:             * 
1017:             * @param msg  the message to display
1018:             */
1019:            public void writeMessage(String msg) {
1020:                info.message(msg);
1021:            }
1022:
1023:            /**
1024:             * Write a warning message into the info area. Typically some form of
1025:             * unexpected behaviour has occurred.
1026:             * 
1027:             * @param msg  Description of the Parameter
1028:             */
1029:            public void writeWarningMessage(String msg) {
1030:                info.warning(msg);
1031:            }
1032:
1033:            // ==================== USER ACTION IMPLEMENTATIONS ===================
1034:
1035:            // --------------------------------------------------------------------
1036:            /**
1037:             */
1038:            public void userSave() {
1039:                if (saveState.isSaved())
1040:                    info.message(Config.getString("editor.info.noChanges"));
1041:                else {
1042:                    try {
1043:                        save();
1044:                    } catch (IOException ioe) {
1045:                    }
1046:                    // Note we can safely ignore the exception here: a message has
1047:                    // already been displayed in the editor status bar
1048:                }
1049:            }
1050:
1051:            // --------------------------------------------------------------------
1052:            /**
1053:             */
1054:            public void reload() {
1055:                if (filename == null) {
1056:                    info.warning(Config.getString("editor.info.cannotReload"),
1057:                            Config.getString("editor.info.reload"));
1058:                } else if (saveState.isChanged()) {
1059:                    int answer = DialogManager.askQuestion(this ,
1060:                            "really-reload");
1061:                    if (answer == 0)
1062:                        doReload();
1063:                } else {
1064:                    doReload();
1065:                }
1066:            }
1067:
1068:            // --------------------------------------------------------------------
1069:
1070:            /**
1071:             * Prints source code from Editor
1072:             * 
1073:             * @param printerJob  A PrinterJob to print to.
1074:             */
1075:            public void print(PrinterJob printerJob) {
1076:                PrintHandler pt = new PrintHandler(printerJob,
1077:                        getPageFormat(printerJob));
1078:                pt.print();
1079:            }
1080:
1081:            /**
1082:             * Return a validated version of the global PageFormat for BlueJ
1083:             */
1084:            public PageFormat getPageFormat(PrinterJob job) {
1085:                return job.validatePage(PkgMgrFrame.getPageFormat());
1086:            }
1087:
1088:            /**
1089:             * Generalised version of print function. This is what is typically called
1090:             * when print is initiated from within the source code editor menu. This
1091:             * sets up and runs the print process as a separate lower priority thread.
1092:             */
1093:            public void print() {
1094:                // create a printjob
1095:                PrinterJob job = PrinterJob.getPrinterJob();
1096:                if (job.printDialog()) {
1097:                    PrintHandler pt = new PrintHandler(job, getPageFormat(job));
1098:                    Thread printJobThread = new Thread(pt);
1099:                    printJobThread.setPriority((Thread.currentThread()
1100:                            .getPriority() - 1));
1101:                    printJobThread.start();
1102:                }
1103:            }
1104:
1105:            // --------------------------------------------------------------------
1106:            /**
1107:             * Implementation of the "page setup" user function. This provides a dialog
1108:             * for print page setup. PageSetup is global to BlueJ. Calling this from the 
1109:             * Editor is effectively the same as calling from PkgMgrFrame as this saves 
1110:             * back to PkgMgrFrame's global page format object.
1111:             */
1112:            public void pageSetup() {
1113:                PrinterJob job = PrinterJob.getPrinterJob();
1114:                PageFormat pageFormat = job.pageDialog(PkgMgrFrame
1115:                        .getPageFormat());
1116:                PkgMgrFrame.setPageFormat(pageFormat);
1117:            }
1118:
1119:            // --------------------------------------------------------------------
1120:            /**
1121:             * The editor has been closed. Hide the editor window now.
1122:             */
1123:            public void doClose() {
1124:                setVisible(false);
1125:                if (watcher != null) {
1126:                    watcher.closeEvent(this );
1127:                }
1128:            }
1129:
1130:            // --------------------------------------------------------------------
1131:            /**
1132:             * Check whether TABs need expanding in this editor. If they do, return
1133:             * true. At the same time, set this flag to true.
1134:             * 
1135:             * @return Description of the Return Value
1136:             */
1137:            public boolean checkExpandTabs() {
1138:                if (tabsAreExpanded)
1139:                    return false;
1140:
1141:                else {
1142:                    tabsAreExpanded = true;
1143:                    return true;
1144:                }
1145:            }
1146:
1147:            // --------------------------------------------------------------------
1148:            /**
1149:             * Implementation of "find" user function.
1150:             */
1151:            public void find() {
1152:                Finder finder = MoeEditorManager.editorManager.getFinder();
1153:                finder.show(this , currentTextPane.getSelectedText(), false);
1154:            }
1155:
1156:            // --------------------------------------------------------------------
1157:            /**
1158:             * Implementation of "replace" user function. Replace adds extra
1159:             * functionality to that of a find dialog, as well as altered behaviour. It
1160:             * can remain open for multiple functions.
1161:             */
1162:            public void replace() {
1163:                Finder finder = MoeEditorManager.editorManager.getFinder();
1164:                finder.show(this , currentTextPane.getSelectedText(), true);
1165:            }
1166:
1167:            // --------------------------------------------------------------------
1168:            /**
1169:             * Implementation of "find-next" user function.
1170:             */
1171:            public void findNext() {
1172:                Finder finder = MoeEditorManager.editorManager.getFinder();
1173:                String s = currentTextPane.getSelectedText();
1174:                if (s == null) {
1175:                    s = finder.getSearchString();
1176:                    if (s == null) {
1177:                        info.warning(DialogManager
1178:                                .getMessage("no-search-string"));
1179:                        return;
1180:                    }
1181:                }
1182:                findNextString(finder, s, false);
1183:            }
1184:
1185:            // --------------------------------------------------------------------
1186:            /**
1187:             * Implementation of "find-next-reverse" user function.
1188:             */
1189:            public void findNextBackward() {
1190:                Finder finder = MoeEditorManager.editorManager.getFinder();
1191:                String s = currentTextPane.getSelectedText();
1192:                if (s == null) {
1193:                    s = finder.getSearchString();
1194:                    if (s == null) {
1195:                        info.warning(DialogManager
1196:                                .getMessage("no-search-string"));
1197:                        return;
1198:                    }
1199:                }
1200:                findNextString(finder, s, true);
1201:            }
1202:
1203:            // --------------------------------------------------------------------
1204:
1205:            /**
1206:             * Finds the first cvs-style conflict and selects it
1207:             */
1208:            public void findFirstConflict() {
1209:                setCaretLocation(new LineColumn(0, 0));
1210:                findNextConflict();
1211:            }
1212:
1213:            private void findNextConflict() {
1214:                findString("=======", false, false, true, false);
1215:                findString("<<<<<<<", true, false, false, false);
1216:                LineColumn startPos = getCaretLocation();
1217:                findString(">>>>>>>", false, false, false, false);
1218:                LineColumn endPos = getCaretLocation();
1219:                setSelection(startPos, endPos);
1220:            }
1221:
1222:            /**
1223:             * Do a find with info in the info area.
1224:             */
1225:            private void findNextString(Finder finder, String s,
1226:                    boolean backward) {
1227:                boolean found = findString(s, backward, finder.getIgnoreCase(),
1228:                        finder.getWholeWord(), (!finder.getSearchFound()));
1229:
1230:                finder.setSearchString(s);
1231:                finder.setSearchFound(found);
1232:            }
1233:
1234:            // --------------------------------------------------------------------
1235:            /**
1236:             * Do a find with info in the info area.
1237:             */
1238:            boolean findString(String s, boolean backward, boolean ignoreCase,
1239:                    boolean wholeWord, boolean wrap) {
1240:                if (s.length() == 0) {
1241:                    info.warning(Config
1242:                            .getString("editor.info.emptySearchString"));
1243:                    return false;
1244:                }
1245:
1246:                boolean found;
1247:                if (backward)
1248:                    found = doFindBackward(s, ignoreCase, wholeWord, wrap);
1249:                else
1250:                    found = doFind(s, ignoreCase, wholeWord, wrap);
1251:
1252:                StringBuffer msg = new StringBuffer(Config
1253:                        .getString("editor.find.find.label")
1254:                        + " ");
1255:                msg.append(backward ? Config.getString("editor.find.backward")
1256:                        : Config.getString("editor.find.forward"));
1257:                if (ignoreCase || wholeWord || wrap)
1258:                    msg.append(" (");
1259:
1260:                if (ignoreCase)
1261:                    msg.append(Config.getString("editor.find.ignoreCase")
1262:                            .toLowerCase()
1263:                            + ", ");
1264:
1265:                if (wholeWord)
1266:                    msg.append(Config.getString("editor.find.wholeWord")
1267:                            .toLowerCase()
1268:                            + ", ");
1269:
1270:                if (wrap)
1271:                    msg.append(Config.getString("editor.find.wrapAround")
1272:                            .toLowerCase()
1273:                            + ", ");
1274:
1275:                if (ignoreCase || wholeWord || wrap)
1276:                    msg.replace(msg.length() - 2, msg.length(), "): ");
1277:                else
1278:                    msg.append(": ");
1279:
1280:                msg.append(s);
1281:
1282:                if (found)
1283:                    info.message(msg.toString());
1284:                else
1285:                    info.warning(msg.toString(), Config
1286:                            .getString("editor.info.notFound"));
1287:
1288:                return found;
1289:            }
1290:
1291:            // --------------------------------------------------------------------
1292:            /**
1293:             * doFind - do a find without visible feedback. Returns false if not found.
1294:             */
1295:            boolean doFind(String s, boolean ignoreCase, boolean wholeWord,
1296:                    boolean wrap) {
1297:                int docLength = document.getLength();
1298:                int startPosition = currentTextPane.getCaretPosition();
1299:                int endPos = docLength;
1300:
1301:                boolean found = false;
1302:                boolean finished = false;
1303:
1304:                // first line searched starts from current caret position
1305:                int start = startPosition;
1306:                Element line = getLineAt(start);
1307:                int lineEnd = Math.min(line.getEndOffset(), endPos);
1308:
1309:                // following lines search from start of line
1310:                try {
1311:                    while (!found && !finished) {
1312:                        String lineText = document.getText(start, lineEnd
1313:                                - start);
1314:                        if (lineText != null && lineText.length() > 0) {
1315:                            int foundPos = findSubstring(lineText, s,
1316:                                    ignoreCase, wholeWord, false);
1317:                            if (foundPos != -1) {
1318:                                currentTextPane.select(start + foundPos, start
1319:                                        + foundPos + s.length());
1320:                                found = true;
1321:                            }
1322:                        }
1323:                        if (lineEnd >= endPos) {
1324:                            if (wrap) {
1325:                                // do the wrapping
1326:                                endPos = startPosition;
1327:                                line = document.getParagraphElement(0);
1328:                                start = line.getStartOffset();
1329:                                lineEnd = Math.min(line.getEndOffset(), endPos);
1330:                                wrap = false;
1331:                                // don't wrap again
1332:                            } else {
1333:                                finished = true;
1334:                            }
1335:                        } else {
1336:                            // go to next line
1337:                            line = document.getParagraphElement(lineEnd + 1);
1338:                            start = line.getStartOffset();
1339:                            lineEnd = Math.min(line.getEndOffset(), endPos);
1340:                        }
1341:                    }
1342:                } catch (BadLocationException ex) {
1343:                    Debug.message("error in editor find operation");
1344:                }
1345:                return found;
1346:            }
1347:
1348:            // --------------------------------------------------------------------
1349:            /**
1350:             * doFindBackward - do a find backwards without visible feedback. Returns
1351:             * false if not found.
1352:             */
1353:            boolean doFindBackward(String s, boolean ignoreCase,
1354:                    boolean wholeWord, boolean wrap) {
1355:                int docLength = document.getLength();
1356:                int startPosition = currentTextPane.getCaretPosition() - 1;
1357:                if (startPosition < 0) {
1358:                    startPosition = docLength;
1359:                }
1360:                int endPos = 0; // where the search ends
1361:
1362:                boolean found = false;
1363:                boolean finished = false;
1364:
1365:                int start = startPosition; // start of next partial search
1366:                Element line = getLineAt(start);
1367:                int lineStart = Math.max(line.getStartOffset(), endPos);
1368:
1369:                try {
1370:                    while (!found && !finished) {
1371:                        String lineText = document.getText(lineStart, start
1372:                                - lineStart);
1373:                        if (lineText != null && lineText.length() > 0) {
1374:                            int foundPos = findSubstring(lineText, s,
1375:                                    ignoreCase, wholeWord, true);
1376:                            if (foundPos != -1) {
1377:                                currentTextPane.select(lineStart + foundPos,
1378:                                        lineStart + foundPos + s.length());
1379:                                found = true;
1380:                            }
1381:                        }
1382:                        if (lineStart <= endPos) { // reached end of search
1383:                            if (wrap) { // do the wrapping around
1384:                                endPos = startPosition;
1385:                                line = document.getParagraphElement(docLength);
1386:                                start = line.getEndOffset();
1387:                                lineStart = Math.max(line.getStartOffset(),
1388:                                        endPos);
1389:                                wrap = false; // don't wrap again
1390:                            } else {
1391:                                finished = true;
1392:                            }
1393:                        } else { // go to next line
1394:                            line = document.getParagraphElement(lineStart - 1);
1395:                            start = line.getEndOffset();
1396:                            lineStart = Math.max(line.getStartOffset(), endPos);
1397:                        }
1398:                    }
1399:                } catch (BadLocationException ex) {
1400:                    Debug.reportError("error in editor find operation");
1401:                    ex.printStackTrace();
1402:                }
1403:                return found;
1404:            }
1405:
1406:            /**
1407:             * Transfers caret to user specified line number location.
1408:             */
1409:            public void goToLine() {
1410:                if (goToLineDialog == null) {
1411:                    goToLineDialog = new GoToLineDialog(this );
1412:                }
1413:
1414:                DialogManager.centreDialog(goToLineDialog);
1415:                goToLineDialog.showDialog(numberOfLines());
1416:                int newPosition = goToLineDialog.getLineNumber();
1417:                if (newPosition > 0) {
1418:                    setSelection(newPosition, 1, 0);
1419:                }
1420:            }
1421:
1422:            /**
1423:             * Find the position of a substring in a given string, ignoring case or searching for
1424:             * whole words if desired. Return the position of the substring or -1.
1425:             *
1426:             * @param  text        the full string to be searched
1427:             * @param  sub         the substring that we're looking for
1428:             * @param  ignoreCase  if true, case is ignored
1429:             * @param  wholeWord   if true, and the search string resembles something like a word,
1430:             *                    find only whole-word ocurrences
1431:             * @param  backwards   Description of the Parameter
1432:             * @return             Description of the Return Value
1433:             * @returns            the index of the substring, or -1 if not found
1434:             */
1435:            private int findSubstring(String text, String sub,
1436:                    boolean ignoreCase, boolean wholeWord, boolean backwards) {
1437:                int strlen = text.length();
1438:                int sublen = sub.length();
1439:
1440:                if (sublen == 0) {
1441:                    return -1;
1442:                }
1443:
1444:                // 'wholeWord' search does not make much sense when the search string is
1445:                // not a word
1446:                // (ar at least the first and last character is a letter). Check that.
1447:                if (!Character.isJavaIdentifierPart(sub.charAt(0))
1448:                        || !Character.isJavaIdentifierPart(sub
1449:                                .charAt(sublen - 1))) {
1450:                    wholeWord = false;
1451:                }
1452:
1453:                boolean found = false;
1454:                int pos = (backwards ? strlen - sublen : 0);
1455:                boolean itsOver = (backwards ? (pos < 0)
1456:                        : (pos + sublen > strlen));
1457:
1458:                while (!found && !itsOver) {
1459:                    found = text.regionMatches(ignoreCase, pos, sub, 0, sublen);
1460:                    if (found && wholeWord) {
1461:                        found = ((pos == 0) || !Character
1462:                                .isJavaIdentifierPart(text.charAt(pos - 1)))
1463:                                && ((pos + sublen >= strlen) || !Character
1464:                                        .isJavaIdentifierPart(text.charAt(pos
1465:                                                + sublen)));
1466:                    }
1467:                    if (!found) {
1468:                        pos = (backwards ? pos - 1 : pos + 1);
1469:                        itsOver = (backwards ? (pos < 0)
1470:                                : (pos + sublen > strlen));
1471:                    }
1472:                }
1473:                if (found) {
1474:                    return pos;
1475:                } else {
1476:                    return -1;
1477:                }
1478:            }
1479:
1480:            // --------------------------------------------------------------------
1481:            /**
1482:             * Implementation of "compile" user function.
1483:             */
1484:            public void compile() {
1485:                if (watcher == null) {
1486:                    return;
1487:                }
1488:                if (!viewingCode()) {
1489:                    info.warning(" ");
1490:                    return;
1491:                }
1492:
1493:                info.message(Config.getString("editor.info.compiling"));
1494:                watcher.compile(this );
1495:            }
1496:
1497:            // --------------------------------------------------------------------
1498:            /**
1499:             * Toggle the interface popup menu. This is used when using keys to toggle
1500:             * the interface view. Toggling the menu will result in invoking the action.
1501:             */
1502:            public void toggleInterfaceMenu() {
1503:                if (!sourceIsCode)
1504:                    return;
1505:
1506:                if (interfaceToggle.getSelectedIndex() == 0)
1507:                    interfaceToggle.setSelectedIndex(1);
1508:                else
1509:                    interfaceToggle.setSelectedIndex(0);
1510:            }
1511:
1512:            // --------------------------------------------------------------------
1513:            /**
1514:             * Implementation of "toggle-interface-view" user function. The menu has
1515:             * already been changed - now see what it is and do it.
1516:             */
1517:            public void toggleInterface() {
1518:                if (!sourceIsCode) {
1519:                    return;
1520:                }
1521:
1522:                boolean wantHTML = (interfaceToggle.getSelectedItem() == interfaceString);
1523:                if (wantHTML && !viewingHTML) {
1524:                    switchToInterfaceView();
1525:                } else if (!wantHTML && viewingHTML) {
1526:                    switchToSourceView();
1527:                }
1528:            }
1529:
1530:            /**
1531:             * Allow the enabling/disabling of print menu option. Added to disable the
1532:             * printing og javadoc html for the time being until until implemented.
1533:             * (This is reliant on the use of j2sdk1.4 and Java Unified Print Service
1534:             * implementation JSR 6)
1535:             * 
1536:             * @param flag  true to enable printing from menu.
1537:             */
1538:            public void enablePrinting(boolean flag) {
1539:                Action printAction = actions.getActionByName("print");
1540:                if (printAction != null) {
1541:                    printAction.setEnabled(flag);
1542:                }
1543:                Action pageSetupAction = actions.getActionByName("page-setup");
1544:                if (pageSetupAction != null) {
1545:                    pageSetupAction.setEnabled(flag);
1546:                }
1547:
1548:            }
1549:
1550:            // --------------------------------------------------------------------
1551:            /**
1552:             * Switch on the source view (it it isn't showing already).
1553:             */
1554:            private void switchToSourceView() {
1555:                if (!viewingHTML) {
1556:                    return;
1557:                }
1558:
1559:                // enable print option
1560:                enablePrinting(true);
1561:                document = sourceDocument;
1562:                currentTextPane = sourcePane;
1563:                viewingHTML = false;
1564:                scrollPane.setViewportView(currentTextPane);
1565:                checkSyntaxStatus();
1566:                currentTextPane.requestFocus();
1567:            }
1568:
1569:            // --------------------------------------------------------------------
1570:            /**
1571:             * Switch on the javadoc interface view (it it isn't showing already). If
1572:             * necessary, generate it first.
1573:             */
1574:            private void switchToInterfaceView() {
1575:                if (viewingHTML) {
1576:                    return;
1577:                }
1578:
1579:                // disable print menu option until implemented
1580:                enablePrinting(false);
1581:                try {
1582:                    save();
1583:                    displayInterface();
1584:                } catch (IOException ioe) {
1585:                    // Could display a dialog here. However, the error message
1586:                    // (from save() call) will already be displayed in the editor
1587:                    // status bar.
1588:                }
1589:            }
1590:
1591:            // --------------------------------------------------------------------
1592:            /**
1593:             * Refresh the HTML display.
1594:             */
1595:            private void refreshHtmlDisplay() {
1596:                try {
1597:                    File urlFile = new File(getDocPath());
1598:                    URL myURL = urlFile.toURI().toURL();
1599:                    htmlPane.setPage(myURL);
1600:                    htmlDocument = (HTMLDocument) htmlPane.getDocument();
1601:                    htmlDocument.setBase(myURL);
1602:                    info.message(Config.getString("editor.info.docLoaded"));
1603:                } catch (Exception exc) {
1604:                    info.warning(
1605:                            Config.getString("editor.info.docDisappeared"),
1606:                            getDocPath());
1607:                    Debug.reportError("loading class interface failed: " + exc);
1608:                }
1609:            }
1610:
1611:            // --------------------------------------------------------------------
1612:            /**
1613:             * Check whether javadoc file is up to date.
1614:             * 
1615:             * @return True is the currently existing documentation is up-to-date.
1616:             */
1617:            private boolean docUpToDate() {
1618:                try {
1619:                    File src = new File(filename);
1620:                    File doc = new File(docFilename);
1621:
1622:                    if (!doc.exists()
1623:                            || (src.exists() && (src.lastModified() > doc
1624:                                    .lastModified()))) {
1625:                        return false;
1626:                    }
1627:                } catch (Exception e) {
1628:                    e.printStackTrace();
1629:                    return false;
1630:                }
1631:                return true;
1632:            }
1633:
1634:            // --------------------------------------------------------------------
1635:            /**
1636:             * We want to display the interface view. This will generate the
1637:             * documentation if necessary.
1638:             * 
1639:             * Don't call this directly to switch to the interface view. Call
1640:             * switchToInterfaceView() instead.
1641:             */
1642:            private void displayInterface() {
1643:                info.message(Config.getString("editor.info.loadingDoc"));
1644:                boolean generateDoc = !docUpToDate();
1645:
1646:                // The following all used to be done in a separate thread, but this is not
1647:                // necessary - setPage() operates asynchronously anyway.
1648:                if (htmlPane == null) {
1649:                    createHTMLPane();
1650:                    if (!generateDoc) {
1651:                        refreshHtmlDisplay();
1652:                    }
1653:                } else if (!generateDoc) {
1654:                    info.message(Config.getString("editor.info.docLoaded"));
1655:                }
1656:
1657:                if (generateDoc) {
1658:                    // clear the existing document
1659:                    htmlDocument = new HTMLDocument();
1660:                    htmlPane.setDocument(htmlDocument);
1661:
1662:                    // interface needs to be re-generated
1663:                    info.message(Config.getString("editor.info.generatingDoc"));
1664:                    BlueJEvent.addListener(this );
1665:                    watcher.generateDoc();
1666:                }
1667:
1668:                document = htmlDocument;
1669:                currentTextPane = htmlPane;
1670:                viewingHTML = true;
1671:                scrollPane.setViewportView(htmlPane);
1672:                currentTextPane.requestFocus();
1673:            }
1674:
1675:            // --------------------------------------------------------------------
1676:            /**
1677:             */
1678:            public void createHTMLPane() {
1679:                htmlPane = new JEditorPane();
1680:                htmlPane.setEditorKit(new HTMLEditorKit());
1681:                htmlPane.setEditable(false);
1682:                htmlPane.addHyperlinkListener(this );
1683:            }
1684:
1685:            // --------------------------------------------------------------------
1686:            /**
1687:             * A hyperlink was activated in the document. Do something appropriate.
1688:             */
1689:            public void hyperlinkUpdate(HyperlinkEvent e) {
1690:                info.clear();
1691:                if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
1692:                    JEditorPane pane = (JEditorPane) e.getSource();
1693:                    if (e instanceof  HTMLFrameHyperlinkEvent) {
1694:                        HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
1695:                        HTMLDocument doc = (HTMLDocument) pane.getDocument();
1696:                        doc.processHTMLFrameHyperlinkEvent(evt);
1697:                    } else {
1698:                        try {
1699:                            pane.setPage(e.getURL());
1700:                        } catch (Throwable t) {
1701:                            info.warning("cannot display hyperlink: "
1702:                                    + e.getURL());
1703:                            Debug.reportError("hyperlink failed: " + t);
1704:                        }
1705:                    }
1706:                }
1707:            }
1708:
1709:            // --------------------------------------------------------------------
1710:            /**
1711:             * Implementation of "toggle-breakpoint" user function.
1712:             */
1713:            public void toggleBreakpoint() {
1714:                if (!viewingCode()) {
1715:                    info.warning(" "); // cause a beep
1716:                    return;
1717:                }
1718:                toggleBreakpoint(sourcePane.getCaretPosition());
1719:            }
1720:
1721:            // --------------------------------------------------------------------
1722:            /**
1723:             * Toggle a breakpoint at a given position.
1724:             */
1725:            public void toggleBreakpoint(int pos) {
1726:                if (positionHasBreakpoint(pos))
1727:                    setUnsetBreakpoint(pos, false); // remove
1728:                else
1729:                    setUnsetBreakpoint(pos, true); // set
1730:            }
1731:
1732:            // --------------------------------------------------------------------
1733:            /**
1734:             * Clear all known breakpoints.
1735:             */
1736:            private void clearAllBreakpoints() {
1737:                if (mayHaveBreakpoints) {
1738:
1739:                    for (int i = 1; i <= numberOfLines(); i++) {
1740:                        if (lineHasBreakpoint(i)) {
1741:                            doRemoveBreakpoint(getPositionInLine(i));
1742:                        }
1743:                    }
1744:                    mayHaveBreakpoints = false;
1745:                }
1746:            }
1747:
1748:            // --------------------------------------------------------------------
1749:            /**
1750:             * Check weather a position has a breakpoint set
1751:             */
1752:            private boolean positionHasBreakpoint(int pos) {
1753:                Element line = getLineAt(pos);
1754:                return Boolean.TRUE.equals(line.getAttributes().getAttribute(
1755:                        MoeSyntaxView.BREAKPOINT));
1756:            }
1757:
1758:            // --------------------------------------------------------------------
1759:            /**
1760:             * Check weather a line has a breakpoint set
1761:             */
1762:            private boolean lineHasBreakpoint(int lineNo) {
1763:                Element line = getLine(lineNo);
1764:                return (Boolean.TRUE.equals(line.getAttributes().getAttribute(
1765:                        MoeSyntaxView.BREAKPOINT)));
1766:            }
1767:
1768:            // --------------------------------------------------------------------
1769:            /**
1770:             * Try to set or remove a breakpoint (depending on the parameter) at the
1771:             * given position. Informs the watcher.
1772:             */
1773:            private void setUnsetBreakpoint(int pos, boolean set) {
1774:                if (watcher != null) {
1775:                    int line = getLineNumberAt(pos);
1776:                    String result = watcher.breakpointToggleEvent(this , line,
1777:                            set);
1778:
1779:                    if (result == null) {
1780:                        // no problem, go ahead
1781:                        SimpleAttributeSet a = new SimpleAttributeSet();
1782:                        if (set) {
1783:                            a.addAttribute(MoeSyntaxView.BREAKPOINT,
1784:                                    Boolean.TRUE);
1785:                            mayHaveBreakpoints = true;
1786:                        } else {
1787:                            a.addAttribute(MoeSyntaxView.BREAKPOINT,
1788:                                    Boolean.FALSE);
1789:                        }
1790:
1791:                        sourceDocument.setParagraphAttributes(pos, a);
1792:                    } else {
1793:                        info.warning(result);
1794:                    }
1795:
1796:                    // force an update of UI
1797:                    repaint();
1798:                } else {
1799:                    info
1800:                            .warning(Config
1801:                                    .getString("editor.info.cannotSetBreak"));
1802:                }
1803:
1804:            }
1805:
1806:            // --------------------------------------------------------------------
1807:            /**
1808:             * Remove a breakpoint without question.
1809:             */
1810:            private void doRemoveBreakpoint(int pos) {
1811:                SimpleAttributeSet a = new SimpleAttributeSet();
1812:                a.addAttribute(MoeSyntaxView.BREAKPOINT, Boolean.FALSE);
1813:                sourceDocument.setParagraphAttributes(pos, a);
1814:                repaint();
1815:            }
1816:
1817:            // --------------------------------------------------------------------
1818:            /**
1819:             * Try to set or remove a step mark (depending on the parameter) at the
1820:             * given position.
1821:             * 
1822:             * @param pos  A position in the line where we'd like the step mark.
1823:             */
1824:            private void setStepMark(int pos) {
1825:                removeStepMark();
1826:                SimpleAttributeSet a = new SimpleAttributeSet();
1827:                a.addAttribute(MoeSyntaxView.STEPMARK, Boolean.TRUE);
1828:                sourceDocument.setParagraphAttributes(pos, a);
1829:                currentStepPos = pos;
1830:                // force an update of UI
1831:                repaint();
1832:            }
1833:
1834:            // ========================= SUPPORT ROUTINES ==========================
1835:
1836:            // --------------------------------------------------------------------
1837:            /**
1838:             * return a boolean representing whether in source editing view
1839:             */
1840:            private boolean viewingCode() {
1841:                return sourceIsCode && (!viewingHTML);
1842:            }
1843:
1844:            // --------------------------------------------------------------------
1845:            /**
1846:             * Return the current line.
1847:             */
1848:            //    private Element getCurrentLine()
1849:            //    {
1850:            //        return document.getParagraphElement(currentTextPane.getCaretPosition());
1851:            //    }
1852:            // --------------------------------------------------------------------
1853:            /**
1854:             * Find and return a line by line number
1855:             */
1856:            private Element getLine(int lineNo) {
1857:                return sourceDocument.getDefaultRootElement().getElement(
1858:                        lineNo - 1);
1859:            }
1860:
1861:            // --------------------------------------------------------------------
1862:            /**
1863:             * Find and return a line by text position
1864:             */
1865:            private Element getLineAt(int pos) {
1866:                return sourceDocument.getParagraphElement(pos);
1867:            }
1868:
1869:            // --------------------------------------------------------------------
1870:            /**
1871:             * Find and return a position in a line.
1872:             */
1873:            private int getPositionInLine(int lineNo) {
1874:                return getLine(lineNo).getStartOffset();
1875:            }
1876:
1877:            // --------------------------------------------------------------------
1878:            /**
1879:             * Return the number of the current line.
1880:             */
1881:            //    private int getCurrentLineNo()
1882:            //    {
1883:            //        return document.getDefaultRootElement().getElementIndex(
1884:            //                                   currentTextPane.getCaretPosition()) + 1;
1885:            //    }
1886:            // --------------------------------------------------------------------
1887:            /**
1888:             * Return the number of the line containing position 'pos'.
1889:             */
1890:            private int getLineNumberAt(int pos) {
1891:                return sourceDocument.getDefaultRootElement().getElementIndex(
1892:                        pos) + 1;
1893:            }
1894:
1895:            // --------------------------------------------------------------------
1896:            /**
1897:             * Revert the buffer contents to the last saved version. Do not ask any
1898:             * question - just do it. Must have a file name.
1899:             */
1900:            public void doReload() {
1901:                FileReader reader = null;
1902:                try {
1903:                    reader = new FileReader(filename);
1904:                    sourcePane.read(reader, null);
1905:                    reader.close();
1906:                    File file = new File(filename);
1907:                    lastModified = file.lastModified();
1908:
1909:                    sourceDocument = (MoeSyntaxDocument) sourcePane
1910:                            .getDocument();
1911:
1912:                    // flag document type as a java file by associating a
1913:                    // JavaTokenMarker for syntax colouring if specified
1914:                    checkSyntaxStatus();
1915:                    sourceDocument.addDocumentListener(this );
1916:                    sourceDocument.addUndoableEditListener(undoManager);
1917:
1918:                    // We want to inform the watcher that the editor content has changed,
1919:                    // and then inform it that we are in "saved" state (synced with file).
1920:                    // But first set state to saved to avoid unnecessary writes to disk.
1921:                    saveState.setState(StatusLabel.SAVED);
1922:                    setChanged(); // contents may have changed - notify watcher
1923:                    setSaved(); // notify watcher that we are saved
1924:                } catch (FileNotFoundException ex) {
1925:                    info.warning(Config
1926:                            .getString("editor.info.fileDisappeared"));
1927:                } catch (IOException ex) {
1928:                    info.warning(Config.getString("editor.info.fileReadError"));
1929:                    setChanged();
1930:                } finally {
1931:                    try {
1932:                        if (reader != null)
1933:                            reader.close();
1934:                    } catch (IOException ioe) {
1935:                    }
1936:                }
1937:            }
1938:
1939:            // --------------------------------------------------------------------
1940:            /**
1941:             * Checks that current status of syntax highlighting option is consistent
1942:             * with desired option eg off/on.
1943:             */
1944:            private void checkSyntaxStatus() {
1945:                if (sourceDocument != null) {
1946:
1947:                    // flag document type as a java file by associating a
1948:                    // JavaTokenMarker for syntax colouring if specified
1949:                    if (viewingCode() && PrefMgr.getFlag(PrefMgr.HILIGHTING)) {
1950:                        if (sourceDocument.getTokenMarker() == null) {
1951:                            sourceDocument
1952:                                    .setTokenMarker(new JavaTokenMarker());
1953:                        }
1954:                    } else {
1955:                        sourceDocument.setTokenMarker(null);
1956:                    }
1957:                }
1958:                // else ??
1959:            }
1960:
1961:            /**
1962:             * Checks that current status of syntax highlighting option is consistent
1963:             * with desired option eg off/on. Called when refreshing or making visible
1964:             * to pick up any Preference Manager changes to this functionality
1965:             */
1966:            private void checkBracketStatus() {
1967:                matchBrackets = PrefMgr.getFlag(PrefMgr.MATCH_BRACKETS);
1968:                // tidies up leftover highlight if matching is switched off
1969:                // while highlighting a valid bracket or refreshes bracket in open
1970:                // editor
1971:                if (matchBrackets)
1972:                    doBracketMatch();
1973:                else
1974:                    moeCaret.removeBracket();
1975:            }
1976:
1977:            /**
1978:             * Tell whether we are currently matching brackets.
1979:             * 
1980:             * @return True, if we are matching brackets, otherwise false.
1981:             */
1982:            public boolean matchBrackets() {
1983:                return matchBrackets;
1984:            }
1985:
1986:            // --------------------------------------------------------------------
1987:            /**
1988:             * Toggle the editor's 'compiled' status. If compiled, enable the breakpoint
1989:             * function.
1990:             */
1991:            private void setCompileStatus(boolean compiled) {
1992:                actions.getActionByName("toggle-breakpoint").setEnabled(
1993:                        compiled && viewingCode());
1994:                if (compiled) {
1995:                    sourceDocument.putProperty(COMPILED, Boolean.TRUE);
1996:                } else {
1997:                    sourceDocument.putProperty(COMPILED, Boolean.FALSE);
1998:                }
1999:
2000:                currentTextPane.repaint();
2001:            }
2002:
2003:            // --------------------------------------------------------------------
2004:            /**
2005:             * Set the saved/changed status of this buffer to SAVED.
2006:             */
2007:            private void setSaved() {
2008:                info.message(Config.getString("editor.info.saved"));
2009:                saveState.setState(StatusLabel.SAVED);
2010:                if (watcher != null) {
2011:                    watcher.saveEvent(this );
2012:                }
2013:            }
2014:
2015:            // --------------------------------------------------------------------
2016:            /**
2017:             * Buffer just went from saved to changed state (called by StatusLabel)
2018:             */
2019:            private void setChanged() {
2020:                if (ignoreChanges) {
2021:                    return;
2022:                }
2023:                setCompileStatus(false);
2024:                if (watcher != null) {
2025:                    watcher.modificationEvent(this );
2026:                }
2027:            }
2028:
2029:            // --------------------------------------------------------------------
2030:            /**
2031:             * Clear the message in the info area.
2032:             */
2033:            void caretMoved() {
2034:                clearMessage();
2035:                if (matchBrackets) {
2036:                    doBracketMatch();
2037:                }
2038:                actions.userAction();
2039:            }
2040:
2041:            /**
2042:             * returns the position of the matching bracket for the source pane's
2043:             * current caret position. Returns -1 if not found or not valid/appropriate
2044:             * 
2045:             * @return the int representing bracket position
2046:             */
2047:            public int getBracketMatch() {
2048:                int pos = -1;
2049:                try {
2050:                    int caretPos = sourcePane.getCaretPosition();
2051:                    if (caretPos != 0) {
2052:                        caretPos--;
2053:                    }
2054:                    pos = TextUtilities.findMatchingBracket(sourceDocument,
2055:                            caretPos);
2056:                } catch (BadLocationException ble) {
2057:                    Debug
2058:                            .reportError("Bad document location reached while trying to match brackets");
2059:                }
2060:                return pos;
2061:            }
2062:
2063:            /**
2064:             * delegates bracket matching to the source pane's caret
2065:             */
2066:            private void doBracketMatch() {
2067:                Caret caret = sourcePane.getCaret();
2068:                if (caret instanceof  MoeCaret) {
2069:                    ((MoeCaret) caret).paintMatchingBracket();
2070:                }
2071:            }
2072:
2073:            /**
2074:             * Set the window title to show the defined title, or else the file name.
2075:             */
2076:            private void setWindowTitle() {
2077:                String title = windowTitle;
2078:
2079:                if (title == null) {
2080:                    if (filename == null)
2081:                        title = "Moe:  <no name>";
2082:                    else
2083:                        title = "Moe:  " + filename;
2084:                }
2085:                setTitle(title);
2086:            }
2087:
2088:            // --------------------------------------------------------------------
2089:            /**
2090:             * Return the path to the class documentation.
2091:             */
2092:            private String getDocPath() {
2093:                return docFilename;
2094:            }
2095:
2096:            // --------------------------------------------------------------------
2097:
2098:            /**
2099:             * Gets the resource attribute of the MoeEditor object
2100:             */
2101:            private String getResource(String name) {
2102:                return Config.getPropString(name, null, resources);
2103:            }
2104:
2105:            // --------------------------------------------------------------------
2106:
2107:            /**
2108:             * Tokenize a string.
2109:             */
2110:            private String[] tokenize(String input) {
2111:                List list = new ArrayList();
2112:                StringTokenizer t = new StringTokenizer(input);
2113:                String tokens[];
2114:
2115:                while (t.hasMoreTokens()) {
2116:                    list.add(t.nextToken());
2117:                }
2118:
2119:                tokens = new String[list.size()];
2120:                list.toArray(tokens);
2121:                return tokens;
2122:            }
2123:
2124:            // ======================= WINDOW INITIALISATION =======================
2125:
2126:            // --------------------------------------------------------------------
2127:            /**
2128:             * Create all the Window components
2129:             */
2130:            private void initWindow() {
2131:                setIconImage(iconImage);
2132:
2133:                // prepare the content pane
2134:
2135:                JPanel contentPane = new JPanel(new BorderLayout(5, 5));
2136:                contentPane.setBorder(BorderFactory.createEmptyBorder(6, 6, 6,
2137:                        6));
2138:                setContentPane(contentPane);
2139:
2140:                // create and add info and status areas
2141:
2142:                JPanel bottomArea = new JPanel();
2143:
2144:                // create panel for info/status
2145:                bottomArea.setLayout(new BorderLayout(5, 5));
2146:
2147:                info = new Info();
2148:                bottomArea.add(info, BorderLayout.CENTER);
2149:
2150:                statusArea = new JPanel();
2151:                statusArea.setLayout(new GridLayout(0, 1));
2152:                // one column, many rows
2153:                statusArea.setBackground(infoColor);
2154:                statusArea.setBorder(BorderFactory
2155:                        .createLineBorder(Color.black));
2156:
2157:                saveState = new StatusLabel(StatusLabel.SAVED);
2158:                statusArea.add(saveState);
2159:                bottomArea.add(statusArea, BorderLayout.EAST);
2160:
2161:                contentPane.add(bottomArea, BorderLayout.SOUTH);
2162:
2163:                // create the text document
2164:
2165:                sourceDocument = new MoeSyntaxDocument();
2166:                sourceDocument.addDocumentListener(this );
2167:                sourceDocument.addUndoableEditListener(undoManager);
2168:
2169:                // create the text pane
2170:
2171:                MoeSyntaxEditorKit kit = new MoeSyntaxEditorKit(false);
2172:                sourcePane = new MoeEditorPane();
2173:
2174:                sourcePane.setDocument(sourceDocument);
2175:                sourcePane.setCaretPosition(0);
2176:                sourcePane.setMargin(new Insets(2, 2, 2, 2));
2177:                sourcePane.setOpaque(true);
2178:                sourcePane.setEditorKit(kit);
2179:                moeCaret = new MoeCaret(this );
2180:                sourcePane.setCaret(moeCaret);
2181:                sourcePane
2182:                        .setBackground(MoeSyntaxDocument.getBackgroundColor());
2183:                //        sourcePane.setSelectionColor(selectionColour);
2184:                sourcePane.setCaretColor(cursorColor);
2185:
2186:                // default showing:
2187:                currentTextPane = sourcePane;
2188:
2189:                scrollPane = new JScrollPane(currentTextPane);
2190:                scrollPane.setPreferredSize(new Dimension(598, 400));
2191:                scrollPane.getVerticalScrollBar().setUnitIncrement(16);
2192:
2193:                contentPane.add(scrollPane, BorderLayout.CENTER);
2194:
2195:                // get table of edit actions
2196:
2197:                actions = MoeActions.getActions(sourcePane);
2198:                actions.setUndoEnabled(false);
2199:                actions.setRedoEnabled(false);
2200:
2201:                // **** temporary: disable all unimplemented actions ****
2202:                actions.getActionByName("show-manual").setEnabled(false);
2203:                // ****
2204:
2205:                // create menubar and menus
2206:
2207:                JMenuBar menubar = createMenuBar();
2208:                setJMenuBar(menubar);
2209:
2210:                // create toolbar
2211:
2212:                toolbar = createToolbar();
2213:                contentPane.add(toolbar, BorderLayout.NORTH);
2214:
2215:                // add event listener to handle the window close requests
2216:
2217:                addWindowListener(new WindowAdapter() {
2218:                    public void windowClosing(WindowEvent e) {
2219:                        close();
2220:                    }
2221:
2222:                    public void windowActivated(WindowEvent e) {
2223:                        checkForChangeOnDisk();
2224:                    }
2225:                });
2226:
2227:                setFocusTraversalPolicy(new MoeFocusTraversalPolicy());
2228:
2229:                setWindowTitle();
2230:                pack();
2231:            }
2232:
2233:            // --------------------------------------------------------------------
2234:
2235:            /**
2236:             * Create the editor's menu bar.
2237:             */
2238:            private JMenuBar createMenuBar() {
2239:                JMenuBar menubar = new JMenuBar();
2240:                JMenu menu = null;
2241:
2242:                String[] menuKeys = tokenize(getResource("menubar"));
2243:                for (int i = 0; i < menuKeys.length; i++) {
2244:                    menu = createMenu(menuKeys[i]);
2245:                    if (menu != null) {
2246:                        menubar.add(menu);
2247:                    }
2248:                }
2249:                return menubar;
2250:            }
2251:
2252:            // --------------------------------------------------------------------
2253:
2254:            /**
2255:             * Create a single menu for the editor's menu bar. The key for the menu (as
2256:             * defined in moe.properties) is supplied.
2257:             */
2258:            private JMenu createMenu(String key) {
2259:                JMenuItem item;
2260:                String label;
2261:
2262:                // get menu title
2263:                JMenu menu = new JMenu(Config.getString("editor." + key
2264:                        + LabelSuffix));
2265:
2266:                // get menu definition
2267:                String itemString = getResource(key);
2268:                if (itemString == null) {
2269:                    Debug
2270:                            .message("Moe: cannot find menu definition for "
2271:                                    + key);
2272:                    return null;
2273:                }
2274:
2275:                // cut menu definition into separate items
2276:                String[] itemKeys = tokenize(itemString);
2277:
2278:                // create menu item for each item
2279:                for (int i = 0; i < itemKeys.length; i++) {
2280:                    if (itemKeys[i].equals("-")) {
2281:                        menu.addSeparator();
2282:                    } else {
2283:                        Action action = actions.getActionByName(itemKeys[i]);
2284:                        if (action == null) {
2285:                            Debug.message("Moe: cannot find action "
2286:                                    + itemKeys[i]);
2287:                        } else {
2288:                            item = menu.add(action);
2289:                            label = Config.getString("editor." + itemKeys[i]
2290:                                    + LabelSuffix);
2291:                            if (label != null) {
2292:                                item.setText(label);
2293:                            }
2294:                            KeyStroke[] keys = actions
2295:                                    .getKeyStrokesForAction(action);
2296:                            if (keys != null) {
2297:                                item.setAccelerator(chooseKey(keys));
2298:                            }
2299:                        }
2300:                    }
2301:                }
2302:                return menu;
2303:            }
2304:
2305:            /**
2306:             * Choose a key to use in the menu from all defined keys.
2307:             */
2308:            private KeyStroke chooseKey(KeyStroke[] keys) {
2309:                if (keys.length == 1) {
2310:                    return keys[0];
2311:                } else {
2312:                    KeyStroke key = keys[0];
2313:                    // give preference to shortcuts using letter keys (CTRL-V, rather
2314:                    // than F2)
2315:                    for (int i = 1; i < keys.length; i++) {
2316:                        if (keys[i].getKeyCode() >= 'A'
2317:                                && keys[i].getKeyCode() <= 'Z') {
2318:                            key = keys[i];
2319:                        }
2320:                    }
2321:                    return key;
2322:                }
2323:            }
2324:
2325:            // --------------------------------------------------------------------
2326:
2327:            /**
2328:             * Create the toolbar.
2329:             * 
2330:             * @return The toolbar component, ready made.
2331:             */
2332:            private JComponent createToolbar() {
2333:                JPanel toolbar = new JPanel();
2334:                toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS));
2335:                //((FlowLayout)toolbar.getLayout()).setAlignment(FlowLayout.LEFT);
2336:
2337:                String[] toolKeys = tokenize(getResource("toolbar"));
2338:                for (int i = 0; i < toolKeys.length; i++) {
2339:                    toolbar.add(createToolbarButton(toolKeys[i], false));
2340:                    toolbar.add(Box.createHorizontalStrut(4));
2341:                }
2342:
2343:                toolbar.add(Box.createHorizontalGlue());
2344:                toolbar.add(Box.createHorizontalGlue());
2345:                toolbar.add(createInterfaceSelector());
2346:
2347:                return toolbar;
2348:            }
2349:
2350:            // --------------------------------------------------------------------
2351:
2352:            /**
2353:             * Create a button on the toolbar.
2354:             */
2355:            private AbstractButton createToolbarButton(String key,
2356:                    boolean isToggle) {
2357:                final String label = Config.getString("editor." + key
2358:                        + LabelSuffix);
2359:                AbstractButton button;
2360:
2361:                String actionName = getResource(key + ActionSuffix);
2362:                if (actionName == null) {
2363:                    actionName = key;
2364:                }
2365:                Action action = actions.getActionByName(actionName);
2366:                Action tbAction = new ToolbarAction(action, label);
2367:
2368:                if (isToggle) {
2369:                    button = new JToggleButton(tbAction);
2370:                } else {
2371:                    button = new JButton(tbAction);
2372:                }
2373:
2374:                if (action == null) {
2375:                    button.setEnabled(false);
2376:                    Debug.message("Moe: action not found for button " + label);
2377:                }
2378:
2379:                button.setRequestFocusEnabled(false);
2380:                // never get keyboard focus
2381:
2382:                if (!Config.isMacOS()) {
2383:                    // on all other platforms than MacOS, the default insets needs to
2384:                    // be changed to make the buttons smaller
2385:                    Insets margin = button.getMargin();
2386:                    button
2387:                            .setMargin(new Insets(margin.top, 3, margin.bottom,
2388:                                    3));
2389:                } else {
2390:                    Utility.changeToMacButton(button);
2391:                }
2392:
2393:                button.setFont(PrefMgr.getStandardFont());
2394:                return button;
2395:            }
2396:
2397:            // --------------------------------------------------------------------
2398:
2399:            /**
2400:             * Create a combo box for the toolbar
2401:             */
2402:            private JComboBox createInterfaceSelector() {
2403:                String[] choiceStrings = { implementationString,
2404:                        interfaceString };
2405:                interfaceToggle = new JComboBox(choiceStrings);
2406:
2407:                interfaceToggle.setRequestFocusEnabled(false);
2408:                interfaceToggle.setFont(PrefMgr.getStandardFont());
2409:                interfaceToggle.setBorder(new EmptyBorder(2, 2, 2, 2));
2410:                interfaceToggle.setForeground(envOpColour);
2411:
2412:                String actionName = "toggle-interface-view";
2413:                Action action = actions.getActionByName(actionName);
2414:                if (action != null) { // should never be null...
2415:                    interfaceToggle.setAction(action);
2416:                } else {
2417:                    interfaceToggle.setEnabled(false);
2418:                    Debug.message("Moe: action not found: " + actionName);
2419:                }
2420:                if (!sourceIsCode) {
2421:                    interfaceToggle.setEnabled(false);
2422:                }
2423:                return interfaceToggle;
2424:            }
2425:
2426:            // --------------------------------------------------------------------
2427:
2428:            /**
2429:             * Inner class for printing thread to allow printing to occur as a
2430:             * background operation.
2431:             * 
2432:             * @author Bruce Quig
2433:             */
2434:            class PrintHandler implements  Runnable {
2435:                PrinterJob printJob;
2436:                PageFormat pageFormat;
2437:
2438:                /**
2439:                 * Construct the PrintHandler.
2440:                 */
2441:                public PrintHandler(PrinterJob pj, PageFormat format) {
2442:                    super ();
2443:                    printJob = pj;
2444:                    pageFormat = format;
2445:                }
2446:
2447:                /**
2448:                 * Implementation of Runnable interface
2449:                 */
2450:                public void run() {
2451:                    print();
2452:                }
2453:
2454:                /**
2455:                 * Create MoePrinter and then invoke print method
2456:                 */
2457:                public void print() {
2458:                    if (printer == null) {
2459:                        printer = new MoePrinter();
2460:                    }
2461:
2462:                    // print document, using new pageformat object at present
2463:                    info.message(Config.getString("editor.info.printing"));
2464:                    if (printer.printDocument(printJob, sourceDocument,
2465:                            windowTitle, printFont, pageFormat)) {
2466:                        info.message(Config.getString("editor.info.printed"));
2467:                    } else {
2468:                        info.message(Config.getString("editor.info.cancelled"));
2469:                    }
2470:
2471:                }
2472:
2473:            }
2474:
2475:            // --------------------------------------------------------------------
2476:
2477:            /**
2478:             * Class for thread listening to edit changes.
2479:             */
2480:            class TextInsertNotifier implements  Runnable {
2481:                private DocumentEvent evt;
2482:                private JEditorPane editorPane;
2483:
2484:                /**
2485:                 * Sets the event attribute of the TextInsertNotifier object
2486:                 */
2487:                public void setEvent(DocumentEvent e, JEditorPane editorPane) {
2488:                    evt = e;
2489:                    this .editorPane = editorPane;
2490:                }
2491:
2492:                /**
2493:                 * Main processing method for the TextInsertNotifier object
2494:                 */
2495:                public void run() {
2496:                    actions.textInsertAction(evt, editorPane);
2497:                }
2498:            }
2499:
2500:            /**
2501:             * Custom focus traversal implementation to make sure that the text area
2502:             * gets and never loses focus.
2503:             */
2504:            class MoeFocusTraversalPolicy extends FocusTraversalPolicy {
2505:                public Component getComponentAfter(Container focusCycleRoot,
2506:                        Component aComponent) {
2507:                    return currentTextPane;
2508:                }
2509:
2510:                public Component getComponentBefore(Container focusCycleRoot,
2511:                        Component aComponent) {
2512:                    return currentTextPane;
2513:                }
2514:
2515:                public Component getDefaultComponent(Container focusCycleRoot) {
2516:                    return currentTextPane;
2517:                }
2518:
2519:                public Component getFirstComponent(Container focusCycleRoot) {
2520:                    return currentTextPane;
2521:                }
2522:
2523:                public Component getInitialComponent(Window window) {
2524:                    return currentTextPane;
2525:                }
2526:
2527:                public Component getLastComponent(Container focusCycleRoot) {
2528:                    return currentTextPane;
2529:                }
2530:            }
2531:
2532:            /**
2533:             * An abstract action which delegates to a sub-action, and which
2534:             * mirrors the "enabled" state of the sub-action. This allows having
2535:             * actions with alternative labels.
2536:             * 
2537:             * @author Davin McCall
2538:             */
2539:            class ToolbarAction extends AbstractAction implements 
2540:                    PropertyChangeListener {
2541:                private Action subAction;
2542:
2543:                public ToolbarAction(Action subAction, String label) {
2544:                    super (label);
2545:                    this .subAction = subAction;
2546:                    subAction.addPropertyChangeListener(this );
2547:                    setEnabled(subAction.isEnabled());
2548:                }
2549:
2550:                public void actionPerformed(ActionEvent e) {
2551:                    subAction.actionPerformed(e);
2552:                }
2553:
2554:                public void propertyChange(PropertyChangeEvent evt) {
2555:                    // If the enabled state of the sub-action changed,
2556:                    // then we should change our own state.
2557:                    if (evt.getPropertyName().equals("enabled")) {
2558:                        Object newVal = evt.getNewValue();
2559:                        if (newVal instanceof  Boolean) {
2560:                            boolean state = ((Boolean) newVal).booleanValue();
2561:                            setEnabled(state);
2562:                        }
2563:                    }
2564:                }
2565:            }
2566:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.