KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > ui > MainFrame


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  * END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.ui;
35
36 import javax.swing.*;
37 import javax.swing.text.*;
38 import javax.swing.event.*;
39 import javax.swing.border.*;
40 import java.awt.event.*;
41 import java.awt.*;
42 import java.awt.print.*;
43 import java.beans.*;
44
45 import java.io.*;
46 import java.util.Hashtable JavaDoc;
47 import java.util.HashSet JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.LinkedList JavaDoc;
50 import java.util.ArrayList JavaDoc;
51 import java.util.Vector JavaDoc;
52 import java.util.Enumeration JavaDoc;
53 import java.net.URL JavaDoc;
54 import java.net.MalformedURLException JavaDoc;
55 import java.awt.datatransfer.*;
56
57 import edu.rice.cs.drjava.DrJava;
58 import edu.rice.cs.drjava.DrJavaRoot;
59 import edu.rice.cs.drjava.platform.*;
60 import edu.rice.cs.drjava.config.*;
61 import edu.rice.cs.drjava.model.*;
62 import edu.rice.cs.drjava.model.compiler.CompilerListener;
63 import edu.rice.cs.drjava.model.definitions.NoSuchDocumentException;
64 import edu.rice.cs.drjava.model.definitions.DocumentUIListener;
65 import edu.rice.cs.drjava.model.definitions.CompoundUndoManager;
66 import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException;
67 import edu.rice.cs.drjava.model.definitions.InvalidPackageException;
68 import edu.rice.cs.drjava.model.definitions.reducedmodel.*;
69 import edu.rice.cs.drjava.model.debug.*;
70 import edu.rice.cs.drjava.model.repl.*;
71 import edu.rice.cs.drjava.ui.config.ConfigFrame;
72 import edu.rice.cs.drjava.ui.predictive.PredictiveInputFrame;
73 import edu.rice.cs.drjava.ui.predictive.PredictiveInputModel;
74 import edu.rice.cs.drjava.ui.ClipboardHistoryFrame;
75 import edu.rice.cs.drjava.model.ClipboardHistoryModel;
76 import edu.rice.cs.drjava.model.FileSaveSelector;
77 import edu.rice.cs.drjava.project.*;
78
79 import edu.rice.cs.plt.tuple.Pair;
80 import edu.rice.cs.util.ClassPathVector;
81 import edu.rice.cs.util.FileOpenSelector;
82 import edu.rice.cs.util.FileOps;
83 import edu.rice.cs.util.UnexpectedException;
84 import edu.rice.cs.util.ExitingNotAllowedException;
85 import edu.rice.cs.util.OperationCanceledException;
86 import edu.rice.cs.util.classloader.ClassFileError;
87 import edu.rice.cs.util.docnavigation.*;
88 import edu.rice.cs.util.swing.AsyncTask;
89 import edu.rice.cs.util.swing.AsyncTaskLauncher;
90 import edu.rice.cs.util.swing.BorderlessScrollPane;
91 import edu.rice.cs.util.swing.BorderlessSplitPane;
92 import edu.rice.cs.util.swing.ConfirmCheckBoxDialog;
93 import edu.rice.cs.util.swing.DelegatingAction;
94 import edu.rice.cs.util.swing.DirectoryChooser;
95 import edu.rice.cs.util.swing.FileDisplayManager;
96 import edu.rice.cs.util.swing.HighlightManager;
97 import edu.rice.cs.util.swing.RightClickMouseAdapter;
98 import edu.rice.cs.util.swing.SwingWorker;
99 import edu.rice.cs.util.swing.Utilities;
100 import edu.rice.cs.util.swing.*;
101 import edu.rice.cs.util.text.AbstractDocumentInterface;
102
103 import static edu.rice.cs.drjava.config.OptionConstants.*;
104
105 /** DrJava's main window. */
106 public class MainFrame extends JFrame implements ClipboardOwner {
107
108   private static final int INTERACTIONS_TAB = 0;
109   private static final String JavaDoc ICON_PATH = "/edu/rice/cs/drjava/ui/icons/";
110   private static final String JavaDoc DEBUGGER_OUT_OF_SYNC =
111     " Current document is out of sync with the debugger and should be recompiled!";
112   
113   /** Number of milliseconds to wait before displaying "Stepping..." message after a step is requested in
114    * the debugger.
115    */

116   private static final int DEBUG_STEP_TIMER_VALUE = 2000;
117   
118   /** The model which controls all logic in DrJava. */
119   private final SingleDisplayModel _model;
120   
121   /** The main model listener attached by the main frame to the global model */
122   private final ModelListener _mainListener;
123   
124   /** Maps an OpenDefDoc to its JScrollPane. */
125   private final Hashtable JavaDoc<OpenDefinitionsDocument, JScrollPane> _defScrollPanes;
126   
127   /** The currently displayed DefinitionsPane. */
128   private volatile DefinitionsPane _currentDefPane;
129   
130   /** The filename currently being displayed. */
131   private volatile String JavaDoc _fileTitle = "";
132   
133   // These fields should be final but can't be, as the code is currently
134
// organized, because they are set in helper methods, not the constructor
135

136   // Tabbed panel fields
137
public final LinkedList JavaDoc<TabbedPanel> _tabs = new LinkedList JavaDoc<TabbedPanel>();
138     
139   private final JTabbedPane _tabbedPane;
140   private final CompilerErrorPanel _compilerErrorPanel;
141   private final InteractionsPane _consolePane;
142   private final JScrollPane _consoleScroll;
143   private final ConsoleController _consoleController; // move to controller
144
private final InteractionsPane _interactionsPane;
145   private final JPanel _interactionsContainer;
146   private final InteractionsController _interactionsController; // move to controller
147
private final JUnitPanel _junitErrorPanel;
148   private final JavadocErrorPanel _javadocErrorPanel;
149   private final FindReplacePanel _findReplace;
150   private final BreakpointsPanel _breakpointsPanel;
151   private final BookmarksPanel _bookmarksPanel;
152   private final LinkedList JavaDoc<Pair<FindResultsPanel,Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>>> _findResults =
153     new LinkedList JavaDoc<Pair<FindResultsPanel,Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>>>();
154   
155   private volatile boolean _showDebugger; // whether the supporting context is debugger capable
156

157   private volatile InteractionsScriptController _interactionsScriptController;
158   private volatile InteractionsScriptPane _interactionsScriptPane;
159   private volatile DebugPanel _debugPanel;
160   private volatile Component _lastFocusOwner;
161   
162   /** Panel to hold both InteractionsPane and its sync message. */
163   
164   // Status bar fields
165
private final JPanel _statusBar = new JPanel(new BorderLayout()); //( layout );
166
private final JLabel _fileNameField = new JLabel();
167   private final JLabel _sbMessage = new JLabel(); //("This is the text for the center message");
168
private final JLabel _currLocationField = new JLabel();
169   private final PositionListener _posListener = new PositionListener();
170   
171   // Split panes for layout
172
private final JSplitPane _docSplitPane;
173   private final JSplitPane _debugSplitPane;
174   private final JSplitPane _mainSplit;
175   
176   // private Container _docCollectionWidget;
177
private volatile JButton _compileButton;
178   private volatile JButton _closeButton;
179   private volatile JButton _undoButton;
180   private volatile JButton _redoButton;
181   private volatile JButton _runButton;
182   private volatile JButton _junitButton;
183   
184   private final JToolBar _toolBar;
185   private final JFileChooser _interactionsHistoryChooser;
186   
187   // Menu fields
188
private final JMenuBar _menuBar;
189   private final JMenu _fileMenu;
190   private final JMenu _editMenu;
191   private final JMenu _toolsMenu;
192   private final JMenu _projectMenu;
193   private final JMenu _languageLevelMenu;
194   private final JMenu _helpMenu;
195   
196   private volatile JMenu _debugMenu;
197   private volatile JMenuItem _debuggerEnabledMenuItem;
198   
199   // Popup menus
200
private JPopupMenu _navPanePopupMenu;
201   private JPopupMenu _navPanePopupMenuForExternal;
202   private JPopupMenu _navPanePopupMenuForAuxiliary;
203   private JPopupMenu _navPanePopupMenuForRoot;
204   private JPopupMenu _navPaneFolderPopupMenu;
205   private JPopupMenu _interactionsPanePopupMenu;
206   private JPopupMenu _consolePanePopupMenu;
207   
208   // Cached frames and dialogs
209
private final ConfigFrame _configFrame;
210   private final HelpFrame _helpFrame;
211   private final QuickStartFrame _quickStartFrame;
212   private final AboutDialog _aboutDialog;
213   private final RecentDocFrame _recentDocFrame; /** Holds/shows the history of documents for ctrl-tab. */
214   
215 // private ProjectPropertiesFrame _projectPropertiesFrame;
216

217   /** Keeps track of the recent files list in the File menu. */
218   private final RecentFileManager _recentFileManager;
219   
220   /** Keeps track of the recent projects list in the Project menu */
221   private final RecentFileManager _recentProjectManager;
222   
223   private volatile File _currentProjFile;
224   
225   /** Timer to display "Stepping..." message if a step takes longer than a certain amount of time. All accesses
226    * must be synchronized on it.
227    */

228   private final Timer _debugStepTimer;
229   
230   /** The current highlight displaying the location of the debugger's thread,
231    * if there is one. If there is none, this is null.
232    */

233   private volatile HighlightManager.HighlightInfo _currentThreadLocationHighlight = null;
234   
235   /** Table to map breakpoints to their corresponding highlight objects. */
236   private final Hashtable JavaDoc<Breakpoint, HighlightManager.HighlightInfo> _documentBreakpointHighlights;
237   
238   /** Table to map bookmarks to their corresponding highlight objects. */
239   private final Hashtable JavaDoc<DocumentRegion, HighlightManager.HighlightInfo> _documentBookmarkHighlights;
240   
241   /** Whether to display a prompt message before quitting. */
242   private volatile boolean _promptBeforeQuit;
243   
244   /** For opening files. We have a persistent dialog to keep track of the last directory from which we opened. */
245   private final JFileChooser _openChooser;
246   
247   /** For opening project files. */
248   private final JFileChooser _openProjectChooser;
249   
250   /** For saving files. We have a persistent dialog to keep track of the last directory from which we saved. */
251   private final JFileChooser _saveChooser;
252   
253   /** Filter for regular java files (.java and .j). */
254   private final javax.swing.filechooser.FileFilter JavaDoc _javaSourceFilter = new JavaSourceFilter();
255   
256   /** Filter for drjava project files (.pjt) */
257   private final javax.swing.filechooser.FileFilter JavaDoc _projectFilter = new javax.swing.filechooser.FileFilter JavaDoc() {
258     public boolean accept(File f) {
259       return f.isDirectory() || f.getPath().endsWith(PROJECT_FILE_EXTENSION);
260     }
261     public String JavaDoc getDescription() { return "DrJava Project Files (*.pjt)"; }
262   };
263   
264   
265   /** Returns the files to open to the model (command pattern). */
266   private final FileOpenSelector _openSelector = new FileOpenSelector() {
267     public File[] getFiles() throws OperationCanceledException {
268       //_openChooser.removeChoosableFileFilter(_projectFilter);
269
_openChooser.resetChoosableFileFilters();
270       
271       _openChooser.setFileFilter(_javaSourceFilter);
272       return getOpenFiles(_openChooser);
273     }
274   };
275   
276   /** Returns the files to open to the model (command pattern). */
277   private final FileOpenSelector _openFileOrProjectSelector = new FileOpenSelector() {
278     public File[] getFiles() throws OperationCanceledException {
279       //_openChooser.removeChoosableFileFilter(_projectFilter);
280
_openChooser.resetChoosableFileFilters();
281       
282       _openChooser.addChoosableFileFilter(_projectFilter);
283       _openChooser.setFileFilter(_javaSourceFilter);
284       return getOpenFiles(_openChooser);
285     }
286   };
287  
288   /** Returns the project file to open. */
289   private final FileOpenSelector _openProjectSelector = new FileOpenSelector() {
290     public File[] getFiles() throws OperationCanceledException {
291       File[] retFiles = getOpenFiles(_openProjectChooser);
292       return retFiles;
293     }
294   };
295   
296   /** Returns the file to save to the model (command pattern). */
297   private final FileSaveSelector _saveSelector = new FileSaveSelector() {
298     public File getFile() throws OperationCanceledException { return getSaveFile(_saveChooser); }
299     public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
300     public boolean verifyOverwrite() { return _verifyOverwrite(); }
301     public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) {
302       _model.setActiveDocument(doc);
303       String JavaDoc text = "File " + oldFile.getAbsolutePath() +
304         "\ncould not be found on disk! It was probably moved\n" +
305         "or deleted. Would you like to save it in a new file?";
306       int rc = JOptionPane.showConfirmDialog(MainFrame.this,
307                                              text,
308                                              "File Moved or Deleted",
309                                              JOptionPane.YES_NO_OPTION);
310       return (rc == JOptionPane.YES_OPTION);
311     }
312   };
313   
314   /** Returns the file to save to the model (command pattern). */
315   private final FileSaveSelector _saveAsSelector = new FileSaveSelector() {
316     public File getFile() throws OperationCanceledException { return getSaveFile(_saveChooser); }
317     public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
318     public boolean verifyOverwrite() { return _verifyOverwrite(); }
319     public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
320   };
321
322   /** Returns the file to save to the model (command pattern).
323   private final FileSaveSelector _renameSelector = new FileSaveSelector() {
324     public File getFile() throws OperationCanceledException { return getSaveFile(_saveChooser); }
325     public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
326     public boolean verifyOverwrite() { return _verifyOverwrite(); }
327     public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
328   }; */

329   
330   /** Provides the view's contribution to the Javadoc interaction. */
331   private final JavadocDialog _javadocSelector = new JavadocDialog(this);
332   
333   /** Provides a chooser to open a directory */
334   private final DirectoryChooser _folderChooser;
335   private final JCheckBox _openRecursiveCheckBox;
336   
337   private final Action _moveToAuxiliaryAction = new AbstractAction("Include With Project") {
338     { /* initalization block */
339       String JavaDoc msg =
340       "<html>Open this document each time this project is opened.<br>"+
341       "This file would then be compiled and tested with the<br>"+
342       "rest of the project.</html>";
343       putValue(Action.SHORT_DESCRIPTION, msg);
344     }
345     public void actionPerformed(ActionEvent ae) { _moveToAuxiliary(); }
346   };
347   private final Action _removeAuxiliaryAction = new AbstractAction("Do Not Include With Project") {
348     {
349       putValue(Action.SHORT_DESCRIPTION, "Do not open this document next time this project is opened.");
350     }
351     public void actionPerformed(ActionEvent ae) { _removeAuxiliary(); }
352   };
353   /** Resets the document in the definitions pane to a blank one. */
354   private final Action _newAction = new AbstractAction("New") {
355     public void actionPerformed(ActionEvent ae) {
356 // System.out.println("------------------new----------------------");
357
_new();
358     }
359   };
360   
361   private final Action _newProjectAction = new AbstractAction("New") {
362     public void actionPerformed(ActionEvent ae) { _newProject(); }
363   };
364   
365   private volatile AbstractAction _runProjectAction = new AbstractAction("Run Main Document of Project") {
366     public void actionPerformed(ActionEvent ae) { _runProject(); }
367   };
368   
369   /** The jar options dialog. */
370   private final JarOptionsDialog _jarOptionsDialog;
371   
372   /** Initializes the "Create Jar from Project dialog. */
373   private void initJarOptionsDialog() {
374     if (DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue())
375       _jarOptionsDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STATE));
376   }
377   
378   /** Reset the position of the "Create Jar from Project" dialog. */
379   public void resetJarOptionsDialogPosition() {
380     _jarOptionsDialog.setFrameState("default");
381     if (DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue()) {
382       DrJava.getConfig().setSetting(DIALOG_JAROPTIONS_STATE, "default");
383     }
384   }
385   
386   private final Action _jarProjectAction = new AbstractAction("Create Jar File from Project...") {
387     public void actionPerformed(ActionEvent ae) {
388       new SwingWorker() {
389         public Object JavaDoc construct() {
390           _jarOptionsDialog.setVisible(true);
391           return null;
392         }
393       }.start();
394     }
395   };
396   
397   
398   /** Sets the document in the definitions pane to a new templated junit test class. */
399   private final Action _newJUnitTestAction = new AbstractAction("New JUnit Test Case...") {
400     public void actionPerformed(ActionEvent ae) {
401       String JavaDoc testName = JOptionPane.showInputDialog(MainFrame.this,
402                                                     "Please enter a name for the test class:",
403                                                     "New JUnit Test Case",
404                                                     JOptionPane.QUESTION_MESSAGE);
405       if (testName != null) {
406         String JavaDoc ext;
407         for(int i=0; i < DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS.length; i++) {
408           ext = "." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[i];
409           if (testName.endsWith(ext)) testName = testName.substring(0, testName.length() - ext.length());
410         }
411         // For now, don't include setUp and tearDown
412
_model.newTestCase(testName, false, false);
413       }
414     }
415   };
416   
417   /**
418    * Asks user for file name and and reads that file into
419    * the definitions pane.
420    */

421   private final Action _openAction = new AbstractAction("Open...") {
422     public void actionPerformed(ActionEvent ae) {
423       _open();
424       _findReplace.updateFirstDocInSearch();
425     }
426   };
427   
428   /** Asks user for directory name and and reads it's files (and subdirectories files, on request) to
429    * the definitions pane.
430    */

431   private final Action _openFolderAction = new AbstractAction("Open Folder...") {
432     public void actionPerformed(ActionEvent ae) {
433       _openFolder();
434       _findReplace.updateFirstDocInSearch();
435     }
436   };
437   
438   /** Asks user for file name and and reads that file into the definitions pane. */
439   private final Action _openFileOrProjectAction = new AbstractAction("Open...") {
440     public void actionPerformed(ActionEvent ae) {
441       _openFileOrProject();
442       _findReplace.updateFirstDocInSearch();
443     }
444   };
445   
446   /** Asks user for project file name and and reads the associated files into the file navigator (and places the first
447    * source file in the editor pane)
448    */

449   private final Action _openProjectAction = new AbstractAction("Open...") {
450     public void actionPerformed(ActionEvent ae) { _openProject(); }
451   };
452   
453   private final Action _closeProjectAction = new AbstractAction("Close") {
454     public void actionPerformed(ActionEvent ae) {
455       _closeProject();
456       _findReplace.updateFirstDocInSearch();
457     }
458   };
459   
460   
461   /** Closes the current active document, prompting to save if necessary. */
462   private final Action _closeAction = new AbstractAction("Close") {
463     public void actionPerformed(ActionEvent ae) {
464       _close();
465       _findReplace.updateFirstDocInSearch();
466     }
467   };
468   
469   /** Closes all open documents, prompting to save if necessary. */
470   private final Action _closeAllAction = new AbstractAction("Close All") {
471     public void actionPerformed(ActionEvent ae) {
472       _closeAll();
473       _findReplace.updateFirstDocInSearch();
474     }
475   };
476   
477   /** Closes all open documents, prompting to save if necessary. */
478   private final Action _closeFolderAction = new AbstractAction("Close Folder") {
479     public void actionPerformed(ActionEvent ae) {
480       _closeFolder();
481       _findReplace.updateFirstDocInSearch();
482     }
483   };
484   
485   /** Opens all the files in the current folder. */
486   private final Action _openAllFolderAction = new AbstractAction("Open All Files") {
487     public void actionPerformed(ActionEvent ae) {
488       
489       // Get the Folder that was clicked on by the user. When the user clicks on a directory component in the
490
// navigation pane, the current directory is updated in the openChooser JFileChooser component. So the
491
// clicked on directory is obtained in this way
492
File dir = _openChooser.getCurrentDirectory();
493       _openFolder(dir, false);
494       _findReplace.updateFirstDocInSearch();
495     }
496   };
497   
498   /** Opens a files in the current folder. */
499   private final Action _openOneFolderAction = new AbstractAction("Open File in Folder") {
500     public void actionPerformed(ActionEvent ae) {
501       _open();
502       _findReplace.updateFirstDocInSearch();
503     }
504   };
505   
506   /** Creates a new untitled, empty file in the current folder. */
507   public final Action _newFileFolderAction = new AbstractAction("Create New File in Folder") {
508     public void actionPerformed(ActionEvent ae) {
509       //make this new document the document in the document pane
510
_new();
511       _findReplace.updateFirstDocInSearch();
512     }
513   };
514   
515   /** Tests all the files in a folder. */
516   private volatile AbstractAction _junitFolderAction = new AbstractAction("Test Folder") {
517     public final void actionPerformed(ActionEvent ae) { _junitFolder(); }
518   };
519   
520   /** Saves the current document. */
521   private final Action _saveAction = new AbstractAction("Save") {
522     public final void actionPerformed(ActionEvent ae) { _save(); }
523   };
524   
525   /** Ensures that pack() is run in the event thread. Only used in test code */
526   public void pack() {
527     Utilities.invokeAndWait(new Runnable JavaDoc() { public void run() { packHelp(); } });
528   }
529   
530   /** Helper method that provides access to super.pack() within the anonymous class new Runnable() {...} above */
531   private void packHelp() { super.pack(); }
532   
533   /** Supports MainFrameTest.*/
534   public boolean saveEnabledHuh() { return _saveAction.isEnabled(); }
535   
536   /** Asks the user for a file name and saves the document
537    * currently in the definitions pane to that file.
538    */

539   private final Action _saveAsAction = new AbstractAction("Save As...") {
540     public void actionPerformed(ActionEvent ae) { _saveAs(); }
541   };
542
543   /** Asks the user for a file name and renames and saves the document
544    * currently in the definitions pane to that file.
545    */

546   private final Action _renameAction = new AbstractAction("Rename") {
547     public void actionPerformed(ActionEvent ae) { _rename(); }
548   };
549   
550   private final Action _saveProjectAction = new AbstractAction("Save") {
551     public void actionPerformed(ActionEvent ae) {
552       _saveAll(); // saves project file and all modified project source files; does not save external files
553
}
554   };
555   
556   private final Action _saveProjectAsAction = new AbstractAction("Save As...") {
557     public void actionPerformed(ActionEvent ae) {
558       if (_saveProjectAs()) { // asks the user for a new project file name; sets _projectFile in global model to this value
559
_saveAll(); // performs a save all operation using this new project file name, but ONLY if the "Save as" was not cancelled
560
}
561     }
562   };
563   
564   /** Reverts the current document. */
565   private final Action _revertAction = new AbstractAction("Revert to Saved") {
566     public void actionPerformed(ActionEvent ae) {
567       String JavaDoc title = "Revert to Saved?";
568       
569       String JavaDoc message = "Are you sure you want to revert the current " +
570         "file to the version on disk?";
571       
572       int rc = JOptionPane.showConfirmDialog(MainFrame.this,
573                                              message,
574                                              title,
575                                              JOptionPane.YES_NO_OPTION);
576       if (rc == JOptionPane.YES_OPTION) {
577         _revert();
578       }
579     }
580   };
581   
582   /** Reverts all open documents.
583    * (not working yet)
584    private Action _revertAllAction = new AbstractAction("Revert All to Saved") {
585    public void actionPerformed(ActionEvent ae) {
586    String title = "Revert All to Saved?";
587    
588    String message = "Are you sure you want to revert all open " +
589    "files to the versions on disk?";
590    
591    int rc = JOptionPane.showConfirmDialog(MainFrame.this,
592    message,
593    title,
594    JOptionPane.YES_NO_OPTION);
595    if (rc == JOptionPane.YES_OPTION) {
596    _revertAll();
597    }
598    }
599    };*/

600   
601   /** Saves all documents, prompting for file names as necessary. */
602   final Action _saveAllAction = new AbstractAction("Save All") {
603     public void actionPerformed(ActionEvent ae) { _saveAll(); }
604   };
605   
606   /** Prints the current document. */
607   private final Action _printDefDocAction = new AbstractAction("Print...") {
608     public void actionPerformed(ActionEvent ae) { _printDefDoc(); }
609   };
610   
611   /** Prints the console document. */
612   private final Action _printConsoleAction = new AbstractAction("Print Console...") {
613     public void actionPerformed(ActionEvent ae) { _printConsole(); }
614   };
615   
616   /** Prints the interactions document. */
617   private final Action _printInteractionsAction = new AbstractAction("Print Interactions...") {
618     public void actionPerformed(ActionEvent ae) { _printInteractions(); }
619   };
620   
621   /** Opens the print preview window. */
622   private final Action _printDefDocPreviewAction = new AbstractAction("Print Preview...") {
623     public void actionPerformed(ActionEvent ae) { _printDefDocPreview(); }
624   };
625   
626   /** Opens the print preview window. */
627   private final Action _printConsolePreviewAction = new AbstractAction("Print Preview...") {
628     public void actionPerformed(ActionEvent ae) { _printConsolePreview(); }
629   };
630   
631   /** Opens the print preview window. */
632   private final Action _printInteractionsPreviewAction = new AbstractAction("Print Preview...") {
633     public void actionPerformed(ActionEvent ae) { _printInteractionsPreview(); }
634   };
635   
636   /** Opens the page setup window. */
637   private final Action _pageSetupAction = new AbstractAction("Page Setup...") {
638     public void actionPerformed(ActionEvent ae) { _pageSetup(); }
639   };
640   
641 // /** Compiles all the project. */
642
// private Action _compileOpenProjectAction = new AbstractAction("Compile Open Project Files") {
643
// public void actionPerformed(ActionEvent ae) { _compileAll(); } // right now, it's the same as compile all
644
// };
645

646  /** Compiles the document in the definitions pane. */
647   private final Action _compileAction = new AbstractAction("Compile Current Document") {
648     public void actionPerformed(ActionEvent ae) {
649       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
650         _mainSplit.resetToPreferredSizes();
651       _compile();
652     }
653   };
654   
655   /** Compiles all the project. */
656   private volatile AbstractAction _compileProjectAction = new AbstractAction("Compile Project") {
657     public void actionPerformed(ActionEvent ae) {
658       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
659         _mainSplit.resetToPreferredSizes();
660       _compileProject();
661       _findReplace.updateFirstDocInSearch();
662     }
663   };
664   
665   /** Compiles all documents in the navigators active group. */
666   private volatile AbstractAction _compileFolderAction = new AbstractAction("Compile Folder") {
667     public void actionPerformed(ActionEvent ae) {
668       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
669         _mainSplit.resetToPreferredSizes();
670       _compileFolder();
671       _findReplace.updateFirstDocInSearch();
672     }
673   };
674   
675   /** Compiles all open documents. */
676   private volatile AbstractAction _compileAllAction = new AbstractAction("Compile All Documents") {
677     public void actionPerformed(ActionEvent ae) {
678       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
679         _mainSplit.resetToPreferredSizes();
680       _compileAll();
681       _findReplace.updateFirstDocInSearch();
682     }
683   };
684   
685   /** cleans the build directory */
686   private volatile AbstractAction _cleanAction = new AbstractAction("Clean Build Directory") {
687     public void actionPerformed(ActionEvent ae) { _clean(); }
688   };
689   
690   /** Finds and runs the main method of the current document, if it exists. */
691   private volatile AbstractAction _runAction = new AbstractAction("Run Document's Main Method") {
692     public void actionPerformed(ActionEvent ae) { _runMain(); }
693   };
694   
695   /** Runs JUnit on the document in the definitions pane. */
696   private volatile AbstractAction _junitAction = new AbstractAction("Test Current Document") {
697     public void actionPerformed(ActionEvent ae) {
698       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
699       _junit();
700     }
701   };
702   
703   /** Runs JUnit over all open JUnit tests. */
704   private volatile AbstractAction _junitAllAction = new AbstractAction("Test All Documents") {
705     public void actionPerformed(ActionEvent e) {
706       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
707       _junitAll();
708       _findReplace.updateFirstDocInSearch();
709     }
710     
711   };
712   
713   /** Runs JUnit over all open JUnit tests in the project directory. */
714   private volatile AbstractAction _junitProjectAction = new AbstractAction("Test Project") {
715     public void actionPerformed(ActionEvent e) {
716       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
717       _junitProject();
718       _findReplace.updateFirstDocInSearch();
719     }
720   };
721   
722   
723 // /** JUnit a directory. */
724
// private final Action _junitProjectAction = new AbstractAction("Test Project") {
725
// public void actionPerformed(ActionEvent e) {
726
// new Thread("Running JUnit Tests") {
727
// public void run() {
728
// if (_model.isProjectActive()) {
729
// try {
730
// // hourglassOn(); // also done in junitStarted
731
// _model.junitAll();
732
// }
733
// finally {
734
// // hourglassOff(); // also done in junitEnded
735
// }
736
// }
737
// }
738
// }.start();
739
// }
740
// };
741

742   /** Runs Javadoc on all open documents (and the files in their packages). */
743   private final Action _javadocAllAction = new AbstractAction("Javadoc All Documents") {
744     public void actionPerformed(ActionEvent ae) {
745       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
746         _mainSplit.resetToPreferredSizes();
747       try {
748         // hourglassOn();
749
JavadocModel jm = _model.getJavadocModel();
750         File suggestedDir = jm.suggestJavadocDestination(_model.getActiveDocument());
751         _javadocSelector.setSuggestedDir(suggestedDir);
752         String JavaDoc cps = _model.getClassPath().toString();
753         jm.javadocAll(_javadocSelector, _saveSelector, cps);
754       }
755       catch (IOException ioe) { _showIOError(ioe); }
756       finally {
757         // hourglassOff();
758
}
759     }
760   };
761   
762   /** Runs Javadoc on the current document. */
763   private final Action _javadocCurrentAction = new AbstractAction("Preview Javadoc for Current Document") {
764     public void actionPerformed(ActionEvent ae) {
765       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
766         _mainSplit.resetToPreferredSizes();
767       try { _model.getActiveDocument().generateJavadoc(_saveSelector); }
768       catch (IOException ioe) { _showIOError(ioe); }
769     }
770   };
771   
772   /** Default cut action. Returns focus to the correct pane. */
773   final Action cutAction = new DefaultEditorKit.CutAction() {
774     public void actionPerformed(ActionEvent e) {
775       Component c = MainFrame.this.getFocusOwner();
776       super.actionPerformed(e);
777       if (_currentDefPane.hasFocus()) {
778         String JavaDoc s = Utilities.getClipboardSelection(c);
779         if ((s!=null) && (s.length()!=0)) { ClipboardHistoryModel.singleton().put(s); }
780       }
781       if (c != null) c.requestFocusInWindow();
782     }
783   };
784   
785   /** Default copy action. Returns focus to the correct pane. */
786   final Action copyAction = new DefaultEditorKit.CopyAction() {
787     public void actionPerformed(ActionEvent e) {
788       Component c = MainFrame.this.getFocusOwner();
789       super.actionPerformed(e);
790       if (_currentDefPane.hasFocus() && (_currentDefPane.getSelectedText()!=null)) {
791         String JavaDoc s = Utilities.getClipboardSelection(c);
792         if ((s!=null) && (s.length()!=0)) { ClipboardHistoryModel.singleton().put(s); }
793       }
794       if (c != null) c.requestFocusInWindow();
795     }
796   };
797   
798   /** We lost ownership of what we put in the clipboard. */
799   public void lostOwnership(Clipboard clipboard, Transferable contents) {
800     // ignore
801
}
802   
803   /** Default paste action. Returns focus to the correct pane. */
804   final Action pasteAction = new DefaultEditorKit.PasteAction() {
805     public void actionPerformed(ActionEvent e) {
806       Component c = MainFrame.this.getFocusOwner();
807       if (_currentDefPane.hasFocus()) {
808         _currentDefPane.endCompoundEdit();
809 // CompoundUndoManager undoMan = _model.getActiveDocument().getUndoManager(); // French keyboard fix
810
// int key = undoMan.startCompoundEdit(); // French keyboard fix
811
super.actionPerformed(e);
812         _currentDefPane.endCompoundEdit(); // replaced line below for French keyboard fix
813
// undoMan.endCompoundEdit(key); // French keyboard fix
814
}
815       else super.actionPerformed(e);
816       
817       if (c != null) c.requestFocusInWindow();
818     }
819   };
820   
821   /** Reset the position of the "Clipboard History" dialog. */
822   public void resetClipboardHistoryDialogPosition() {
823     if (DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) {
824       DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, "default");
825     }
826   }
827   
828   /** The "Clipboard History" dialog. */
829   private ClipboardHistoryFrame _clipboardHistoryDialog = null;
830   
831   /** Asks the user for a file name and goes there. */
832   private final Action _pasteHistoryAction = new AbstractAction("Paste from History...") {
833     public void actionPerformed(final ActionEvent ae) {
834       final ClipboardHistoryFrame.CloseAction cancelAction = new ClipboardHistoryFrame.CloseAction() {
835         public Object JavaDoc apply(String JavaDoc s) {
836           // "Clipboard History" dialog position and size.
837
if ((DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue())
838                 && (_clipboardHistoryDialog != null) && (_clipboardHistoryDialog.getFrameState() != null)) {
839             DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, (_clipboardHistoryDialog.getFrameState().toString()));
840           }
841           else {
842             // Reset to defaults to restore pristine behavior.
843
DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, DIALOG_CLIPBOARD_HISTORY_STATE.getDefault());
844           }
845           return null;
846         }
847       };
848       ClipboardHistoryFrame.CloseAction okAction = new ClipboardHistoryFrame.CloseAction() {
849         public Object JavaDoc apply(String JavaDoc s) {
850           cancelAction.apply(null);
851           
852           StringSelection ssel = new StringSelection(s);
853           Clipboard cb = MainFrame.this.getToolkit().getSystemClipboard();
854           if (cb!=null) {
855             cb.setContents(ssel, MainFrame.this);
856             pasteAction.actionPerformed(ae);
857           }
858           return null;
859         }
860       };
861       
862       _clipboardHistoryDialog = new ClipboardHistoryFrame(MainFrame.this,
863                                                           "Clipboard History", ClipboardHistoryModel.singleton(),
864                                                           okAction, cancelAction);
865       if (DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) {
866         _clipboardHistoryDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STATE));
867       }
868       _clipboardHistoryDialog.setVisible(true);
869     }
870   };
871   
872   /** Copies whatever is currently in the interactions pane at the prompt to the definitions pane. If the
873    * current string is empty, then it will attempt to return the last entry from the interactions pane's history.
874    */

875   private final Action _copyInteractionToDefinitionsAction =
876     new AbstractAction("Lift Current Interaction to Definitions") {
877     public void actionPerformed(ActionEvent a) {
878       String JavaDoc text = _interactionsController.getDocument().getCurrentInput();
879       if (! text.equals("")) {
880         _putTextIntoDefinitions(text + "\n");
881         return;
882       }
883       try { text = _interactionsController.getDocument().lastEntry(); }
884       catch(Exception JavaDoc e) { return; } // no entry to promote
885

886       //It is assumed that empty strings are not put into the history
887
_putTextIntoDefinitions(text + "\n");
888       return;
889     }
890   };
891   
892   /** Action that copies the previous interaction to the definitions pane.
893    * Is there a good way to get the last history element without perturbing the current document?
894    Action copyPreviousInteractionToDefinitionsAction = new AbstractAction("Copy previous interaction to definitions") {
895    public void actionPerformed(ActionEvent e) {
896    _putTextIntoDefinitions(_interactionsController.getDocument().getCurrentInput() + "\n");
897    }
898    };*/

899   
900   /** Undoes the last change to the active definitions document. */
901   private final DelegatingAction _undoAction = new DelegatingAction() {
902     public void actionPerformed(ActionEvent e) {
903       _currentDefPane.endCompoundEdit();
904       super.actionPerformed(e);
905       _currentDefPane.requestFocusInWindow();
906       OpenDefinitionsDocument doc = _model.getActiveDocument();
907 // Utilities.showDebug("isModifiedSinceSave() = " + doc.isModifiedSinceSave());
908
_saveAction.setEnabled(doc.isModifiedSinceSave() || doc.isUntitled());
909 // Utilities.showDebug("check status");
910
}
911   };
912   
913   /** Redoes the last undo to the active definitions document. */
914   private final DelegatingAction _redoAction = new DelegatingAction() {
915     public void actionPerformed(ActionEvent e) {
916       super.actionPerformed(e);
917       _currentDefPane.requestFocusInWindow();
918       OpenDefinitionsDocument doc = _model.getActiveDocument();
919       _saveAction.setEnabled(doc.isModifiedSinceSave() || doc.isUntitled());
920     }
921   };
922   
923   /** Quits DrJava. Optionally displays a prompt before quitting. */
924   private final Action _quitAction = new AbstractAction("Quit") {
925     public void actionPerformed(ActionEvent ae) { _quit(); }
926   };
927   
928   
929    /** Quits DrJava. Optionally displays a prompt before quitting. */
930   private final Action _forceQuitAction = new AbstractAction("Force Quit") {
931     public void actionPerformed(ActionEvent ae) { _forceQuit(); }
932   };
933   
934   /** Selects all text in window. */
935   private final Action _selectAllAction = new AbstractAction("Select All") {
936     public void actionPerformed(ActionEvent ae) { _selectAll(); }
937   };
938   
939   private void _showFindReplaceTab() {
940       if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
941         _mainSplit.resetToPreferredSizes();
942       if (! _findReplace.isDisplayed()) {
943         showTab(_findReplace);
944         _findReplace.beginListeningTo(_currentDefPane);
945       }
946       _findReplace.setVisible(true);
947       _tabbedPane.setSelectedComponent(_findReplace);
948   }
949   
950   /** Shows the find/replace tab. */
951   private final Action _findReplaceAction = new AbstractAction("Find/Replace") {
952     public void actionPerformed(ActionEvent ae) {
953       _showFindReplaceTab();
954       // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
955
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { _findReplace.requestFocusInWindow(); } });
956     }
957   };
958   
959   /** Find the next instance of the find word. */
960   private final Action _findNextAction = new AbstractAction("Find Next") {
961     public void actionPerformed(ActionEvent ae) {
962       _showFindReplaceTab();
963       if (!DrJava.getConfig().getSetting(FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
964         // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
965
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { _findReplace.requestFocusInWindow(); } });
966       }
967       _findReplace.findNext();
968       _currentDefPane.requestFocusInWindow();
969       // atempt to fix intermittent bug where _currentDefPane listens but does not echo and won't undo!
970
}
971   };
972   
973   /** Does the find next in the opposite direction. If the direction is backward it searches forward. */
974   private final Action _findPrevAction = new AbstractAction("Find Previous") {
975     public void actionPerformed(ActionEvent ae) {
976       _showFindReplaceTab();
977       if (!DrJava.getConfig().getSetting(FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
978         // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
979
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { _findReplace.requestFocusInWindow(); } });
980       }
981       _findReplace.findPrevious();
982       _currentDefPane.requestFocusInWindow();
983     }
984   };
985   
986   /** Asks the user for a line number and goes there. */
987   private final Action _gotoLineAction = new AbstractAction("Go to Line...") {
988     public void actionPerformed(ActionEvent ae) {
989       int pos = _gotoLine();
990       _currentDefPane.requestFocusInWindow();
991       if (pos != -1) _currentDefPane.setCaretPosition(pos);
992       // The preceding is a brute force attempt to fix intermittent failure to display caret
993
}
994   };
995
996   /** Wrapper class for the "Go to File" dialog list entries. Provides the ability to have the same
997    * OpenDefinitionsDocument in there multiple times with different toString() results.
998    */

999   private static class GoToFileListEntry implements Comparable JavaDoc<GoToFileListEntry> {
1000    public final OpenDefinitionsDocument doc;
1001    private final String JavaDoc str;
1002    public GoToFileListEntry(OpenDefinitionsDocument d, String JavaDoc s) {
1003      doc = d;
1004      str = s;
1005    }
1006    public String JavaDoc toString() { return str; }
1007    public int compareTo(GoToFileListEntry other) { return str.toLowerCase().compareTo(other.str.toLowerCase()); }
1008    public boolean equals(Object JavaDoc other) {
1009      if (! (other instanceof GoToFileListEntry)) return false;
1010      return str.equals(((GoToFileListEntry)other).str);
1011    }
1012    public int hashCode() { return str.hashCode(); }
1013  }
1014
1015  /** Reset the position of the "Go to File" dialog. */
1016  public void resetGotoFileDialogPosition() {
1017    initGotoFileDialog();
1018    _gotoFileDialog.setFrameState("default");
1019    if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) {
1020      DrJava.getConfig().setSetting(DIALOG_GOTOFILE_STATE, "default");
1021    }
1022  }
1023  
1024  /** Initialize dialog if necessary. */
1025  void initGotoFileDialog() {
1026    if (_gotoFileDialog == null) {
1027      PredictiveInputFrame.InfoSupplier<GoToFileListEntry> info =
1028        new PredictiveInputFrame.InfoSupplier<GoToFileListEntry>() {
1029        public String JavaDoc apply(GoToFileListEntry entry) {
1030          final StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
1031          
1032          if (entry.doc != null) {
1033            try {
1034              try { sb.append(FileOps.makeRelativeTo(entry.doc.getRawFile(), entry.doc.getSourceRoot())); }
1035              catch(IOException e) { sb.append(entry.doc.getFile()); }
1036            }
1037            catch(edu.rice.cs.drjava.model.FileMovedException e) { sb.append(entry + " was moved"); }
1038            catch(java.lang.IllegalStateException JavaDoc e) { sb.append(entry); }
1039            catch(InvalidPackageException e) { sb.append(entry); }
1040          }
1041          else sb.append(entry);
1042          return sb.toString();
1043        }
1044      };
1045      PredictiveInputFrame.CloseAction<GoToFileListEntry> okAction =
1046        new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
1047        public Object JavaDoc apply(PredictiveInputFrame<GoToFileListEntry> p) {
1048          if (p.getItem() != null) {
1049            final OpenDefinitionsDocument newDoc = p.getItem().doc;
1050// final boolean docChanged = ! newDoc.equals(_model.getActiveDocument());
1051
// if (docChanged) addToBrowserHistory();
1052
_model.setActiveDocument(newDoc);
1053            final int curLine = newDoc.getCurrentLine();
1054            final String JavaDoc t = p.getText();
1055            final int last = t.lastIndexOf(':');
1056            if (last >= 0) {
1057              try {
1058                String JavaDoc end = t.substring(last + 1);
1059                int val = Integer.parseInt(end);
1060                int maxLines = p.getItem().doc.getNumberOfLines();
1061                final int lineNum = Math.max(1, Math.min(maxLines, val));
1062                SwingUtilities.invokeLater(new Runnable JavaDoc() {
1063                  public void run() {
1064                    try { _jumpToLine(lineNum); }
1065                    catch (RuntimeException JavaDoc e) { _jumpToLine(curLine); }
1066// if (docChanged) addToBrowserHistory();
1067
}
1068                });
1069              }
1070              catch(RuntimeException JavaDoc e) { /* ignore */ }
1071            }
1072// if (docChanged) {
1073
// // defer executing this code until after active document switch (if any) is complete
1074
// SwingUtilities.invokeLater(new Runnable() {
1075
// public void run() {
1076
// addToBrowserHistory();
1077
// }
1078
// });
1079
// }
1080
}
1081          hourglassOff();
1082          return null;
1083        }
1084      };
1085      PredictiveInputFrame.CloseAction<GoToFileListEntry> cancelAction =
1086        new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
1087        public Object JavaDoc apply(PredictiveInputFrame<GoToFileListEntry> p) {
1088          hourglassOff();
1089          return null;
1090        }
1091      };
1092      java.util.ArrayList JavaDoc<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>> strategies =
1093        new java.util.ArrayList JavaDoc<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>>();
1094      strategies.add(new PredictiveInputModel.FragmentLineNumStrategy<GoToFileListEntry>());
1095      strategies.add(new PredictiveInputModel.PrefixLineNumStrategy<GoToFileListEntry>());
1096      strategies.add(new PredictiveInputModel.RegExLineNumStrategy<GoToFileListEntry>());
1097      _gotoFileDialog =
1098        new PredictiveInputFrame<GoToFileListEntry>(MainFrame.this,
1099                                                    "Go to File",
1100                                                    true, // force
1101
true, // ignore case
1102
info,
1103                                                    strategies,
1104                                                    okAction,
1105                                                    cancelAction,
1106                                                    new GoToFileListEntry(null, "dummy")) {
1107        public void setOwnerEnabled(boolean b) {
1108          if (b) { hourglassOff(); } else { hourglassOn(); }
1109        }
1110      };
1111      // putting one dummy entry in the list; it will be changed later anyway
1112

1113      if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) {
1114        _gotoFileDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STATE));
1115      }
1116    }
1117  }
1118
1119  /** The "Go to File" dialog instance. */
1120  volatile PredictiveInputFrame<GoToFileListEntry> _gotoFileDialog = null;
1121 
1122  /** Asks the user for a file name and goes there. */
1123  private final Action _gotoFileAction = new AbstractAction("Go to File...") {
1124    public void actionPerformed(ActionEvent ae) {
1125      initGotoFileDialog();
1126      List JavaDoc<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments();
1127      if ((docs==null) || (docs.size() == 0)) {
1128        return; // do nothing
1129
}
1130      GoToFileListEntry currentEntry = null;
1131      ArrayList JavaDoc<GoToFileListEntry> list;
1132      if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) {
1133        list = new ArrayList JavaDoc<GoToFileListEntry>(2 * docs.size());
1134      }
1135      else {
1136        list = new ArrayList JavaDoc<GoToFileListEntry>(docs.size());
1137      }
1138      for(OpenDefinitionsDocument d: docs) {
1139        GoToFileListEntry entry = new GoToFileListEntry(d, d.toString());
1140        if (d.equals(_model.getActiveDocument())) {
1141          currentEntry = entry;
1142        }
1143        list.add(entry);
1144        if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) {
1145          try {
1146            try {
1147              File relative = FileOps.makeRelativeTo(d.getFile(), d.getSourceRoot());
1148              if (!relative.toString().equals(d.toString())) {
1149                list.add(new GoToFileListEntry(d, d.getPackageName() + "." + d.toString()));
1150              }
1151            }
1152            catch(IOException e) {
1153              // ignore
1154
}
1155            catch(edu.rice.cs.drjava.model.definitions.InvalidPackageException e) {
1156              // ignore
1157
}
1158          }
1159          catch(IllegalStateException JavaDoc e) {
1160            // ignore
1161
}
1162        }
1163      }
1164      _gotoFileDialog.setItems(true, list); // ignore case
1165
if (currentEntry != null) {
1166        _gotoFileDialog.setCurrentItem(currentEntry);
1167      }
1168      hourglassOn();
1169      /* if (! Utilities.TEST_MODE) */
1170      _gotoFileDialog.setVisible(true);
1171    }
1172  };
1173   
1174  /** Goes to the file specified by the word the cursor is on. */
1175  void _gotoFileUnderCursor() {
1176// Utilities.show("Calling gotoFileUnderCursor()");
1177
List JavaDoc<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments();
1178    if ((docs == null) || (docs.size() == 0)) return; // do nothing
1179

1180    GoToFileListEntry currentEntry = null;
1181    ArrayList JavaDoc<GoToFileListEntry> list;
1182    list = new ArrayList JavaDoc<GoToFileListEntry>(docs.size());
1183    for(OpenDefinitionsDocument d: docs) {
1184      GoToFileListEntry entry = new GoToFileListEntry(d, d.toString());
1185      if (d.equals(_model.getActiveDocument())) currentEntry = entry;
1186      list.add(entry);
1187    }
1188    
1189    PredictiveInputModel<GoToFileListEntry> pim =
1190      new PredictiveInputModel<GoToFileListEntry>(true,
1191                                                  new PredictiveInputModel.PrefixStrategy<GoToFileListEntry>(),
1192                                                  list);
1193    OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
1194    odd.acquireReadLock();
1195    String JavaDoc mask = "";
1196    try {
1197      int loc = getCurrentDefPane().getCaretPosition();
1198      String JavaDoc s = odd.getText();
1199      // find start
1200
int start = loc;
1201      while(start>0) {
1202        if (! Character.isJavaIdentifierPart(s.charAt(start-1))) { break; }
1203        --start;
1204      }
1205      while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start<loc)) {
1206        ++start;
1207      }
1208      // find end
1209
int end = loc-1;
1210      while(end<s.length()-1) {
1211        if (! Character.isJavaIdentifierPart(s.charAt(end+1))) { break; }
1212        ++end;
1213      }
1214      if ((start>=0) && (end<s.length())) {
1215        mask = s.substring(start, end + 1);
1216        pim.setMask(mask);
1217      }
1218    }
1219    finally { odd.releaseReadLock(); }
1220    
1221// Utilities.show("Matching items are: " + pim.getMatchingItems());
1222

1223    if (pim.getMatchingItems().size() == 1) {
1224      // exactly one match, go to file
1225
if (pim.getCurrentItem() != null) {
1226// boolean docChanged = !pim.getCurrentItem().doc.equals(_model.getActiveDocument());
1227
// if (docChanged) { addToBrowserHistory(); }
1228
_model.setActiveDocument(pim.getCurrentItem().doc);
1229// if (docChanged) {
1230
// // defer executing this code until after active document switch (if any) is complete
1231
// SwingUtilities.invokeLater(new Runnable() {
1232
// public void run() { addToBrowserHistory(); } });
1233
// }
1234
}
1235    }
1236    else {
1237      // try appending ".java" and see if it's unique
1238
pim.extendMask(".java");
1239      if (pim.getMatchingItems().size() == 1) {
1240        // exactly one match with ".java" appended, go to file
1241
if (pim.getCurrentItem() != null) {
1242// boolean docChanged = !pim.getCurrentItem().doc.equals(_model.getActiveDocument());
1243
// if (docChanged) { addToBrowserHistory(); }
1244
_model.setActiveDocument(pim.getCurrentItem().doc);
1245// if (docChanged) {
1246
// // defer executing this code until after active document switch (if any) is complete
1247
// SwingUtilities.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
1248
// }
1249
}
1250      }
1251      else {
1252        // not exactly one match
1253
pim.setMask(mask);
1254        if (pim.getMatchingItems().size() == 0) {
1255          // if there are no matches, shorten the mask until there is at least one
1256
mask = pim.getMask();
1257          while(mask.length()>0) {
1258            mask = mask.substring(0, mask.length() - 1);
1259            pim.setMask(mask);
1260            if (pim.getMatchingItems().size()>0) { break; }
1261          }
1262        }
1263        initGotoFileDialog();
1264        _gotoFileDialog.setModel(true, pim); // ignore case
1265
if (currentEntry != null) _gotoFileDialog.setCurrentItem(currentEntry);
1266        hourglassOn();
1267        /* The following predicate suppresses the display of the dialog during unit testing. If the unit test is revised
1268         * to confirm that the dialog is displayed, this test must be removed. */

1269        if (MainFrame.this.isVisible()) _gotoFileDialog.setVisible(true); // predicate suppresses display in unit tests
1270
}
1271    }
1272  }
1273  
1274  /** Goes to the file specified by the word the cursor is on. */
1275  final Action gotoFileUnderCursorAction = new AbstractAction("Go to File Under Cursor") {
1276    public void actionPerformed(ActionEvent ae) {
1277      _gotoFileUnderCursor();
1278    }
1279  };
1280  
1281
1282  /** Wrapper class for the "Open Javadoc" dialog list entries. Provides the ability to have the same class name in
1283    * there multiple times in different packages.
1284    */

1285  private static class OpenJavadocListEntry implements Comparable JavaDoc<OpenJavadocListEntry> {
1286    private final String JavaDoc str, fullStr;
1287    private final URL JavaDoc url;
1288    public OpenJavadocListEntry(String JavaDoc s, String JavaDoc full, URL JavaDoc u) {
1289      str = s;
1290      fullStr = full;
1291      url = u;
1292    }
1293    public String JavaDoc toString() { return str; }
1294    public String JavaDoc getFullString() { return fullStr; }
1295    public URL JavaDoc getURL() { return url; }
1296    public int compareTo(OpenJavadocListEntry other) {
1297      return str.toLowerCase().compareTo(other.str.toLowerCase());
1298    }
1299    public boolean equals(Object JavaDoc other) {
1300      if (!(other instanceof OpenJavadocListEntry)) return false;
1301      return fullStr.equals(((OpenJavadocListEntry)other).fullStr);
1302    }
1303    public int hashCode() {
1304      return fullStr.hashCode();
1305    }
1306  }
1307
1308  /** Reset the position of the "Open Javadoc" dialog. */
1309  public void resetOpenJavadocDialogPosition() {
1310    initOpenJavadocDialog();
1311    _openJavadocDialog.setFrameState("default");
1312    if (DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) {
1313      DrJava.getConfig().setSetting(DIALOG_OPENJAVADOC_STATE, "default");
1314    }
1315  }
1316  
1317  /** Initialize dialog if necessary. */
1318  void initOpenJavadocDialog() {
1319    if (_openJavadocDialog==null) {
1320      PredictiveInputFrame.InfoSupplier<OpenJavadocListEntry> info =
1321        new PredictiveInputFrame.InfoSupplier<OpenJavadocListEntry>() {
1322        public String JavaDoc apply(OpenJavadocListEntry entry) {
1323          return entry.getFullString();
1324        }
1325      };
1326      PredictiveInputFrame.CloseAction<OpenJavadocListEntry> okAction =
1327        new PredictiveInputFrame.CloseAction<OpenJavadocListEntry>() {
1328        public Object JavaDoc apply(PredictiveInputFrame<OpenJavadocListEntry> p) {
1329          if (p.getItem()!=null) {
1330            PlatformFactory.ONLY.openURL(p.getItem().getURL());
1331          }
1332          hourglassOff();
1333          return null;
1334        }
1335      };
1336      PredictiveInputFrame.CloseAction<OpenJavadocListEntry> cancelAction =
1337        new PredictiveInputFrame.CloseAction<OpenJavadocListEntry>() {
1338        public Object JavaDoc apply(PredictiveInputFrame<OpenJavadocListEntry> p) {
1339          hourglassOff();
1340          return null;
1341        }
1342      };
1343      java.util.ArrayList JavaDoc<PredictiveInputModel.MatchingStrategy<OpenJavadocListEntry>> strategies =
1344        new java.util.ArrayList JavaDoc<PredictiveInputModel.MatchingStrategy<OpenJavadocListEntry>>();
1345      strategies.add(new PredictiveInputModel.FragmentStrategy<OpenJavadocListEntry>());
1346      strategies.add(new PredictiveInputModel.PrefixStrategy<OpenJavadocListEntry>());
1347      strategies.add(new PredictiveInputModel.RegExStrategy<OpenJavadocListEntry>());
1348      _openJavadocDialog =
1349        new PredictiveInputFrame<OpenJavadocListEntry>(MainFrame.this,
1350                                                       "Open Java API Javadoc Webpage",
1351                                                       true, // force
1352
true, // ignore case
1353
info,
1354                                                       strategies,
1355                                                       okAction,
1356                                                       cancelAction,
1357                                                       new OpenJavadocListEntry("dummy", "dummy", null)) {
1358        public void setOwnerEnabled(boolean b) {
1359          if (b) { hourglassOff(); } else { hourglassOn(); }
1360        }
1361      };
1362      // putting one dummy entry in the list; it will be changed later anyway
1363

1364      if (DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) {
1365        _openJavadocDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STATE));
1366      }
1367      generateOpenJavadocList();
1368    }
1369  }
1370  
1371  /** Generate Javadoc class list. */
1372  void generateOpenJavadocList() {
1373    if (_openJavadocList==null) {
1374      // generate list
1375
String JavaDoc linkVersion = DrJava.getConfig().getSetting(JAVADOC_LINK_VERSION);
1376      String JavaDoc base = "";
1377      if (linkVersion.equals(JAVADOC_1_3_TEXT)) {
1378        base = DrJava.getConfig().getSetting(JAVADOC_1_3_LINK);
1379      }
1380      else if (linkVersion.equals(JAVADOC_1_4_TEXT)) {
1381        base = DrJava.getConfig().getSetting(JAVADOC_1_4_LINK);
1382      }
1383      else if (linkVersion.equals(JAVADOC_1_5_TEXT)) {
1384        base = DrJava.getConfig().getSetting(JAVADOC_1_5_LINK);
1385      }
1386      else {
1387        // no valid Javadoc URL
1388
return;
1389      }
1390      // TODO: put this in an AsyncTask
1391
try {
1392        _openJavadocList = new ArrayList JavaDoc<OpenJavadocListEntry>();
1393        URL JavaDoc url = new URL JavaDoc(base + "/allclasses-frame.html");
1394        BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
1395        String JavaDoc line = br.readLine();
1396        while(line!=null) {
1397          final String JavaDoc aText = "<a HREF=\"";
1398          int aPos = line.toLowerCase().indexOf(aText);
1399          int aEndPos = line.toLowerCase().indexOf(".html\" ",aPos);
1400          if ((aPos>=0) && (aEndPos>=0)) {
1401            String JavaDoc link = line.substring(aPos+aText.length(), aEndPos);
1402            String JavaDoc fullClassName = link.replace('/', '.');
1403            String JavaDoc simpleClassName = fullClassName;
1404            int lastDot = fullClassName.lastIndexOf('.');
1405            if (lastDot>=0) { simpleClassName = fullClassName.substring(lastDot + 1); }
1406            try {
1407              _openJavadocList.add(new OpenJavadocListEntry(simpleClassName, fullClassName, new URL JavaDoc(base + "/" + link + ".html")));
1408            }
1409            catch(MalformedURLException JavaDoc mue) { /* ignore, we'll just not put this class in the list */ }
1410          }
1411          line = br.readLine();
1412        }
1413      }
1414      catch(IOException ioe) { /* ignore, we'll just have an incomplete list */ }
1415      if (_openJavadocList.size()==0) { _openJavadocList = null; }
1416    }
1417  }
1418
1419  /** The "Open Javadoc" dialog instance. */
1420  PredictiveInputFrame<OpenJavadocListEntry> _openJavadocDialog = null;
1421  
1422  /** The list of Java API classes. */
1423  List JavaDoc<OpenJavadocListEntry> _openJavadocList = null;
1424 
1425  /** Asks the user for a file name and goes there. */
1426  private Action _openJavadocAction = new AbstractAction("Open Java API Javadoc...") {
1427    public void actionPerformed(ActionEvent ae) {
1428      initOpenJavadocDialog();
1429      _openJavadocDialog.setItems(true, _openJavadocList); // ignore case
1430
hourglassOn();
1431      _openJavadocDialog.setVisible(true);
1432    }
1433  };
1434   
1435  /** Opens the Javadoc specified by the word the cursor is on. */
1436  void _openJavadocUnderCursor() {
1437    generateOpenJavadocList();
1438    if (_openJavadocList == null) {
1439      Utilities.show("Cannot load Java API class list. No network connectivity?");
1440      return;
1441    }
1442    PredictiveInputModel<OpenJavadocListEntry> pim =
1443      new PredictiveInputModel<OpenJavadocListEntry>(true,
1444                                                     new PredictiveInputModel.PrefixStrategy<OpenJavadocListEntry>(),
1445                                                     _openJavadocList);
1446    OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
1447    odd.acquireReadLock();
1448    String JavaDoc mask = "";
1449    try {
1450      int loc = getCurrentDefPane().getCaretPosition();
1451      String JavaDoc s = odd.getText();
1452      // find start
1453
int start = loc;
1454      while(start>0) {
1455        if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; }
1456        --start;
1457      }
1458      while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start<loc)) {
1459        ++start;
1460      }
1461      // find end
1462
int end = loc-1;
1463      while(end<s.length()-1) {
1464        if (!Character.isJavaIdentifierPart(s.charAt(end+1))) { break; }
1465        ++end;
1466      }
1467      if ((start>=0) && (end<s.length())) {
1468        mask = s.substring(start, end + 1);
1469        pim.setMask(mask);
1470      }
1471    }
1472    finally { odd.releaseReadLock(); }
1473    
1474// Utilities.show("Matching items are: " + pim.getMatchingItems());
1475

1476    if (pim.getMatchingItems().size() == 1) {
1477      // exactly one match, go to file
1478
if (pim.getCurrentItem() != null) {
1479        PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL());
1480      }
1481    }
1482    else {
1483      // try appending ".java" and see if it's unique
1484
pim.extendMask(".java");
1485      if (pim.getMatchingItems().size() == 1) {
1486        // exactly one match with ".java" appended, go to file
1487
if (pim.getCurrentItem() != null) {
1488          PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL());
1489        }
1490      }
1491      else {
1492        // not exactly one match
1493
pim.setMask(mask);
1494        OpenJavadocListEntry foundItem = null;
1495        int found = 0;
1496        if (pim.getMatchingItems().size() == 0) {
1497          // if there are no matches, shorten the mask until there is at least one
1498
mask = pim.getMask();
1499          while(mask.length()>0) {
1500            mask = mask.substring(0, mask.length() - 1);
1501            pim.setMask(mask);
1502            if (pim.getMatchingItems().size() > 0) { break; }
1503          }
1504        }
1505        else {
1506          // there are several matches, see if there is an exact match
1507
for(OpenJavadocListEntry e: pim.getMatchingItems()) {
1508            if (e.toString().equalsIgnoreCase(mask)) {
1509              ++found;
1510              foundItem = e;
1511            }
1512          }
1513        }
1514        if (found==1) {
1515          // open unique item and return
1516
PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL());
1517        }
1518        else {
1519          initOpenJavadocDialog();
1520          _openJavadocDialog.setModel(true, pim); // ignore case
1521
hourglassOn();
1522          _openJavadocDialog.setVisible(true);
1523        }
1524      }
1525    }
1526  }
1527  
1528  /** Open Javadoc page specified by the word the cursor is on. */
1529  final Action _openJavadocUnderCursorAction = new AbstractAction("Open Java API Javadoc for Word Under Cursor...") {
1530    public void actionPerformed(ActionEvent ae) {
1531      _openJavadocUnderCursor();
1532    }
1533  };
1534
1535  /** Reset the position of the "Complete Word" dialog. */
1536  public void resetCompleteWordDialogPosition() {
1537    initCompleteWordDialog();
1538    _completeWordDialog.setFrameState("default");
1539    if (DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) {
1540      DrJava.getConfig().setSetting(DIALOG_COMPLETE_WORD_STATE, "default");
1541    }
1542  }
1543  
1544  /** Initialize dialog if necessary. */
1545  void initCompleteWordDialog() {
1546    if (_completeWordDialog == null) {
1547      PredictiveInputFrame.CloseAction<GoToFileListEntry> okAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
1548        public Object JavaDoc apply(PredictiveInputFrame<GoToFileListEntry> p) {
1549          if (p.getItem()!=null) {
1550            OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
1551            try {
1552              String JavaDoc mask = "";
1553              int loc = getCurrentDefPane().getCaretPosition();
1554              String JavaDoc s = odd.getText(AbstractDJDocument.DOCSTART, loc);
1555              
1556              // check that we're at the end of a word
1557
if ((loc<s.length()) && (!Character.isWhitespace(s.charAt(loc))) &&
1558                  ("()[]{}<>.,:;/*+-!~&|%".indexOf(s.charAt(loc)) == -1)) return null;
1559              
1560              // find start
1561
int start = loc;
1562              while(start>0) {
1563                if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; }
1564                --start;
1565              }
1566              while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start < loc)) {
1567                ++start;
1568              }
1569              
1570              if (!s.substring(start, loc).equals(p.getItem().toString())) {
1571                odd.remove(start, loc-start);
1572                odd.insertString(start, p.getItem().toString(), null);
1573              }
1574            }
1575            catch(BadLocationException ble) { /* ignore, just don't auto-complete */ }
1576            finally { odd.releaseWriteLock(); }
1577          }
1578          hourglassOff();
1579          return null;
1580        }
1581      };
1582      PredictiveInputFrame.CloseAction<GoToFileListEntry> cancelAction =
1583        new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
1584        public Object JavaDoc apply(PredictiveInputFrame<GoToFileListEntry> p) {
1585          hourglassOff();
1586          return null;
1587        }
1588      };
1589      java.util.ArrayList JavaDoc<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>> strategies =
1590        new java.util.ArrayList JavaDoc<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>>();
1591      strategies.add(new PredictiveInputModel.FragmentStrategy<GoToFileListEntry>());
1592      strategies.add(new PredictiveInputModel.PrefixStrategy<GoToFileListEntry>());
1593      strategies.add(new PredictiveInputModel.RegExStrategy<GoToFileListEntry>());
1594      _completeWordDialog =
1595        new PredictiveInputFrame<GoToFileListEntry>(MainFrame.this,
1596                                                    "Auto-Complete Word",
1597                                                    true, // force
1598
true, // ignore case
1599
null,
1600                                                    strategies,
1601                                                    okAction,
1602                                                    cancelAction,
1603                                                    new GoToFileListEntry(null, "dummy")) {
1604        public void setOwnerEnabled(boolean b) {
1605          if (b) { hourglassOff(); } else { hourglassOn(); }
1606        }
1607      };
1608      // putting one dummy entry in the list; it will be changed later anyway
1609

1610      if (DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) {
1611        _completeWordDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STATE));
1612      }
1613    }
1614  }
1615
1616
1617  /** The "Complete File" dialog instance. */
1618  volatile PredictiveInputFrame<GoToFileListEntry> _completeFileDialog = null;
1619  /** The "Complete Word" dialog instance. */
1620  volatile PredictiveInputFrame<GoToFileListEntry> _completeWordDialog = null;
1621   
1622  /** Complete the word the cursor is on. */
1623  void _completeWordUnderCursor() {
1624    List JavaDoc<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments();
1625    if ((docs==null) || (docs.size() == 0)) return; // do nothing
1626

1627    GoToFileListEntry currentEntry = null;
1628    ArrayList JavaDoc<GoToFileListEntry> list;
1629    if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue()) &&
1630        (_completeClassList.size()>0)) {
1631      list = _completeClassList;
1632    }
1633    else {
1634      list = new ArrayList JavaDoc<GoToFileListEntry>(docs.size());
1635      for(OpenDefinitionsDocument d: docs) {
1636        if (d.isUntitled()) continue;
1637        String JavaDoc str = d.toString();
1638        if (str.lastIndexOf('.')>=0) {
1639          str = str.substring(0, str.lastIndexOf('.'));
1640        }
1641        GoToFileListEntry entry = new GoToFileListEntry(d, str);
1642        if (d.equals(_model.getActiveDocument())) currentEntry = entry;
1643        list.add(entry);
1644      }
1645    }
1646    
1647    PredictiveInputModel<GoToFileListEntry> pim =
1648      new PredictiveInputModel<GoToFileListEntry>(true, new PredictiveInputModel.PrefixStrategy<GoToFileListEntry>(),
1649                                                  list);
1650    OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
1651    odd.acquireWriteLock();
1652    boolean uniqueMatch = true;
1653    try {
1654      String JavaDoc mask = "";
1655      int loc = getCurrentDefPane().getCaretPosition();
1656      String JavaDoc s = odd.getText(AbstractDJDocument.DOCSTART, loc);
1657      
1658      // check that we're at the end of a word
1659
if ((loc<s.length()) && (!Character.isWhitespace(s.charAt(loc))) &&
1660          ("()[]{}<>.,:;/*+-!~&|%".indexOf(s.charAt(loc)) == -1)) return;
1661      
1662      // find start
1663
int start = loc;
1664      while(start > 0) {
1665        if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; }
1666        --start;
1667      }
1668      while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start < loc)) {
1669        ++start;
1670      }
1671      
1672      int end = loc-1;
1673      
1674      if ((start>=0) && (end < s.length())) {
1675        mask = s.substring(start, end + 1);
1676        pim.setMask(mask);
1677      }
1678      
1679      if (pim.getMatchingItems().size() == 1) {
1680        if (pim.getCurrentItem() != null) {
1681          // exactly one match, auto-complete
1682
if (! s.substring(start, loc).equals(pim.getCurrentItem().toString())) {
1683            odd.remove(start, loc - start);
1684            odd.insertString(start, pim.getCurrentItem().toString(), null);
1685          }
1686          return;
1687        }
1688      }
1689      else {
1690        // not exactly one match
1691
uniqueMatch = false;
1692        pim.setMask(mask);
1693        if (pim.getMatchingItems().size() == 0) {
1694          // if there are no matches, shorten the mask until there is at least one
1695
mask = pim.getMask();
1696          while(mask.length() > 0) {
1697            mask = mask.substring(0, mask.length() - 1);
1698            pim.setMask(mask);
1699            if (pim.getMatchingItems().size() > 0) { break; }
1700          }
1701        }
1702        initCompleteWordDialog();
1703        _completeWordDialog.setModel(true, pim); // ignore case
1704
_completeWordDialog.selectStrategy();
1705        if (currentEntry != null) _completeWordDialog.setCurrentItem(currentEntry);
1706        hourglassOn();
1707        _completeWordDialog.setVisible(true);
1708      }
1709    }
1710    catch(BadLocationException ble) { /* ignore, just don't auto-complete */ }
1711    finally {
1712      if (uniqueMatch) { odd.releaseWriteLock(); }
1713    }
1714  }
1715  
1716  /** Auto-completes word the cursor is on. */
1717  final Action completeWordUnderCursorAction = new AbstractAction("Auto-Complete Word Under Cursor") {
1718    public void actionPerformed(ActionEvent ae) {
1719      _completeWordUnderCursor();
1720    }
1721  };
1722
1723  /** Indents the current selection. */
1724  private final Action _indentLinesAction = new AbstractAction("Indent Line(s)") {
1725    public void actionPerformed(ActionEvent ae) {
1726      _currentDefPane.endCompoundEdit();
1727      _currentDefPane.indent();
1728    }
1729  };
1730  
1731  /** Action for commenting out a block of text using wing comments. */
1732  private final Action _commentLinesAction = new AbstractAction("Comment Line(s)") {
1733    public void actionPerformed(ActionEvent ae) {
1734      hourglassOn();
1735      try{ commentLines(); }
1736      finally{ hourglassOff(); }
1737    }
1738  };
1739  
1740  /** Action for un-commenting a block of commented text. */
1741  private final Action _uncommentLinesAction = new AbstractAction("Uncomment Line(s)") {
1742    public void actionPerformed(ActionEvent ae){
1743      hourglassOn();
1744      try{ uncommentLines(); }
1745      finally{ hourglassOff(); }
1746    }
1747  };
1748  
1749  /** Clears DrJava's output console. */
1750  private final Action _clearConsoleAction = new AbstractAction("Clear Console") {
1751    public void actionPerformed(ActionEvent ae) { _model.resetConsole(); }
1752  };
1753  
1754  /** Shows the DebugConsole. */
1755  private final Action _showDebugConsoleAction = new AbstractAction("Show DrJava Debug Console") {
1756    public void actionPerformed(ActionEvent e) { DrJavaRoot.showDrJavaDebugConsole(MainFrame.this); }
1757  };
1758  
1759  /* Enables the reset interactions command. Not currently used, since this action is NEVER disabled. */
1760  public void enableResetInteractions() { _resetInteractionsAction.setEnabled(true); }
1761  
1762  /** Resets the Interactions pane. */
1763  private final Action _resetInteractionsAction = new AbstractAction("Reset Interactions") {
1764    public void actionPerformed(ActionEvent ae) {
1765      if (! DrJava.getConfig().getSetting(INTERACTIONS_RESET_PROMPT).booleanValue()) {
1766        _doResetInteractions();
1767        return;
1768      }
1769      
1770      String JavaDoc title = "Confirm Reset Interactions";
1771      String JavaDoc message = "Are you sure you want to reset the Interactions Pane?";
1772      ConfirmCheckBoxDialog dialog =
1773        new ConfirmCheckBoxDialog(MainFrame.this, title, message);
1774      int rc = dialog.show();
1775      if (rc == JOptionPane.YES_OPTION) {
1776        _doResetInteractions();
1777        
1778        if (dialog.getCheckBoxValue()) {
1779          DrJava.getConfig().setSetting(INTERACTIONS_RESET_PROMPT, Boolean.FALSE);
1780        }
1781      }
1782    }
1783  };
1784  
1785  private void _doResetInteractions() {
1786    _tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
1787    
1788    // Lots of work, so use another thread
1789
new Thread JavaDoc(new Runnable JavaDoc() {
1790      public void run() {_model.resetInteractions(_model.getWorkingDirectory(), true);
1791      }
1792    }).start();
1793  }
1794  
1795  /** Defines actions that displays the interactions classpath. */
1796  private final Action _viewInteractionsClassPathAction = new AbstractAction("View Interactions Classpath...") {
1797    public void actionPerformed(ActionEvent e) { viewInteractionsClassPath(); }
1798  };
1799  
1800  /** Displays the interactions classpath. */
1801  public void viewInteractionsClassPath() {
1802    final StringBuilder JavaDoc cpBuf = new StringBuilder JavaDoc();
1803    ClassPathVector classPathElements = _model.getInteractionsClassPath();
1804    for(int i = 0; i < classPathElements.size(); i++) {
1805      cpBuf.append(classPathElements.get(i).getPath());
1806      if (i + 1 < classPathElements.size()) cpBuf.append("\n");
1807    }
1808    String JavaDoc classPath = cpBuf.toString();
1809    
1810    new DrJavaScrollableDialog(this, "Interactions Classpath", "Current Interpreter Classpath", classPath).show();
1811  }
1812 
1813  /** Shows the user documentation. */
1814  private final Action _helpAction = new AbstractAction("Help") {
1815    public void actionPerformed(ActionEvent ae) {
1816      // Create frame if we haven't yet
1817
// if (_helpFrame == null) {
1818
// _helpFrame = new HelpFrame();
1819
// }
1820
_helpFrame.setVisible(true);
1821    }
1822  };
1823  
1824  /** Shows the quick start documentation. */
1825  private final Action _quickStartAction = new AbstractAction("QuickStart") {
1826    public void actionPerformed(ActionEvent ae) {
1827      // Create frame if we haven't yet
1828
// if (_quickStartFrame == null) {
1829
// _quickStartFrame = new QuickStartFrame();
1830
// }
1831
_quickStartFrame.setVisible(true);
1832    }
1833  };
1834  
1835  /** Pops up an info dialog. */
1836  private final Action _aboutAction = new AbstractAction("About") {
1837    public void actionPerformed(ActionEvent ae) {
1838      // Create dialog if we haven't yet
1839
// if (_aboutDialog == null) _aboutDialog = new AboutDialog(MainFrame.this);
1840
Point p = MainFrame.this.getLocation();
1841      _aboutDialog.setVisible(true);
1842// _aboutDialog.setLocation(p.x+(MainFrame.this.getWidth() - _aboutDialog.getWidth())/2,
1843
// p.y+(MainFrame.this.getHeight()-_aboutDialog.getHeight())/2);
1844

1845    }
1846  };
1847  
1848  /** Pops up the DrJava errors dialog. */
1849  private final Action _errorsAction = new AbstractAction("DrJava Errors") {
1850    public void actionPerformed(ActionEvent ae) {
1851      setPopupLoc(DrJavaErrorWindow.singleton());
1852      DrJavaErrorWindow.singleton().setVisible(true);
1853    }
1854  };
1855  
1856  /** Switches to next document. */
1857  private final Action _switchToNextAction = new AbstractAction("Next Document") {
1858    public void actionPerformed(ActionEvent ae) {
1859      this.setEnabled(false);
1860      if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
1861        _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
1862      //disables switching documents while the next one is opening up, in order to prevent out of control switching
1863
// addToBrowserHistory();
1864
_model.setActiveNextDocument();
1865      _findReplace.updateFirstDocInSearch();
1866      this.setEnabled(true);
1867// // defer executing this code until after active document switch (if any) is complete
1868
// SwingUtilities.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
1869
}
1870  };
1871  
1872  /** Switches to previous document. */
1873  private final Action _switchToPrevAction = new AbstractAction("Previous Document") {
1874    public void actionPerformed(ActionEvent ae) {
1875      this.setEnabled(false);
1876      if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
1877        _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
1878// addToBrowserHistory();
1879
_model.setActivePreviousDocument();
1880      _findReplace.updateFirstDocInSearch();
1881      this.setEnabled(true);
1882// // defer executing this code until after active document switch (if any) is complete
1883
// SwingUtilities.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
1884
}
1885  };
1886  
1887  /** Switches focus to next pane. */
1888  private final Action _switchToNextPaneAction = new AbstractAction("Next Pane") {
1889    public void actionPerformed(ActionEvent ae) {
1890      if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
1891        _mainSplit.resetToPreferredSizes();
1892      this.setEnabled(false);
1893      _switchPaneFocus(true);
1894      this.setEnabled(true);
1895    }
1896  };
1897  
1898  /** Browse back in the browser history. */
1899  private final Action _browseBackAction = new AbstractAction("Browse Back") {
1900    public void actionPerformed(ActionEvent ae) {
1901      this.setEnabled(false);
1902      if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
1903        _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
1904      //disables switching documents while the next one is opening up, in order to prevent out of control switching
1905

1906      RegionManager rm = _model.getBrowserHistoryManager();
1907      
1908      // add current location to history
1909
addToBrowserHistory();
1910      
1911      // then move back
1912
DocumentRegion r = rm.prevCurrentRegion();
1913      scrollToDocumentAndOffset(r.getDocument(), r.getStartOffset(), false, false);
1914      
1915      this.setEnabled(true);
1916    }
1917  };
1918  
1919  /** Browse forward in the browser history. */
1920  private final Action _browseForwardAction = new AbstractAction("Browse Forward") {
1921    public void actionPerformed(ActionEvent ae) {
1922      this.setEnabled(false);
1923      if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
1924        _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
1925      //disables switching documents while the next one is opening up, in order to prevent out of control switching
1926

1927      RegionManager rm = _model.getBrowserHistoryManager();
1928      
1929      // add current location to history
1930
addToBrowserHistory();
1931      
1932      // then move forward
1933
DocumentRegion r = rm.nextCurrentRegion();
1934      scrollToDocumentAndOffset(r.getDocument(), r.getStartOffset(), false, false);
1935
1936      this.setEnabled(true);
1937    }
1938  };
1939  
1940  /** Switches focus to previous pane. */
1941  private final Action _switchToPreviousPaneAction = new AbstractAction("Previous Pane") {
1942    public void actionPerformed(ActionEvent ae) {
1943      if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
1944        _mainSplit.resetToPreferredSizes();
1945      this.setEnabled(false);
1946      _switchPaneFocus(false);
1947      this.setEnabled(true);
1948    }
1949  };
1950  
1951  /** Go to the closing brace. */
1952  private final Action _gotoClosingBraceAction = new AbstractAction("Go to Closing Brace") {
1953    public void actionPerformed(ActionEvent ae) {
1954        OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
1955        odd.acquireReadLock();
1956        try {
1957          int pos = odd.findNextEnclosingBrace(getCurrentDefPane().getCaretPosition(), '{', '}');
1958          if (pos!=AbstractDJDocument.ERROR_INDEX) { getCurrentDefPane().setCaretPosition(pos); }
1959        }
1960        catch(BadLocationException ble) { /* just ignore and don't move */ }
1961        finally { odd.releaseReadLock(); }
1962    }
1963  };
1964  
1965  /** Go to the opening brace. */
1966  private final Action _gotoOpeningBraceAction = new AbstractAction("Go to Opening Brace") {
1967    public void actionPerformed(ActionEvent ae) {
1968        OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
1969        odd.acquireReadLock();
1970        try {
1971          int pos = odd.findPrevEnclosingBrace(getCurrentDefPane().getCaretPosition(), '{', '}');
1972          if (pos!=AbstractDJDocument.ERROR_INDEX) { getCurrentDefPane().setCaretPosition(pos); }
1973        }
1974        catch(BadLocationException ble) { /* just ignore and don't move */ }
1975        finally { odd.releaseReadLock(); }
1976    }
1977  };
1978  
1979  /** This takes a component and gives it focus, showing it if it's a tab. The interactionsPane and consolePane
1980   * are wrapped in scrollpanes, so we have to specifically check for those and unwrap them.
1981   * @param c the pane to switch focus to
1982   */

1983  private void _switchToPane(Component c) {
1984    Component newC = c;
1985    if (c == _interactionsContainer) newC = _interactionsPane;
1986    
1987    if (c == _consoleScroll) newC = _consolePane;
1988    
1989    showTab(newC);
1990  }
1991  
1992  /** This method allows the user to cycle through the definitions pane and all of the open tabs.
1993   * @param next true if we want to go to the next pane, false if the previous.
1994   */

1995  private void _switchPaneFocus(boolean next) {
1996    int numTabs = _tabbedPane.getTabCount();
1997
1998    /* If next, then we go to the next tab */
1999    if (next) _switchToPane(_tabbedPane.getComponentAt((numTabs+_tabbedPane.getSelectedIndex()+1)%numTabs));
2000    else _switchToPane(_tabbedPane.getComponentAt((numTabs+_tabbedPane.getSelectedIndex()-1)%numTabs));
2001  }
2002  
2003  /** Calls the ConfigFrame to edit preferences */
2004
2005  private final Action _editPreferencesAction = new AbstractAction("Preferences ...") {
2006
2007    public void actionPerformed(ActionEvent ae) {
2008      // Create frame if we haven't yet
2009
// if (_configFrame == null) {
2010
// _configFrame = new ConfigFrame(MainFrame.this);
2011
// }
2012
_configFrame.setUp();
2013      setPopupLoc(_configFrame);
2014      _configFrame.setVisible(true);
2015      _configFrame.toFront();
2016    }
2017  };
2018  
2019  private volatile AbstractAction _projectPropertiesAction = new AbstractAction("Project Properties") {
2020    public void actionPerformed(ActionEvent ae) { _editProject(); }
2021  };
2022    
2023  /** Enables the debugger */
2024  private final Action _toggleDebuggerAction = new AbstractAction("Debug Mode") {
2025    public void actionPerformed(ActionEvent ae) {
2026      this.setEnabled(false);
2027      debuggerToggle();
2028      this.setEnabled(true);
2029    }
2030  };
2031  
2032  /** Resumes debugging */
2033  private final Action _resumeDebugAction = new AbstractAction("Resume Debugger") {
2034    public void actionPerformed(ActionEvent ae) {
2035      try { debuggerResume(); }
2036      catch (DebugException de) { _showDebugError(de); }
2037    }
2038  };
2039  
2040  /** Steps into the next method call */
2041  private final Action _stepIntoDebugAction = new AbstractAction("Step Into") {
2042    public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.STEP_INTO); }
2043  };
2044  
2045  /** Runs the next line, without stepping into methods */
2046  private final Action _stepOverDebugAction = new AbstractAction("Step Over") {
2047    public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.STEP_OVER); }
2048  };
2049  
2050  /** Steps out of the next method call */
2051  private final Action _stepOutDebugAction = new AbstractAction("Step Out") {
2052    public void actionPerformed(ActionEvent ae) {
2053      debuggerStep(Debugger.STEP_OUT);
2054    }
2055  };
2056  
2057  /** Suspend debugging */
2058  /*private Action _suspendDebugAction =
2059   new AbstractAction("Suspend Debugger")
2060   {
2061   public void actionPerformed(ActionEvent ae) {
2062   _debugSuspend();
2063   }
2064   };*/

2065  
2066  /** Toggles a breakpoint on the current line */
2067  final Action _toggleBreakpointAction = new AbstractAction("Toggle Breakpoint on Current Line") {
2068    public void actionPerformed(ActionEvent ae) { debuggerToggleBreakpoint(); }
2069  };
2070  
2071  /** Clears all breakpoints */
2072  private final Action _clearAllBreakpointsAction = new AbstractAction("Clear All Breakpoints") {
2073    public void actionPerformed(ActionEvent ae) { debuggerClearAllBreakpoints(); }
2074  };
2075  
2076  /** Shows the breakpoints tab. */
2077  private final Action _breakpointsPanelAction = new AbstractAction("Breakpoints") {
2078    public void actionPerformed(ActionEvent ae) {
2079      if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
2080        _mainSplit.resetToPreferredSizes();
2081      if (! _breakpointsPanel.isDisplayed()) {
2082        showTab(_breakpointsPanel);
2083      }
2084      _breakpointsPanel.setVisible(true);
2085      _tabbedPane.setSelectedComponent(_breakpointsPanel);
2086      // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _breakpointsPanel has been selected
2087
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { _breakpointsPanel.requestFocusInWindow(); } });
2088    }
2089  };
2090
2091  /** Shows the bookmarks tab. */
2092  private final Action _bookmarksPanelAction = new AbstractAction("Bookmarks") {
2093    public void actionPerformed(ActionEvent ae) {
2094      if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
2095        _mainSplit.resetToPreferredSizes();
2096      if (! _bookmarksPanel.isDisplayed()) {
2097        showTab(_bookmarksPanel);
2098      }
2099      _bookmarksPanel.setVisible(true);
2100      _tabbedPane.setSelectedComponent(_bookmarksPanel);
2101      // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _bookmarksPanel has been selected
2102
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { _bookmarksPanel.requestFocusInWindow(); } });
2103    }
2104  };
2105  
2106  /** Toggles a bookmark. */
2107  private final Action _toggleBookmarkAction = new AbstractAction("Toggle Bookmark") {
2108    public void actionPerformed(ActionEvent ae) { toggleBookmark(); }
2109  };
2110
2111  /** Toggle a bookmark. */
2112  public void toggleBookmark() {
2113    addToBrowserHistory();
2114    final OpenDefinitionsDocument doc = _model.getActiveDocument();
2115    
2116    int startSel = _currentDefPane.getSelectionStart();
2117    int endSel = _currentDefPane.getSelectionEnd();
2118    doc.acquireReadLock();
2119    try {
2120      if (startSel>endSel) { int temp = startSel; startSel = endSel; endSel = temp; }
2121      else if (startSel==endSel) {
2122        // nothing selected
2123
endSel = doc.getLineEndPos(startSel);
2124        startSel = doc.getLineStartPos(startSel);
2125      }
2126      DocumentRegion r = _model.getBookmarkManager().getRegionOverlapping(doc, startSel, endSel);
2127      if (r == null) {
2128        final Position startPos = doc.createPosition(startSel);
2129        final Position endPos = doc.createPosition(endSel);
2130        SimpleDocumentRegion newR = new SimpleDocumentRegion(doc, doc.getFile(), startPos.getOffset(), endPos.getOffset());
2131        _model.getBookmarkManager().addRegion(newR);
2132      }
2133      else {
2134        _model.getBookmarkManager().removeRegion(r);
2135      }
2136    }
2137    catch (FileMovedException fme) {
2138      throw new UnexpectedException(fme);
2139    }
2140    catch (BadLocationException ble) {
2141      throw new UnexpectedException(ble);
2142    }
2143    finally { doc.releaseReadLock(); }
2144  }
2145  
2146  /** Add the current location to the browser history. */
2147  public void addToBrowserHistory() { _model.addToBrowserHistory(); }
2148
2149  /** Create a new find results tab.
2150    * @param rm the region manager that will contain the regions
2151    * @param title the title for the panel
2152    * @return new find results tab. */

2153  public FindResultsPanel createFindResultsPanel(final RegionManager<MovingDocumentRegion> rm, String JavaDoc title) {
2154    final FindResultsPanel panel = new FindResultsPanel(this, rm, title);
2155    final Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights =
2156      new Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>();
2157    Pair<FindResultsPanel,Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair =
2158      new Pair<FindResultsPanel,Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>>(panel, highlights);
2159    _findResults.add(pair);
2160    
2161    // hook highlighting listener to find results manager
2162
rm.addListener(new RegionManagerListener<MovingDocumentRegion>() {
2163      public void regionAdded(MovingDocumentRegion r, int index) {
2164        DefinitionsPane bpPane = getDefPaneGivenODD(r.getDocument());
2165        highlights.put(r, bpPane.getHighlightManager().
2166                         addHighlight(r.getStartOffset(), r.getEndOffset(), panel.getSelectedPainter()));
2167      }
2168      public void regionChanged(MovingDocumentRegion r, int index) {
2169        regionRemoved(r);
2170        regionAdded(r, index);
2171      }
2172      public void regionRemoved(MovingDocumentRegion r) {
2173        HighlightManager.HighlightInfo highlight = highlights.get(r);
2174        if (highlight != null) highlight.remove();
2175        highlights.remove(r);
2176      }
2177    });
2178    
2179    _tabs.addLast(panel);
2180    panel.getMainPanel().addFocusListener(new FocusAdapter() {
2181      public void focusGained(FocusEvent e) { _lastFocusOwner = panel; }
2182    });
2183    
2184    return panel;
2185  }
2186  
2187  /** Shows a find results tab. */
2188  public void showFindResultsPanel(final FindResultsPanel panel) {
2189    if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
2190      _mainSplit.resetToPreferredSizes();
2191    if (! panel.isDisplayed()) {
2192      showTab(panel);
2193    }
2194    panel.setVisible(true);
2195    _tabbedPane.setSelectedComponent(panel);
2196    // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the findResultsPanel has been selected
2197
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { panel.requestFocusInWindow(); } });
2198  };
2199  
2200  /** Cuts from the caret to the end of the current line to the clipboard. */
2201  protected final Action _cutLineAction = new AbstractAction("Cut Line") {
2202    public void actionPerformed(ActionEvent ae) {
2203      ActionMap _actionMap = _currentDefPane.getActionMap();
2204      int oldCol = _model.getActiveDocument().getCurrentCol();
2205      _actionMap.get(DefaultEditorKit.selectionEndLineAction).actionPerformed(ae);
2206      // if oldCol is equal to the current column, then selectionEndLine did
2207
// nothing, so we're at the end of the line and should remove the newline
2208
// character
2209
if (oldCol == _model.getActiveDocument().getCurrentCol()) {
2210        // Puts newline character on the clipboard also, not just content as before.
2211
_actionMap.get(DefaultEditorKit.selectionForwardAction).actionPerformed(ae);
2212        cutAction.actionPerformed(ae);
2213      }
2214      else cutAction.actionPerformed(ae);
2215    }
2216  };
2217  
2218  /** Deletes text from the caret to the end of the current line. */
2219  protected final Action _clearLineAction = new AbstractAction("Clear Line") {
2220    public void actionPerformed(ActionEvent ae) {
2221      ActionMap _actionMap = _currentDefPane.getActionMap();
2222      _actionMap.get(DefaultEditorKit.selectionEndLineAction).actionPerformed(ae);
2223      _actionMap.get(DefaultEditorKit.deleteNextCharAction).actionPerformed(ae);
2224    }
2225  };
2226  
2227  /** Moves the caret to the "intelligent" beginning of the line.
2228   * @see #_getBeginLinePos
2229   */

2230  private final Action _beginLineAction = new AbstractAction("Begin Line") {
2231    public void actionPerformed(ActionEvent ae) {
2232      int beginLinePos = _getBeginLinePos();
2233      _currentDefPane.setCaretPosition(beginLinePos);
2234    }
2235  };
2236
2237  /** Selects to the "intelligent" beginning of the line.
2238   * @see #_getBeginLinePos
2239   */

2240  private final Action _selectionBeginLineAction = new AbstractAction("Select to Beginning of Line") {
2241    public void actionPerformed(ActionEvent ae) {
2242      int beginLinePos = _getBeginLinePos();
2243      _currentDefPane.moveCaretPosition(beginLinePos);
2244    }
2245  };
2246  
2247  /** Returns the "intelligent" beginning of line. If the caret is to fhe right of the first non-whitespace character,
2248   * the position of the first non-whitespace character is returned. If the caret is on or to the left of the first
2249   * non-whitespace character, the beginning of the line is returned.
2250   */

2251  private int _getBeginLinePos() {
2252    try {
2253      int currPos = _currentDefPane.getCaretPosition();
2254      OpenDefinitionsDocument openDoc = _model.getActiveDocument();
2255      openDoc.setCurrentLocation(currPos);
2256      return openDoc.getIntelligentBeginLinePos(currPos);
2257    }
2258    catch (BadLocationException ble) {
2259      // Shouldn't happen: we're using a legal position
2260
throw new UnexpectedException(ble);
2261    }
2262  }
2263  
2264  private final FileOpenSelector _interactionsHistoryFileSelector = new FileOpenSelector() {
2265    public File[] getFiles() throws OperationCanceledException {
2266      return getOpenFiles(_interactionsHistoryChooser);
2267    }
2268  };
2269  
2270  /** Interprets the commands in a file in the interactions window. */
2271  private final Action _executeHistoryAction = new AbstractAction("Execute Interactions History...") {
2272    public void actionPerformed(ActionEvent ae) {
2273      // Show interactions tab
2274
_tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
2275      
2276      _interactionsHistoryChooser.setDialogTitle("Execute Interactions History");
2277      try { _model.loadHistory(_interactionsHistoryFileSelector); }
2278      catch (FileNotFoundException fnf) { _showFileNotFoundError(fnf); }
2279      catch (IOException ioe) { _showIOError(ioe); }
2280      _interactionsPane.requestFocusInWindow();
2281    }
2282  };
2283  
2284  /** Closes the currently executing interactions script, if there is one. */
2285  private void _closeInteractionsScript() {
2286    if (_interactionsScriptController != null) {
2287      _interactionsContainer.remove(_interactionsScriptPane);
2288      _interactionsScriptController = null;
2289      _interactionsScriptPane = null;
2290      _tabbedPane.invalidate();
2291      _tabbedPane.repaint();
2292    }
2293  }
2294  
2295  /** Action to load an interactions history as a replayable script. */
2296  private final Action _loadHistoryScriptAction = new AbstractAction("Load Interactions History as Script...") {
2297    public void actionPerformed(ActionEvent e) {
2298      try {
2299        _interactionsHistoryChooser.setDialogTitle("Load Interactions History");
2300        InteractionsScriptModel ism = _model.loadHistoryAsScript(_interactionsHistoryFileSelector);
2301        _interactionsScriptController = new InteractionsScriptController(ism, new AbstractAction("Close") {
2302          public void actionPerformed(ActionEvent e) {
2303            _closeInteractionsScript();
2304            _interactionsPane.requestFocusInWindow();
2305          }
2306        }, _interactionsPane);
2307        _interactionsScriptPane = _interactionsScriptController.getPane();
2308        _interactionsContainer.add(_interactionsScriptPane, BorderLayout.EAST);
2309        _tabbedPane.invalidate();
2310        _tabbedPane.repaint();
2311      }
2312      catch (FileNotFoundException fnf) { _showFileNotFoundError(fnf); }
2313      catch (IOException ioe) { _showIOError(ioe); }
2314      catch (OperationCanceledException oce) {
2315      }
2316    }
2317  };
2318  
2319  /** Save the commands in the interactions window's history to a file */
2320  private final Action _saveHistoryAction = new AbstractAction("Save Interactions History...") {
2321    public void actionPerformed(ActionEvent ae) {
2322      String JavaDoc[] options = {"Yes","No","Cancel"};
2323      int resp = JOptionPane.showOptionDialog(MainFrame.this,
2324                                              "Edit interactions history before saving?",
2325                                              "Edit History?",
2326                                              JOptionPane.YES_NO_CANCEL_OPTION,
2327                                              JOptionPane.QUESTION_MESSAGE,
2328                                              null,options,
2329                                              options[1]);
2330      // Cancel
2331
if (resp == 2 || resp == JOptionPane.CLOSED_OPTION) return;
2332      
2333      String JavaDoc history = _model.getHistoryAsStringWithSemicolons();
2334      
2335      // Edit the history
2336
if (resp == 0)
2337        history = (new HistorySaveDialog(MainFrame.this)).editHistory(history);
2338      if (history == null) return; // save cancelled
2339

2340      _interactionsHistoryChooser.setDialogTitle("Save Interactions History");
2341      FileSaveSelector selector = new FileSaveSelector() {
2342        public File getFile() throws OperationCanceledException {
2343          // Don't try to set the fileName with getSaveFile;
2344
// just display the dialog and get file with getChosenFile, otherwise
2345
// the suggested file name will be whatever document is open.
2346
// ED (8.14.03): Had to add this next block of code from getSaveFile to
2347
// fix bug #788311 "NullPointer when saving history"
2348
File selection = _interactionsHistoryChooser.getSelectedFile();//_saveChooser.getSelectedFile();
2349
if (selection != null) {
2350            _interactionsHistoryChooser.setSelectedFile(selection.getParentFile());
2351            _interactionsHistoryChooser.setSelectedFile(selection);
2352            _interactionsHistoryChooser.setSelectedFile(null);
2353          }
2354// return getSaveFile(_interactionsHistoryChooser);
2355
int rc = _interactionsHistoryChooser.showSaveDialog(MainFrame.this);
2356          File c = getChosenFile(_interactionsHistoryChooser, rc);
2357          //Moved from history itself to here to account for bug #989232, non-existant default
2358
//history file found
2359
if (c.getName().indexOf('.') == -1)
2360            c = new File(c.getAbsolutePath() + "." + InteractionsHistoryFilter.HIST_EXTENSION);
2361          _interactionsHistoryChooser.setSelectedFile(c);
2362          return c;
2363        }
2364        public boolean warnFileOpen(File f) { return true; }
2365        public boolean verifyOverwrite() { return _verifyOverwrite(); }
2366        public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) {
2367          return true;
2368        }
2369      };
2370      
2371      try { _model.saveHistory(selector, history);}
2372      catch (IOException ioe) {
2373        _showIOError(new IOException("An error occured writing the history to a file"));
2374      }
2375      _interactionsPane.requestFocusInWindow();
2376    }
2377  };
2378  
2379  /** Clears the commands in the interaction history. */
2380  private final Action _clearHistoryAction = new AbstractAction("Clear Interactions History") {
2381    public void actionPerformed(ActionEvent ae) {
2382      _model.clearHistory();
2383      _interactionsPane.requestFocusInWindow();
2384    }
2385  };
2386  
2387  /** How DrJava responds to window events. */
2388  private final WindowListener _windowCloseListener = new WindowAdapter() {
2389    public void windowActivated(WindowEvent ev) { }
2390    public void windowClosed(WindowEvent ev) { }
2391    public void windowClosing(WindowEvent ev) { _quit(); }
2392    public void windowDeactivated(WindowEvent ev) { }
2393    public void windowDeiconified(WindowEvent ev) {
2394      try { _model.getActiveDocument().revertIfModifiedOnDisk(); }
2395      catch (FileMovedException fme) { _showFileMovedError(fme); }
2396      catch (IOException e) { _showIOError(e);}
2397    }
2398    public void windowIconified(WindowEvent ev) { }
2399    public void windowOpened(WindowEvent ev) { _currentDefPane.requestFocusInWindow(); }
2400  };
2401  
2402  private final MouseListener _resetFindReplaceListener = new MouseListener() {
2403    public void mouseClicked (MouseEvent e) { }
2404    public void mousePressed (MouseEvent e) { }
2405    //as mouseReleased event so that it happens after the document has been set in the model and defPane
2406
public void mouseReleased (MouseEvent e) {_findReplace.updateFirstDocInSearch();}
2407    public void mouseEntered (MouseEvent e) { }
2408    public void mouseExited (MouseEvent e) { }
2409  };
2410  
2411  // ------------- File Display Managers for File Icons ------------
2412

2413  private static final DJFileDisplayManager _djFileDisplayManager20;
2414  private static final DJFileDisplayManager _djFileDisplayManager30;
2415  private static final OddDisplayManager _oddDisplayManager20;
2416  private static final OddDisplayManager _oddDisplayManager30;
2417  private static final Icon _djProjectIcon;
2418  
2419  static {
2420    Icon java, dj0, dj1, dj2, other, star, jup, juf;
2421    
2422    java = MainFrame.getIcon("JavaIcon20.gif");
2423    dj0 = MainFrame.getIcon("ElementaryIcon20.gif");
2424    dj1 = MainFrame.getIcon("IntermediateIcon20.gif");
2425    dj2 = MainFrame.getIcon("AdvancedIcon20.gif");
2426    other = MainFrame.getIcon("OtherIcon20.gif");
2427    _djFileDisplayManager20 = new DJFileDisplayManager(java,dj0,dj1,dj2,other);
2428    
2429    java = MainFrame.getIcon("JavaIcon30.gif");
2430    dj0 = MainFrame.getIcon("ElementaryIcon30.gif");
2431    dj1 = MainFrame.getIcon("IntermediateIcon30.gif");
2432    dj2 = MainFrame.getIcon("AdvancedIcon30.gif");
2433    other = MainFrame.getIcon("OtherIcon30.gif");
2434    _djFileDisplayManager30 = new DJFileDisplayManager(java,dj0,dj1,dj2,other);
2435    
2436    star = MainFrame.getIcon("ModStar20.gif");
2437    jup = MainFrame.getIcon("JUnitPass20.gif");
2438    juf = MainFrame.getIcon("JUnitFail20.gif");
2439    _oddDisplayManager20 = new OddDisplayManager(_djFileDisplayManager20,star,jup,juf);
2440    
2441    star = MainFrame.getIcon("ModStar30.gif");
2442    jup = MainFrame.getIcon("JUnitPass30.gif");
2443    juf = MainFrame.getIcon("JUnitFail30.gif");
2444    _oddDisplayManager30 = new OddDisplayManager(_djFileDisplayManager30,star,jup,juf);
2445    
2446    _djProjectIcon = MainFrame.getIcon("ProjectIcon.gif");
2447  }
2448  
2449  
2450  /** This manager is meant to retrieve the correct icons for the given filename. The only files recognized
2451   * are the files obviously listed below in the function (.java, .dj0, .dj1, .dj2). The icons that represent
2452   * each filetype are given into the managers constructor upon instantiation. This class is static since
2453   * it currently does not depend of the main frame for information.
2454   */

2455  private static class DJFileDisplayManager extends DefaultFileDisplayManager {
2456    private final Icon _java;
2457    private final Icon _dj0;
2458    private final Icon _dj1;
2459    private final Icon _dj2;
2460    private final Icon _other;
2461    
2462    public DJFileDisplayManager(Icon java, Icon dj0, Icon dj1, Icon dj2, Icon other) {
2463      _java = java;
2464      _dj0 = dj0;
2465      _dj1 = dj1;
2466      _dj2 = dj2;
2467      _other = other;
2468    }
2469    /** This method chooses the custom icon only for the known filetypes. If these filetypes are not receiving
2470      * the correct icons, make sure the filenames are correct and that the icons are present in the ui/icons
2471      * directory.
2472      */

2473    public Icon getIcon(File f) {
2474      if (f == null) return _other;
2475      Icon ret = null;
2476      if (!f.isDirectory()) {
2477        String JavaDoc name = f.getName().toLowerCase();
2478        if (name.endsWith(".java")) ret = _java;
2479        if (name.endsWith(".dj0")) ret = _dj0;
2480        if (name.endsWith(".dj1")) ret = _dj1;
2481        if (name.endsWith(".dj2")) ret = _dj2;
2482      }
2483      if (ret == null) {
2484        ret = super.getIcon(f);
2485        if (ret.getIconHeight() < _java.getIconHeight()) {
2486          ret = new CenteredIcon(ret, _java.getIconWidth(), _java.getIconHeight());
2487        }
2488      }
2489      return ret;
2490    }
2491  }
2492  
2493  /** This class wraps the file display managers by superimposing any notification icons on top of the base
2494    * file icon. Currently, only the modified star is allowed, but everything is set up to add notification
2495    * icons for whether a document has passed the junit test (for display in the tree). This class is static
2496    * for now. It may be necessary to make it dynamic when implementing the junit notifications.
2497    */

2498  private static class OddDisplayManager implements DisplayManager<OpenDefinitionsDocument> {
2499    private final Icon _star;
2500// private Icon _juPass;
2501
// private Icon _juFail;
2502
private final FileDisplayManager _default;
2503    
2504    /** Standard constructor.
2505     * @param star The star icon will be put flush to the left 1/4 the way down
2506     * @param junitPass indicator of junit success, placed at bottom right
2507     * @param junitFail indicator of junit failure, placed at bottom right
2508     */

2509    public OddDisplayManager(FileDisplayManager fdm, Icon star, Icon junitPass, Icon junitFail) {
2510      _star = star;
2511// _juPass = junitPass;
2512
// _juFail = junitFail;
2513
_default = fdm;
2514    }
2515    public Icon getIcon(OpenDefinitionsDocument odd) {
2516      File f = null;
2517      try { f = odd.getFile(); }
2518      catch(FileMovedException fme) { /* do nothing */ }
2519      
2520      if (odd.isModifiedSinceSave()) return makeLayeredIcon(_default.getIcon(f), _star);
2521      return _default.getIcon(f);
2522    }
2523    public String JavaDoc getName(OpenDefinitionsDocument doc) { return doc.getFileName(); }
2524    private LayeredIcon makeLayeredIcon(Icon base, Icon star) {
2525      return new LayeredIcon(new Icon[]{base, star}, new int[]{0, 0},
2526                             new int[]{0, (base.getIconHeight() / 4)});
2527    }
2528  };
2529  
2530  /** This is what is given to the JTreeSortNavigator. This simply resolves the INavItem to an OpenDefDoc
2531    * using the model and forwards it to the OddDisplayManager for size 20.
2532    */

2533  private final DisplayManager<INavigatorItem> _navPaneDisplayManager = new DisplayManager<INavigatorItem>() {
2534    public Icon getIcon(INavigatorItem item) {
2535      OpenDefinitionsDocument odd = (OpenDefinitionsDocument) item; // FIX THIS!
2536
return _oddDisplayManager20.getIcon(odd);
2537    }
2538    public String JavaDoc getName(INavigatorItem name) { return name.getName(); }
2539  };
2540  
2541  
2542  public static DJFileDisplayManager getFileDisplayManager20() { return _djFileDisplayManager20; }
2543  public static DJFileDisplayManager getFileDisplayManager30() { return _djFileDisplayManager30; }
2544  public static OddDisplayManager getOddDisplayManager20() { return _oddDisplayManager20; }
2545  public static OddDisplayManager getOddDisplayManager30() { return _oddDisplayManager30; }
2546  public DisplayManager<INavigatorItem> getNavPaneDisplayManager() { return _navPaneDisplayManager; }
2547  
2548  /* ----------------------- Constructor is here! --------------------------- */
2549  
2550  /** Creates the main window, and shows it. */
2551  public MainFrame() {
2552    
2553    // Cache the config object, since we use it many, many times.
2554
final Configuration config = DrJava.getConfig();
2555   
2556  
2557// Utilities.show("MainFrame starting");
2558

2559    // create our model
2560
_model = new DefaultGlobalModel();
2561
2562    _showDebugger = _model.getDebugger().isAvailable();
2563    _findReplace = new FindReplacePanel(this, _model);
2564 
2565    if (_showDebugger) {
2566      _debugPanel = new DebugPanel(this);
2567      _breakpointsPanel = new BreakpointsPanel(this);
2568    }
2569    else {
2570      _debugPanel = null;
2571      _breakpointsPanel = null;
2572    }
2573        
2574    _compilerErrorPanel = new CompilerErrorPanel(_model, this);
2575    _consoleController = new ConsoleController(_model.getConsoleDocument(), _model.getSwingConsoleDocument());
2576    _consolePane = _consoleController.getPane();
2577    
2578    _consoleScroll = new BorderlessScrollPane(_consolePane) {
2579      public boolean requestFocusInWindow() { return _consolePane.requestFocusInWindow(); }
2580    };
2581    
2582    _interactionsController =
2583      new InteractionsController(_model.getInteractionsModel(), _model.getSwingInteractionsDocument());
2584    _interactionsPane = _interactionsController.getPane();
2585    
2586    _interactionsContainer = new JPanel(new BorderLayout()) {
2587      public boolean requestFocusInWindow() { return _interactionsPane.requestFocusInWindow(); }
2588    };
2589    
2590    _junitErrorPanel = new JUnitPanel(_model, this);
2591    _javadocErrorPanel = new JavadocErrorPanel(_model, this);
2592    
2593    _bookmarksPanel = new BookmarksPanel(this);
2594
2595    // Initialize the status bar
2596
_setUpStatusBar();
2597
2598    // Preliminary layout
2599

2600    /* Definitions Pane */
2601    
2602    /* Ensure that DefinitionsPane uses the correct EditorKit! This has to be stored as a static field on
2603     * DefinitionsPane because the JEditorPane constructor uses it before we get a chance to assign it to an instance
2604     * field ... */

2605    DefinitionsPane.setEditorKit(_model.getEditorKit());
2606
2607    _defScrollPanes = new Hashtable JavaDoc<OpenDefinitionsDocument, JScrollPane>();
2608    
2609    /* Other panes */
2610     _tabbedPane = new JTabbedPane();
2611     
2612     JScrollPane defScroll = _createDefScrollPane(_model.getActiveDocument());
2613    
2614    _docSplitPane =
2615      new BorderlessSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
2616                              new JScrollPane(_model.getDocumentNavigator().asContainer()), defScroll);
2617    _debugSplitPane = new BorderlessSplitPane(JSplitPane.VERTICAL_SPLIT, true);
2618    _mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, _docSplitPane, _tabbedPane);
2619
2620// Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
2621
// // The OptionListener for LIGHTWEIGHT_PARSING_ENABLED.
2622
// OptionListener<Boolean> parsingEnabledListener = new OptionListener<Boolean>() {
2623
// public void optionChanged(OptionEvent<Boolean> oce) {
2624
// if (oce.value) {
2625
// _model.getParsingControl().addListener(new LightWeightParsingListener() {
2626
// public void enclosingClassNameUpdated(OpenDefinitionsDocument doc, String old, String updated) {
2627
// if (doc==_model.getActiveDocument()) { updateFileTitle(); }
2628
// }
2629
// });
2630
// }
2631
// _model.getParsingControl().reset();
2632
// _model.getParsingControl().setAutomaticUpdates(oce.value);
2633
// updateFileTitle();
2634
// }
2635
// };
2636
// DrJava.getConfig().addOptionListener(LIGHTWEIGHT_PARSING_ENABLED, parsingEnabledListener);
2637
// parsingEnabledListener.optionChanged(new OptionEvent<Boolean>(LIGHTWEIGHT_PARSING_ENABLED,
2638
// DrJava.getConfig().getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()));
2639

2640// Utilities.show("Global Model started");
2641

2642    _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener);
2643    _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs);
2644    
2645    /* Listens for clicks in the document navigator to reset the first document in an all-documents search for wrapping
2646     * purposes. */

2647    _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener);
2648     
2649    if (_showDebugger) _model.getDebugger().addListener(new UIDebugListener()); // add listener to debug manager
2650

2651    // Timer to display a message if a debugging step takes a long time
2652
_debugStepTimer = new Timer(DEBUG_STEP_TIMER_VALUE, new ActionListener() {
2653      public void actionPerformed(ActionEvent e) {
2654        _model.printDebugMessage("Stepping...");
2655      }
2656    });
2657    _debugStepTimer.setRepeats(false);
2658    
2659    // Working directory is default place to start (bug #895998).
2660
File workDir = _model.getMasterWorkingDirectory();
2661
2662    // Overrides JFileChooser to display the full path of the directory
2663
_openChooser = new JFileChooser() {
2664      public void setCurrentDirectory(File dir) {
2665        //next two lines are order dependent!
2666
super.setCurrentDirectory(dir);
2667        setDialogTitle("Open: " + getCurrentDirectory());
2668      }
2669    };
2670    _openChooser.setPreferredSize(new Dimension(650, 410));
2671    _openChooser.setCurrentDirectory(workDir);
2672    _openChooser.setFileFilter(_javaSourceFilter);
2673    _openChooser.setMultiSelectionEnabled(true);
2674    
2675    _openRecursiveCheckBox = new JCheckBox("Open folders recursively");
2676    _openRecursiveCheckBox.setSelected(config.getSetting(OptionConstants.OPEN_FOLDER_RECURSIVE).booleanValue());
2677    
2678    _folderChooser = makeFolderChooser(workDir);
2679    
2680    //Get most recently opened project for filechooser
2681
Vector JavaDoc<File> recentProjects = config.getSetting(RECENT_PROJECTS);
2682    _openProjectChooser = new JFileChooser();
2683    _openProjectChooser.setPreferredSize(new Dimension(650, 410));
2684    
2685    if (recentProjects.size() > 0 && recentProjects.elementAt(0).getParentFile() != null)
2686      _openProjectChooser.setCurrentDirectory(recentProjects.elementAt(0).getParentFile());
2687    else
2688      _openProjectChooser.setCurrentDirectory(workDir);
2689    
2690    _openProjectChooser.setFileFilter(_projectFilter);
2691    _openProjectChooser.setMultiSelectionEnabled(false);
2692    _saveChooser = new JFileChooser() {
2693      public void setCurrentDirectory(File dir) {
2694        //next two lines are order dependent!
2695
super.setCurrentDirectory(dir);
2696        setDialogTitle("Save: " + getCurrentDirectory());
2697      }
2698    };
2699    _saveChooser.setPreferredSize(new Dimension(650, 410));
2700    _saveChooser.setCurrentDirectory(workDir);
2701    _saveChooser.setFileFilter(_javaSourceFilter);
2702    
2703    _interactionsHistoryChooser = new JFileChooser();
2704    _interactionsHistoryChooser.setPreferredSize(new Dimension(650, 410));
2705    _interactionsHistoryChooser.setCurrentDirectory(workDir);
2706    _interactionsHistoryChooser.setFileFilter(new InteractionsHistoryFilter());
2707    _interactionsHistoryChooser.setMultiSelectionEnabled(true);
2708    
2709    //set up the hourglass cursor
2710
setGlassPane(new GlassPane());
2711    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
2712    
2713    // Set up listeners
2714
addWindowListener(_windowCloseListener);
2715    
2716    // Create the main model listener and attach it to the global model
2717
_mainListener = new ModelListener();
2718    _model.addListener(_mainListener);
2719    
2720    // Initialize tabs before DefPane
2721
_setUpTabs();
2722    
2723    // DefinitionsPane
2724
_recentDocFrame = new RecentDocFrame(this);
2725    _recentDocFrame.pokeDocument(_model.getActiveDocument());
2726    _currentDefPane = (DefinitionsPane) defScroll.getViewport().getView();
2727    _currentDefPane.notifyActive();
2728  
2729    // Get proper cross-platform mask.
2730
int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
2731    
2732    // set up key-bindings
2733
KeyBindingManager.Singleton.setMainFrame(this);
2734    KeyBindingManager.Singleton.setActionMap(_currentDefPane.getActionMap());
2735    _setUpKeyBindingMaps();
2736    
2737    _posListener.updateLocation();
2738    
2739    // Need to set undo/redo actions to point to the initial def pane
2740
// on switching documents later these pointers will also switch
2741
_undoAction.setDelegatee(_currentDefPane.getUndoAction());
2742    _redoAction.setDelegatee(_currentDefPane.getRedoAction());
2743    
2744    _compilerErrorPanel.reset();
2745    _junitErrorPanel.reset();
2746    _javadocErrorPanel.reset();
2747    
2748    // Create menubar and menus
2749
_menuBar = new MenuBar();
2750    _fileMenu = _setUpFileMenu(mask);
2751    _editMenu = _setUpEditMenu(mask);
2752    _toolsMenu = _setUpToolsMenu(mask);
2753    _projectMenu = _setUpProjectMenu(mask);
2754    
2755    if (_showDebugger) _debugMenu = _setUpDebugMenu(mask);
2756    _languageLevelMenu = _setUpLanguageLevelMenu(mask);
2757    _helpMenu = _setUpHelpMenu(mask);
2758    
2759    // initialize menu bar and actions
2760
_setUpActions();
2761    _setUpMenuBar();
2762
2763    // _setUpDocumentSelector();
2764
_setUpContextMenus();
2765    
2766    // Create toolbar and buttons
2767

2768    _toolBar = new JToolBar();
2769    _undoButton = _createManualToolbarButton(_undoAction);
2770    _redoButton = _createManualToolbarButton(_redoAction);
2771    
2772    // initialize _toolBar
2773

2774    _setUpToolBar();
2775    
2776    // add recent file and project manager
2777

2778    _recentFileManager =
2779      new RecentFileManager(_fileMenu.getItemCount() - 2, _fileMenu,
2780                            new RecentFileManager.RecentFileAction() {
2781                              public void actionPerformed(FileOpenSelector selector) { open(selector); }
2782                            },
2783                            OptionConstants.RECENT_FILES);
2784                                               
2785    _recentProjectManager =
2786      new RecentFileManager(_projectMenu.getItemCount()-2, _projectMenu,
2787                            new RecentFileManager.RecentFileAction() {
2788                              public void actionPerformed(FileOpenSelector selector) { openProject(selector); }
2789                            },
2790                            OptionConstants.RECENT_PROJECTS);
2791    
2792    // Set frame icon
2793
setIconImage(getIcon("drjava64.png").getImage());
2794    
2795    // Size and position
2796
int x = config.getSetting(WINDOW_X).intValue();
2797    int y = config.getSetting(WINDOW_Y).intValue();
2798    int width = config.getSetting(WINDOW_WIDTH).intValue();
2799    int height = config.getSetting(WINDOW_HEIGHT).intValue();
2800    
2801    // Bounds checking.
2802
// suggested from zaq@nosi.com, to keep the frame on the screen!
2803
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
2804    
2805    final int menubarHeight = 24;
2806    if (height > screenSize.height - menubarHeight) height = screenSize.height - menubarHeight; // Too tall, so resize
2807

2808    if (width > screenSize.width) width = screenSize.width; // Too wide, so resize
2809

2810    // I assume that we want to be contained on the default screen.
2811
// TODO: support spanning screens in multi-screen setups.
2812
Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().
2813      getDefaultConfiguration().getBounds();
2814    
2815    if (x == Integer.MAX_VALUE) x = (bounds.width - width + bounds.x) / 2; // magic value for "not set" - center.
2816
if (y == Integer.MAX_VALUE) y = (bounds.height - height + bounds.y) / 2; // magic value for "not set" - center.
2817
if (x < bounds.x) x = bounds.x; // Too far left, move to left edge.
2818
if (y < bounds.y) y = bounds.y; // Too far up, move to top edge.
2819
if ((x + width) > (bounds.x + bounds.width)) x = bounds.width - width + bounds.x;
2820                                                                               // Too far right, move to right edge.
2821
if ((y + height) > (bounds.y + bounds.height)) y = bounds.height - height + bounds.y;
2822                                                                               // Too far down, move to bottom edge.
2823

2824    // Set to the new correct size and location
2825
setBounds(x, y, width, height);
2826    
2827    _setUpPanes();
2828    updateFileTitle();
2829    
2830    _promptBeforeQuit = config.getSetting(QUIT_PROMPT).booleanValue();
2831    
2832    // Set the fonts
2833
_setMainFont();
2834    Font doclistFont = config.getSetting(FONT_DOCLIST);
2835    _model.getDocCollectionWidget().setFont(doclistFont);
2836    
2837    // Set the colors
2838
_updateNormalColor();
2839    _updateBackgroundColor();
2840    
2841    // Add OptionListeners for the colors.
2842
config.addOptionListener(DEFINITIONS_NORMAL_COLOR, new NormalColorOptionListener());
2843    config.addOptionListener(DEFINITIONS_BACKGROUND_COLOR, new BackgroundColorOptionListener());
2844    
2845    /* Add option listeners for changes to config options. NOTE: We should only add listeners to view-related (or view-
2846     * dependent) config options here. Model options should go in DefaultGlobalModel._registerOptionListeners(). */

2847    config.addOptionListener(FONT_MAIN, new MainFontOptionListener());
2848    config.addOptionListener(FONT_LINE_NUMBERS, new LineNumbersFontOptionListener());
2849    config.addOptionListener(FONT_DOCLIST, new DoclistFontOptionListener());
2850    config.addOptionListener(FONT_TOOLBAR, new ToolbarFontOptionListener());
2851    config.addOptionListener(TOOLBAR_ICONS_ENABLED, new ToolbarOptionListener());
2852    config.addOptionListener(TOOLBAR_TEXT_ENABLED, new ToolbarOptionListener());
2853    config.addOptionListener(TOOLBAR_ENABLED, new ToolbarOptionListener());
2854    config.addOptionListener(LINEENUM_ENABLED, new LineEnumOptionListener());
2855    config.addOptionListener(QUIT_PROMPT, new QuitPromptOptionListener());
2856    config.addOptionListener(RECENT_FILES_MAX_SIZE, new RecentFilesOptionListener());
2857    
2858    config.addOptionListener(LOOK_AND_FEEL, new OptionListener<String JavaDoc>() {
2859      public void optionChanged(OptionEvent<String JavaDoc> oe) {
2860// try {
2861
// UIManager.setLookAndFeel(oe.value);
2862
// SwingUtilities.updateComponentTreeUI(MainFrame.this);
2863
// if (_debugPanel != null) {
2864
// SwingUtilities.updateComponentTreeUI(_debugPanel);
2865
// }
2866
// if (_configFrame != null) {
2867
// SwingUtilities.updateComponentTreeUI(_configFrame);
2868
// }
2869
// if (_helpFrame != null) {
2870
// SwingUtilities.updateComponentTreeUI(_helpFrame);
2871
// }
2872
// if (_aboutDialog != null) {
2873
// SwingUtilities.updateComponentTreeUI(_aboutDialog);
2874
// }
2875
// SwingUtilities.updateComponentTreeUI(_navPanePopupMenu);
2876
// SwingUtilities.updateComponentTreeUI(_interactionsPanePopupMenu);
2877
// SwingUtilities.updateComponentTreeUI(_consolePanePopupMenu);
2878
// SwingUtilities.updateComponentTreeUI(_openChooser);
2879
// SwingUtilities.updateComponentTreeUI(_saveChooser);
2880
// Iterator<TabbedPanel> it = _tabs.iterator();
2881
// while (it.hasNext()) {
2882
// SwingUtilities.updateComponentTreeUI(it.next());
2883
// }
2884
// }
2885
// catch (Exception ex) {
2886
// _showError(ex, "Could Not Set Look and Feel",
2887
// "An error occurred while trying to set the look and feel.");
2888
// }
2889

2890        String JavaDoc title = "Apply Look and Feel";
2891        String JavaDoc msg = "Look and feel changes will take effect when you restart DrJava.";
2892        if (config.getSetting(WARN_CHANGE_LAF).booleanValue()) {
2893          ConfirmCheckBoxDialog dialog =
2894            new ConfirmCheckBoxDialog(_configFrame, title, msg,
2895                                      "Do not show this message again",
2896                                      JOptionPane.INFORMATION_MESSAGE,
2897                                      JOptionPane.DEFAULT_OPTION);
2898          if (dialog.show() == JOptionPane.OK_OPTION && dialog.getCheckBoxValue()) {
2899            config.setSetting(WARN_CHANGE_LAF, Boolean.FALSE);
2900          }
2901        }
2902      }
2903    });
2904    
2905   
2906    config.addOptionListener(SLAVE_JVM_ARGS, new OptionListener<String JavaDoc>() {
2907      public void optionChanged(OptionEvent<String JavaDoc> oe) {
2908        if (!oe.value.equals("")) {
2909          int result = JOptionPane.
2910            showConfirmDialog(_configFrame,
2911                              "Specifying Interations JVM Args is an advanced option. Invalid arguments may cause\n" +
2912                              "the Interactions Pane to stop working.\n" + "Are you sure you want to set this option?\n" +
2913                              "(You will have to reset the interactions pane before changes take effect.)",
2914                              "Confirm Interactions JVM Arguments", JOptionPane.YES_NO_OPTION);
2915          if (result!=JOptionPane.YES_OPTION) config.setSetting(oe.option, "");
2916        }
2917      }
2918    });
2919    
2920    config.addOptionListener(MASTER_JVM_ARGS, new OptionListener<String JavaDoc>() {
2921      public void optionChanged(OptionEvent<String JavaDoc> oe) {
2922        if (!oe.value.equals("")) {
2923          int result = JOptionPane.
2924            showConfirmDialog(_configFrame,
2925                              "Specifying Main JVM Args is an advanced option. Invalid arguments may cause\n" +
2926                              "DrJava to fail on start up. You may need to edit or delete your .drjava preferences file\n" +
2927                              "to recover.\n Are you sure you want to set this option?\n" +
2928                              "(You will have to restart Drjava before changes take effect.)",
2929                              "Confirm Main JVM Arguments", JOptionPane.YES_NO_OPTION);
2930          if (result!=JOptionPane.YES_OPTION) config.setSetting(oe.option, "");
2931        }
2932      }
2933    });
2934    
2935    config.addOptionListener(ALLOW_PRIVATE_ACCESS, new OptionListener<Boolean JavaDoc>() {
2936      public void optionChanged(OptionEvent<Boolean JavaDoc> oce) {
2937        _model.getInteractionsModel().setPrivateAccessible(oce.value.booleanValue());
2938      }
2939    });
2940    
2941    config.addOptionListener(FORCE_TEST_SUFFIX, new OptionListener<Boolean JavaDoc>() {
2942      public void optionChanged(OptionEvent<Boolean JavaDoc> oce) {
2943        _model.getJUnitModel().setForceTestSuffix(oce.value.booleanValue());
2944      }
2945    });
2946      
2947    // The OptionListener for JAVADOC_LINK_VERSION.
2948
OptionListener<String JavaDoc> choiceOptionListener = new OptionListener<String JavaDoc>() {
2949      public void optionChanged(OptionEvent<String JavaDoc> oce) {
2950        _openJavadocList = null;
2951        _openJavadocAction.setEnabled(!oce.value.equals(JAVADOC_NONE_TEXT));
2952        _openJavadocUnderCursorAction.setEnabled(!oce.value.equals(JAVADOC_NONE_TEXT));
2953      }
2954    };
2955    DrJava.getConfig().addOptionListener(JAVADOC_LINK_VERSION, choiceOptionListener);
2956    
2957    // The OptionListener for JAVADOC_XXX_LINK.
2958
OptionListener<String JavaDoc> link13OptionListener = new OptionListener<String JavaDoc>() {
2959      public void optionChanged(OptionEvent<String JavaDoc> oce) {
2960        String JavaDoc linkVersion = DrJava.getConfig().getSetting(JAVADOC_LINK_VERSION);
2961        if (linkVersion.equals(JAVADOC_1_3_TEXT)) {
2962          _openJavadocList = null;
2963        }
2964      }
2965    };
2966    DrJava.getConfig().addOptionListener(JAVADOC_1_3_LINK, link13OptionListener);
2967    OptionListener<String JavaDoc> link14OptionListener = new OptionListener<String JavaDoc>() {
2968      public void optionChanged(OptionEvent<String JavaDoc> oce) {
2969        String JavaDoc linkVersion = DrJava.getConfig().getSetting(JAVADOC_LINK_VERSION);
2970        if (linkVersion.equals(JAVADOC_1_4_TEXT)) {
2971          _openJavadocList = null;
2972        }
2973      }
2974    };
2975    DrJava.getConfig().addOptionListener(JAVADOC_1_4_LINK, link14OptionListener);
2976    OptionListener<String JavaDoc> link15OptionListener = new OptionListener<String JavaDoc>() {
2977      public void optionChanged(OptionEvent<String JavaDoc> oce) {
2978        String JavaDoc linkVersion = DrJava.getConfig().getSetting(JAVADOC_LINK_VERSION);
2979        if (linkVersion.equals(JAVADOC_1_5_TEXT)) {
2980          _openJavadocList = null;
2981        }
2982      }
2983    };
2984    DrJava.getConfig().addOptionListener(JAVADOC_1_5_LINK, link15OptionListener);
2985    
2986    // Initialize DocumentRegion highlights hashtables, for easy removal of highlights
2987
_documentBreakpointHighlights = new Hashtable JavaDoc<Breakpoint, HighlightManager.HighlightInfo>();
2988    _documentBookmarkHighlights = new Hashtable JavaDoc<DocumentRegion, HighlightManager.HighlightInfo>();
2989    
2990    // Initialize cached frames and dialogs
2991
_configFrame = new ConfigFrame(this);
2992    _helpFrame = new HelpFrame();
2993    _aboutDialog = new AboutDialog(MainFrame.this);
2994    _quickStartFrame = new QuickStartFrame();
2995    _interactionsScriptController = null;
2996    _jarOptionsDialog = new JarOptionsDialog(MainFrame.this);
2997    initJarOptionsDialog();
2998// _projectPropertiesFrame = null;
2999

3000    // If any errors occurred while parsing config file, show them
3001
_showConfigException();
3002    
3003    KeyBindingManager.Singleton.setShouldCheckConflict(false);
3004    
3005    // Platform-specific UI setup.
3006
PlatformFactory.ONLY.afterUISetup(_aboutAction, _editPreferencesAction, _quitAction);
3007    setUpKeys();
3008    
3009    // discard ` character if it was used for the next/prev recent doc feature
3010
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
3011      public boolean dispatchKeyEvent(KeyEvent e) {
3012        boolean discardEvent = false;
3013        
3014        if ((e.getID() == KeyEvent.KEY_TYPED) &&
3015            (e.getKeyChar()=='`') &&
3016            (((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) ||
3017             ((e.getModifiersEx() & (InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK))
3018                == (InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK))) &&
3019            (e.getComponent().getClass().equals(DefinitionsPane.class))) {
3020// System.out.println("discarding `, modifiers = "+e.getModifiersEx()+": "+e.getComponent());
3021
discardEvent = true;
3022        }
3023        
3024        return discardEvent;
3025      }
3026    });
3027  } // End of MainFrame constructor
3028

3029  public void setVisible(boolean b) {
3030     _updateToolBarVisible();
3031    super.setVisible(b);
3032  }
3033  
3034  /** Set a new painters for existing breakpoint highlights. */
3035  void refreshBreakpointHighlightPainter() {
3036    for(java.util.Map.Entry<Breakpoint,HighlightManager.HighlightInfo> pair: _documentBreakpointHighlights.entrySet()) {
3037      if (pair.getKey().isEnabled()) {
3038        pair.getValue().refresh(DefinitionsPane.BREAKPOINT_PAINTER);
3039      }
3040      else {
3041        pair.getValue().refresh(DefinitionsPane.DISABLED_BREAKPOINT_PAINTER);
3042      }
3043    }
3044  }
3045  
3046  /** Set new painter for existing bookmark highlights. */
3047  void refreshBookmarkHighlightPainter() {
3048    for(HighlightManager.HighlightInfo hi: _documentBookmarkHighlights.values()) {
3049      hi.refresh(DefinitionsPane.BOOKMARK_PAINTER);
3050    }
3051  }
3052  
3053  /** Set new painter for existing find results highlights. */
3054  void refreshFindResultsHighlightPainter(FindResultsPanel panel,
3055                                          ReverseHighlighter.DefaultUnderlineHighlightPainter painter) {
3056    for(Pair<FindResultsPanel,Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair: _findResults) {
3057      if (pair.first()==panel) {
3058        Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights = pair.second();
3059        for(HighlightManager.HighlightInfo hi: highlights.values()) {
3060          hi.refresh(painter);
3061        }
3062      }
3063    }
3064  }
3065  
3066  /** Creates the folder chooser during MainFrame initialization which does not run in event thread. */
3067  private DirectoryChooser makeFolderChooser(final File workDir) {
3068    final DirectoryChooser dc = new DirectoryChooser(this);
3069    /* The following code fragement was moved to the event thread because setSelectedFile occasionally generates an
3070     * ArrayOutOfBoundsException otherwise. */

3071    Utilities.invokeLater(new Runnable JavaDoc() {
3072      public void run() {
3073        dc.setSelectedFile(workDir);
3074        dc.setApproveButtonText("Select");
3075        dc.setDialogTitle("Open Folder");
3076        dc.setAccessory(_openRecursiveCheckBox);
3077      }
3078    });
3079    return dc;
3080  }
3081//
3082
// private JFileChooser makeFolderChooser(File workDir) {
3083
// _folderChooser = new JFileChooser();
3084
// _folderChooser.setMultiSelectionEnabled(false);
3085
// _folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3086
// _folderChooser.setCurrentDirectory(workDir);
3087
// _folderChooser.setApproveButtonText("Select");
3088
// _folderChooser.setFileFilter(new DirectoryFilter());
3089
// _folderChooser.setDialogTitle("Open Folder");
3090
//
3091
//
3092
// Container button_row = (Container)findButtonContainer(_folderChooser, _folderChooser.getApproveButtonText());
3093
// Container buttons = (Container) button_row.getParent();
3094
//
3095
//// Component c2 = ((BorderLayout)_folderChooser.getLayout()).getLayoutComponent(BorderLayout.SOUTH);
3096
//
3097
//// System.out.println("c1: " + c1);
3098
//// System.out.println("c2: " + c2);
3099
//
3100
//
3101
//// JPanel buttons = (JPanel)c2;
3102
//// JPanel button_row = (JPanel)buttons.getComponent(3);
3103
// JPanel bottom_row = new JPanel();
3104
// bottom_row.setLayout(new BorderLayout());
3105
// bottom_row.add(new JCheckBox("Recursive Open"), BorderLayout.CENTER);
3106
// bottom_row.add(button_row, BorderLayout.EAST);
3107
// buttons.add(bottom_row);
3108
//
3109
// return _folderChooser;
3110
// }
3111

3112// private Container findButtonContainer(Container container, String buttonText) {
3113
// Container answer = null;
3114
// Component[] cs = container.getComponents();
3115
// for(Component c: cs) {
3116
// if (c instanceof JButton && ((JButton)c).getText().equals(buttonText)) {
3117
// return container;
3118
// }else if (c instanceof Container) {
3119
// answer = findButtonContainer((Container)c, buttonText);
3120
// }
3121
//
3122
// if (answer != null) break;
3123
// }
3124
// return answer;
3125
// }
3126

3127
3128  /** Sets up the ctrl-tab listener. */
3129  private void setUpKeys() { setFocusTraversalKeysEnabled(false); }
3130  
3131  /** Relying on inherited dispose() method. */
3132    
3133  /** @return The model providing the logic for this view. */
3134  public SingleDisplayModel getModel() { return _model; }
3135  
3136  /** Returns the frame's interactions pane. (Package private accessor) */
3137  InteractionsPane getInteractionsPane() { return _interactionsPane; }
3138  
3139  /** Returns the frame's interactions controller. (Package private accessor) */
3140  InteractionsController getInteractionsController() { return _interactionsController; }
3141  
3142  /** @return The frame's close button (Package private accessor). */
3143  JButton getCloseButton() { return _closeButton; }
3144  
3145  /** For testing purposes.
3146   * @return The frame's compileAll button (Package private accessor)
3147   */

3148  JButton getCompileAllButton() { return _compileButton; }
3149  
3150  private volatile int _hourglassNestLevel = 0;
3151  
3152  /** Make the cursor an hourglass. Only runs in the event thread. */
3153  public void hourglassOn() {
3154    assert EventQueue.isDispatchThread();
3155    _hourglassNestLevel++;
3156    if (_hourglassNestLevel == 1) {
3157    getGlassPane().setVisible(true);
3158    _currentDefPane.setEditable(false);
3159    setAllowKeyEvents(false);
3160    }
3161  }
3162  
3163  /** Return the cursor to normal. Only runs in the event thread. */
3164  public void hourglassOff() {
3165    assert EventQueue.isDispatchThread();
3166    _hourglassNestLevel--;
3167    if (_hourglassNestLevel == 0) {
3168      getGlassPane().setVisible(false);
3169      _currentDefPane.setEditable(true);
3170      setAllowKeyEvents(true);
3171    }
3172  }
3173  
3174  private volatile boolean _allowKeyEvents = true;
3175  
3176  public void setAllowKeyEvents(boolean a) { _allowKeyEvents = a; }
3177  
3178  public boolean getAllowKeyEvents() { return _allowKeyEvents; }
3179  
3180  /** Toggles whether the debugger is enabled or disabled, and updates the display accordingly. Only runs in the
3181    * event thread. */

3182  public void debuggerToggle() {
3183    assert EventQueue.isDispatchThread();
3184    // Make sure the debugger is available
3185
Debugger debugger = _model.getDebugger();
3186    if (!debugger.isAvailable()) return;
3187    
3188    try {
3189      if (isDebuggerReady()) debugger.shutdown();
3190      else {
3191        // Turn on debugger
3192
hourglassOn();
3193        try {
3194          debugger.startUp(); // may kick active document (if unmodified) out of memory!
3195
_model.refreshActiveDocument();
3196          _updateDebugStatus();
3197        }
3198        finally { hourglassOff(); }
3199      }
3200    }
3201    catch (DebugException de) {
3202      _showError(de, "Debugger Error", "Could not start the debugger.");
3203    }
3204    catch (NoClassDefFoundError JavaDoc err) {
3205      _showError(err, "Debugger Error",
3206                 "Unable to find the JPDA package for the debugger.\n" +
3207                 "Please make sure either tools.jar or jpda.jar is\n" +
3208                 "in your classpath when you start DrJava.");
3209      _setDebugMenuItemsEnabled(false);
3210    }
3211  }
3212  
3213  /** Display the debugger tab and update the Debug menu accordingly. */
3214  public void showDebugger() {
3215    _setDebugMenuItemsEnabled(true);
3216    _showDebuggerPanel();
3217  }
3218  
3219  /** Hide the debugger tab and update the Debug menu accordingly. */
3220  public void hideDebugger() {
3221    _setDebugMenuItemsEnabled(false);
3222    _hideDebuggerPanel();
3223  }
3224  
3225  private void _showDebuggerPanel() {
3226    _debugSplitPane.setTopComponent(_docSplitPane);
3227    _mainSplit.setTopComponent(_debugSplitPane);
3228    _debugPanel.updateData();
3229    _lastFocusOwner.requestFocusInWindow();
3230  }
3231  
3232  private void _hideDebuggerPanel() {
3233    _mainSplit.setTopComponent(_docSplitPane);
3234    _lastFocusOwner.requestFocusInWindow();
3235  }
3236  
3237  public void updateFileTitle(String JavaDoc text) { _fileNameField.setText(text); }
3238  
3239  /** Updates the title bar with the name of the active document. */
3240  public void updateFileTitle() {
3241    OpenDefinitionsDocument doc = _model.getActiveDocument();
3242    String JavaDoc fileName = doc.getCompletePath();
3243    if (! fileName.equals(_fileTitle)) {
3244      _fileTitle = fileName;
3245      setTitle("File: " + fileName);
3246      _model.getDocCollectionWidget().repaint();
3247    }
3248    
3249    String JavaDoc fileTitle = doc.getCompletePath();
3250
3251// Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
3252
// if (DrJava.getConfig().getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()) {
3253
// String temp = _model.getParsingControl().getEnclosingClassName(doc);
3254
// if ((temp != null) && (temp.length() > 0)) { fileTitle = fileTitle + " - " + temp; }
3255
// }
3256

3257    if (! _fileNameField.getText().equals(fileTitle)) { _fileNameField.setText(fileTitle); }
3258    
3259    // Two files in different directories can have the same _fileTitle
3260
_fileNameField.setToolTipText("Full path for file: " + doc.getCompletePath());
3261  }
3262  
3263  /** Prompt the user to select a place to open files from, then load them. Ask the user if they'd like to save
3264   * previous changes (if the current document has been modified) before opening.
3265   * @param jfc the open dialog from which to extract information
3266   * @return an array of the files that were chosen
3267   */

3268  public File[] getOpenFiles(JFileChooser jfc) throws OperationCanceledException {
3269    int rc = jfc.showOpenDialog(this);
3270    return getChosenFiles(jfc, rc);
3271  }
3272  
3273  /** Prompt the user to select a place to save the current document. */
3274  public File getSaveFile(JFileChooser jfc) throws OperationCanceledException {
3275    // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X!
3276
// File selection = jfc.getSelectedFile();//_saveChooser.getSelectedFile();
3277
// if (selection != null) {
3278
// jfc.setSelectedFile(selection.getParentFile());
3279
// jfc.setSelectedFile(selection);
3280
// jfc.setSelectedFile(null);
3281
// }
3282

3283    OpenDefinitionsDocument active = _model.getActiveDocument();
3284    
3285    // Fill in class name
3286
//if (active.isUntitled()) {
3287
try {
3288      String JavaDoc className = active.getFirstTopLevelClassName();
3289      if (!className.equals("")) {
3290        jfc.setSelectedFile(new File(jfc.getCurrentDirectory(), className));
3291      }
3292    }
3293    catch (ClassNameNotFoundException e) {
3294      // Don't set selected file
3295
}
3296    
3297    _saveChooser.removeChoosableFileFilter(_projectFilter);
3298    _saveChooser.removeChoosableFileFilter(_javaSourceFilter);
3299    _saveChooser.setFileFilter(_javaSourceFilter);
3300    int rc = jfc.showSaveDialog(this);
3301    return getChosenFile(jfc, rc);
3302  }
3303  
3304  /** Returns the current DefinitionsPane. */
3305  public DefinitionsPane getCurrentDefPane() { return _currentDefPane; }
3306  
3307  /** Returns the currently shown error panel if there is one. Otherwise returns null. */
3308  public ErrorPanel getSelectedErrorPanel() {
3309    Component c = _tabbedPane.getSelectedComponent();
3310    if (c instanceof ErrorPanel) return (ErrorPanel) c;
3311    return null;
3312  }
3313  
3314  /** Returns whether the compiler output tab is currently showing. */
3315  public boolean isCompilerTabSelected() {
3316    return _tabbedPane.getSelectedComponent() == _compilerErrorPanel;
3317  }
3318  
3319  /** Returns whether the test output tab is currently showing. */
3320  public boolean isTestTabSelected() {
3321    return _tabbedPane.getSelectedComponent() == _junitErrorPanel;
3322  }
3323  
3324  /** Returns whether the JavaDoc output tab is currently showing. */
3325  public boolean isJavadocTabSelected() {
3326    return _tabbedPane.getSelectedComponent() == _javadocErrorPanel;
3327  }
3328  
3329  /** Makes sure save and compile buttons and menu items are enabled and disabled appropriately after document
3330   * modifications.
3331   */

3332  private void _installNewDocumentListener(final OpenDefinitionsDocument d) {
3333    d.addDocumentListener(new DocumentUIListener() {
3334      public void changedUpdate(DocumentEvent e) {
3335        
3336        // Commented out because the only attributes that affect the status of buttons are inserts and removes
3337
// Utilities.invokeLater(new Runnable() {
3338
// public void run() {
3339
// OpenDefinitionsDocument doc = _model.getActiveDocument();
3340
// if (doc.isModifiedSinceSave()) {
3341
// _saveAction.setEnabled(true);
3342
// if (isDebuggerReady() && _debugPanel.getStatusText().equals(""))
3343
// _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
3344
// updateFileTitle();
3345
// }
3346
// }
3347
// });
3348
}
3349      public void insertUpdate(DocumentEvent e) {
3350        Utilities.invokeLater(new Runnable JavaDoc() {
3351          public void run() {
3352            _saveAction.setEnabled(true);
3353            if (isDebuggerReady() && _debugPanel.getStatusText().equals(""))
3354              _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
3355// updateFileTitle(); // title not changed by insert operation
3356
}
3357        });
3358      }
3359      public void removeUpdate(DocumentEvent e) {
3360        Utilities.invokeLater(new Runnable JavaDoc() {
3361          public void run() {
3362            _saveAction.setEnabled(true);
3363            if (isDebuggerReady() && _debugPanel.getStatusText().equals(""))
3364              _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
3365// updateFileTitle(); // title not changed by remove operation
3366
}
3367        });
3368      }
3369    });
3370  }
3371  
3372  
3373  /** Changes the message text toward the right of the status bar
3374   * @param msg The message to place in the status bar
3375   */

3376  public void setStatusMessage(String JavaDoc msg) { _sbMessage.setText(msg); }
3377  
3378  /** Sets the message text in the status bar to the null string. */
3379  public void clearStatusMessage() { _sbMessage.setText(""); }
3380  
3381  /** Sets the font of the status bar message
3382   * @param f The new font of the status bar message
3383   */

3384  public void setStatusMessageFont(Font f) { _sbMessage.setFont(f); }
3385  
3386  /** Sets the color of the text in the status bar message
3387   * @param c The color of the text
3388   */

3389  public void setStatusMessageColor(Color c) { _sbMessage.setForeground(c); }
3390  
3391  // Made package protected rather than private in order to facilitate the ProjectMenuTest.testSaveProject
3392
void _moveToAuxiliary() {
3393    OpenDefinitionsDocument d = _model.getDocumentNavigator().getCurrent();
3394    if (d != null) {
3395      if (! d.isUntitled()) {
3396        _model.addAuxiliaryFile(d);
3397        try{
3398          _model.getDocumentNavigator().refreshDocument(d, _model.fixPathForNavigator(d.getFile().getCanonicalPath()));
3399        }
3400        catch(IOException e) { /* do nothing */ }
3401      }
3402    }
3403  }
3404  
3405  private void _removeAuxiliary() {
3406    OpenDefinitionsDocument d = _model.getDocumentNavigator().getCurrent();
3407    if (d != null) {
3408      if (! d.isUntitled()) {
3409        _model.removeAuxiliaryFile(d);
3410        try{
3411          _model.getDocumentNavigator().refreshDocument(d, _model.fixPathForNavigator(d.getFile().getCanonicalPath()));
3412        }
3413        catch(IOException e) { /* do nothing */ }
3414      }
3415    }
3416  }
3417  
3418  private void _new() { _model.newFile(); }
3419  
3420  private void _open() { open(_openSelector); }
3421  
3422  private void _openFolder() { openFolder(_folderChooser); }
3423  
3424  private void _openFileOrProject() {
3425    try {
3426      final File[] fileList = _openFileOrProjectSelector.getFiles();
3427      
3428      FileOpenSelector fos = new FileOpenSelector() {
3429        public File[] getFiles() { return fileList; }
3430      };
3431      
3432      if (_openChooser.getFileFilter().equals(_projectFilter)) openProject(fos);
3433      else open(fos);
3434    }
3435    catch(OperationCanceledException oce) { /* do nothing */ }
3436  }
3437  
3438  /** Puts the given text into the current definitions pane at the current caret position. */
3439  private void _putTextIntoDefinitions(String JavaDoc text) {
3440    int caretPos = _currentDefPane.getCaretPosition();
3441    
3442    try { _model.getActiveDocument().insertString(caretPos, text, null); }
3443    catch (BadLocationException ble) { throw new UnexpectedException(ble); }
3444  }
3445  
3446  /** Sets the left navigator pane to the correct component as dictated by the model. */
3447  private void _resetNavigatorPane() {
3448    if (_model.getDocumentNavigator() instanceof JTreeSortNavigator) {
3449      JTreeSortNavigator<?> nav = (JTreeSortNavigator<?>)_model.getDocumentNavigator();
3450      nav.setDisplayManager(getNavPaneDisplayManager());
3451      nav.setRootIcon(_djProjectIcon);
3452    }
3453    _docSplitPane.remove(_docSplitPane.getLeftComponent());
3454    _docSplitPane.setLeftComponent(new JScrollPane(_model.getDocumentNavigator().asContainer()));
3455    Font doclistFont = DrJava.getConfig().getSetting(FONT_DOCLIST);
3456    _model.getDocCollectionWidget().setFont(doclistFont);
3457    _updateNormalColor();
3458    _updateBackgroundColor();
3459  }
3460  
3461  /** Asks the user to select the project file to open and starts the process of opening the project. */
3462  private void _openProject() { openProject(_openProjectSelector); }
3463  
3464  public void openProject(FileOpenSelector projectSelector) {
3465    
3466    try {
3467      hourglassOn();
3468      final File[] file = projectSelector.getFiles();
3469      if (file.length < 1)
3470        throw new IllegalStateException JavaDoc("Open project file selection not canceled but no project file was selected.");
3471      
3472      // make sure there are no open projects
3473
if (!_model.isProjectActive() || (_model.isProjectActive() && _closeProject())) _openProjectHelper(file[0]);
3474    }
3475    catch(OperationCanceledException oce) {
3476      /* do nothing, we just won't open anything */
3477    }
3478    catch(Exception JavaDoc e) { e.printStackTrace(System.out); }
3479    finally { hourglassOff(); }
3480  }
3481  
3482  
3483  /** Oversees the opening of the project by delegating to the model to parse and initialize the project
3484   * while resetting the navigator pane and opening up the files itself.
3485   * @param projectFile the file of the project to open
3486   */

3487  private void _openProjectHelper(File projectFile) {
3488    _currentProjFile = projectFile;
3489    try {
3490      _mainListener.resetFNFCount();
3491      _model.openProject(projectFile);
3492      if (_mainListener.filesNotFound()) _model.setProjectChanged(true);
3493      _completeClassList = new ArrayList JavaDoc<GoToFileListEntry>(); // reset auto-completion list
3494
}
3495    catch(MalformedProjectFileException e) {
3496      _showProjectFileParseError(e); // add to an error adapter
3497
return;
3498    }
3499    catch(FileNotFoundException e) {
3500      _showFileNotFoundError(e); // add to an error adapter
3501
return;
3502    }
3503    catch(IOException e) {
3504      _showIOError(e); // add to an error adapter
3505
return;
3506    }
3507  }
3508  
3509  private void _openProjectUpdate() {
3510    if (_model.isProjectActive()) {
3511      _closeProjectAction.setEnabled(true);
3512      _saveProjectAction.setEnabled(true);
3513      _saveProjectAsAction.setEnabled(true);
3514      _projectPropertiesAction.setEnabled(true);
3515// _junitProjectAction.setEnabled(true);
3516
_junitProjectAction.setEnabled(true);
3517// _compileOpenProjectAction.setEnabled(true);
3518
_compileProjectAction.setEnabled(true);
3519      _jarProjectAction.setEnabled(true);
3520      if (_model.getBuildDirectory() != null) _cleanAction.setEnabled(true);
3521      _resetNavigatorPane();
3522// _compileButton.setToolTipText("<html>Compile all documents in the project.source tree<br>Auxiliary and external files are excluded.</html>");
3523
}
3524  }
3525  
3526  /** Closes project when DrJava is not in the process of quitting.
3527   * @return true if the project is closed, false if cancelled.
3528   */

3529  boolean _closeProject() {
3530    _completeClassList = new ArrayList JavaDoc<GoToFileListEntry>(); // reset auto-completion list
3531
return _closeProject(false);
3532  }
3533  
3534  /** Saves the project file; closes all open project files; and calls _model.closeProject(quitting) the
3535    * clean up the state of the global model. It also restores the list view navigator
3536    * @ param quitting whether the project is being closed as part of quitting DrJava
3537    * @return true if the project is closed, false if cancelled
3538    */

3539  boolean _closeProject(boolean quitting) {
3540    if (_checkProjectClose()) {
3541      List JavaDoc<OpenDefinitionsDocument> projDocs = _model.getProjectDocuments();
3542// System.err.println("projDocs = " + projDocs);
3543
boolean couldClose = _model.closeFiles(projDocs);
3544      if (! couldClose) return false;
3545      // project file has been saved and all files closed
3546
if (quitting) return true;
3547      _model.closeProject(quitting);
3548
3549      Component renderer = _model.getDocumentNavigator().getRenderer();
3550      new ForegroundColorListener(renderer);
3551      new BackgroundColorListener(renderer);
3552      _resetNavigatorPane();
3553      if (_model.getDocumentCount() == 1) {
3554        _model.setActiveFirstDocument();
3555      }
3556      _closeProjectAction.setEnabled(false);
3557      _saveProjectAction.setEnabled(false);
3558      _saveProjectAsAction.setEnabled(false);
3559      _projectPropertiesAction.setEnabled(false);
3560// _junitProjectAction.setEnabled(false);
3561
_jarProjectAction.setEnabled(false);
3562      _junitProjectAction.setEnabled(false);
3563// _compileOpenProjectAction.setEnabled(false);
3564
_compileProjectAction.setEnabled(false);
3565      _setUpContextMenus();
3566      _currentProjFile = null;
3567// _compileButton.setToolTipText("Compile all open documents");
3568
return true;
3569    }
3570    else return false; // Project closing cancelled in _checkProjectClose dialog
3571
}
3572  
3573  private boolean _checkProjectClose() {
3574    if (_model.isProjectChanged()) {
3575      String JavaDoc fname = _model.getProjectFile().getName();
3576      String JavaDoc text = fname + " has been modified. Would you like to save it?";
3577      int rc =
3578        JOptionPane.showConfirmDialog(MainFrame.this, text, "Save " + fname + "?", JOptionPane.YES_NO_CANCEL_OPTION);
3579      switch (rc) {
3580        case JOptionPane.YES_OPTION:
3581          _saveProject();
3582          return true;
3583        case JOptionPane.NO_OPTION:
3584          return true;
3585        case JOptionPane.CLOSED_OPTION:
3586        case JOptionPane.CANCEL_OPTION:
3587          return false;
3588        default:
3589          throw new RuntimeException JavaDoc("Invalid rc: " + rc);
3590      }
3591    }
3592    return true;
3593  }
3594  
3595  public File getCurrentProject() { return _currentProjFile; }
3596  
3597  /** Opens all the files returned by the FileOpenSelector prompting the user to handle the cases where files are
3598   * already open, files are missing, or the action was canceled by the user
3599   * @param openSelector the selector that returns the files to open
3600   */

3601  public void open(FileOpenSelector openSelector) {
3602    try {
3603      hourglassOn();
3604      _model.openFiles(openSelector);
3605    }
3606    catch (AlreadyOpenException aoe) {
3607      OpenDefinitionsDocument[] openDocs = aoe.getOpenDocuments();
3608      for(OpenDefinitionsDocument openDoc : openDocs) {
3609        String JavaDoc fileName;
3610        try { fileName = openDoc.getFile().getName(); }
3611        catch (IllegalStateException JavaDoc ise) {
3612          // Can't happen: this open document must have a file
3613
throw new UnexpectedException(ise);
3614        }
3615        catch (FileMovedException fme) {
3616          // File was deleted, but use the same name anyway
3617
fileName = fme.getFile().getName();
3618        }
3619        try {
3620          File f = openDoc.getFile();
3621          if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f);
3622        }
3623        catch (IllegalStateException JavaDoc ise) {
3624          // Impossible: saved => has a file
3625
throw new UnexpectedException(ise);
3626        }
3627        catch (FileMovedException fme) {
3628          File f = fme.getFile();
3629          // Recover, show it in the list anyway
3630
if (! _model.inProject(f))
3631            _recentFileManager.updateOpenFiles(f);
3632        }
3633      }
3634    }
3635    catch (OperationCanceledException oce) { /* do not open file */ }
3636    catch (FileNotFoundException fnf) {
3637      _showFileNotFoundError(fnf);
3638    }
3639    catch (IOException ioe) { _showIOError(ioe); }
3640    finally { hourglassOff(); }
3641  }
3642  
3643  
3644  /** Opens all the files in the directory returned by the FolderSelector.
3645   * @param chooser the selector that returns the files to open
3646   */

3647  public void openFolder(DirectoryChooser chooser) {
3648    String JavaDoc type = "'." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[DrJava.getConfig().getSetting(LANGUAGE_LEVEL)] + "' ";
3649    chooser.setDialogTitle("Open All " + type + "Files in ...");
3650    
3651    File openDir = null;
3652    try {
3653      File activeFile = _model.getActiveDocument().getFile();
3654      if (activeFile != null) openDir = activeFile.getParentFile();
3655      else openDir = _model.getProjectRoot();
3656    }
3657    catch(FileMovedException e) { /* do nothing */ }
3658    
3659    int result = chooser.showDialog(openDir);
3660    if (result != DirectoryChooser.APPROVE_OPTION) return; // canceled or error
3661

3662    File dir = chooser.getSelectedDirectory();
3663    boolean rec = _openRecursiveCheckBox.isSelected();
3664    DrJava.getConfig().setSetting(OptionConstants.OPEN_FOLDER_RECURSIVE, Boolean.valueOf(rec));
3665    _openFolder(dir, rec);
3666  }
3667  
3668  /** Opens all the files in the specified directory; it opens all files in nested folders if rec is true.
3669   * @param dir the specified directory
3670   * @param rec true if files in nested folders should be opened
3671   */

3672  private void _openFolder(File dir, boolean rec) {
3673    hourglassOn();
3674    try { _model.openFolder(dir, rec); }
3675    catch(AlreadyOpenException e) { /* do nothing */ }
3676    catch(IOException e) { _showIOError(e); }
3677    catch(OperationCanceledException oce) { /* do nothing */ }
3678    finally { hourglassOff(); }
3679  }
3680    
3681  /** Delegates directly to the model to close the active document */
3682  private void _close() {
3683    // LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
3684
// l.add(_model.getActiveDocument());
3685
// _model.closeFiles(l);
3686

3687    if ((_model.isProjectActive() && _model.getActiveDocument().inProjectPath()) ||
3688        _model.getActiveDocument().isAuxiliaryFile()) {
3689      
3690      String JavaDoc fileName = null;
3691      OpenDefinitionsDocument doc = _model.getActiveDocument();
3692      try{
3693        if (doc.isUntitled()) fileName = "File";
3694        else fileName = _model.getActiveDocument().getFile().getName();
3695      }
3696      catch(FileMovedException e) { fileName = e.getFile().getName(); }
3697      String JavaDoc text = "Closing this file will permanently remove it from the current project." +
3698        "\nAre you sure that you want to close this file?";
3699      
3700      Object JavaDoc[] options = {"Yes", "No"};
3701      int rc =
3702        JOptionPane.showOptionDialog(MainFrame.this, text,"Close " + fileName + "?", JOptionPane.YES_NO_OPTION,
3703                                     JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
3704      if (rc != JOptionPane.YES_OPTION) return;
3705      _model.setProjectChanged(true);
3706    }
3707    
3708    //Either this is an external file or user actually wants to close it
3709
_model.closeFile(_model.getActiveDocument());
3710  }
3711  
3712  private void _closeFolder() {
3713    OpenDefinitionsDocument d;
3714    Enumeration JavaDoc<OpenDefinitionsDocument> e = _model.getDocumentNavigator().getDocuments();
3715    final LinkedList JavaDoc<OpenDefinitionsDocument> l = new LinkedList JavaDoc<OpenDefinitionsDocument>();
3716    if (_model.getDocumentNavigator().isGroupSelected()) {
3717      while (e.hasMoreElements()) {
3718        d = e.nextElement();
3719        if (_model.getDocumentNavigator().isSelectedInGroup(d)) { l.add(d); }
3720      }
3721      _model.closeFiles(l);
3722      if (! l.isEmpty()) _model.setProjectChanged(true);
3723    }
3724  }
3725  
3726  private void _printDefDoc() {
3727    try {
3728      _model.getActiveDocument().print();
3729    }
3730    catch (FileMovedException fme) {
3731      _showFileMovedError(fme);
3732    }
3733    catch (PrinterException e) {
3734      _showError(e, "Print Error", "An error occured while printing.");
3735    }
3736    catch (BadLocationException e) {
3737      _showError(e, "Print Error", "An error occured while printing.");
3738    }
3739  }
3740  
3741  private void _printConsole() {
3742    try {
3743      _model.getConsoleDocument().print();
3744    }
3745    catch (PrinterException e) {
3746      _showError(e, "Print Error", "An error occured while printing.");
3747    }
3748  }
3749  
3750  private void _printInteractions() {
3751    try {
3752      _model.getInteractionsDocument().print();
3753    }
3754    catch (PrinterException e) {
3755      _showError(e, "Print Error", "An error occured while printing.");
3756    }
3757  }
3758  
3759  /** Opens a new PrintPreview frame. */
3760  private void _printDefDocPreview() {
3761    try {
3762      _model.getActiveDocument().preparePrintJob();
3763      new PreviewDefDocFrame(_model, this);
3764    }
3765    catch (FileMovedException fme) {
3766      _showFileMovedError(fme);
3767    }
3768    catch (BadLocationException e) {
3769      _showError(e, "Print Error",
3770                 "An error occured while preparing the print preview.");
3771    }
3772    catch (IllegalStateException JavaDoc e) {
3773      _showError(e, "Print Error",
3774                 "An error occured while preparing the print preview.");
3775    }
3776  }
3777
3778  private void _printConsolePreview() {
3779    try {
3780      _model.getConsoleDocument().preparePrintJob();
3781      new PreviewConsoleFrame(_model, this, false);
3782    }
3783    catch (IllegalStateException JavaDoc e) {
3784      _showError(e, "Print Error",
3785                 "An error occured while preparing the print preview.");
3786    }
3787  }
3788  
3789  private void _printInteractionsPreview() {
3790    try {
3791      _model.getInteractionsDocument().preparePrintJob();
3792      new PreviewConsoleFrame(_model, this, true);
3793    }
3794    catch (IllegalStateException JavaDoc e) {
3795      _showError(e, "Print Error",
3796                 "An error occured while preparing the print preview.");
3797    }
3798  }
3799  
3800  private void _pageSetup() {
3801    PrinterJob job = PrinterJob.getPrinterJob();
3802    _model.setPageFormat(job.pageDialog(_model.getPageFormat()));
3803  }
3804  
3805  //Called by testCases
3806
void closeAll() { _closeAll(); }
3807  
3808  private void _closeAll() {
3809    if (!_model.isProjectActive() || _model.isProjectActive() && _closeProject())
3810      _model.closeAllFiles();
3811  }
3812  
3813  private boolean _save() {
3814    try {
3815      if (_model.getActiveDocument().saveFile(_saveSelector)) {
3816        _currentDefPane.hasWarnedAboutModified(false);
3817        
3818        /**This highlights the document in the navigator */
3819        _model.setActiveDocument(_model.getActiveDocument());
3820        
3821        return true;
3822      }
3823      else return false;
3824    }
3825    catch (IOException ioe) {
3826      _showIOError(ioe);
3827      return false;
3828    }
3829  }
3830  
3831  
3832  private boolean _saveAs() {
3833    try {
3834      boolean toReturn = _model.getActiveDocument().saveFileAs(_saveAsSelector);
3835      /** this highlights the document in the navigator */
3836      _model.setActiveDocument(_model.getActiveDocument());
3837      return toReturn;
3838    }
3839    catch (IOException ioe) {
3840      _showIOError(ioe);
3841      return false;
3842    }
3843  }
3844
3845  private boolean _rename() {
3846    try {
3847      if (!_model.getActiveDocument().fileExists()) {
3848        return _saveAs();
3849      }
3850      else {
3851        File fileToDelete;
3852        try {
3853          fileToDelete = _model.getActiveDocument().getFile();
3854        } catch (FileMovedException fme) {
3855          return _saveAs();
3856        }
3857        boolean toReturn = _model.getActiveDocument().saveFileAs(_saveAsSelector);
3858        /** Delete the old file if save was successful */
3859        if (toReturn && !_model.getActiveDocument().getFile().equals(fileToDelete)) fileToDelete.delete();
3860        /** this highlights the document in the navigator */
3861        _model.setActiveDocument(_model.getActiveDocument());
3862        return toReturn;
3863      }
3864    }
3865    catch (IOException ioe) {
3866      _showIOError(ioe);
3867      return false;
3868    }
3869  }
3870  
3871  /* Package private to allow use in MainFrameTest. */
3872  void _saveAll() {
3873    hourglassOn();
3874    try {
3875      if (_model.isProjectActive()) _saveProject();
3876      _model.saveAllFiles(_saveSelector);
3877    }
3878    catch (IOException ioe) { _showIOError(ioe); }
3879    finally { hourglassOff(); }
3880  }
3881  
3882  // Called by the ProjectPropertiesFrame
3883
void saveProject() { _saveProject(); }
3884  
3885  private void _saveProject() {
3886    //File file = _model.getProjectFile();
3887
_saveProjectHelper(_currentProjFile);
3888  }
3889  
3890  /** Edit project frame. */
3891  private void _editProject() {
3892    ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(this);
3893    ppf.setVisible(true);
3894    ppf.reset();
3895    ppf.toFront(); // ppf actions save state of ppf in global model
3896
}
3897  
3898  /** Closes all files and makes a new project. */
3899  private void _newProject() {
3900
3901    _closeProject(true); // suppress resetting interactions; it will be done in _model.newProject() below
3902
_saveChooser.setFileFilter(_projectFilter);
3903    int rc = _saveChooser.showSaveDialog(this);
3904    if (rc == JFileChooser.APPROVE_OPTION) {
3905      File pf = _saveChooser.getSelectedFile(); // project file
3906
if (pf.exists() && !_verifyOverwrite()) { return; }
3907
3908      String JavaDoc fileName = pf.getName();
3909      // ensure that saved file has extesion ".pjt"
3910
if (! fileName.endsWith(".pjt")) {
3911        int lastIndex = fileName.lastIndexOf(".");
3912        if (lastIndex == -1) pf = new File (pf.getAbsolutePath() + ".pjt");
3913        else pf = new File(fileName.substring(0, lastIndex) + ".pjt");
3914      }
3915      
3916      _model.createNewProject(pf); // sets model to a new FileGroupingState for project file pf
3917
// ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(MainFrame.this, file);
3918
// ppf.saveSettings(); // Saves new project profile in global model
3919
_editProject(); // edits the properties of the new FileGroupingState
3920
try { _model.configNewProject(); } // configures the new project in the model
3921
catch(IOException e) { throw new UnexpectedException(e); }
3922      _currentProjFile = pf;
3923    }
3924  }
3925
3926  /** Pops up the _saveChooser dialog, asks the user for a new project file name, and sets the project file to the
3927   * specified file. Nothing is written in the file system; this action is performed by a subsequent _saveAll().
3928   * @return false if the user canceled the action */

3929  private boolean _saveProjectAs() {
3930    
3931// // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X!
3932
_saveChooser.removeChoosableFileFilter(_projectFilter);
3933    _saveChooser.removeChoosableFileFilter(_javaSourceFilter);
3934    _saveChooser.setFileFilter(_projectFilter);
3935// File selection = _saveChooser.getSelectedFile();
3936
// if (selection != null) { // what is this block of commands for?
3937
// _saveChooser.setSelectedFile(selection.getParentFile());
3938
// _saveChooser.setSelectedFile(selection);
3939
// _saveChooser.setSelectedFile(null);
3940
// }
3941

3942    if (_currentProjFile != null) _saveChooser.setSelectedFile(_currentProjFile);
3943    
3944    int rc = _saveChooser.showSaveDialog(this);
3945    if (rc == JFileChooser.APPROVE_OPTION) {
3946      File file = _saveChooser.getSelectedFile();
3947      if (! file.exists() || _verifyOverwrite()) {
3948        _model.setProjectFile(file);
3949        _currentProjFile = file;
3950      }
3951    }
3952    
3953    return (rc == JFileChooser.APPROVE_OPTION);
3954  }
3955  
3956  void _saveProjectHelper(File file) {
3957    try {
3958      if (file.getName().indexOf(".") == -1) file = new File (file.getAbsolutePath() + ".pjt");
3959      String JavaDoc fileName = file.getCanonicalPath();
3960      _model.saveProject(file, gatherProjectDocInfo());
3961// if (!(_model.getDocumentNavigator() instanceof JTreeSortNavigator)) {
3962
// _openProjectHelper(file);
3963
// }
3964
}
3965    catch(IOException ioe) { _showIOError(ioe); }
3966    _recentProjectManager.updateOpenFiles(file);
3967    _model.setProjectChanged(false);
3968  }
3969  
3970  public Hashtable JavaDoc<OpenDefinitionsDocument,DocumentInfoGetter> gatherProjectDocInfo() {
3971    Hashtable JavaDoc<OpenDefinitionsDocument,DocumentInfoGetter> map =
3972      new Hashtable JavaDoc<OpenDefinitionsDocument,DocumentInfoGetter>();
3973    List JavaDoc<OpenDefinitionsDocument> docs = _model.getProjectDocuments();
3974    for(OpenDefinitionsDocument doc: docs) {
3975      map.put(doc, _makeInfoGetter(doc));
3976    }
3977    return map;
3978  }
3979  /** Gets the information to be save for a project document.
3980   * Implementation may change if the scroll/selection information is later stored in a place other than the
3981   * definitions pane. Hopefully this info will eventually be backed up in the OpenDefinitionsDocument in which
3982   * case all this code should be refactored into the model's _saveProject method
3983   */

3984  private DocumentInfoGetter _makeInfoGetter(final OpenDefinitionsDocument doc) {
3985    JScrollPane s = _defScrollPanes.get(doc);
3986    if (s == null) {
3987      s = _createDefScrollPane(doc);
3988    }
3989    final JScrollPane scroller = s;
3990    final DefinitionsPane pane = (DefinitionsPane)scroller.getViewport().getView();
3991    
3992    return new DocumentInfoGetter() {
3993      public Pair<Integer JavaDoc,Integer JavaDoc> getSelection() {
3994        Integer JavaDoc selStart = new Integer JavaDoc(pane.getSelectionStart());
3995        Integer JavaDoc selEnd = new Integer JavaDoc(pane.getSelectionEnd());
3996        if (pane.getCaretPosition() == selStart) return new Pair<Integer JavaDoc,Integer JavaDoc>(selEnd,selStart);
3997        return new Pair<Integer JavaDoc,Integer JavaDoc>(selStart,selEnd);
3998      }
3999      public Pair<Integer JavaDoc,Integer JavaDoc> getScroll() {
4000        Integer JavaDoc scrollv = new Integer JavaDoc(pane.getVerticalScroll());
4001        Integer JavaDoc scrollh = new Integer JavaDoc(pane.getHorizontalScroll());
4002        return new Pair<Integer JavaDoc,Integer JavaDoc>(scrollv,scrollh);
4003      }
4004      public File getFile() { return doc.getRawFile(); }
4005      public String JavaDoc getPackage() { return doc.getPackageName(); }
4006      public boolean isActive() { return _model.getActiveDocument() == doc; }
4007      public boolean isUntitled() { return doc.isUntitled(); }
4008    };
4009  }
4010  
4011  private void _revert() {
4012    _revert(_model.getActiveDocument());
4013  }
4014  
4015  private void _revert(OpenDefinitionsDocument doc) {
4016    try {
4017      _model.getActiveDocument().revertFile();
4018    }
4019    catch (FileMovedException fme) {
4020      _showFileMovedError(fme);
4021    }
4022    catch (IOException ioe) {
4023      _showIOError(ioe);
4024    }
4025  }
4026  
4027  /**
4028   private void _revertAll() {
4029   try {
4030   _model.revertAllFiles();
4031   }
4032   catch (FileMovedException fme) {
4033   _showFileMovedError(fme);
4034   }
4035   catch (IOException ioe) {
4036   _showIOError(ioe);
4037   }
4038   }
4039   */

4040  
4041  private void _quit() {
4042// AbstractGlobalModel._log.log("MainFrame.quit() called");
4043
if (_promptBeforeQuit) {
4044      String JavaDoc title = "Quit DrJava?";
4045      String JavaDoc message = "Are you sure you want to quit DrJava?";
4046      ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, title, message);
4047      int rc = dialog.show();
4048      if (rc != JOptionPane.YES_OPTION) return;
4049      else {
4050        // Only remember the checkbox if they say yes
4051
if (dialog.getCheckBoxValue() == true) {
4052          DrJava.getConfig().setSetting(QUIT_PROMPT, Boolean.FALSE);
4053        }
4054      }
4055    }
4056    // tried passing false here. seemed to help with bug
4057
// [ 1478796 ] DrJava Does Not Shut Down With Project Open
4058
// on HP tc1100 and Toshiba Portege tablet PCs, but did not help in all cases
4059
if (! _closeProject(true)) { return; /* if user pressed cancel, do not quit */ }
4060    
4061    _recentFileManager.saveRecentFiles();
4062    _recentProjectManager.saveRecentFiles();
4063    _storePositionInfo();
4064    
4065    // Save recent files, but only if there wasn't a problem at startUp
4066
// (Don't want to overwrite a custom config file with a simple typo.)
4067
if (! DrJava.getConfig().hadStartupException()) {
4068      try { DrJava.getConfig().saveConfiguration(); }
4069      catch (IOException ioe) { _showIOError(ioe); }
4070    }
4071    //DrJava.consoleOut().println("Quitting DrJava...");
4072
dispose(); // Free GUI elements of this frame
4073
_model.quit();
4074  }
4075  
4076  private void _forceQuit() { _model.forceQuit(); }
4077  
4078  /** Stores the current position and size info for window and panes to the config framework. */
4079  private void _storePositionInfo() {
4080    Configuration config = DrJava.getConfig();
4081    
4082    // Window bounds.
4083
if (config.getSetting(WINDOW_STORE_POSITION).booleanValue()) {
4084      Rectangle bounds = getBounds();
4085      config.setSetting(WINDOW_HEIGHT, new Integer JavaDoc(bounds.height));
4086      config.setSetting(WINDOW_WIDTH, new Integer JavaDoc(bounds.width));
4087      config.setSetting(WINDOW_X, new Integer JavaDoc(bounds.x));
4088      config.setSetting(WINDOW_Y, new Integer JavaDoc(bounds.y));
4089    }
4090    else {
4091      // Reset to defaults to restore pristine behavior.
4092
config.setSetting(WINDOW_HEIGHT, WINDOW_HEIGHT.getDefault());
4093      config.setSetting(WINDOW_WIDTH, WINDOW_WIDTH.getDefault());
4094      config.setSetting(WINDOW_X, WINDOW_X.getDefault());
4095      config.setSetting(WINDOW_Y, WINDOW_Y.getDefault());
4096    }
4097    
4098    // "Go to File" dialog position and size.
4099
if ((DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue())
4100          && (_gotoFileDialog != null) && (_gotoFileDialog.getFrameState() != null)) {
4101      config.setSetting(DIALOG_GOTOFILE_STATE, (_gotoFileDialog.getFrameState().toString()));
4102    }
4103    else {
4104      // Reset to defaults to restore pristine behavior.
4105
config.setSetting(DIALOG_GOTOFILE_STATE, DIALOG_GOTOFILE_STATE.getDefault());
4106    }
4107    
4108    // "Open Javadoc" dialog position and size.
4109
if ((DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue())
4110          && (_openJavadocDialog != null) && (_openJavadocDialog.getFrameState() != null)) {
4111      config.setSetting(DIALOG_OPENJAVADOC_STATE, (_openJavadocDialog.getFrameState().toString()));
4112    }
4113    else {
4114      // Reset to defaults to restore pristine behavior.
4115
config.setSetting(DIALOG_OPENJAVADOC_STATE, DIALOG_OPENJAVADOC_STATE.getDefault());
4116    }
4117    
4118    // "Complete Word" dialog position and size.
4119
if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue())
4120          && (_completeWordDialog != null) && (_completeWordDialog.getFrameState() != null)) {
4121      config.setSetting(DIALOG_COMPLETE_WORD_STATE, (_completeWordDialog.getFrameState().toString()));
4122    }
4123    else {
4124      // Reset to defaults to restore pristine behavior.
4125
config.setSetting(DIALOG_COMPLETE_WORD_STATE, DIALOG_COMPLETE_WORD_STATE.getDefault());
4126    }
4127        
4128    // "Create Jar from Project" dialog position and size.
4129
if ((DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue())
4130          && (_jarOptionsDialog != null) && (_jarOptionsDialog.getFrameState() != null)) {
4131      config.setSetting(DIALOG_JAROPTIONS_STATE, (_jarOptionsDialog.getFrameState().toString()));
4132    }
4133    else {
4134      // Reset to defaults to restore pristine behavior.
4135
config.setSetting(DIALOG_JAROPTIONS_STATE, DIALOG_JAROPTIONS_STATE.getDefault());
4136    }
4137    
4138    // Panel heights.
4139
if (_showDebugger) config.setSetting(DEBUG_PANEL_HEIGHT, new Integer JavaDoc(_debugPanel.getHeight()));
4140    
4141    // Doc list width.
4142
config.setSetting(DOC_LIST_WIDTH, new Integer JavaDoc(_docSplitPane.getDividerLocation()));
4143  }
4144  
4145  private void _cleanUpForCompile() { if (isDebuggerReady()) _model.getDebugger().shutdown(); }
4146  
4147  private void _compile() {
4148    _cleanUpForCompile();
4149    hourglassOn();
4150    try {
4151      final OpenDefinitionsDocument doc = _model.getActiveDocument();
4152// new Thread("Compile Document") {
4153
// public void run() {
4154
try { _model.getCompilerModel().compile(doc); }
4155          catch (FileMovedException fme) { _showFileMovedError(fme); }
4156          catch (IOException ioe) { _showIOError(ioe); }
4157// }
4158
// }.start();
4159
}
4160    finally { hourglassOff();}
4161// update(getGraphics());
4162
}
4163  
4164  private void _compileFolder() {
4165    _cleanUpForCompile();
4166    hourglassOn();
4167    try {
4168      OpenDefinitionsDocument d;
4169      Enumeration JavaDoc<OpenDefinitionsDocument> e = _model.getDocumentNavigator().getDocuments();
4170      final LinkedList JavaDoc<OpenDefinitionsDocument> l = new LinkedList JavaDoc<OpenDefinitionsDocument>();
4171      if (_model.getDocumentNavigator().isGroupSelected()) {
4172        while (e.hasMoreElements()) {
4173          d = e.nextElement();
4174          if (_model.getDocumentNavigator().isSelectedInGroup(d)) l.add(d);
4175        }
4176        
4177// new Thread("Compile Folder") {
4178
// public void run() {
4179
try { _model.getCompilerModel().compile(l); }
4180            catch (FileMovedException fme) { _showFileMovedError(fme); }
4181            catch (IOException ioe) { _showIOError(ioe); }
4182// }
4183
// }.start();
4184
}
4185    }
4186    finally { hourglassOff(); }
4187// update(getGraphics());
4188
}
4189  
4190  private void _compileProject() {
4191    _cleanUpForCompile();
4192// new Thread("Compile All") {
4193
// public void run() {
4194
hourglassOn();
4195    try { _model.getCompilerModel().compileProject(); }
4196    catch (FileMovedException fme) { _showFileMovedError(fme); }
4197    catch (IOException ioe) { _showIOError(ioe); }
4198    finally { hourglassOff();}
4199// }
4200
// }.start();
4201
// update(getGraphics());
4202
}
4203  
4204  private void _compileAll() {
4205    _cleanUpForCompile();
4206// new Thread("Compile All") {
4207
// public void run() {
4208
hourglassOn();
4209    try { _model.getCompilerModel().compileAll(); }
4210    catch (FileMovedException fme) { _showFileMovedError(fme); }
4211    catch (IOException ioe) { _showIOError(ioe); }
4212    finally { hourglassOff();}
4213// }
4214
// }.start();
4215
// update(getGraphics());
4216
}
4217  
4218  private boolean showCleanWarning() {
4219    if (DrJava.getConfig().getSetting(PROMPT_BEFORE_CLEAN).booleanValue()) {
4220      String JavaDoc buildDirTxt = "";
4221      try {
4222        buildDirTxt = _model.getBuildDirectory().getCanonicalPath();
4223      }
4224      catch (Exception JavaDoc e) {
4225        buildDirTxt = _model.getBuildDirectory().getPath();
4226      }
4227      ConfirmCheckBoxDialog dialog =
4228        new ConfirmCheckBoxDialog(MainFrame.this,
4229                                  "Clean Build Directory?",
4230                                  "Cleaning your build directory will delete all\n" +
4231                                  "class files and empty folders within that directory.\n" +
4232                                  "Are you sure you want to clean\n" +
4233                                  buildDirTxt + "?",
4234                                  "Do not show this message again");
4235      int rc = dialog.show();
4236      switch (rc) {
4237        case JOptionPane.YES_OPTION:
4238          _saveAll();
4239          // Only remember checkbox if they say yes
4240
if (dialog.getCheckBoxValue()) {
4241            DrJava.getConfig().setSetting(PROMPT_BEFORE_CLEAN, Boolean.FALSE);
4242          }
4243          return true;
4244        case JOptionPane.NO_OPTION:
4245          return false;
4246        case JOptionPane.CANCEL_OPTION:
4247          return false;
4248        case JOptionPane.CLOSED_OPTION:
4249          return false;
4250        default:
4251          throw new RuntimeException JavaDoc("Invalid rc from showConfirmDialog: " + rc);
4252      }
4253    }
4254    return true;
4255  }
4256  
4257// private void _clean() {
4258
// final SwingWorker worker = new SwingWorker() {
4259
// public Object construct() {
4260
// if (showCleanWarning()) {
4261
// try {
4262
// hourglassOn();
4263
// _model.cleanBuildDirectory();
4264
// }
4265
// catch (FileMovedException fme) { _showFileMovedError(fme); }
4266
// catch (IOException ioe) { _showIOError(ioe); }
4267
// finally { hourglassOff(); }
4268
// }
4269
// return null;
4270
// }
4271
// };
4272
// worker.start();
4273
// }
4274

4275  private void _clean() {
4276   _model.cleanBuildDirectory(); // The model performs this as an AsyncTask
4277
}
4278
4279  /** List with entries for the complete dialog. */
4280  ArrayList JavaDoc<GoToFileListEntry> _completeClassList = new ArrayList JavaDoc<GoToFileListEntry>();
4281  
4282  /** Scan the build directory for class files and update the auto-completion list. */
4283  private void _scanClassFiles() {
4284    Thread JavaDoc t = new Thread JavaDoc(new Runnable JavaDoc() {
4285      public void run() {
4286        List JavaDoc<File> classFiles = _model.getClassFiles();
4287        
4288        HashSet JavaDoc<GoToFileListEntry> hs = new HashSet JavaDoc<GoToFileListEntry>(classFiles.size());
4289        DummyOpenDefDoc dummyDoc = new DummyOpenDefDoc();
4290        for(File f: classFiles) {
4291          String JavaDoc s = f.toString();
4292          if (s.lastIndexOf(java.io.File.separatorChar)>=0) {
4293            s = s.substring(s.lastIndexOf(java.io.File.separatorChar)+1);
4294          }
4295          s = s.substring(0, s.lastIndexOf(".class"));
4296          s = s.replace('$', '.');
4297          int pos = 0;
4298          boolean ok = true;
4299          while((pos=s.indexOf('.', pos)) >= 0) {
4300            if ((s.length()<=pos+1) || (Character.isDigit(s.charAt(pos+1)))) {
4301              ok = false;
4302              break;
4303            }
4304            ++pos;
4305          }
4306          if (ok) {
4307            if (s.lastIndexOf('.') >= 0) {
4308              s = s.substring(s.lastIndexOf('.') + 1);
4309            }
4310            GoToFileListEntry entry = new GoToFileListEntry(dummyDoc, s);
4311            hs.add(entry);
4312          }
4313        }
4314        _completeClassList = new ArrayList JavaDoc<GoToFileListEntry>(hs);
4315      }
4316    });
4317    t.setPriority(Thread.MIN_PRIORITY);
4318    t.start();
4319  }
4320  
4321  private void _runProject() {
4322    if (_model.isProjectActive()) {
4323      try {
4324        final File f = _model.getMainClass();
4325        if (f != null) {
4326          OpenDefinitionsDocument doc = _model.getDocumentForFile(f);
4327          doc.runMain();
4328        }
4329      }
4330      catch (ClassNameNotFoundException e) {
4331        // Display a warning message if a class name can't be found.
4332
String JavaDoc msg =
4333          "DrJava could not find the top level class name in the\n" +
4334          "current document, so it could not run the class. Please\n" +
4335          "make sure that the class is properly defined first.";
4336        
4337        JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE);
4338      }
4339      catch (FileMovedException fme) { _showFileMovedError(fme); }
4340      catch (IOException ioe) { _showIOError(ioe); }
4341    }
4342    else _runMain();
4343  }
4344  
4345  /** Internal helper method to run the main method of the current document in the interactions pane. */
4346  private void _runMain() {
4347    
4348    try { _model.getActiveDocument().runMain(); }
4349    
4350    catch (ClassNameNotFoundException e) {
4351      // Display a warning message if a class name can't be found.
4352
String JavaDoc msg =
4353        "DrJava could not find the top level class name in the\n" +
4354        "current document, so it could not run the class. Please\n" +
4355        "make sure that the class is properly defined first.";
4356      
4357      JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE);
4358    }
4359    catch (FileMovedException fme) { _showFileMovedError(fme); }
4360    catch (IOException ioe) { _showIOError(ioe); }
4361  }
4362  
4363  private void _junit() {
4364    hourglassOn(); // turned off in JUnitStarted/NonTestCase
4365
new Thread JavaDoc("Run JUnit on Current Document") {
4366      public void run() {
4367        _disableJUnitActions();
4368// hourglassOn(); // moved into the prelude before this thread start
4369
try {
4370          _model.getJUnitModel().junit(_model.getActiveDocument());
4371// _model.getActiveDocument().startJUnit(); // Equivalent to preceding
4372
}
4373
4374        catch (FileMovedException fme) { _showFileMovedError(fme); }
4375        catch (IOException ioe) { _showIOError(ioe); }
4376        catch (ClassNotFoundException JavaDoc cnfe) { _showClassNotFoundError(cnfe); }
4377        catch (NoClassDefFoundError JavaDoc ncde) { _showNoClassDefError(ncde); }
4378        catch (ExitingNotAllowedException enae) {
4379          JOptionPane.showMessageDialog(MainFrame.this,
4380                                        "An exception occurred while running JUnit, which could\n" +
4381                                        "not be caught by DrJava. Details about the exception should\n" +
4382                                        "have been printed to your console.\n\n",
4383                                        "Error Running JUnit",
4384                                        JOptionPane.ERROR_MESSAGE);
4385        }
4386      }
4387    }.start();
4388  }
4389  
4390  private void _junitFolder() {
4391    hourglassOn(); // turned off when JUnitStarted event is fired
4392
new Thread JavaDoc("Run JUnit on specified folder") {
4393      public void run() {
4394        INavigatorItem n;
4395        _disableJUnitActions();
4396// hourglassOn(); // turned off when JUnitStarted event is fired
4397
if (_model.getDocumentNavigator().isGroupSelected()) {
4398          Enumeration JavaDoc<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments();
4399          final LinkedList JavaDoc<OpenDefinitionsDocument> l = new LinkedList JavaDoc<OpenDefinitionsDocument>();
4400          while (docs.hasMoreElements()) {
4401            OpenDefinitionsDocument doc = docs.nextElement();
4402            if (_model.getDocumentNavigator().isSelectedInGroup(doc))
4403              l.add(doc);
4404          }
4405          try { _model.getJUnitModel().junitDocs(l); }
4406          catch(UnexpectedException e) { _junitInterrupted(e); }
4407        }
4408      }
4409    }.start();
4410  }
4411  
4412  /** Tests the documents in the project source tree. Assumes that DrJava is in project mode. */
4413  private void _junitProject() {
4414    hourglassOn(); // turned off in JUnitStarted/NonTestCase event
4415
new Thread JavaDoc("Running Junit Tests") {
4416      public void run() {
4417        _disableJUnitActions();
4418// hourglassOn(); // turned off in JUnitStarted/NonTestCase event
4419
try { _model.getJUnitModel().junitProject(); }
4420        catch(UnexpectedException e) { _junitInterrupted(e); }
4421      }
4422    }.start();
4423  }
4424  
4425  /** Tests all open documents. */
4426  private void _junitAll() {
4427    hourglassOn(); // turned off in JUnitStarted/NonTestCase event
4428
new Thread JavaDoc("Running Junit Tests") {
4429      public void run() {
4430        _disableJUnitActions();
4431// hourglassOn(); // turned off in JUnitStarted/NonTestCase event
4432
try { _model.getJUnitModel().junitAll(); }
4433        catch(UnexpectedException e) { _junitInterrupted(e); }
4434      }
4435    }.start();
4436  }
4437  
4438  /* These are used to save the state of the enabled property of the actions dissabled during junit testing. */
4439  private volatile DecoratedAction _junit_compileProjectDecoratedAction;
4440  private volatile DecoratedAction _junit_compileAllDecoratedAction;
4441  private volatile DecoratedAction _junit_compileFolderDecoratedAction;
4442  private volatile DecoratedAction _junit_junitFolderDecoratedAction;
4443  private volatile DecoratedAction _junit_junitAllDecoratedAction;
4444  private volatile DecoratedAction _junit_junitDecoratedAction;
4445  private volatile DecoratedAction _junit_junitOpenProjectFilesDecoratedAction;
4446  private volatile DecoratedAction _junit_cleanDecoratedAction;
4447  private volatile DecoratedAction _junit_projectPropertiesDecoratedAction;
4448  private volatile DecoratedAction _junit_runProjectDecoratedAction;
4449  private volatile DecoratedAction _junit_runDecoratedAction;
4450  
4451  /** An AbstractAction that prevents changes to the decoree's enabled flag. */
4452  private class DecoratedAction extends AbstractAction {
4453    /** The AbstractAction that is being decorated. */
4454    AbstractAction _decoree;
4455    /** The "shallow" enabled flag. */
4456    boolean _shallowEnabled;
4457    /** Create an action decorating the specified action, then sets the decoree's enabled flag to b. */
4458    public DecoratedAction(AbstractAction a, boolean b) {
4459      super((String JavaDoc)a.getValue("Name"));
4460      _decoree = a;
4461      _shallowEnabled = _decoree.isEnabled();
4462      _decoree.setEnabled(b);
4463    }
4464    public void actionPerformed(ActionEvent ae) { _decoree.actionPerformed(ae); }
4465    /** Do not change the decoree's enabled flag, but cache this value in the shallow enabled flag. */
4466    public void setEnabled(boolean b) { _shallowEnabled = b; }
4467    /** Write the shallow enabled flag to the decoree, then return the decoree */
4468    public AbstractAction getUpdatedDecoree() { _decoree.setEnabled(_shallowEnabled); return _decoree; }
4469  }
4470  
4471  /** Sets the enabled status to false of all actions that could conflict with JUnit while its is running a test.
4472   * This method saves aside the previous enable state of each action so that when the test is finished, any action
4473   * dissabled before the test will remain dissabled afterward.
4474   */

4475  private void _disableJUnitActions() {
4476    // _compileProjectActionEnabled = _compileProjectAction.isEnabled();
4477
// _compileAllActionEnabled = _compileAllAction.isEnabled();
4478
//_compileFolderActionEnabled = _compileFolderAction.isEnabled();
4479
//_junitFolderActionEnabled = _junitFolderAction.isEnabled();
4480
//_junitAllActionEnabled = _junitAllAction.isEnabled();
4481
//_junitActionEnabled = _junitAction.isEnabled();
4482
//_junitProjectActionEnabled = _junitProjectAction.isEnabled();
4483
//_cleanActionEnabled = _cleanAction.isEnabled();
4484
//_projectPropertiesActionEnabled = _projectPropertiesAction.isEnabled();
4485
//_runProjectActionEnabled = _runProjectAction.isEnabled();
4486

4487    // _compileProjectAction.setEnabled(false);
4488
//_compileAllAction.setEnabled(false);
4489
//_compileFolderAction.setEnabled(false);
4490
//_junitFolderAction.setEnabled(false);
4491
//_junitAllAction.setEnabled(false);
4492
//_junitAction.setEnabled(false);
4493
//_junitProjectAction.setEnabled(false);
4494
//_cleanAction.setEnabled(false);
4495
//_projectPropertiesAction.setEnabled(false);
4496
//_runProjectAction.setEnabled(false);
4497

4498    _compileProjectAction = _junit_compileProjectDecoratedAction = new DecoratedAction(_compileProjectAction, false);
4499    _compileAllAction = _junit_compileAllDecoratedAction = new DecoratedAction(_compileAllAction, false);
4500    _compileFolderAction = _junit_compileFolderDecoratedAction = new DecoratedAction(_compileFolderAction, false);
4501    _junitFolderAction = _junit_junitFolderDecoratedAction = new DecoratedAction(_junitFolderAction, false);
4502    _junitAllAction = _junit_junitAllDecoratedAction = new DecoratedAction(_junitAllAction, false);
4503    _junitAction = _junit_junitDecoratedAction = new DecoratedAction(_junitAction, false);
4504    _junitProjectAction = _junit_junitOpenProjectFilesDecoratedAction = new DecoratedAction(_junitProjectAction, false);
4505    _cleanAction = _junit_cleanDecoratedAction = new DecoratedAction(_cleanAction, false);
4506    _projectPropertiesAction = _junit_projectPropertiesDecoratedAction = new DecoratedAction(_projectPropertiesAction, false);
4507    _runProjectAction = _junit_runProjectDecoratedAction = new DecoratedAction(_runProjectAction, false);
4508    _runAction = _junit_runDecoratedAction = new DecoratedAction(_runAction, false);
4509  }
4510  private void _restoreJUnitActionsEnabled() {
4511// _compileProjectAction.setEnabled(_compileProjectActionEnabled);
4512
// _compileAllAction.setEnabled(_compileAllActionEnabled);
4513
// //_compileOpenProjectAction.setEnabled(_compileOpenProjectActionEnabled);
4514
// _compileFolderAction.setEnabled(_compileFolderActionEnabled);
4515
// _junitFolderAction.setEnabled(_junitFolderActionEnabled);
4516
// _junitAllAction.setEnabled(_junitAllActionEnabled);
4517
// _junitAction.setEnabled(_junitActionEnabled);
4518
// _junitProjectAction.setEnabled(_junitProjectActionEnabled);
4519
// //_junitProjectAction.setEnabled(_junitProjectActionEnabled);
4520
// _cleanAction.setEnabled(_cleanActionEnabled);
4521
// _projectPropertiesAction.setEnabled(_projectPropertiesActionEnabled);
4522
// _runProjectAction.setEnabled(_runProjectActionEnabled);
4523

4524    _compileProjectAction = _junit_compileProjectDecoratedAction.getUpdatedDecoree();
4525    _compileAllAction = _junit_compileAllDecoratedAction.getUpdatedDecoree();
4526    _compileFolderAction = _junit_compileFolderDecoratedAction.getUpdatedDecoree();
4527    _junitFolderAction = _junit_junitFolderDecoratedAction.getUpdatedDecoree();
4528    _junitAllAction = _junit_junitAllDecoratedAction.getUpdatedDecoree();
4529    _junitAction = _junit_junitDecoratedAction.getUpdatedDecoree();
4530    _junitProjectAction = _junit_junitOpenProjectFilesDecoratedAction.getUpdatedDecoree();
4531    _cleanAction = _junit_cleanDecoratedAction.getUpdatedDecoree();
4532    _projectPropertiesAction = _junit_projectPropertiesDecoratedAction.getUpdatedDecoree();
4533    _runProjectAction = _junit_runProjectDecoratedAction.getUpdatedDecoree();
4534    _runAction = _junit_runDecoratedAction.getUpdatedDecoree();
4535  }
4536  
4537// /**
4538
// * Suspends the current execution of the debugger
4539
// */
4540
// private void debuggerSuspend() throws DebugException {
4541
// if (isDebuggerReady())
4542
// _model.getDebugger().suspend();
4543
// }
4544

4545  /** Resumes the debugger's current execution. */
4546  void debuggerResume() throws DebugException {
4547    if (isDebuggerReady()) {
4548      _model.getDebugger().resume();
4549      _removeThreadLocationHighlight();
4550    }
4551  }
4552  
4553  /** Steps in the debugger. */
4554  void debuggerStep(int flag) {
4555    if (isDebuggerReady()) {
4556      try { _model.getDebugger().step(flag); }
4557      catch (IllegalStateException JavaDoc ise) {
4558        // This may happen if the user if stepping very frequently,
4559
// and is even more likely if they are using both hotkeys
4560
// and UI buttons. Ignore it in this case.
4561
// Hopefully, there are no other situations where
4562
// the user can be trying to step while there are no
4563
// suspended threads.
4564
}
4565      catch (DebugException de) {
4566        _showError(de, "Debugger Error",
4567                   "Could not create a step request.");
4568      }
4569    }
4570  }
4571  
4572  /** Toggles a breakpoint on the current line. */
4573  void debuggerToggleBreakpoint() {
4574    addToBrowserHistory();
4575    OpenDefinitionsDocument doc = _model.getActiveDocument();
4576      
4577      boolean isUntitled = doc.isUntitled();
4578      if (isUntitled) {
4579        JOptionPane.showMessageDialog(this,
4580                                      "You must save and compile this document before you can\n" +
4581                                      "set a breakpoint in it.",
4582                                      "Must Save and Compile",
4583                                      JOptionPane.ERROR_MESSAGE);
4584        return;
4585      }
4586      
4587      boolean isModified = doc.isModifiedSinceSave();
4588      if (isDebuggerReady() && isModified && !_currentDefPane.hasWarnedAboutModified() &&
4589          DrJava.getConfig().getSetting(WARN_BREAKPOINT_OUT_OF_SYNC).booleanValue()) {
4590        String JavaDoc message =
4591          "This document has been modified and may be out of sync\n" +
4592          "with the debugger. It is recommended that you first\n" +
4593          "save and recompile before continuing to use the debugger,\n" +
4594          "to avoid any unexpected errors. Would you still like to\n" +
4595          "toggle the breakpoint on the specified line?";
4596        String JavaDoc title = "Toggle breakpoint on modified file?";
4597        
4598        ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(this, title, message);
4599        int rc = dialog.show();
4600        switch (rc) {
4601          case JOptionPane.YES_OPTION:
4602            _currentDefPane.hasWarnedAboutModified(true);
4603            if (dialog.getCheckBoxValue()) {
4604              DrJava.getConfig().setSetting(WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE);
4605            }
4606            break;
4607            
4608          case JOptionPane.NO_OPTION:
4609            if (dialog.getCheckBoxValue()) {
4610                DrJava.getConfig().setSetting(WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE);
4611            }
4612            return;
4613            
4614          case JOptionPane.CANCEL_OPTION:
4615          case JOptionPane.CLOSED_OPTION:
4616            // do nothing
4617
return;
4618            
4619          default:
4620            throw new RuntimeException JavaDoc("Invalid rc from showConfirmDialog: " + rc);
4621        }
4622        
4623      }
4624      
4625      try {
4626        Debugger debugger = _model.getDebugger();
4627        debugger.toggleBreakpoint(doc, _currentDefPane.getCaretPosition(), _currentDefPane.getCurrentLine(), true);
4628      }
4629      catch (DebugException de) {
4630        _showError(de, "Debugger Error", "Could not set a breakpoint at the current line.");
4631      }
4632    }
4633  
4634  
4635// private void _getText(String name) { _field = name; }
4636

4637// /** Adds a watch to a given variable or field. */
4638
// void debuggerAddWatch() {
4639
// if (isDebuggerReady()) {
4640
// //final String field;
4641
// OpenDefinitionsDocument doc = _model.getActiveDocument();
4642
// final JDialog getFieldDialog = new JDialog(this, "Choose Field to be Watched", true);
4643
// //getFieldDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
4644
// final JTextField fieldName = new JTextField();
4645
// getFieldDialog.setSize(new Dimension(150, 60));
4646
// getFieldDialog.getContentPane().add(fieldName);
4647
// fieldName.addActionListener(new ActionListener() {
4648
// public void actionPerformed(ActionEvent ae) {
4649
// _getText(fieldName.getText());
4650
// getFieldDialog.dispose();
4651
// }
4652
// });
4653
// getFieldDialog.setLocation(300,300);
4654
// getFieldDialog.show();
4655
// Debugger debugger = _model.getDebugger();
4656
// debugger.addWatch(_field);
4657
// }
4658
// }
4659

4660// /** Displays all breakpoints currently set in the debugger. */
4661
// void _printBreakpoints() { _model.getDebugger().printBreakpoints(); }
4662

4663  /** Clears all breakpoints from the debugger. */
4664  void debuggerClearAllBreakpoints() {
4665    _model.getBreakpointManager().clearRegions();
4666  }
4667  
4668  void _showFileMovedError(FileMovedException fme) {
4669    try {
4670      File f = fme.getFile();
4671      OpenDefinitionsDocument doc = _model.getDocumentForFile(f);
4672      if (doc != null && _saveSelector.shouldSaveAfterFileMoved(doc, f)) _saveAs();
4673    }
4674    catch (IOException ioe) { /* Couldn't find the document, so ignore the FME */ }
4675  }
4676  
4677  void _showProjectFileParseError(MalformedProjectFileException mpfe) {
4678    _showError(mpfe, "Invalid Project File", "DrJava could not read the given project file.");
4679  }
4680  
4681  void _showFileNotFoundError(FileNotFoundException fnf) {
4682    _showError(fnf, "File Not Found", "The specified file was not found on disk.");
4683  }
4684  
4685  void _showIOError(IOException ioe) {
4686    _showError(ioe, "Input/output error", "An I/O exception occurred during the last operation.");
4687  }
4688  
4689  void _showClassNotFoundError(ClassNotFoundException JavaDoc cnfe) {
4690    _showError(cnfe, "Class Not Found",
4691               "A ClassNotFound exception occurred during the last operation.\n" +
4692               "Please check that your classpath includes all relevant directories.\n\n");
4693  }
4694  
4695  void _showNoClassDefError(NoClassDefFoundError JavaDoc ncde) {
4696    _showError(ncde, "No Class Def",
4697               "A NoClassDefFoundError occurred during the last operation.\n" +
4698               "Please check that your classpath includes all relevant paths.\n\n");
4699  }
4700  
4701  void _showDebugError(DebugException de) {
4702    _showError(de, "Debug Error", "A Debugger error occurred in the last operation.\n\n");
4703  }
4704  
4705  void _showJUnitInterrupted(UnexpectedException e) {
4706    _showWarning(e.getCause(), "JUnit Testing Interrupted",
4707                 "The slave JVM has thrown a RemoteException probably indicating that it has been reset.\n\n");
4708  }
4709  
4710  private void _showError(Throwable JavaDoc e, String JavaDoc title, String JavaDoc message) {
4711    JOptionPane.showMessageDialog(this, message + "\n" + e, title, JOptionPane.ERROR_MESSAGE);
4712  }
4713  
4714  private void _showWarning(Throwable JavaDoc e, String JavaDoc title, String JavaDoc message) {
4715    JOptionPane.showMessageDialog(this, message + "\n" + e, title, JOptionPane.WARNING_MESSAGE);
4716  }
4717  
4718  /** Check if any errors occurred while parsing the config file, and display a message if necessary. */
4719  private void _showConfigException() {
4720    if (DrJava.getConfig().hadStartupException()) {
4721      Exception JavaDoc e = DrJava.getConfig().getStartupException();
4722      _showError(e, "Error in Config File",
4723                 "Could not read the '.drjava' configuration file\n" +
4724                 "in your home directory. Starting with default\n" +
4725                 "values instead.\n\n" + "The problem was:\n");
4726    }
4727  }
4728  
4729  /** Returns the File selected by the JFileChooser.
4730   * @param fc File chooser presented to the user
4731   * @param choice return value from fc
4732   * @return Selected File
4733   * @throws OperationCanceledException if file choice canceled
4734   * @throws RuntimeException if fc returns a bad file or choice
4735   */

4736  private File getChosenFile(JFileChooser fc, int choice) throws OperationCanceledException {
4737    switch (choice) {
4738      case JFileChooser.CANCEL_OPTION:
4739      case JFileChooser.ERROR_OPTION:
4740        throw new OperationCanceledException();
4741      case JFileChooser.APPROVE_OPTION:
4742        File chosen = fc.getSelectedFile();
4743        if (chosen != null) {
4744          //append the appropriate language level extension if not written by user
4745
if (fc.getFileFilter() instanceof JavaSourceFilter) {
4746            if (chosen.getName().indexOf(".") == -1)
4747              return new File(chosen.getAbsolutePath() +
4748                              "." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[DrJava.getConfig().getSetting(LANGUAGE_LEVEL)]);
4749          }
4750          return chosen;
4751        }
4752        else
4753          throw new RuntimeException JavaDoc("Filechooser returned null file");
4754      default: // impossible since rc must be one of these
4755
throw new RuntimeException JavaDoc("Filechooser returned bad rc " + choice);
4756    }
4757  }
4758  /**
4759   * Returns the Files selected by the JFileChooser.
4760   * @param fc File chooser presented to the user
4761   * @param choice return value from fc
4762   * @return Selected Files - this array will be size 1 for single-selection dialogs.
4763   * @throws OperationCanceledException if file choice canceled
4764   * @throws RuntimeException if fc returns a bad file or choice
4765   */

4766  private File[] getChosenFiles(JFileChooser fc, int choice) throws OperationCanceledException {
4767    switch (choice) {
4768      case JFileChooser.CANCEL_OPTION:case JFileChooser.ERROR_OPTION:
4769        throw new OperationCanceledException();
4770      case JFileChooser.APPROVE_OPTION:
4771        File[] chosen = fc.getSelectedFiles();
4772        if (chosen == null)
4773          throw new UnexpectedException(new OperationCanceledException(), "filechooser returned null file");
4774        
4775        // Following code reviewed for bug 70902-- JVF
4776
// If this is a single-selection dialog, getSelectedFiles() will always
4777
// return a zero-size array -- handle it differently.
4778
if (chosen.length == 0) {
4779          if (!fc.isMultiSelectionEnabled()) {
4780            return new File[] { fc.getSelectedFile() };
4781          }
4782          else {
4783            /* This is the workaround for bug 70902: sometimes Mac OS X will return
4784             * APPROVE_OPTION when the user clicks the close (x) control button
4785             * on the dialog window, even though nothing is selected.
4786             */

4787            throw new OperationCanceledException();
4788          }
4789        }
4790        else {
4791          return chosen;
4792        }
4793        
4794      default: // impossible since rc must be one of these
4795
throw new UnexpectedException(new OperationCanceledException(), "filechooser returned bad rc " + choice);
4796    }
4797  }
4798  
4799  private void _selectAll() { _currentDefPane.selectAll(); }
4800  
4801  /** Jump to the specified line and return the offset.
4802   * @return offset */

4803  private int _jumpToLine(int lineNum) {
4804    int pos = _model.getActiveDocument().gotoLine(lineNum);
4805    _currentDefPane.setCaretPosition(pos);
4806    _currentDefPane.centerViewOnOffset(pos);
4807    return pos;
4808  }
4809  
4810  /** Ask the user what line they'd like to jump to, then go there. */
4811  private int _gotoLine() {
4812    final String JavaDoc msg = "What line would you like to go to?";
4813    final String JavaDoc title = "Go to Line";
4814    String JavaDoc lineStr = JOptionPane.showInputDialog(this, msg, title, JOptionPane.QUESTION_MESSAGE);
4815    try {
4816      if (lineStr != null) {
4817        int lineNum = Integer.parseInt(lineStr);
4818        return _jumpToLine(lineNum); }
4819    }
4820    catch (NumberFormatException JavaDoc nfe) {
4821      // invalid input for line number
4822
Toolkit.getDefaultToolkit().beep();
4823      // Do nothing.
4824
}
4825    //catch (BadLocationException ble) { }
4826
return -1;
4827  }
4828  
4829  /** Removes the ErrorCaretListener corresponding to the given document, after that document has been closed.
4830   * (Allows pane and listener to be garbage collected...)
4831   */

4832  private void _removeErrorListener(OpenDefinitionsDocument doc) {
4833    JScrollPane scroll = _defScrollPanes.get(doc);
4834    if (scroll != null) {
4835      DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView();
4836      pane.removeCaretListener(pane.getErrorCaretListener());
4837    }
4838  }
4839  
4840  /** Initializes all action objects. Adds icons and descriptions to several of the actions. Note: this
4841   * initialization will later be done in the constructor of each action, which will subclass AbstractAction.
4842   */

4843  private void _setUpActions() {
4844    _setUpAction(_newAction, "New", "Create a new document");
4845    _setUpAction(_newJUnitTestAction, "New", "Create a new JUnit test case class");
4846    _setUpAction(_newProjectAction, "New", "Make a new project");
4847    _setUpAction(_openAction, "Open", "Open an existing file");
4848    _setUpAction(_openFolderAction, "Open Folder", "OpenAll", "Open all files within a directory");
4849    _setUpAction(_openFileOrProjectAction, "Open", "Open an existing file or project");
4850    _setUpAction(_openProjectAction, "Open", "Open an existing project");
4851    _setUpAction(_saveAction, "Save", "Save the current document");
4852    _setUpAction(_saveAsAction, "Save As", "SaveAs", "Save the current document with a new name");
4853    _setUpAction(_renameAction, "Rename", "Rename", "Rename the current document");
4854    _setUpAction(_saveProjectAction, "Save", "Save", "Save the current project");
4855    _saveProjectAction.setEnabled(false);
4856    _setUpAction(_saveProjectAsAction, "Save As", "SaveAs", "Save current project to new project file");
4857    _saveProjectAsAction.setEnabled(false);
4858    _setUpAction(_revertAction, "Revert", "Revert the current document to the saved version");
4859    // No longer used
4860
// _setUpAction(_revertAllAction, "Revert All", "RevertAll",
4861
// "Revert all open documents to the saved versions");
4862

4863    _setUpAction(_closeAction, "Close", "Close the current document");
4864    _setUpAction(_closeAllAction, "Close All", "CloseAll", "Close all documents");
4865    _setUpAction(_closeProjectAction, "Close", "CloseAll", "Close the current project");
4866    _closeProjectAction.setEnabled(false);
4867    
4868    _setUpAction(_projectPropertiesAction, "Project Properties", "Preferences", "Edit Project Properties");
4869    _projectPropertiesAction.setEnabled(false);
4870    
4871// _setUpAction(_junitProjectAction, "Test", "Test", "Test the current project");
4872
// _junitProjectAction.setEnabled(false);
4873
_setUpAction(_junitProjectAction, "Test Project", "Test the documents in the project source tree");
4874    _junitProjectAction.setEnabled(false);
4875    
4876// _setUpAction(_compileOpenProjectAction, "Compile", "Compile", "Compile the open project documents");
4877
_setUpAction(_compileProjectAction, "Compile Project", "Compile the documents in the project source tree");
4878// _compileOpenProjectAction.setEnabled(false);
4879
_compileProjectAction.setEnabled(false);
4880    
4881    _setUpAction(_runProjectAction, "Run Project", "Run the project's main method");
4882    _runProjectAction.setEnabled(false);
4883    
4884    _setUpAction(_jarProjectAction, "Jar", "Create a jar archive from this project");
4885    _jarProjectAction.setEnabled(false);
4886    
4887    _setUpAction(_saveAllAction, "Save All", "SaveAll", "Save all open documents");
4888    
4889    _setUpAction(_cleanAction, "Clean", "Clean Build directory");
4890    _cleanAction.setEnabled(false);
4891    _setUpAction(_compileAction, "Compile Current Document", "Compile the current document");
4892    _setUpAction(_compileAllAction, "Compile", "Compile all open documents");
4893    _setUpAction(_printDefDocAction, "Print", "Print the current main document");
4894    _setUpAction(_printConsoleAction, "Print", "Print the Console pane");
4895    _setUpAction(_printInteractionsAction, "Print", "Print the Interactions pane");
4896    _setUpAction(_pageSetupAction, "Page Setup", "PageSetup", "Change the printer settings");
4897    _setUpAction(_printDefDocPreviewAction, "Print Preview", "PrintPreview", "Preview how the document will be printed");
4898    _setUpAction(_printConsolePreviewAction, "Print Preview", "PrintPreview",
4899                 "Preview how the console document will be printed");
4900    _setUpAction(_printInteractionsPreviewAction, "Print Preview", "PrintPreview",
4901                 "Preview how the interactions document will be printed");
4902    
4903    _setUpAction(_quitAction, "Quit", "Quit", "Quit DrJava");
4904    
4905    _setUpAction(_undoAction, "Undo", "Undo previous command");
4906    _setUpAction(_redoAction, "Redo", "Redo last undo");
4907    _undoAction.putValue(Action.NAME, "Undo Previous Command");
4908    _redoAction.putValue(Action.NAME, "Redo Last Undo");
4909    
4910    _setUpAction(cutAction, "Cut", "Cut selected text to the clipboard");
4911    _setUpAction(copyAction, "Copy", "Copy selected text to the clipboard");
4912    _setUpAction(pasteAction, "Paste", "Paste text from the clipboard");
4913    _setUpAction(_pasteHistoryAction, "Paste from History", "Paste text from the clipboard history");
4914    _setUpAction(_selectAllAction, "Select All", "Select all text");
4915    
4916    cutAction.putValue(Action.NAME, "Cut");
4917    copyAction.putValue(Action.NAME, "Copy");
4918    pasteAction.putValue(Action.NAME, "Paste");
4919    _pasteHistoryAction.putValue(Action.NAME, "Paste from History");
4920    
4921    _setUpAction(_indentLinesAction, "Indent Lines", "Indent all selected lines");
4922    _setUpAction(_commentLinesAction, "Comment Lines", "Comment out all selected lines");
4923    _setUpAction(_uncommentLinesAction, "Uncomment Lines", "Uncomment all selected lines");
4924    
4925    _setUpAction(completeWordUnderCursorAction, "Auto-Complete Word Under Cursor",
4926                 "Auto-complete the word the cursor is currently located on");
4927    _setUpAction(_bookmarksPanelAction, "Bookmarks", "Display the bookmarks panel");
4928    _setUpAction(_toggleBookmarkAction, "Toggle Bookmark", "Toggle the bookmark at the current cursor location");
4929
4930    _setUpAction(_findReplaceAction, "Find", "Find or replace text in the document");
4931    _setUpAction(_findNextAction, "Find Next", "Repeats the last find");
4932    _setUpAction(_findPrevAction, "Find Previous", "Repeats the last find in the opposite direction");
4933    _setUpAction(_gotoLineAction, "Go to line", "Go to a line number in the document");
4934    _setUpAction(_gotoFileAction, "Go to File", "Go to a file specified by its name");
4935    _setUpAction(gotoFileUnderCursorAction, "Go to File Under Cursor",
4936                 "Go to the file specified by the word the cursor is located on");
4937    
4938    _setUpAction(_switchToPrevAction, "Previous Document", "Up", "Switch to the previous document");
4939    _setUpAction(_switchToNextAction, "Next Document", "Down", "Switch to the next document");
4940    
4941    _setUpAction(_browseBackAction, "Back", "Back", "Move back in the browser history");
4942    _setUpAction(_browseForwardAction, "Forward", "Forward", "Move forward in the browser history");
4943    
4944    _setUpAction(_switchToPreviousPaneAction, "Previous Pane", "Switch focus to the previous pane");
4945    _setUpAction(_switchToNextPaneAction, "Next Pane", "Switch focus to the next pane");
4946    _setUpAction(_gotoOpeningBraceAction, "Go to Opening Brace", "Go th the opening brace of the block enclosing the cursor");
4947    _setUpAction(_gotoClosingBraceAction, "Go to Closing Brace", "Go th the closing brace of the block enclosing the cursor");
4948    
4949    _setUpAction(_editPreferencesAction, "Preferences", "Edit configurable settings in DrJava");
4950    
4951    _setUpAction(_junitAction, "Test Current", "Run JUnit over the current document");
4952    _setUpAction(_junitAllAction, "Test", "Run JUnit over all open JUnit tests");
4953    _setUpAction(_javadocAllAction, "Javadoc", "Create and save Javadoc for the packages of all open documents");
4954    _setUpAction(_javadocCurrentAction, "Preview Javadoc Current", "Preview the Javadoc for the current document");
4955    _setUpAction(_runAction, "Run", "Run the main method of the current document");
4956    
4957    _setUpAction(_openJavadocAction, "Open Java API Javadoc...", "Open the Java API Javadoc Web page for a class");
4958    _setUpAction(_openJavadocUnderCursorAction, "Open Java API Javadoc for Word Under Cursor...", "Open the Java API "+
4959                 "Javadoc Web page for the word under the cursor");
4960    
4961    _setUpAction(_executeHistoryAction, "Execute History", "Load and execute a history of interactions from a file");
4962    _setUpAction(_loadHistoryScriptAction, "Load History as Script",
4963                 "Load a history from a file as a series of interactions");
4964    _setUpAction(_saveHistoryAction, "Save History", "Save the history of interactions to a file");
4965    _setUpAction(_clearHistoryAction, "Clear History", "Clear the current history of interactions");
4966    
4967    //_setUpAction(_abortInteractionAction, "Break", "Abort the current interaction");
4968
_setUpAction(_resetInteractionsAction, "Reset", "Reset the Interactions Pane");
4969    _resetInteractionsAction.setEnabled(true);
4970    
4971    _setUpAction(_viewInteractionsClassPathAction, "View Interactions Classpath",
4972                 "Display the classpath in use by the Interactions Pane");
4973    _setUpAction(_copyInteractionToDefinitionsAction, "Lift Current Interaction",
4974                 "Copy the current interaction into the Definitions Pane");
4975    
4976    _setUpAction(_clearConsoleAction, "Clear Console", "Clear all text in the Console Pane");
4977    _setUpAction(_showDebugConsoleAction, "Show DrJava Debug Console", "<html>Show a console for debugging DrJava<br>" +
4978                 "(with \"mainFrame\", \"model\", and \"config\" variables defined)</html>");
4979    
4980    if (_model.getDebugger().isAvailable()) {
4981      _setUpAction(_toggleDebuggerAction, "Debug Mode", "Enable or disable DrJava's debugger");
4982      _setUpAction(_toggleBreakpointAction, "Toggle Breakpoint", "Set or clear a breakpoint on the current line");
4983      _setUpAction(_clearAllBreakpointsAction, "Clear Breakpoints", "Clear all breakpoints in all classes");
4984      _setUpAction(_resumeDebugAction, "Resume", "Resume the current suspended thread");
4985      _setUpAction(_stepIntoDebugAction, "Step Into", "Step into the current line or method call");
4986      _setUpAction(_stepOverDebugAction, "Step Over", "Step over the current line or method call");
4987      _setUpAction(_stepOutDebugAction, "Step Out", "Step out of the current method");
4988      _setUpAction(_breakpointsPanelAction, "Breakpoints", "Display the breakpoints panel");
4989    }
4990    
4991    _setUpAction(_helpAction, "Help", "Show documentation on how to use DrJava");
4992    _setUpAction(_quickStartAction, "Help", "View Quick Start Guide for DrJava");
4993    _setUpAction(_aboutAction, "About", "About DrJava");
4994    _setUpAction(_errorsAction, "DrJava Errors", "drjavaerror", "Show a window with internal DrJava errors");
4995    _setUpAction(_forceQuitAction, "Force Quit", "Force DrJava to quit without cleaning up");
4996  }
4997  
4998  private void _setUpAction(Action a, String JavaDoc name, String JavaDoc icon, String JavaDoc shortDesc) {
4999    a.putValue(Action.SMALL_ICON, _getIcon(icon + "16.gif"));
5000    a.putValue(Action.DEFAULT, name);
5001    a.putValue(Action.SHORT_DESCRIPTION, shortDesc);
5002  }
5003  
5004  private void _setUpAction(Action a, String JavaDoc icon, String JavaDoc shortDesc) { _setUpAction(a, icon, icon, shortDesc); }
5005  
5006  
5007  /** Returns the icon with the given name. All icons are assumed to reside in the /edu/rice/cs/drjava/ui/icons
5008   * directory.
5009   * @param name Name of icon image file
5010   * @return ImageIcon object constructed from the file
5011   */

5012  private ImageIcon _getIcon(String JavaDoc name) { return getIcon(name); }
5013  
5014  public static ImageIcon getIcon(String JavaDoc name) {
5015    URL JavaDoc url = MainFrame.class.getResource(ICON_PATH + name);
5016    if (url != null) return new ImageIcon(url);
5017    
5018    return null;
5019  }
5020  
5021  
5022  /** This allows us to intercept key events when compiling testing and turn them off when the glass pane is up. */
5023  private class MenuBar extends JMenuBar {
5024    public boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
5025      if (MainFrame.this.getAllowKeyEvents()) return super.processKeyBinding(ks, e, condition, pressed);
5026      return false;
5027    }
5028  }
5029  
5030  /** Sets up the components of the menu bar and links them to the private fields within MainFrame. This method
5031   * serves to make the code more legible on the higher calling level, i.e., the constructor.
5032   */

5033  private void _setUpMenuBar() {
5034 
5035    _menuBar.add(_fileMenu);
5036    _menuBar.add(_editMenu);
5037    _menuBar.add(_toolsMenu);
5038    _menuBar.add(_projectMenu);
5039    if (_showDebugger) _menuBar.add(_debugMenu);
5040    _menuBar.add(_languageLevelMenu);
5041    _menuBar.add(_helpMenu);
5042    setJMenuBar(_menuBar);
5043  }
5044  
5045  /** Adds an Action as a menu item to the given menu, using the specified configurable keystroke.
5046   * @param menu Menu to add item to
5047   * @param a Action for the menu item
5048   * @param opt Configurable keystroke for the menu item
5049   */

5050  private void _addMenuItem(JMenu menu, Action a, Option<KeyStroke> opt) {
5051    JMenuItem item;
5052    item = menu.add(a);
5053    _setMenuShortcut(item, a, opt);
5054  }
5055  
5056  /** Sets the given menu item to have the specified configurable keystroke.
5057   * @param item Menu item containing the action
5058   * @param a Action for the menu item
5059   * @param opt Configurable keystroke for the menu item
5060   */

5061  private void _setMenuShortcut(JMenuItem item, Action a, Option<KeyStroke> opt) {
5062    KeyStroke ks = DrJava.getConfig().getSetting(opt);
5063    // Checks that "a" is the action associated with the keystroke.
5064
// Need to check in case two actions were assigned to the same
5065
// key in the config file.
5066
// Also check that the keystroke isn't the NULL_KEYSTROKE, which
5067
// can strangely be triggered by certain keys in Windows.
5068
KeyBindingManager.Singleton.put(opt, a, item, item.getText());
5069    if ((ks != KeyStrokeOption.NULL_KEYSTROKE) &&
5070        (KeyBindingManager.Singleton.get(ks) == a)) {
5071      item.setAccelerator(ks);
5072      //KeyBindingManager.Singleton.addListener(opt, item);
5073
}
5074  }
5075  
5076  /** Creates and returns a file menu. Side effects: sets values for _saveMenuItem. */
5077  private JMenu _setUpFileMenu(int mask) {
5078    JMenu fileMenu = new JMenu("File");
5079    fileMenu.setMnemonic(KeyEvent.VK_F);
5080    // New, open
5081
_addMenuItem(fileMenu, _newAction, KEY_NEW_FILE);
5082    _addMenuItem(fileMenu, _newJUnitTestAction, KEY_NEW_TEST);
5083    _addMenuItem(fileMenu, _openAction, KEY_OPEN_FILE);
5084    _addMenuItem(fileMenu, _openFolderAction, KEY_OPEN_FOLDER);
5085    //_addMenuItem(fileMenu, _openProjectAction, KEY_OPEN_PROJECT);
5086

5087    fileMenu.addSeparator();
5088    
5089    _addMenuItem(fileMenu, _saveAction, KEY_SAVE_FILE);
5090    _saveAction.setEnabled(true);
5091    _addMenuItem(fileMenu, _saveAsAction, KEY_SAVE_FILE_AS);
5092    _addMenuItem(fileMenu, _saveAllAction, KEY_SAVE_ALL_FILES);
5093    _addMenuItem(fileMenu, _renameAction, KEY_RENAME_FILE);
5094    _renameAction.setEnabled(false);
5095// fileMenu.add(_saveProjectAsAction);
5096

5097    _addMenuItem(fileMenu, _revertAction, KEY_REVERT_FILE);
5098    _revertAction.setEnabled(false);
5099    //tmpItem = fileMenu.add(_revertAllAction);
5100

5101    // Close, Close all
5102
fileMenu.addSeparator();
5103    _addMenuItem(fileMenu, _closeAction, KEY_CLOSE_FILE);
5104    _addMenuItem(fileMenu, _closeAllAction, KEY_CLOSE_ALL_FILES);
5105    //_addMenuItem(fileMenu, _closeProjectAction, KEY_CLOSE_PROJECT);
5106

5107    // Page setup, print preview, print
5108
fileMenu.addSeparator();
5109    _addMenuItem(fileMenu, _pageSetupAction, KEY_PAGE_SETUP);
5110    _addMenuItem(fileMenu, _printDefDocPreviewAction, KEY_PRINT_PREVIEW);
5111    _addMenuItem(fileMenu, _printDefDocAction, KEY_PRINT);
5112    
5113    // Quit
5114
fileMenu.addSeparator();
5115    _addMenuItem(fileMenu, _quitAction, KEY_QUIT);
5116    
5117    return fileMenu;
5118  }
5119  
5120  /** Creates and returns a edit menu. */
5121  private JMenu _setUpEditMenu(int mask) {
5122    JMenu editMenu = new JMenu("Edit");
5123    editMenu.setMnemonic(KeyEvent.VK_E);
5124    // Undo, redo
5125
_addMenuItem(editMenu, _undoAction, KEY_UNDO);
5126    _addMenuItem(editMenu, _redoAction, KEY_REDO);
5127    
5128    // Cut, copy, paste, select all
5129
editMenu.addSeparator();
5130    _addMenuItem(editMenu, cutAction, KEY_CUT);
5131    _addMenuItem(editMenu, copyAction, KEY_COPY);
5132    _addMenuItem(editMenu, pasteAction, KEY_PASTE);
5133    _addMenuItem(editMenu, _pasteHistoryAction, KEY_PASTE_FROM_HISTORY);
5134    _addMenuItem(editMenu, _selectAllAction, KEY_SELECT_ALL);
5135    
5136    // Indent lines, comment lines
5137
editMenu.addSeparator();
5138    //_addMenuItem(editMenu, _indentLinesAction, KEY_INDENT);
5139
JMenuItem editItem = editMenu.add(_indentLinesAction);
5140    editItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
5141    _addMenuItem(editMenu, _commentLinesAction, KEY_COMMENT_LINES);
5142    _addMenuItem(editMenu, _uncommentLinesAction, KEY_UNCOMMENT_LINES);
5143    _addMenuItem(editMenu, completeWordUnderCursorAction, KEY_COMPLETE_FILE);
5144    
5145    // Find/replace, goto
5146
editMenu.addSeparator();
5147    _addMenuItem(editMenu, _findReplaceAction, KEY_FIND_REPLACE);
5148    _addMenuItem(editMenu, _findNextAction, KEY_FIND_NEXT);
5149    _addMenuItem(editMenu, _findPrevAction, KEY_FIND_PREV);
5150    _addMenuItem(editMenu, _gotoLineAction, KEY_GOTO_LINE);
5151    _addMenuItem(editMenu, _gotoFileAction, KEY_GOTO_FILE);
5152    _addMenuItem(editMenu, gotoFileUnderCursorAction, KEY_GOTO_FILE_UNDER_CURSOR);
5153    
5154    // Next, prev doc
5155
editMenu.addSeparator();
5156    _addMenuItem(editMenu, _switchToPrevAction, KEY_PREVIOUS_DOCUMENT);
5157    _addMenuItem(editMenu, _switchToNextAction, KEY_NEXT_DOCUMENT);
5158    _addMenuItem(editMenu, _browseBackAction, KEY_BROWSE_BACK);
5159    _addMenuItem(editMenu, _browseForwardAction, KEY_BROWSE_FORWARD);
5160    _addMenuItem(editMenu, _switchToPreviousPaneAction, KEY_PREVIOUS_PANE);
5161    _addMenuItem(editMenu, _switchToNextPaneAction, KEY_NEXT_PANE);
5162    _addMenuItem(editMenu, _gotoOpeningBraceAction, KEY_OPENING_BRACE);
5163    _addMenuItem(editMenu, _gotoClosingBraceAction, KEY_CLOSING_BRACE);
5164    
5165    // access to configurations GUI
5166
editMenu.addSeparator();
5167    _addMenuItem(editMenu, _editPreferencesAction, KEY_PREFERENCES);
5168    
5169    // Add the menus to the menu bar
5170
return editMenu;
5171  }
5172  
5173  /** Creates and returns a tools menu. */
5174  private JMenu _setUpToolsMenu(int mask) {
5175    JMenu toolsMenu = new JMenu("Tools");
5176    toolsMenu.setMnemonic(KeyEvent.VK_T);
5177    
5178    // Compile, Test, Javadoc
5179
_addMenuItem(toolsMenu, _compileAllAction, KEY_COMPILE_ALL);
5180    _addMenuItem(toolsMenu, _compileAction, KEY_COMPILE);
5181    _addMenuItem(toolsMenu, _junitAllAction, KEY_TEST_ALL);
5182    _addMenuItem(toolsMenu, _junitAction, KEY_TEST);
5183    _addMenuItem(toolsMenu, _javadocAllAction, KEY_JAVADOC_ALL);
5184    _addMenuItem(toolsMenu, _javadocCurrentAction, KEY_JAVADOC_CURRENT);
5185    toolsMenu.addSeparator();
5186    
5187    // Open Javadoc
5188
_addMenuItem(toolsMenu, _openJavadocAction, KEY_OPEN_JAVADOC);
5189    _addMenuItem(toolsMenu, _openJavadocUnderCursorAction, KEY_OPEN_JAVADOC_UNDER_CURSOR);
5190    toolsMenu.addSeparator();
5191    
5192    // Run
5193
_addMenuItem(toolsMenu, _runAction, KEY_RUN);
5194    toolsMenu.addSeparator();
5195    
5196    _addMenuItem(toolsMenu, _executeHistoryAction, KEY_EXECUTE_HISTORY);
5197    _addMenuItem(toolsMenu, _loadHistoryScriptAction, KEY_LOAD_HISTORY_SCRIPT);
5198    _addMenuItem(toolsMenu, _saveHistoryAction, KEY_SAVE_HISTORY);
5199    _addMenuItem(toolsMenu, _clearHistoryAction, KEY_CLEAR_HISTORY);
5200    toolsMenu.addSeparator();
5201    
5202    // Abort/reset interactions, clear console
5203
/*
5204     _abortInteractionAction.setEnabled(false);
5205     _addMenuItem(toolsMenu, _abortInteractionAction, KEY_ABORT_INTERACTION);
5206     */

5207    _addMenuItem(toolsMenu, _resetInteractionsAction, KEY_RESET_INTERACTIONS);
5208    _addMenuItem(toolsMenu, _viewInteractionsClassPathAction, KEY_VIEW_INTERACTIONS_CLASSPATH);
5209    _addMenuItem(toolsMenu, _copyInteractionToDefinitionsAction, KEY_LIFT_CURRENT_INTERACTION);
5210    _addMenuItem(toolsMenu, _printInteractionsAction, KEY_PRINT_INTERACTIONS);
5211    toolsMenu.addSeparator();
5212    
5213    _addMenuItem(toolsMenu, _clearConsoleAction, KEY_CLEAR_CONSOLE);
5214    _addMenuItem(toolsMenu, _printConsoleAction, KEY_PRINT_CONSOLE);
5215    if (DrJava.getConfig().getSetting(SHOW_DEBUG_CONSOLE).booleanValue()) {
5216      toolsMenu.add(_showDebugConsoleAction);
5217    }
5218
5219    toolsMenu.addSeparator();
5220    _addMenuItem(toolsMenu, _bookmarksPanelAction, KEY_BOOKMARKS_PANEL);
5221    _addMenuItem(toolsMenu, _toggleBookmarkAction, KEY_BOOKMARKS_TOGGLE);
5222    
5223    // Add the menus to the menu bar
5224
return toolsMenu;
5225  }
5226  
5227  /** Creates and returns a project menu. */
5228  private JMenu _setUpProjectMenu(int mask) {
5229    JMenu projectMenu = new JMenu("Project");
5230    projectMenu.setMnemonic(KeyEvent.VK_P);
5231    // New, open
5232
projectMenu.add(_newProjectAction);
5233    _addMenuItem(projectMenu, _openProjectAction, KEY_OPEN_PROJECT);
5234    
5235    //Save
5236
projectMenu.add(_saveProjectAction);
5237    //SaveAs
5238
projectMenu.add(_saveProjectAsAction);
5239    
5240    // Close
5241
_addMenuItem(projectMenu, _closeProjectAction, KEY_CLOSE_PROJECT);
5242    
5243    projectMenu.addSeparator();
5244    // run project
5245
projectMenu.add(_cleanAction);
5246// projectMenu.add(_compileOpenProjectAction);
5247
projectMenu.add(_compileProjectAction);
5248    projectMenu.add(_jarProjectAction);
5249    projectMenu.add(_runProjectAction);
5250    projectMenu.add(_junitProjectAction);
5251// projectMenu.add(_junitProjectAction);
5252

5253    projectMenu.addSeparator();
5254    // eventually add project options
5255
projectMenu.add(_projectPropertiesAction);
5256    
5257    return projectMenu;
5258  }
5259  
5260  /** Creates and returns a debug menu. */
5261  private JMenu _setUpDebugMenu(int mask) {
5262    JMenu debugMenu = new JMenu("Debugger");
5263    debugMenu.setMnemonic(KeyEvent.VK_D);
5264    // Enable debugging item
5265
_debuggerEnabledMenuItem = _newCheckBoxMenuItem(_toggleDebuggerAction);
5266    _debuggerEnabledMenuItem.setSelected(false);
5267    _setMenuShortcut(_debuggerEnabledMenuItem, _toggleDebuggerAction, KEY_DEBUG_MODE_TOGGLE);
5268    debugMenu.add(_debuggerEnabledMenuItem);
5269    debugMenu.addSeparator();
5270    
5271    _addMenuItem(debugMenu, _toggleBreakpointAction, KEY_DEBUG_BREAKPOINT_TOGGLE);
5272    //_printBreakpointsMenuItem = debugMenu.add(_printBreakpointsAction);
5273
//_clearAllBreakpointsMenuItem =
5274
_addMenuItem(debugMenu, _clearAllBreakpointsAction, KEY_DEBUG_CLEAR_ALL_BREAKPOINTS);
5275    _addMenuItem(debugMenu, _breakpointsPanelAction, KEY_DEBUG_BREAKPOINT_PANEL);
5276    debugMenu.addSeparator();
5277    
5278    //_addMenuItem(debugMenu, _suspendDebugAction, KEY_DEBUG_SUSPEND);
5279
_addMenuItem(debugMenu, _resumeDebugAction, KEY_DEBUG_RESUME);
5280    _addMenuItem(debugMenu, _stepIntoDebugAction, KEY_DEBUG_STEP_INTO);
5281    _addMenuItem(debugMenu, _stepOverDebugAction, KEY_DEBUG_STEP_OVER);
5282    _addMenuItem(debugMenu, _stepOutDebugAction, KEY_DEBUG_STEP_OUT);
5283    
5284    // Start off disabled
5285
_setDebugMenuItemsEnabled(false);
5286    
5287    // Add the menu to the menu bar
5288
return debugMenu;
5289  }
5290  
5291  /**
5292   * Called every time the debug mode checkbox is toggled. The resume and step
5293   * functions should always be disabled.
5294   */

5295  private void _setDebugMenuItemsEnabled(boolean isEnabled) {
5296    
5297    _debuggerEnabledMenuItem.setSelected(isEnabled);
5298    //_suspendDebugAction.setEnabled(false);
5299
_resumeDebugAction.setEnabled(false);
5300    _stepIntoDebugAction.setEnabled(false);
5301    _stepOverDebugAction.setEnabled(false);
5302    _stepOutDebugAction.setEnabled(false);
5303    
5304    if (_showDebugger) _debugPanel.disableButtons();
5305  }
5306  
5307  /** Enables and disables the appropriate menu items in the debug menu depending upon the state of the current thread.
5308   * @param isSuspended is true when the current thread has just been suspended
5309   * false if the current thread has just been resumed
5310   */

5311  private void _setThreadDependentDebugMenuItems(boolean isSuspended) {
5312    //_suspendDebugAction.setEnabled(!isSuspended);
5313
_resumeDebugAction.setEnabled(isSuspended);
5314    _stepIntoDebugAction.setEnabled(isSuspended);
5315    _stepOverDebugAction.setEnabled(isSuspended);
5316    _stepOutDebugAction.setEnabled(isSuspended);
5317    _debugPanel.setThreadDependentButtons(isSuspended);
5318  }
5319  
5320  /** Creates and returns the language levels menu. */
5321  private JMenu _setUpLanguageLevelMenu(int mask) {
5322    JMenu languageLevelMenu = new JMenu("Language Level");
5323    languageLevelMenu.setMnemonic(KeyEvent.VK_L);
5324    ButtonGroup group = new ButtonGroup();
5325    
5326    final Configuration config = DrJava.getConfig();
5327    int currentLanguageLevel = config.getSetting(LANGUAGE_LEVEL);
5328    JRadioButtonMenuItem rbMenuItem;
5329    rbMenuItem = new JRadioButtonMenuItem("Full Java");
5330    rbMenuItem.setToolTipText("Use full Java syntax");
5331    if (currentLanguageLevel == DrJavaRoot.FULL_JAVA) { rbMenuItem.setSelected(true); }
5332    rbMenuItem.addActionListener(new ActionListener() {
5333      public void actionPerformed(ActionEvent e) {
5334        config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.FULL_JAVA);
5335      }});
5336      group.add(rbMenuItem);
5337      languageLevelMenu.add(rbMenuItem);
5338      languageLevelMenu.addSeparator();
5339      
5340      rbMenuItem = new JRadioButtonMenuItem("Elementary");
5341      rbMenuItem.setToolTipText("Use Elementary language-level features");
5342      if (currentLanguageLevel == DrJavaRoot.ELEMENTARY_LEVEL) { rbMenuItem.setSelected(true); }
5343      rbMenuItem.addActionListener(new ActionListener() {
5344        public void actionPerformed(ActionEvent e) {
5345          config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.ELEMENTARY_LEVEL);
5346        }});
5347        group.add(rbMenuItem);
5348        languageLevelMenu.add(rbMenuItem);
5349        
5350        rbMenuItem = new JRadioButtonMenuItem("Intermediate");
5351        rbMenuItem.setToolTipText("Use Intermediate language-level features");
5352        if (currentLanguageLevel == DrJavaRoot.INTERMEDIATE_LEVEL) { rbMenuItem.setSelected(true); }
5353        rbMenuItem.addActionListener(new ActionListener() {
5354          public void actionPerformed(ActionEvent e) {
5355            config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.INTERMEDIATE_LEVEL);
5356          }});
5357          group.add(rbMenuItem);
5358          languageLevelMenu.add(rbMenuItem);
5359          
5360          rbMenuItem = new JRadioButtonMenuItem("Advanced");
5361          rbMenuItem.setToolTipText("Use Advanced language-level features");
5362          if (currentLanguageLevel == DrJavaRoot.ADVANCED_LEVEL) { rbMenuItem.setSelected(true); }
5363          rbMenuItem.addActionListener(new ActionListener() {
5364            public void actionPerformed(ActionEvent e) {
5365              config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.ADVANCED_LEVEL);
5366            }});
5367            group.add(rbMenuItem);
5368            languageLevelMenu.add(rbMenuItem);
5369            return languageLevelMenu;
5370  }
5371  
5372  /** Creates and returns a help menu. */
5373  private JMenu _setUpHelpMenu(int mask) {
5374    JMenu helpMenu = new JMenu("Help");
5375    helpMenu.setMnemonic(KeyEvent.VK_H);
5376    _addMenuItem(helpMenu, _helpAction, KEY_HELP);
5377    _addMenuItem(helpMenu, _quickStartAction, KEY_QUICKSTART);
5378    _addMenuItem(helpMenu, _aboutAction, KEY_ABOUT);
5379    _addMenuItem(helpMenu, _errorsAction, KEY_DRJAVA_ERRORS);
5380    _addMenuItem(helpMenu, _forceQuitAction, KEY_FORCE_QUIT);
5381    return helpMenu;
5382  }
5383  
5384  /** Creates a toolbar button for undo and redo, which behave differently. */
5385  JButton _createManualToolbarButton(Action a) {
5386    final JButton ret;
5387    
5388    Font buttonFont = DrJava.getConfig().getSetting(FONT_TOOLBAR);
5389    
5390    // Check whether icons should be shown
5391
boolean useIcon = DrJava.getConfig().getSetting(TOOLBAR_ICONS_ENABLED).booleanValue();
5392    boolean useText = DrJava.getConfig().getSetting(TOOLBAR_TEXT_ENABLED).booleanValue();
5393    final Icon icon = (useIcon) ? (Icon) a.getValue(Action.SMALL_ICON) : null;
5394    if (icon == null) {
5395      ret = new UnfocusableButton((String JavaDoc) a.getValue(Action.DEFAULT));
5396    }
5397    else {
5398      ret = new UnfocusableButton(icon);
5399      if (useText) ret.setText((String JavaDoc) a.getValue(Action.DEFAULT));
5400    }
5401    ret.setEnabled(false);
5402    ret.addActionListener(a);
5403    ret.setToolTipText( (String JavaDoc) a.getValue(Action.SHORT_DESCRIPTION));
5404    ret.setFont(buttonFont);
5405    Boolean JavaDoc test = a instanceof DelegatingAction;
5406    a.addPropertyChangeListener(new PropertyChangeListener() {
5407      public void propertyChange(PropertyChangeEvent evt) {
5408        if ("enabled".equals(evt.getPropertyName())) {
5409          Boolean JavaDoc val = (Boolean JavaDoc) evt.getNewValue();
5410          ret.setEnabled(val.booleanValue());
5411        }
5412      }
5413    });
5414    
5415    return ret;
5416  }
5417  
5418  /** Sets up all buttons for the toolbar except for undo and redo, which use _createManualToolbarButton. */
5419  public JButton _createToolbarButton(Action a) {
5420    boolean useText = DrJava.getConfig().getSetting(TOOLBAR_TEXT_ENABLED).booleanValue();
5421    boolean useIcons = DrJava.getConfig().getSetting(TOOLBAR_ICONS_ENABLED).booleanValue();
5422    Font buttonFont = DrJava.getConfig().getSetting(FONT_TOOLBAR);
5423    
5424    final JButton result = new UnfocusableButton(a);
5425    result.setText((String JavaDoc) a.getValue(Action.DEFAULT));
5426    result.setFont(buttonFont);
5427    if (!useIcons) result.setIcon(null);
5428    if (!useText && (result.getIcon() != null)) result.setText("");
5429    return result;
5430  }
5431  
5432  /** Removes the button b from the toolbar and creates new button in its place. */
5433  public JButton _updateToolbarButton(JButton b, Action a) {
5434    final JButton result = _createToolbarButton(a);
5435    
5436    int index = _toolBar.getComponentIndex(b);
5437    _toolBar.remove(b);
5438    _toolBar.add(result, index);
5439    
5440    _fixToolbarHeights();
5441
5442    return result;
5443  }
5444  
5445  /** Sets up the toolbar with several useful buttons. Most buttons are always enabled, but those that are not are
5446   * maintained in fields to allow enabling and disabling.
5447   */

5448  private void _setUpToolBar() {
5449 
5450    _toolBar.setFloatable(false);
5451    
5452// _toolBar.addSeparator();
5453

5454    // New, open, save, close
5455
_toolBar.add(_createToolbarButton(_newAction));
5456    _toolBar.add(_createToolbarButton(_openFileOrProjectAction));
5457    _toolBar.add(_createToolbarButton(_saveAction));
5458    _closeButton = _createToolbarButton(_closeAction);
5459    _toolBar.add(_closeButton);
5460    
5461    // Cut, copy, paste
5462
_toolBar.addSeparator();
5463    _toolBar.add(_createToolbarButton(cutAction));
5464    _toolBar.add(_createToolbarButton(copyAction));
5465    _toolBar.add(_createToolbarButton(pasteAction));
5466    
5467    // Undo, redo
5468
// Simple workaround, for now, for bug # 520742:
5469
// Undo/Redo button text in JDK 1.3
5470
// We just manually create the JButtons, and we *don't* set up
5471
// PropertyChangeListeners on the action's name.
5472
//_toolBar.addSeparator();
5473

5474    _toolBar.add(_undoButton);
5475    _toolBar.add(_redoButton);
5476    
5477    // Find
5478
_toolBar.addSeparator();
5479    _toolBar.add(_createToolbarButton(_findReplaceAction));
5480    
5481    // Compile, reset, abort
5482
_toolBar.addSeparator();
5483    _toolBar.add(_compileButton = _createToolbarButton(_compileAllAction));
5484    _toolBar.add(_createToolbarButton(_resetInteractionsAction));
5485    //_toolBar.add(_createToolbarButton(_abortInteractionAction));
5486

5487    // Run, Junit, and JavaDoc
5488
_toolBar.addSeparator();
5489    
5490    _toolBar.add(_runButton = _createToolbarButton(_runAction));
5491    _toolBar.add(_junitButton = _createToolbarButton(_junitAllAction));
5492    _toolBar.add(_createToolbarButton(_javadocAllAction));
5493
5494    // DrJava Errors
5495
_toolBar.addSeparator();
5496    final JButton errorsButton = _createToolbarButton(_errorsAction);
5497    errorsButton.setVisible(false);
5498    errorsButton.setBackground(DrJava.getConfig().getSetting(DRJAVA_ERRORS_BUTTON_COLOR));
5499    DrJavaErrorHandler.setButton(errorsButton);
5500    _toolBar.add(errorsButton);
5501    /** The OptionListener for DRJAVA_ERRORS_BUTTON_COLOR. */
5502    OptionListener<Color> errBtnColorOptionListener = new OptionListener<Color>() {
5503      public void optionChanged(OptionEvent<Color> oce) {
5504        errorsButton.setBackground(oce.value);
5505      }
5506    };
5507    DrJava.getConfig().addOptionListener(DRJAVA_ERRORS_BUTTON_COLOR, errBtnColorOptionListener);
5508    
5509    // Correct the vertical height of the buttons.
5510
_fixToolbarHeights();
5511    
5512    getContentPane().add(_toolBar, BorderLayout.NORTH);
5513// _updateToolBarVisible(); // created a visible GUI component during initialization!
5514
}
5515  
5516  /** Sets the toolbar as either visible or invisible based on the config option. */
5517  private void _updateToolBarVisible() {
5518    _toolBar.setVisible(DrJava.getConfig().getSetting(TOOLBAR_ENABLED));
5519  }
5520  
5521  /** Update the toolbar's buttons, following any change to TOOLBAR_ICONS_ENABLED, TOOLBAR_TEXT_ENABLED, or
5522   * FONT_TOOLBAR (name, style, text)
5523   */

5524  private void _updateToolbarButtons() {
5525    _updateToolBarVisible();
5526    Component[] buttons = _toolBar.getComponents();
5527    
5528    Font toolbarFont = DrJava.getConfig().getSetting(FONT_TOOLBAR);
5529    boolean iconsEnabled = DrJava.getConfig().getSetting(TOOLBAR_ICONS_ENABLED).booleanValue();
5530    boolean textEnabled = DrJava.getConfig().getSetting(TOOLBAR_TEXT_ENABLED).booleanValue();
5531    
5532    for (int i = 0; i< buttons.length; i++) {
5533      
5534      if (buttons[i] instanceof JButton) {
5535        
5536        JButton b = (JButton) buttons[i];
5537        Action a = b.getAction();
5538        
5539        // Work-around for strange configuration of undo/redo buttons
5540
/*
5541         if (a == null) {
5542         ActionListener[] al = b.getActionListeners(); // 1.4 only
5543         
5544         for (int j=0; j<al.length; j++) {
5545         if (al[j] instanceof Action) {
5546         a = (Action) al[j];
5547         break;
5548         }
5549         }
5550         }
5551         */

5552        
5553        b.setFont(toolbarFont);
5554        
5555        if (a == null) {
5556          if (b == _undoButton) a = _undoAction;
5557          else if (b == _redoButton) a = _redoAction;
5558          else continue;
5559        }
5560        
5561        if (b.getIcon() == null) {
5562          if (iconsEnabled) b.setIcon( (Icon) a.getValue(Action.SMALL_ICON));
5563        }
5564        else if (!iconsEnabled && b.getText().equals("")) b.setIcon(null);
5565        
5566        if (b.getText().equals("")) {
5567          if (textEnabled) b.setText( (String JavaDoc) a.getValue(Action.DEFAULT));
5568        }
5569        else if (!textEnabled && b.getIcon() != null) b.setText("");
5570        
5571      }
5572    }
5573    
5574    // Correct the vertical height of the buttons.
5575
_fixToolbarHeights();
5576  }
5577  
5578  /** Ensures that all toolbar buttons have the same height. */
5579  private void _fixToolbarHeights() {
5580    Component[] buttons = _toolBar.getComponents();
5581    
5582    // First, find the maximum height of all the buttons.
5583
int max = 0;
5584    for (int i = 0; i< buttons.length; i++) {
5585      // We only care about the JButtons.
5586
if (buttons[i] instanceof JButton) {
5587        JButton b = (JButton) buttons[i];
5588        
5589        // reset any preferred size we have set
5590
b.setPreferredSize(null);
5591        
5592        // get the preferred height, since that's what we want to use
5593
Dimension d = b.getPreferredSize();
5594        int cur = (int) d.getHeight();
5595        if (cur > max) {
5596          max = cur;
5597        }
5598      }
5599    }
5600    
5601    // Now set all button heights to the max.
5602
for (int i = 0; i< buttons.length; i++) {
5603      // We only care about the JButtons.
5604
if (buttons[i] instanceof JButton) {
5605        JButton b = (JButton) buttons[i];
5606        Dimension d = new Dimension((int) b.getPreferredSize().getWidth(), max);
5607        
5608        // JToolBar inexplicably uses the max size
5609
// also set preferred size for consistency
5610
b.setPreferredSize(d);
5611        b.setMaximumSize(d);
5612      }
5613    }
5614    
5615    // _toolbar.revalidate();
5616
}
5617  
5618  /** Sets up the status bar with the filename field. Only called from MainFrame constructor. */
5619  private void _setUpStatusBar() {
5620    
5621    // Initialize the 3 labels:
5622

5623    _fileNameField.setFont(_fileNameField.getFont().deriveFont(Font.PLAIN));
5624    _sbMessage.setHorizontalAlignment(SwingConstants.RIGHT);
5625    
5626    JPanel fileNameAndMessagePanel = new JPanel(new BorderLayout());
5627    fileNameAndMessagePanel.add(_fileNameField, BorderLayout.CENTER);
5628    fileNameAndMessagePanel.add(_sbMessage, BorderLayout.EAST);
5629
5630    _currLocationField.setFont(_currLocationField.getFont().deriveFont(Font.PLAIN));
5631    _currLocationField.setHorizontalAlignment(SwingConstants.RIGHT);
5632    _currLocationField.setPreferredSize(new Dimension(165,12));
5633// _currLocationField.setVisible(true);
5634

5635    // Initialize the status bar panel
5636
// SpringLayout layout = new SpringLayout();
5637
_statusBar.add( fileNameAndMessagePanel, BorderLayout.CENTER );
5638// _statusBar.add( sbMessagePanel, BorderLayout.CENTER );
5639
_statusBar.add( _currLocationField, BorderLayout.EAST );
5640    _statusBar.setBorder(
5641                         new CompoundBorder(new EmptyBorder(2,2,2,2),
5642                                            new CompoundBorder(new BevelBorder(BevelBorder.LOWERED),
5643                                                               new EmptyBorder(2,2,2,2))));
5644    getContentPane().add(_statusBar, BorderLayout.SOUTH);
5645    
5646// //Adjust constraints for the fileName label so it's next to the left edge.
5647
// layout.getConstraints(_fileNameField).setX(Spring.constant(0));
5648
//
5649
// //Adjust constraints for the message label so it's spaced a bit from the right.
5650
// //and doesn't interfere with the left-most label
5651
// layout.putConstraint(SpringLayout.EAST, _sbMessage, -65,
5652
// SpringLayout.EAST, _statusBar);
5653
//
5654
// //Adjust constraints for the location label so it's next to the right edge.
5655
// layout.putConstraint(SpringLayout.EAST, _currLocationField, 0,
5656
// SpringLayout.EAST, _statusBar);
5657
//
5658
// //Adjust constraints for the panel to set its size
5659
// layout.putConstraint(SpringLayout.SOUTH, _statusBar, 0,
5660
// SpringLayout.SOUTH, _currLocationField);
5661
}
5662  
5663  /** Inner class to handle updating the current position in the document. Registered with the DefinitionsPane. **/
5664  private class PositionListener implements CaretListener {
5665    
5666    public void caretUpdate(final CaretEvent ce ) {
5667      final OpenDefinitionsDocument doc = _model.getActiveDocument();
5668      // The following block of code does not appear to require running in the event thread
5669
// Utilities.invokeLater(new Runnable() {
5670
// public void run() {
5671
doc.acquireReadLock();
5672          try {
5673            doc.setCurrentLocation(ce.getDot());
5674            int line = doc.getCurrentLine();
5675            int col = doc.getCurrentCol();
5676            updateLocation(line, col);
5677          }
5678          finally { doc.releaseReadLock(); }
5679// }
5680
// });
5681
}
5682    
5683    // This method appears safe outside the event thread
5684
public void updateLocation() {
5685      OpenDefinitionsDocument doc = _model.getActiveDocument();
5686      doc.acquireReadLock(); // lock to ensure consistency of two reads from doc
5687
try { updateLocation(doc.getCurrentLine(), doc.getCurrentCol()); }
5688      finally { doc.releaseReadLock(); }
5689    }
5690    
5691    private void updateLocation(int line, int col) {
5692      _currLocationField.setText(line + ":" + col +" \t"); // Space before "\t" required on Mac to avoid obscuring
5693
// Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
5694
// _model.getParsingControl().delay();
5695
}
5696  }
5697  
5698  /* Only called from MainFrame constructor. */
5699  private void _setUpTabs() {
5700 
5701    // Interactions
5702
_interactionsController.setPrevPaneAction(_switchToPreviousPaneAction);
5703    _interactionsController.setNextPaneAction(_switchToNextPaneAction);
5704    
5705    JScrollPane interactionsScroll =
5706      new BorderlessScrollPane(_interactionsPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
5707                                                  JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
5708    _interactionsContainer.add(interactionsScroll, BorderLayout.CENTER);
5709    
5710    if (_showDebugger) {
5711      // hook highlighting listener to breakpoint manager
5712
_model.getBreakpointManager().addListener(new RegionManagerListener<Breakpoint>() {
5713        /* Called when a breakpoint is added. Only runs in event thread. */
5714        public void regionAdded(final Breakpoint bp, int index) {
5715          DefinitionsPane bpPane = getDefPaneGivenODD(bp.getDocument());
5716          _documentBreakpointHighlights.
5717            put(bp, bpPane.getHighlightManager().
5718                  addHighlight(bp.getStartOffset(), bp.getEndOffset(),
5719                               bp.isEnabled() ? DefinitionsPane.BREAKPOINT_PAINTER
5720                                 : DefinitionsPane.DISABLED_BREAKPOINT_PAINTER));
5721          _updateDebugStatus();
5722        }
5723        
5724        /** Called when a breakpoint is changed. Only runs in event thread. */
5725        public void regionChanged(Breakpoint bp, int index) {
5726          regionRemoved(bp);
5727          regionAdded(bp, index);
5728        }
5729        
5730        /** Called when a breakpoint is removed. Only runs in event thread. */
5731        public void regionRemoved(final Breakpoint bp) {
5732          HighlightManager.HighlightInfo highlight = _documentBreakpointHighlights.get(bp);
5733          if (highlight != null) highlight.remove();
5734          _documentBreakpointHighlights.remove(bp);
5735        }
5736      });
5737    }
5738
5739    // hook highlighting listener to bookmark manager
5740
_model.getBookmarkManager().addListener(new RegionManagerListener<DocumentRegion>() {
5741      // listener methods only run in the event thread
5742
public void regionAdded(DocumentRegion r, int index) {
5743        DefinitionsPane bpPane = getDefPaneGivenODD(r.getDocument());
5744        _documentBookmarkHighlights.
5745          put(r, bpPane.getHighlightManager().
5746                addHighlight(r.getStartOffset(), r.getEndOffset(), DefinitionsPane.BOOKMARK_PAINTER));
5747      }
5748      public void regionChanged(DocumentRegion r, int index) {
5749        regionRemoved(r);
5750        regionAdded(r, index);
5751      }
5752      public void regionRemoved(DocumentRegion r) {
5753        HighlightManager.HighlightInfo highlight = _documentBookmarkHighlights.get(r);
5754        if (highlight != null) highlight.remove();
5755        _documentBookmarkHighlights.remove(r);
5756      }
5757    });
5758    
5759    _tabbedPane.addChangeListener(new ChangeListener () {
5760      public void stateChanged(ChangeEvent e) {
5761// Utilities.showDebug("MainFrame.stateChanged called with event");
5762
clearStatusMessage();
5763        
5764        if (_tabbedPane.getSelectedComponent() == _consoleScroll)
5765          // Use SwingUtilities because this action must execute AFTER all pending events in the 33
5766
SwingUtilities.invokeLater(new Runnable JavaDoc() { public void run() { _consolePane.requestFocusInWindow(); } });
5767          
5768        // Update error highlights?
5769
if (_currentDefPane != null) {
5770          int pos = _currentDefPane.getCaretPosition();
5771          _currentDefPane.removeErrorHighlight(); //this line removes the highlighting whenever the current tabbed pane is switched
5772
_currentDefPane.getErrorCaretListener().updateHighlight(pos);
5773        }
5774      }
5775    });
5776    
5777    //_interactionsWithSyncPanel = new JPanel(new BorderLayout());
5778
//_syncStatus = new JLabel("Testing");
5779
//_interactionsWithSyncPanel.add(new BorderlessScrollPane(_interactionsPane), BorderLayout.CENTER);
5780
//_interactionsWithSyncPanel.add(_syncStatus, BorderLayout.SOUTH);
5781

5782    _tabbedPane.add("Interactions", _interactionsContainer);
5783    _tabbedPane.add("Console", _consoleScroll);
5784
5785    _tabs.addLast(_compilerErrorPanel);
5786    _tabs.addLast(_junitErrorPanel);
5787    _tabs.addLast(_javadocErrorPanel);
5788    _tabs.addLast(_findReplace);
5789    if (_showDebugger) { _tabs.addLast(_breakpointsPanel); }
5790    _tabs.addLast(_bookmarksPanel);
5791    
5792    _interactionsPane.addFocusListener(new FocusAdapter() {
5793      public void focusGained(FocusEvent e) { _lastFocusOwner = _interactionsContainer; }
5794    });
5795    _consolePane.addFocusListener(new FocusAdapter() {
5796      public void focusGained(FocusEvent e) { _lastFocusOwner = _consoleScroll; }
5797    });
5798    _compilerErrorPanel.getMainPanel().addFocusListener(new FocusAdapter() {
5799      public void focusGained(FocusEvent e) { _lastFocusOwner = _compilerErrorPanel; }
5800    });
5801    _junitErrorPanel.getMainPanel().addFocusListener(new FocusAdapter() {
5802      public void focusGained(FocusEvent e) { _lastFocusOwner = _junitErrorPanel; }
5803    });
5804    _javadocErrorPanel.getMainPanel().addFocusListener(new FocusAdapter() {
5805      public void focusGained(FocusEvent e) { _lastFocusOwner = _javadocErrorPanel; }
5806    });
5807    _findReplace.getFindField().addFocusListener(new FocusAdapter() {
5808      public void focusGained(FocusEvent e) { _lastFocusOwner = _findReplace; }
5809    });
5810    if (_showDebugger) {
5811      _breakpointsPanel.getMainPanel().addFocusListener(new FocusAdapter() {
5812        public void focusGained(FocusEvent e) { _lastFocusOwner = _breakpointsPanel; }
5813      });
5814    }
5815    _bookmarksPanel.getMainPanel().addFocusListener(new FocusAdapter() {
5816      public void focusGained(FocusEvent e) { _lastFocusOwner = _bookmarksPanel; }
5817    });
5818    
5819    // Show compiler output pane by default
5820
showTab(_compilerErrorPanel);
5821    
5822    _tabbedPane.setSelectedIndex(0);
5823  }
5824  
5825  /** Sets up the context menu to show in the document pane. */
5826  private void _setUpContextMenus() {
5827    // pop-up menu for a folder in tree view
5828
_navPaneFolderPopupMenu = new JPopupMenu();
5829    /*
5830     * Phil Repicky -smallproj
5831     * 2/14/2005
5832     * Make these do something:
5833     * _navPaneFolderPopupMenu.add("Open a File in this Folder Action");
5834     * _navPaneFolderPopupMenu.add("Make a New File in this Folder Action");
5835     */

5836    _navPaneFolderPopupMenu.add(_newFileFolderAction);
5837    _navPaneFolderPopupMenu.add(_openOneFolderAction);
5838    _navPaneFolderPopupMenu.add(_openAllFolderAction);
5839    _navPaneFolderPopupMenu.add(_closeFolderAction);
5840    _navPaneFolderPopupMenu.add(_compileFolderAction);
5841    _navPaneFolderPopupMenu.add(_junitFolderAction);
5842    
5843    _navPanePopupMenuForRoot = new JPopupMenu();
5844    _navPanePopupMenuForRoot.add(_saveProjectAction);
5845    _navPanePopupMenuForRoot.add(_closeProjectAction);
5846    _navPanePopupMenuForRoot.addSeparator();
5847    _navPanePopupMenuForRoot.add(_compileProjectAction);
5848    _navPanePopupMenuForRoot.add(_runProjectAction);
5849    _navPanePopupMenuForRoot.add(_junitProjectAction);
5850    _navPanePopupMenuForRoot.addSeparator();
5851    _navPanePopupMenuForRoot.add(_projectPropertiesAction);
5852    
5853    _navPanePopupMenuForExternal = new JPopupMenu();
5854    _navPanePopupMenuForExternal.add(_saveAction);
5855    _navPanePopupMenuForExternal.add(_saveAsAction);
5856    _navPanePopupMenuForExternal.add(_renameAction);
5857    _navPanePopupMenuForExternal.add(_revertAction);
5858    _navPanePopupMenuForExternal.addSeparator();
5859    _navPanePopupMenuForExternal.add(_closeAction);
5860    _navPanePopupMenuForExternal.addSeparator();
5861    _navPanePopupMenuForExternal.add(_printDefDocAction);
5862    _navPanePopupMenuForExternal.add(_printDefDocPreviewAction);
5863    _navPanePopupMenuForExternal.addSeparator();
5864    _navPanePopupMenuForExternal.add(_compileAction);
5865    _navPanePopupMenuForExternal.add(_junitAction);
5866    _navPanePopupMenuForExternal.add(_javadocCurrentAction);
5867    _navPanePopupMenuForExternal.add(_runAction);
5868    _navPanePopupMenuForExternal.addSeparator();
5869    _navPanePopupMenuForExternal.add(_moveToAuxiliaryAction);
5870    
5871    _navPanePopupMenuForAuxiliary = new JPopupMenu();
5872    _navPanePopupMenuForAuxiliary.add(_saveAction);
5873    _navPanePopupMenuForAuxiliary.add(_saveAsAction);
5874    _navPanePopupMenuForAuxiliary.add(_renameAction);
5875    _navPanePopupMenuForAuxiliary.add(_revertAction);
5876    _navPanePopupMenuForAuxiliary.addSeparator();
5877    _navPanePopupMenuForAuxiliary.add(_closeAction);
5878    _navPanePopupMenuForAuxiliary.addSeparator();
5879    _navPanePopupMenuForAuxiliary.add(_printDefDocAction);
5880    _navPanePopupMenuForAuxiliary.add(_printDefDocPreviewAction);
5881    _navPanePopupMenuForAuxiliary.addSeparator();
5882    _navPanePopupMenuForAuxiliary.add(_compileAction);
5883    _navPanePopupMenuForAuxiliary.add(_junitAction);
5884    _navPanePopupMenuForAuxiliary.add(_javadocCurrentAction);
5885    _navPanePopupMenuForAuxiliary.add(_runAction);
5886    _navPanePopupMenuForAuxiliary.addSeparator();
5887    _navPanePopupMenuForAuxiliary.add(_removeAuxiliaryAction);
5888    
5889    // NavPane menu
5890
_navPanePopupMenu = new JPopupMenu();
5891    _navPanePopupMenu.add(_saveAction);
5892    _navPanePopupMenu.add(_saveAsAction);
5893    _navPanePopupMenu.add(_renameAction);
5894    _navPanePopupMenu.add(_revertAction);
5895    _navPanePopupMenu.addSeparator();
5896    _navPanePopupMenu.add(_closeAction);
5897    _navPanePopupMenu.addSeparator();
5898    _navPanePopupMenu.add(_printDefDocAction);
5899    _navPanePopupMenu.add(_printDefDocPreviewAction);
5900    _navPanePopupMenu.addSeparator();
5901    _navPanePopupMenu.add(_compileAction);
5902    _navPanePopupMenu.add(_junitAction);
5903    _navPanePopupMenu.add(_javadocCurrentAction);
5904    _navPanePopupMenu.add(_runAction);
5905    _model.getDocCollectionWidget().addMouseListener(new RightClickMouseAdapter() {
5906      protected void _popupAction(MouseEvent e) {
5907        if (_model.getDocumentNavigator().selectDocumentAt(e.getX(), e.getY())) {
5908          if (_model.getDocumentNavigator().isGroupSelected())
5909            _navPaneFolderPopupMenu.show(e.getComponent(), e.getX(), e.getY());
5910          
5911          else {
5912            try {
5913              String JavaDoc groupName = _model.getDocumentNavigator().getNameOfSelectedTopLevelGroup();
5914              if (groupName.equals(_model.getSourceBinTitle()))
5915                _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY());
5916              else if (groupName.equals(_model.getExternalBinTitle())) {
5917                INavigatorItem n = _model.getDocumentNavigator().getCurrent();
5918                if (n != null) {
5919                  OpenDefinitionsDocument d = (OpenDefinitionsDocument) n;
5920                  if (d.isUntitled()) { _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); }
5921                  else _navPanePopupMenuForExternal.show(e.getComponent(), e.getX(), e.getY());
5922                }
5923              }
5924              else if (groupName.equals(_model.getAuxiliaryBinTitle()))
5925                _navPanePopupMenuForAuxiliary.show(e.getComponent(), e.getX(), e.getY());
5926            }
5927            catch(GroupNotSelectedException ex) {
5928              // we're looking at the root of the tree, or we're in list view...
5929
if (_model.isProjectActive())
5930                _navPanePopupMenuForRoot.show(e.getComponent(), e.getX(), e.getY());
5931              else _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY());
5932            }
5933          }
5934        }
5935      }
5936    });
5937    
5938    // Interactions pane menu
5939
_interactionsPanePopupMenu = new JPopupMenu();
5940    _interactionsPanePopupMenu.add(cutAction);
5941    _interactionsPanePopupMenu.add(copyAction);
5942    _interactionsPanePopupMenu.add(pasteAction);
5943    _interactionsPanePopupMenu.addSeparator();
5944    _interactionsPanePopupMenu.add(_printInteractionsAction);
5945    _interactionsPanePopupMenu.add(_printInteractionsPreviewAction);
5946    _interactionsPanePopupMenu.addSeparator();
5947    _interactionsPanePopupMenu.add(_executeHistoryAction);
5948    _interactionsPanePopupMenu.add(_loadHistoryScriptAction);
5949    _interactionsPanePopupMenu.add(_saveHistoryAction);
5950    _interactionsPanePopupMenu.add(_clearHistoryAction);
5951    _interactionsPanePopupMenu.addSeparator();
5952    _interactionsPanePopupMenu.add(_resetInteractionsAction);
5953    _interactionsPanePopupMenu.add(_viewInteractionsClassPathAction);
5954    _interactionsPanePopupMenu.add(_copyInteractionToDefinitionsAction);
5955    _interactionsPane.addMouseListener(new RightClickMouseAdapter() {
5956      protected void _popupAction(MouseEvent e) {
5957        _interactionsPane.requestFocusInWindow();
5958        _interactionsPanePopupMenu.show(e.getComponent(), e.getX(), e.getY());
5959      }
5960    });
5961    
5962    _consolePanePopupMenu = new JPopupMenu();
5963    _consolePanePopupMenu.add(_clearConsoleAction);
5964    _consolePanePopupMenu.addSeparator();
5965    _consolePanePopupMenu.add(_printConsoleAction);
5966    _consolePanePopupMenu.add(_printConsolePreviewAction);
5967    _consolePane.addMouseListener(new RightClickMouseAdapter() {
5968      protected void _popupAction(MouseEvent e) {
5969        _consolePane.requestFocusInWindow();
5970        _consolePanePopupMenu.show(e.getComponent(), e.getX(), e.getY());
5971      }
5972    });
5973  }
5974  
5975  private void nextRecentDoc() {
5976    if (_recentDocFrame.isVisible()) _recentDocFrame.next();
5977    else _recentDocFrame.setVisible(true);
5978  }
5979  
5980  private void prevRecentDoc() {
5981    if (_recentDocFrame.isVisible()) _recentDocFrame.prev();
5982    else _recentDocFrame.setVisible(true);
5983  }
5984  
5985  private void hideRecentDocFrame() {
5986    if (_recentDocFrame.isVisible()) {
5987      _recentDocFrame.setVisible(false);
5988      OpenDefinitionsDocument doc = _recentDocFrame.getDocument();
5989      if (doc != null) {
5990// addToBrowserHistory();
5991
_model.setActiveDocument(doc);
5992// addToBrowserHistory();
5993
}
5994    }
5995  }
5996  
5997  KeyListener _historyListener = new KeyListener() {
5998    public void keyPressed(KeyEvent e) {
5999      if (e.getKeyCode()==java.awt.event.KeyEvent.VK_BACK_QUOTE && e.isControlDown() && !e.isShiftDown()) nextRecentDoc();
6000      if (e.getKeyCode()==java.awt.event.KeyEvent.VK_BACK_QUOTE && e.isControlDown() && e.isShiftDown()) prevRecentDoc();
6001// else if (e.getKeyCode()==java.awt.event.KeyEvent.VK_BACK_QUOTE) {
6002
// transferFocusUpCycle();
6003
// }
6004
}
6005    public void keyReleased(KeyEvent e) {
6006      if (e.getKeyCode() == java.awt.event.KeyEvent.VK_CONTROL) hideRecentDocFrame();
6007    }
6008    public void keyTyped(KeyEvent e) { /* noop */ }
6009  };
6010  
6011  FocusListener _focusListenerForRecentDocs = new FocusListener() {
6012    public void focusLost(FocusEvent e) { hideRecentDocFrame(); }
6013    public void focusGained(FocusEvent e) { }
6014  };
6015  
6016  
6017  /** Create a new DefinitionsPane and JScrollPane for an open definitions document.
6018   * @param doc The open definitions document to wrap
6019   * @return JScrollPane containing a DefinitionsPane for the given document.
6020   */

6021  JScrollPane _createDefScrollPane(OpenDefinitionsDocument doc) {
6022    // made this package private to allow testing of disabling editing during compile and successful switching
6023
// on and off of ability to edit
6024
DefinitionsPane pane = new DefinitionsPane(this, doc);
6025  
6026    pane.addKeyListener(_historyListener);
6027    pane.addFocusListener(_focusListenerForRecentDocs);
6028    
6029    // Add listeners
6030
_installNewDocumentListener(doc);
6031    ErrorCaretListener caretListener = new ErrorCaretListener(doc, pane, this);
6032    pane.addErrorCaretListener(caretListener);
6033    
6034    // Limiting line numbers to just lines existing in the document.
6035
doc.addDocumentListener(new DocumentUIListener() {
6036      private void updateUI() {
6037        SwingUtilities.invokeLater(new Runnable JavaDoc() {
6038          public void run() {
6039            // revalidateLineNums();
6040
if ((_breakpointsPanel != null) && (_breakpointsPanel.isDisplayed())) { _breakpointsPanel.repaint(); }
6041            if ((_bookmarksPanel != null) && (_bookmarksPanel.isDisplayed())) { _bookmarksPanel.repaint(); }
6042            for(Pair<FindResultsPanel,Hashtable JavaDoc<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair: _findResults) {
6043              FindResultsPanel panel = pair.first();
6044              if ((panel != null) && (panel.isDisplayed())) { panel.repaint(); }
6045            }
6046          }
6047        });
6048      }
6049      public void changedUpdate(DocumentEvent e) { /* updateUI(); */ } // only attribute changes that matter are inserts and removes
6050
public void insertUpdate(DocumentEvent e) { updateUI(); }
6051      public void removeUpdate(DocumentEvent e) { updateUI(); }
6052    });
6053    
6054    // add a listener to update line and column.
6055
pane.addCaretListener(_posListener);
6056    
6057    // add a focus listener to the pane.
6058
pane.addFocusListener(new LastFocusListener());
6059    
6060    // Add to a scroll pane
6061
final JScrollPane scroll = new BorderlessScrollPane(pane,
6062                                                  JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
6063                                                  JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
6064    pane.setScrollPane(scroll);
6065    //scroll.setBorder(null); // removes all default borders (MacOS X installs default borders)
6066

6067    // can be used to make sure line wrapping occurs
6068
/*scroll.getViewport().addChangeListener(new ChangeListener() {
6069     public void stateChanged(ChangeEvent e) {
6070     pane.setSize(scroll.getViewport().getWidth(), pane.getHeight());
6071     }
6072     });*/

6073    
6074    if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) {
6075      scroll.setRowHeaderView(new LineEnumRule(pane));
6076    }
6077    
6078    _defScrollPanes.put(doc, scroll);
6079    
6080    return scroll;
6081  }
6082  
6083  private void _setUpPanes() {
6084    // DefinitionsPane
6085
JScrollPane defScroll = _defScrollPanes.get(_model.getActiveDocument());
6086    
6087    // Try to create debug panel (see if JSwat is around)
6088
if (_showDebugger) {
6089      try {
6090        // Set the panel's size.
6091
int debugHeight = DrJava.getConfig().getSetting(DEBUG_PANEL_HEIGHT).intValue();
6092        Dimension debugMinSize = _debugPanel.getMinimumSize();
6093        
6094        // TODO: check bounds compared to entire window.
6095
if ((debugHeight > debugMinSize.height)) debugMinSize.height = debugHeight;
6096        _debugPanel.setPreferredSize(debugMinSize);
6097      }
6098      catch(NoClassDefFoundError JavaDoc e) {
6099        // Don't use the debugger
6100
_showDebugger = false;
6101      }
6102    }
6103     
6104    _debugSplitPane.setBottomComponent(_debugPanel);
6105    _mainSplit.setResizeWeight(1.0);
6106    _debugSplitPane.setResizeWeight(1.0);
6107    getContentPane().add(_mainSplit, BorderLayout.CENTER);
6108    // This is annoyingly order-dependent. Since split contains _docSplitPane,
6109
// we need to get split's divider set up first to give _docSplitPane an
6110
// overall size. Then we can set _docSplitPane's divider. Ahh, Swing.
6111
// Also, according to the Swing docs, we need to set these dividers AFTER
6112
// we have shown the window. How annoying.
6113
// int tabHeight = DrJava.getConfig().getSetting(TABS_HEIGHT).intValue();
6114

6115    // 2*getHeight()/3
6116
_mainSplit.setDividerLocation(_mainSplit.getHeight() - 132);
6117// _mainSplit.setDividerLocation(_mainSplit.getHeight() - tabHeight);
6118
_mainSplit.setOneTouchExpandable(true);
6119    _debugSplitPane.setOneTouchExpandable(true);
6120    
6121    int docListWidth = DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue();
6122    
6123    // TODO: Check bounds.
6124
_docSplitPane.setDividerLocation(docListWidth);
6125    _docSplitPane.setOneTouchExpandable(true);
6126  }
6127  
6128  /** Switch to the JScrollPane containing the DefinitionsPane for the active document. Must run in event thread.*/
6129  void _switchDefScrollPane() {
6130    // demoted to package private protection to test the disabling editing while compiling functionality.
6131
// and to support brute force fix to DefinitionsPane bug on return from compile with errors
6132
// Added 2004-May-27
6133
// Notify the definitions pane that is being replaced (becoming inactive)
6134
_currentDefPane.notifyInactive();
6135    
6136// Utilities.showDebug("_switchDefScrollPane called");
6137
// Utilities.showDebug("Right before getting the scrollPane");
6138
JScrollPane scroll = _defScrollPanes.get(_model.getActiveDocument());
6139    
6140    if (scroll == null) scroll = _createDefScrollPane(_model.getActiveDocument());
6141    // Fix OS X scrollbar bug before switching
6142

6143    _reenableScrollBar();
6144    
6145    int oldLocation = _docSplitPane.getDividerLocation();
6146    _docSplitPane.setRightComponent(scroll); //crazy line
6147
_docSplitPane.setDividerLocation(oldLocation);
6148    
6149    // if the current def pane is uneditable, that means we arrived here from a compile with errors. We're
6150
// guaranteed to make it editable again when we return from the compilation, so we take the state
6151
// with us. We guarantee only one definitions pane is un-editable at any time.
6152
if (_currentDefPane.isEditable()) {
6153      _currentDefPane = (DefinitionsPane) scroll.getViewport().getView();
6154      _currentDefPane.notifyActive();
6155    }
6156    else {
6157      try { _currentDefPane.setEditable(true); }
6158      catch(NoSuchDocumentException e) { /* It's OK */ }
6159      
6160      _currentDefPane = (DefinitionsPane) scroll.getViewport().getView();
6161      _currentDefPane.notifyActive();
6162      _currentDefPane.setEditable(false);
6163    }
6164    // reset the undo/redo menu items
6165
resetUndo();
6166    _updateDebugStatus();
6167  }
6168  
6169  /** Resets the undo/redo menu items */
6170  public void resetUndo() {
6171    _undoAction.setDelegatee(_currentDefPane.getUndoAction());
6172    _redoAction.setDelegatee(_currentDefPane.getRedoAction());
6173  }
6174  
6175  public DefinitionsPane getDefPaneGivenODD(OpenDefinitionsDocument doc) {
6176    JScrollPane scroll = _defScrollPanes.get(doc);
6177    if (scroll == null) {
6178      throw new UnexpectedException(new Exception JavaDoc("Region set in a closed document."));
6179    }
6180    
6181    DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView();
6182    return pane;
6183  }
6184  
6185  /** Addresses Mac OS X bug where the scrollbars are disabled in one document after opening another. */
6186  private void _reenableScrollBar() {
6187    JScrollPane scroll = _defScrollPanes.get(_model.getActiveDocument());
6188    if (scroll == null)
6189      throw new UnexpectedException(new Exception JavaDoc("Current definitions scroll pane not found."));
6190    
6191    JScrollBar oldbar = scroll.getVerticalScrollBar();
6192    JScrollBar newbar = scroll.createVerticalScrollBar();
6193    newbar.setMinimum(oldbar.getMinimum());
6194    newbar.setMaximum(oldbar.getMaximum());
6195    newbar.setValue(oldbar.getValue());
6196    newbar.setVisibleAmount(oldbar.getVisibleAmount());
6197    newbar.setEnabled(true);
6198    newbar.revalidate();
6199    scroll.setVerticalScrollBar(newbar);
6200    
6201    // This needs to be repeated for the horizontal scrollbar
6202
oldbar = scroll.getHorizontalScrollBar();
6203    newbar = scroll.createHorizontalScrollBar();
6204    newbar.setMinimum(oldbar.getMinimum());
6205    newbar.setMaximum(oldbar.getMaximum());
6206    newbar.setValue(oldbar.getValue());
6207    newbar.setVisibleAmount(oldbar.getVisibleAmount());
6208    newbar.setEnabled(true);
6209    newbar.revalidate();
6210    scroll.setHorizontalScrollBar(newbar);
6211    scroll.revalidate();
6212  }
6213  
6214  /** Returns a JRadioButtonMenuItem that looks like a JCheckBoxMenuItem. This is a workaround for a known
6215   * bug on OS X's version of Java. (See http://developer.apple.com/qa/qa2001/qa1154.html)
6216   * @param action Action for the menu item
6217   * @return JRadioButtonMenuItem with a checkbox icon
6218   */

6219  private JMenuItem _newCheckBoxMenuItem(Action action) {
6220    String JavaDoc RADIO_ICON_KEY = "RadioButtonMenuItem.checkIcon";
6221    String JavaDoc CHECK_ICON_KEY = "CheckBoxMenuItem.checkIcon";
6222    
6223    // Store the default radio button icon to put back later
6224
Object JavaDoc radioIcon = UIManager.get(RADIO_ICON_KEY);
6225    
6226    // Replace radio button's checkIcon with that of JCheckBoxMenuItem
6227
// so that our menu item looks like a checkbox
6228
UIManager.put(RADIO_ICON_KEY, UIManager.get(CHECK_ICON_KEY));
6229    JRadioButtonMenuItem pseudoCheckBox = new JRadioButtonMenuItem(action);
6230    
6231    // Put original radio button checkIcon back.
6232
UIManager.put(RADIO_ICON_KEY, radioIcon);
6233    
6234    return pseudoCheckBox;
6235  }
6236  
6237  /** Gets the absolute file, or if necessary, the canonical file.
6238   * @param f the file for which to get the full path
6239   * @return the file representing the full path to the given file
6240   */

6241  private File _getFullFile(File f) throws IOException {
6242    if (PlatformFactory.ONLY.isWindowsPlatform() &&
6243        ((f.getAbsolutePath().indexOf("..") != -1) || (f.getAbsolutePath().indexOf("./") != -1) ||
6244         (f.getAbsolutePath().indexOf(".\\") != -1))) {
6245      return f.getCanonicalFile();
6246    }
6247    return f.getAbsoluteFile();
6248  }
6249  
6250  /** Sets the current directory to be that of the given file. */
6251  private void _setCurrentDirectory(File file) {
6252    /* We want to use absolute paths whenever possible, since canonical paths resolve symbolic links and can be quite
6253     * long and unintuitive. However, Windows blows up if you set the current directory of a JFileChooser to an
6254     * absolute path with ".." in it. In that case, we'll use the canonical path for the file chooser. (Fix for
6255     * bug 707734) Extended this to fix "./" and ".\" also (bug 774896)
6256     */

6257    try {
6258      file = _getFullFile(file);
6259      _openChooser.setCurrentDirectory(file);
6260      _saveChooser.setCurrentDirectory(file);
6261      DrJava.getConfig().setSetting(LAST_DIRECTORY, file);
6262    }
6263    catch (IOException ioe) {
6264      // If getCanonicalFile throws an IOException, we can't set the directory of the file chooser. Oh well.
6265
}
6266  }
6267  
6268  /** Sets the current directory to be that of document's file. */
6269  private void _setCurrentDirectory(OpenDefinitionsDocument doc) {
6270    try {
6271      File file = doc.getFile();
6272      if (file != null) _setCurrentDirectory(file); // if no file, leave in current directory
6273
}
6274    catch (FileMovedException fme) {
6275      // file was deleted, but try to go the directory
6276
_setCurrentDirectory(fme.getFile());
6277    }
6278  }
6279  
6280  /** Sets the font of all panes and panels to the main font. */
6281  private void _setMainFont() {
6282    
6283    Font f = DrJava.getConfig().getSetting(FONT_MAIN);
6284    
6285    for (JScrollPane scroll: _defScrollPanes.values()) {
6286      if (scroll != null) {
6287        DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView();
6288        pane.setFont(f);
6289        // Update the font of the line enumeration rule
6290
if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) {
6291          scroll.setRowHeaderView( new LineEnumRule(pane) );
6292        }
6293      }
6294    }
6295    
6296    // Update Interactions Pane
6297
_interactionsPane.setFont(f);
6298    _interactionsController.setDefaultFont(f);
6299    
6300    // Update Console Pane
6301
_consolePane.setFont(f);
6302    _consoleController.setDefaultFont(f);
6303    
6304    _findReplace.setFieldFont(f);
6305    _compilerErrorPanel.setListFont(f);
6306    _junitErrorPanel.setListFont(f);
6307    _javadocErrorPanel.setListFont(f);
6308  }
6309  
6310  /** Updates the text color for the doc list. */
6311  private void _updateNormalColor() {
6312    // Get the new value.
6313
Color norm = DrJava.getConfig().getSetting(DEFINITIONS_NORMAL_COLOR);
6314    
6315    // Change the text (foreground) color for the doc list.
6316
_model.getDocCollectionWidget().setForeground(norm);
6317    
6318    // We also need to immediately repaint the foremost scroll pane.
6319
_repaintLineNums();
6320  }
6321  
6322  /** Updates the background color for the doc list. */
6323  private void _updateBackgroundColor() {
6324    // Get the new value.
6325
Color back = DrJava.getConfig().getSetting(DEFINITIONS_BACKGROUND_COLOR);
6326    
6327    // Change the background color for the doc list.
6328
_model.getDocCollectionWidget().setBackground(back);
6329    
6330    // We also need to immediately repaint the foremost scroll pane.
6331
_repaintLineNums();
6332  }
6333  
6334  /** Updates the font and colors of the line number display. */
6335  private void _updateLineNums() {
6336    if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) {
6337      
6338      // Update the font for all line number displays
6339
for (JScrollPane spane: _defScrollPanes.values()) {
6340        
6341        LineEnumRule ler = (LineEnumRule) spane.getRowHeader().getView();
6342        ler.updateFont();
6343        ler.revalidate();
6344      }
6345      
6346      // We also need to immediately repaint the foremost scroll pane.
6347
_repaintLineNums();
6348    }
6349  }
6350  
6351  /** Repaints the line numbers on the active scroll pane. */
6352  private void _repaintLineNums() {
6353    JScrollPane front = _defScrollPanes.get(_model.getActiveDocument());
6354    if (front != null) {
6355      JViewport rhvport = front.getRowHeader();
6356      
6357      if (rhvport != null) {
6358        Component view = rhvport.getView();
6359        if (view != null) {
6360          view.repaint();
6361        }
6362      }
6363    }
6364  }
6365  
6366// /** Revalidate the line numers, i.e. also redraw the ones not currently visible. */
6367
// public void revalidateLineNums() {
6368
// if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) {
6369
// JScrollPane sp = _defScrollPanes.get(_model.getActiveDocument());
6370
// if (sp!=null) {
6371
// LineEnumRule ler = (LineEnumRule)sp.getRowHeader().getView();
6372
// ler.revalidate();
6373
// _repaintLineNums();
6374
// }
6375
// }
6376
// }
6377

6378  /** Update the row header (line number enumeration) for the definitions scroll pane. */
6379  private void _updateDefScrollRowHeader() {
6380    boolean ruleEnabled = DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue();
6381    
6382    for (JScrollPane scroll: _defScrollPanes.values()) {
6383      if (scroll != null) {
6384        DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView();
6385        if (scroll.getRowHeader() == null || scroll.getRowHeader().getView() == null) {
6386          if (ruleEnabled) scroll.setRowHeaderView(new LineEnumRule(pane));
6387        }
6388        else if (! ruleEnabled) scroll.setRowHeaderView(null);
6389      }
6390    }
6391  }
6392  
6393  /** Removes the current highlight. */
6394  private void _removeThreadLocationHighlight() {
6395    if (_currentThreadLocationHighlight != null) {
6396      _currentThreadLocationHighlight.remove();
6397      _currentThreadLocationHighlight = null;
6398    }
6399  }
6400  
6401  /** Disable any step timer. */
6402  private void _disableStepTimer() {
6403    synchronized(_debugStepTimer) { if (_debugStepTimer.isRunning()) _debugStepTimer.stop(); }
6404  }
6405  
6406  /** Checks if debugPanel's status bar displays the DEBUGGER_OUT_OF_SYNC message but the current document is
6407   * in sync. Clears the debugPanel's status bar in this case. Does not assume that frame is in debug mode.
6408   * Must be executed in event thread.
6409   */

6410  private void _updateDebugStatus() {
6411    if (! isDebuggerReady()) return;
6412    
6413    // if the document is untitled, don't show that it is out of sync since it can't be debugged anyway
6414
if (_model.getActiveDocument().isUntitled() || _model.getActiveDocument().getClassFileInSync()) {
6415      // Hide message
6416
if (_debugPanel.getStatusText().equals(DEBUGGER_OUT_OF_SYNC)) _debugPanel.setStatusText("");
6417    }
6418    else {
6419      // Show message
6420
if (_debugPanel.getStatusText().equals("")) {
6421        _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
6422      }
6423    }
6424    _debugPanel.repaint(); // display the updated panel
6425
}
6426  
6427  /** Ensures that the interactions pane is not editable during an interaction. */
6428  protected void _disableInteractionsPane() {
6429    // Only change GUI from event-dispatching thread
6430
Runnable JavaDoc command = new Runnable JavaDoc() {
6431      public void run() {
6432        _interactionsPane.setEditable(false);
6433        _interactionsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
6434        
6435        if (_interactionsScriptController != null) _interactionsScriptController.setActionsDisabled();
6436      }
6437    };
6438    Utilities.invokeLater(command);
6439  }
6440  
6441  /** Ensures that the interactions pane is editable after an interaction completes. */
6442  protected void _enableInteractionsPane() {
6443    // Only change GUI from event-dispatching thread
6444
Runnable JavaDoc command = new Runnable JavaDoc() {
6445      public void run() {
6446// if (isDebuggerReady()) {
6447
// _disableStepTimer();
6448
// Debugger manager = _model.getDebugger();
6449
// manager.clearCurrentStepRequest();
6450
// _removeThreadLocationHighlight();
6451
// }
6452

6453        _interactionsPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
6454        _interactionsPane.setEditable(true);
6455        _interactionsController.moveToEnd();
6456        if (_interactionsPane.hasFocus()) _interactionsPane.getCaret().setVisible(true);
6457        if (_interactionsScriptController != null) _interactionsScriptController.setActionsEnabled();
6458      }
6459    };
6460    Utilities.invokeLater(command);
6461  }
6462  
6463  // Comment out current selection using wing commenting. Non-private for testing purposes only. */
6464
void commentLines() {
6465    // Delegate everything to the DefinitionsDocument.
6466
OpenDefinitionsDocument openDoc = _model.getActiveDocument();
6467    int caretPos = _currentDefPane.getCaretPosition();
6468    openDoc.setCurrentLocation(caretPos);
6469    int start = _currentDefPane.getSelectionStart();
6470    int end = _currentDefPane.getSelectionEnd();
6471// _currentDefPane.endCompoundEdit();
6472
// _currentDefPane.notifyInactive();
6473
int newEnd = openDoc.commentLines(start, end);
6474// _currentDefPane.notifyActive();
6475
_currentDefPane.setCaretPosition(start+2);
6476    if (start != end) _currentDefPane.moveCaretPosition(newEnd);
6477  }
6478  
6479  // Uncomment out current selection using wing commenting. Public for testing purposes only. */
6480
public void uncommentLines() {
6481    // Delegate everything to the DefinitionsDocument.
6482
OpenDefinitionsDocument openDoc = _model.getActiveDocument();
6483    int caretPos = _currentDefPane.getCaretPosition();
6484    openDoc.setCurrentLocation(caretPos);
6485    int start = _currentDefPane.getSelectionStart();
6486    int end = _currentDefPane.getSelectionEnd();
6487    _currentDefPane.endCompoundEdit();
6488    
6489    //notify inactive to prevent refreshing of the DefPane every time an insertion is made
6490
// _currentDefPane.notifyInactive();
6491
openDoc.setCurrentLocation(start);
6492    Position startPos;
6493    try { startPos = openDoc.createUnwrappedPosition(start); }
6494    catch (BadLocationException e) { throw new UnexpectedException(e); }
6495    
6496    int startOffset = startPos.getOffset();
6497    int newEnd = openDoc.uncommentLines(start, end);
6498// _currentDefPane.notifyActive();
6499
if (startOffset != startPos.getOffset()) start -= 2;
6500    _currentDefPane.setCaretPosition(start);
6501    if (start != end) _currentDefPane.moveCaretPosition(newEnd);
6502  }
6503  
6504  
6505  /** Blocks access to DrJava while the hourglass cursor is on. */
6506  private static class GlassPane extends JComponent {
6507    
6508    /** Creates a new GlassPane over the DrJava window. */
6509    public GlassPane() {
6510      addKeyListener(new KeyAdapter() { });
6511      addMouseListener(new MouseAdapter() { });
6512      super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
6513    }
6514  }
6515  
6516  /** Called when a specific document and offset should be displayed. Must be executed only in the event thread.
6517   * @param doc Document to display
6518   * @param offset Offset to display
6519   * @param shouldHighlight true iff the line should be highlighted.
6520   */

6521  public void scrollToDocumentAndOffset(final OpenDefinitionsDocument doc, final int offset,
6522                                        final boolean shouldHighlight) {
6523    scrollToDocumentAndOffset(doc, offset, shouldHighlight, true);
6524  }
6525  
6526  /** Called when a specific document and offset should be displayed. Must be executed only in the event thread.
6527   * @param doc Document to display
6528   * @param offset Offset to display
6529   * @param shouldHighlight true iff the line should be highlighted.
6530   * @param shouldAddToHistory true if the location before and after the switch should be added to the browser history
6531   */

6532  public void scrollToDocumentAndOffset(final OpenDefinitionsDocument doc, final int offset,
6533                                        final boolean shouldHighlight, final boolean shouldAddToHistory) {
6534    if (shouldAddToHistory) addToBrowserHistory();
6535    
6536    boolean toSameDoc = _model.getActiveDocument().equals(doc);
6537    
6538    if (! toSameDoc) {
6539      _model.setActiveDocument(doc);
6540      _findReplace.updateFirstDocInSearch();
6541    }
6542    else _model.refreshActiveDocument();
6543    
6544    Runnable JavaDoc command = new Runnable JavaDoc() {
6545      public void run() {
6546        // get the line number after the switch of documents was made
6547
int lineNumber = doc.getLineOfOffset(offset)+1;
6548        
6549        // this block occurs if the documents is already open and as such has a positive size
6550
if (_currentDefPane.getSize().getWidth() > 0 && _currentDefPane.getSize().getHeight() > 0) {
6551          _currentDefPane.centerViewOnOffset(offset);
6552          _currentDefPane.requestFocusInWindow();
6553        }
6554               
6555        if (shouldHighlight) {
6556          _removeThreadLocationHighlight();
6557          int startOffset = doc.getOffset(lineNumber);
6558          if (startOffset > -1) {
6559            int endOffset = doc.getLineEndPos(startOffset);
6560            if (endOffset > -1) {
6561              _currentThreadLocationHighlight = _currentDefPane.getHighlightManager().
6562                addHighlight(startOffset, endOffset, DefinitionsPane.THREAD_PAINTER);
6563            }
6564          }
6565        }
6566
6567        if (shouldHighlight) {
6568          // Give the interactions pane focus so we can debug
6569
_interactionsPane.requestFocusInWindow();
6570          showTab(_interactionsPane);
6571        }
6572        _updateDebugStatus();
6573
6574// if (shouldAddToHistory) { addToBrowserHistory(); }
6575
}
6576    };
6577    
6578    /* Comment by mgricken: If ! toSameDoc, the _currentDefPane hasn't been created yet for a new document.
6579     * Consequently, we need to use SwingUtilities.invokeLater if ! toSameDoc. */

6580    if (toSameDoc) Utilities.invokeLater(command);
6581    else SwingUtilities.invokeLater(command);
6582  }
6583  
6584  /** Listens to events from the debugger. */
6585  private class UIDebugListener implements DebugListener {
6586    /* Must be executed in evevt thread.*/
6587    public void debuggerStarted() { showDebugger(); }
6588    
6589    /* Must be executed in evevt thread.*/
6590    public void debuggerShutdown() {
6591      _disableStepTimer();
6592      
6593      hideDebugger();
6594      _removeThreadLocationHighlight();
6595    }
6596    
6597    /** Called when a step is requested on the current thread. Must be executed in event thread. */
6598    public void stepRequested() {
6599      // Print a message if step takes a long time
6600
synchronized(_debugStepTimer) { if (!_debugStepTimer.isRunning()) _debugStepTimer.start(); }
6601    }
6602    
6603    public void currThreadSuspended() {
6604      _disableStepTimer();
6605      
6606      // Only change GUI from event-dispatching thread
6607
Runnable JavaDoc command = new Runnable JavaDoc() {
6608        public void run() { _setThreadDependentDebugMenuItems(true); }
6609      };
6610      Utilities.invokeLater(command);
6611    }
6612    
6613    /* Must be executed in the event thread. */
6614    public void currThreadResumed() {
6615          _setThreadDependentDebugMenuItems(false);
6616          _removeThreadLocationHighlight();
6617    }
6618    
6619    /** Called when the given line is reached by the current thread in the debugger, to request that the line be
6620     * displayed. Must be executed only in the event thread.
6621     * @param doc Document to display
6622     * @param lineNumber Line to display or highlight
6623     * @param shouldHighlight true iff the line should be highlighted.
6624     */

6625    public void threadLocationUpdated(OpenDefinitionsDocument doc, int lineNumber, boolean shouldHighlight) {
6626      scrollToDocumentAndOffset(doc, doc.getOffset(lineNumber), shouldHighlight);
6627    }
6628    
6629    /* Must be executed in event thread. */
6630    public void currThreadDied() {
6631      _disableStepTimer();
6632      
6633      if (isDebuggerReady()) {
6634        try {
6635          if (!_model.getDebugger().hasSuspendedThreads()) {
6636            // no more suspended threads, resume default debugger state
6637
// all thread dependent debug menu items are disabled
6638
_setThreadDependentDebugMenuItems(false);
6639            _removeThreadLocationHighlight();
6640            // Make sure we're at the prompt
6641
// (This should really be fixed in InteractionsController, not here.)
6642
_interactionsController.moveToPrompt(); // there are no suspended threads, bring back prompt
6643
}
6644        }
6645        catch (DebugException de) {
6646          _showError(de, "Debugger Error", "Error with a thread in the debugger.");
6647        }
6648      }
6649    }
6650                            
6651    public void currThreadSet(DebugThreadData dtd) { }
6652    public void regionAdded(final Breakpoint bp, int index) { }
6653    public void breakpointReached(Breakpoint bp) { }
6654    public void regionChanged(Breakpoint bp, int index) { }
6655    public void regionRemoved(final Breakpoint bp) { }
6656    public void watchSet(final DebugWatchData w) { }
6657    public void watchRemoved(final DebugWatchData w) { }
6658    public void threadStarted() { }
6659    public void nonCurrThreadDied() { }
6660  }
6661
6662  /** @author jlugo */
6663  private class DJAsyncTaskLauncher extends AsyncTaskLauncher {
6664    
6665    protected boolean shouldSetEnabled() { return true; }
6666    
6667    protected void setParentContainerEnabled(boolean enabled) {
6668      if (enabled) hourglassOff();
6669      else hourglassOn();
6670    }
6671    
6672    protected IAsyncProgress createProgressMonitor(final String JavaDoc description, final int min, final int max) {
6673      return new IAsyncProgress() {
6674        private ProgressMonitor _monitor = new ProgressMonitor(MainFrame.this, description, "", min, max);
6675        
6676        public void close() { _monitor.close(); }
6677        public int getMaximum() { return _monitor.getMaximum() ; }
6678        public int getMillisToDecideToPopup() { return _monitor.getMillisToDecideToPopup(); }
6679        public int getMillisToPopup() { return _monitor.getMillisToPopup(); }
6680        public int getMinimum() { return _monitor.getMinimum(); }
6681        public String JavaDoc getNote() { return _monitor.getNote(); }
6682        public boolean isCanceled() { return _monitor.isCanceled(); }
6683        public void setMaximum(int m) { _monitor.setMaximum(m); }
6684        public void setMinimum(int m) { _monitor.setMinimum(m); }
6685        public void setNote(String JavaDoc note) { _monitor.setNote(note); }
6686        public void setProgress(int nv) { _monitor.setProgress(nv); }
6687      };
6688    }
6689  }
6690  
6691  /** Inner class to listen to all events in the model. */
6692 private class ModelListener implements GlobalModelListener {
6693
6694   public <P,R> void executeAsyncTask(AsyncTask<P,R> task, P param, boolean showProgress, boolean lockUI) {
6695     new DJAsyncTaskLauncher().executeTask(task, param, showProgress, lockUI);
6696   }
6697   public void handleAlreadyOpenDocument(OpenDefinitionsDocument doc) {
6698// boolean docChanged = !doc.equals(_model.getActiveDocument());
6699
// if (docChanged) { addToBrowserHistory(); }
6700

6701     // Always switch to doc
6702
_model.setActiveDocument(doc);
6703     
6704// // defer executing this code until after active document switch (if any) is complete
6705
// SwingUtilities.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
6706

6707     // Prompt to revert if modified
6708
if (doc.isModifiedSinceSave()) {
6709       String JavaDoc title = "Revert to Saved?";
6710       String JavaDoc message = doc.getFileName() + " is already open and modified.\n" +
6711         "Would you like to revert to the version on disk?\n";
6712       int choice = JOptionPane.showConfirmDialog(MainFrame.this, message, title, JOptionPane.YES_NO_OPTION);
6713       if (choice == JOptionPane.YES_OPTION) {
6714         _revert(doc);
6715       }
6716     }
6717   }
6718   
6719   public void newFileCreated(final OpenDefinitionsDocument doc) {
6720     Utilities.invokeLater(new Runnable JavaDoc() { public void run() { _createDefScrollPane(doc); } });
6721   }
6722    
6723    private volatile int _fnfCount = 0;
6724    
6725    private boolean resetFNFCount() { return _fnfCount == 0; }
6726    
6727    private boolean filesNotFound() { return _fnfCount > 0; }
6728    
6729    public void fileNotFound(File f) {
6730      _fnfCount++;
6731      _showFileNotFoundError(new FileNotFoundException("File " + f + " cannot be found"));
6732    }
6733    
6734    public void fileSaved(final OpenDefinitionsDocument doc) {
6735// new ScrollableDialog(null, "fileSaved called in ModelListener", "", "").show();
6736
Utilities.invokeLater(new Runnable JavaDoc() {
6737        public void run() {
6738          doc.documentSaved(); // used to update the document cache
6739
_saveAction.setEnabled(false);
6740          _renameAction.setEnabled(true);
6741          _revertAction.setEnabled(true);
6742          updateFileTitle();
6743          _currentDefPane.requestFocusInWindow();
6744          try {
6745            File f = doc.getFile();
6746            if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f);
6747          }
6748          catch (FileMovedException fme) {
6749            File f = fme.getFile();
6750            // Recover, show it in the list anyway
6751
if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f);
6752          }
6753          // Check class file sync status, in case file was renamed
6754
_updateDebugStatus();
6755        }
6756      });
6757    }
6758    
6759    public void fileOpened(final OpenDefinitionsDocument doc) {
6760      Utilities.invokeLater(new Runnable JavaDoc() { public void run() { _fileOpened(doc); } });
6761    }
6762    
6763    private void _fileOpened(final OpenDefinitionsDocument doc) {
6764      try {
6765        File f = doc.getFile();
6766        if (! _model.inProject(f)) {
6767          _recentFileManager.updateOpenFiles(f);
6768
6769        }
6770      }
6771      catch (FileMovedException fme) {
6772        File f = fme.getFile();
6773        // Recover, show it in the list anyway
6774
if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f);
6775      }
6776    }
6777
6778    /** NOTE: Makes certain that this action occurs in the event dispatching thread */
6779    public void fileClosed(final OpenDefinitionsDocument doc) {
6780      Utilities.invokeLater(new Runnable JavaDoc() {public void run() { _fileClosed(doc); } });
6781    }
6782    
6783    /** Does the work of closing a file */
6784    private void _fileClosed(OpenDefinitionsDocument doc) {
6785      _recentDocFrame.closeDocument(doc);
6786      _removeErrorListener(doc);
6787      JScrollPane jsp = _defScrollPanes.get(doc);
6788      if (jsp != null) {
6789        ((DefinitionsPane)jsp.getViewport().getView()).close();
6790        _defScrollPanes.remove(doc);
6791      }
6792    }
6793    
6794    public void fileReverted(OpenDefinitionsDocument doc) {
6795      Utilities.invokeLater(new Runnable JavaDoc() {
6796        public void run() {
6797          updateFileTitle();
6798          _saveAction.setEnabled(false);
6799          _currentDefPane.resetUndo();
6800          _currentDefPane.hasWarnedAboutModified(false);
6801          _currentDefPane.setPositionAndScroll(0);
6802          _updateDebugStatus();
6803        }
6804      });
6805    }
6806    
6807    public void undoableEditHappened() {
6808      Utilities.invokeLater(new Runnable JavaDoc() {
6809        public void run() {
6810          _currentDefPane.getUndoAction().updateUndoState();
6811          _currentDefPane.getRedoAction().updateRedoState();
6812        }
6813      });
6814    }
6815    
6816    public void activeDocumentChanged(final OpenDefinitionsDocument active) {
6817// Utilities.showDebug("MainFrame Listener: ActiveDocument changed to " + active);
6818
// code that accesses the GUI must run in the event-dispatching thread.
6819
Utilities.invokeLater(new Runnable JavaDoc() { // invokeAndWait can create occasional deadlocks.
6820
public void run() {
6821          _recentDocFrame.pokeDocument(active);
6822          _switchDefScrollPane();
6823          
6824          boolean isModified = active.isModifiedSinceSave();
6825          boolean canCompile = (! isModified && ! active.isUntitled());
6826          _saveAction.setEnabled(! canCompile);
6827          _renameAction.setEnabled(! active.isUntitled());
6828          _revertAction.setEnabled(! active.isUntitled());
6829          
6830          // Update error highlights
6831
int pos = _currentDefPane.getCaretPosition();
6832          _currentDefPane.getErrorCaretListener().updateHighlight(pos);
6833          
6834          // Update FileChoosers' directory
6835
_setCurrentDirectory(active);
6836          
6837          // Update title and position
6838
updateFileTitle();
6839          _currentDefPane.requestFocusInWindow();
6840          _posListener.updateLocation();
6841          
6842          // update display (adding "*") in navigatgorPane
6843
if (isModified) _model.getDocumentNavigator().repaint();
6844          
6845          try { active.revertIfModifiedOnDisk(); }
6846          catch (FileMovedException fme) { _showFileMovedError(fme); }
6847          catch (IOException e) { _showIOError(e); }
6848          
6849          // Change Find/Replace to the new defpane
6850
if (_findReplace.isDisplayed()) {
6851            _findReplace.stopListening();
6852            _findReplace.beginListeningTo(_currentDefPane);
6853            //uninstallFindReplaceDialog(_findReplace);
6854
//installFindReplaceDialog(_findReplace);
6855
}
6856        }
6857      });
6858    }
6859    
6860    public void focusOnDefinitionsPane() {
6861      _currentDefPane.requestFocusInWindow();
6862    }
6863    
6864    public void interactionStarted() {
6865      Utilities.invokeLater(new Runnable JavaDoc() {
6866        public void run() {
6867          _disableInteractionsPane();
6868          _runAction.setEnabled(false);
6869          _runProjectAction.setEnabled(false);
6870        }
6871      });
6872    }
6873    
6874    public void interactionEnded() {
6875      Utilities.invokeLater(new Runnable JavaDoc() {
6876        public void run() {
6877          _enableInteractionsPane();
6878          _runAction.setEnabled(true);
6879          _runProjectAction.setEnabled(_model.isProjectActive());
6880        }
6881      });
6882    }
6883    
6884    public void interactionErrorOccurred(final int offset, final int length) {
6885      Utilities.invokeLater(new Runnable JavaDoc() { public void run() { _interactionsPane.highlightError(offset, length); } });
6886    }
6887    
6888    /** Called when the active interpreter is changed.
6889     * @param inProgress Whether the new interpreter is currently in progress
6890     * with an interaction (ie. whether an interactionEnded event will be fired)
6891     */

6892    public void interpreterChanged(final boolean inProgress) {
6893      Utilities.invokeLater(new Runnable JavaDoc() {
6894        public void run() {
6895          _runAction.setEnabled(! inProgress);
6896          _runProjectAction.setEnabled(! inProgress);
6897          if (inProgress) _disableInteractionsPane();
6898          else _enableInteractionsPane();
6899        }
6900      });
6901    }
6902    
6903    public void compileStarted() {
6904      // Only change GUI from event-dispatching thread
6905
Utilities.invokeLater(new Runnable JavaDoc() {
6906        public void run() {
6907// hourglassOn();
6908
showTab(_compilerErrorPanel);
6909          _compilerErrorPanel.setCompilationInProgress();
6910          _saveAction.setEnabled(false);
6911        }
6912      });
6913    }
6914    
6915    public void compileEnded(File workDir, final List JavaDoc<? extends File> excludedFiles) {
6916      // Only change GUI from event-dispatching thread
6917
Utilities.invokeLater(new Runnable JavaDoc() {
6918        public void run() {
6919// try {
6920
_compilerErrorPanel.reset(excludedFiles.toArray(new File[0]));
6921          if (isDebuggerReady()) {
6922// _model.getActiveDocument().checkIfClassFileInSync();
6923

6924            _updateDebugStatus();
6925          }
6926// }
6927
// finally { hourglassOff(); }
6928
if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue()) &&
6929              (_model.getBuildDirectory() != null)) {
6930            _scanClassFiles();
6931          }
6932          _model.refreshActiveDocument();
6933        }
6934      });
6935    }
6936    
6937    public void runStarted(final OpenDefinitionsDocument doc) {
6938      // Only change GUI from event-dispatching thread
6939
Utilities.invokeLater(new Runnable JavaDoc() {
6940        public void run() {
6941          // Switch to the interactions pane to show results.
6942
showTab(_interactionsPane);
6943        }
6944      });
6945    }
6946    
6947    public void junitStarted() {
6948      /* Note: simpleHourglassOn() is done by various junit commands (other than junitClasses); hourglass must be off
6949       * for actual testing; the balancing simpleHourglassOff() is located here and in nonTestCase */

6950      
6951      // Only change GUI from event-dispatching thread
6952
// new ScrollableDialog(null, "junitStarted(" + docs + ") called in MainFrame", "", "").show();
6953
Utilities.invokeLater(new Runnable JavaDoc() {
6954        public void run() {
6955          // new ScrollableDialog(null, "Ready for hourglassOn in junitStarted", "", "").show();
6956

6957          try { showTab(_junitErrorPanel);
6958            _junitErrorPanel.setJUnitInProgress();
6959            // _junitAction.setEnabled(false);
6960
// _junitAllAction.setEnabled(false);
6961
}
6962          finally { hourglassOff(); }
6963        }
6964      });
6965    }
6966    
6967    /** We are junit'ing a specific list of classes given their source files. */
6968    public void junitClassesStarted() {
6969      // Only change GUI from event-dispatching thread
6970
// new ScrollableDialog(null, "junitClassesStarted called in MainFrame", "", "").show();
6971
Utilities.invokeLater(new Runnable JavaDoc() {
6972        public void run() {
6973// new ScrollableDialog(null, "Ready for hourglassOn in junitClassesStarted", "", "").show();
6974
// hourglassOn();
6975
showTab(_junitErrorPanel);
6976          _junitErrorPanel.setJUnitInProgress();
6977          // _junitAction.setEnabled(false);
6978
// _junitAllAction.setEnabled(false);
6979
} // no hourglassOff here because junitClasses does not perform hourglassOn
6980
});
6981    }
6982    
6983    //public void junitRunning() { }
6984

6985    public void junitSuiteStarted(final int numTests) {
6986      Utilities.invokeLater(new Runnable JavaDoc() { public void run() { _junitErrorPanel.progressReset(numTests); } });
6987    }
6988    
6989    public void junitTestStarted(final String JavaDoc name) {
6990      Utilities.invokeLater(new Runnable JavaDoc() {
6991        public void run() { _junitErrorPanel.getErrorListPane().testStarted(name); /* this does nothing! */ }
6992      });
6993    }
6994    
6995    public void junitTestEnded(final String JavaDoc name, final boolean succeeded, final boolean causedError) {
6996// new ScrollableDialog(null, "junitTestEnded(" + name + ", " + succeeded + ", " + causedError + ")", "", "").show();
6997
// syncUI...?
6998
Utilities.invokeLater(new Runnable JavaDoc() {
6999        public void run() {
7000          _junitErrorPanel.getErrorListPane().testEnded(name, succeeded, causedError); // this does nothing!
7001
_junitErrorPanel.progressStep(succeeded);
7002          _model.refreshActiveDocument();
7003        }
7004      });
7005    }
7006    
7007    public void junitEnded() {
7008      // Only change GUI from event-dispatching thread
7009
// new ScrollableDialog(null, "MainFrame.junitEnded() called", "", "").show();
7010
Utilities.invokeLater(new Runnable JavaDoc() {
7011        public void run() {
7012          try {
7013            _restoreJUnitActionsEnabled();
7014            _junitErrorPanel.reset();
7015            _model.refreshActiveDocument();
7016          }
7017          finally {
7018// new ScrollableDialog(null, "MainFrame.junitEnded() ready to return", "", "").show();
7019
// hourglassOff();
7020
}
7021        }
7022      });
7023    }
7024    
7025    /** Fire just before javadoc asynchronous thread is started. Only runs in the event thread. */
7026    public void javadocStarted() {
7027      
7028// // Only change GUI from event-dispatching thread
7029
// Runnable command = new Runnable() {
7030
// public void run() {
7031
// // if we don't lock edits, our error highlighting might break
7032
hourglassOn();
7033      
7034      showTab(_javadocErrorPanel);
7035      _javadocErrorPanel.setJavadocInProgress();
7036      _javadocAllAction.setEnabled(false);
7037      _javadocCurrentAction.setEnabled(false);
7038// }
7039
// };
7040
// Utilities.invokeLater(command);
7041
}
7042    
7043
7044    public void javadocEnded(final boolean success, final File destDir, final boolean allDocs) {
7045      // Only change GUI from event-dispatching thread
7046
Runnable JavaDoc command = new Runnable JavaDoc() {
7047        public void run() {
7048          try {
7049            showTab(_javadocErrorPanel);
7050            _javadocAllAction.setEnabled(true);
7051            _javadocCurrentAction.setEnabled(true);
7052            _javadocErrorPanel.reset();
7053            _model.refreshActiveDocument();
7054          }
7055          finally { hourglassOff(); }
7056          
7057          // Display the results.
7058
if (success) {
7059            String JavaDoc className;
7060            try {
7061              className = _model.getActiveDocument().getQualifiedClassName();
7062              className = className.replace('.', File.separatorChar);
7063            }
7064            catch (ClassNameNotFoundException cnf) {
7065              // If there is no class name, pass the empty string as a flag.
7066
// We don't want to blow up here.
7067
className = "";
7068            }
7069            try {
7070              String JavaDoc fileName = (allDocs || className.equals("")) ?
7071                "index.html" : (className + ".html");
7072              File index = new File(destDir, fileName);
7073              URL JavaDoc address = FileOps.toURL(index.getAbsoluteFile());
7074
7075              if (! PlatformFactory.ONLY.openURL(address)) {
7076                JavadocFrame _javadocFrame = new JavadocFrame(destDir, className, allDocs);
7077                _javadocFrame.setVisible(true);
7078              }
7079            }
7080            catch (MalformedURLException JavaDoc me) { throw new UnexpectedException(me); }
7081            catch (IllegalStateException JavaDoc ise) {
7082              // JavadocFrame couldn't find any output files!
7083
// Display a message.
7084
String JavaDoc msg =
7085                "Javadoc completed successfully, but did not produce any HTML files.\n" +
7086                "Please ensure that your access level in Preferences is appropriate.";
7087              JOptionPane.showMessageDialog(MainFrame.this, msg,
7088                                            "No output to display.",
7089                                            JOptionPane.INFORMATION_MESSAGE);
7090            }
7091          }
7092        }
7093      };
7094      Utilities.invokeLater(command);
7095    }
7096    
7097    public void interpreterExited(final int status) {
7098      // Only show prompt if option is set and not in TEST_MODE
7099
if (DrJava.getConfig().getSetting(INTERACTIONS_EXIT_PROMPT).booleanValue() && ! Utilities.TEST_MODE &&
7100          MainFrame.this.isVisible()) {
7101        // Synchronously pop up a dialog box concerning restarting the JVM.
7102
Utilities.invokeAndWait(new Runnable JavaDoc() {
7103          public void run() {
7104            String JavaDoc msg = "The interactions window was terminated by a call " +
7105              "to System.exit(" + status + ").\n" +
7106              "The interactions window will now be restarted.";
7107            
7108            String JavaDoc title = "Interactions terminated by System.exit(" + status + ")";
7109            
7110            ConfirmCheckBoxDialog dialog =
7111              new ConfirmCheckBoxDialog(MainFrame.this, title, msg,
7112                                        "Do not show this message again",
7113                                        JOptionPane.INFORMATION_MESSAGE,
7114                                        JOptionPane.DEFAULT_OPTION);
7115            if (dialog.show() == JOptionPane.OK_OPTION && dialog.getCheckBoxValue()) {
7116              DrJava.getConfig().setSetting(INTERACTIONS_EXIT_PROMPT, Boolean.FALSE);
7117            }
7118          }
7119        });
7120      }
7121    }
7122    
7123    public void interpreterResetFailed(Throwable JavaDoc t) { interpreterReady(FileOption.NULL_FILE); }
7124    
7125    public void interpreterResetting() {
7126      // Only change GUI from event-dispatching thread
7127
Runnable JavaDoc command = new Runnable JavaDoc() {
7128        public void run() {
7129          Debugger dm = _model.getDebugger();
7130// if (dm.isAvailable() && dm.isReady()) dm.shutdown();
7131
// _resetInteractionsAction.setEnabled(false);
7132
_junitAction.setEnabled(false);
7133          _junitAllAction.setEnabled(false);
7134          _junitProjectAction.setEnabled(false);
7135          _runAction.setEnabled(false);
7136          _runProjectAction.setEnabled(false);
7137          _closeInteractionsScript();
7138          _interactionsPane.setEditable(false);
7139          _interactionsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
7140          if (_showDebugger) _toggleDebuggerAction.setEnabled(false);
7141        }
7142      };
7143      Utilities.invokeLater(command);
7144    }
7145    
7146    public void interpreterReady(File wd) {
7147      // Only change GUI from event-dispatching thread
7148
Runnable JavaDoc command = new Runnable JavaDoc() {
7149        public void run() {
7150          interactionEnded();
7151          _runAction.setEnabled(true);
7152          _runProjectAction.setEnabled(_model.isProjectActive());
7153          _junitAction.setEnabled(true);
7154          _junitAllAction.setEnabled(true);
7155          _junitProjectAction.setEnabled(_model.isProjectActive());
7156// This action should not be enabled until the slave JVM is used
7157
// _resetInteractionsAction.setEnabled(true);
7158
if (_showDebugger) {
7159            _toggleDebuggerAction.setEnabled(true);
7160          }
7161// Moved this line here from interpreterResetting since
7162
// it was possible to get an InputBox in InteractionsController
7163
// between interpreterResetting and interpreterReady.
7164
// Fixes bug #917054 "Interactions Reset Bug".
7165
_interactionsController.interruptConsoleInput();
7166        }
7167      };
7168      Utilities.invokeLater(command);
7169    }
7170    
7171    public void slaveJVMUsed() { /* _resetInteractionsAction.setEnabled(true); */ }
7172    
7173    public void consoleReset() { }
7174    
7175    public void saveBeforeCompile() {
7176      // The following event thread switch supports legacy test code that calls compile methods outside of the
7177
// event thread. The wait is necessary because compilation process cannot proceed until saving is complete.
7178
Utilities.invokeAndWait(new Runnable JavaDoc() {
7179        public void run() {
7180          _saveAllBeforeProceeding
7181            ("To compile, you must first save ALL modified files.\n" + "Would you like to save and then compile?",
7182             ALWAYS_SAVE_BEFORE_COMPILE,
7183             "Always save before compiling");
7184        }
7185      });
7186    }
7187    
7188    /** Compile all open source files if this option is configured or running as a unit test. Otherwise, pop up a
7189      * dialog to ask if all open source files should be compiled in order to test the program.
7190      */

7191    public void compileBeforeJUnit(final CompilerListener testAfterCompile) {
7192// System.err.println("in compileBeforeJUnit, TEST_MODE = " + Utilities.TEST_MODE);
7193
if (DrJava.getConfig().getSetting(ALWAYS_COMPILE_BEFORE_JUNIT).booleanValue() || Utilities.TEST_MODE) {
7194        // Compile all open source files
7195
_model.getCompilerModel().addListener(testAfterCompile); // listener removes itself
7196
_compileAll();
7197      }
7198      else { // pop up a window to ask if all open files should be compiled before testing
7199
Utilities.invokeLater(new Runnable JavaDoc() {
7200          public void run() {
7201            String JavaDoc title = "Must Compile All Source Files to Run Unit Tests";
7202            String JavaDoc msg = "To unit test all documents, you must first compile all out of sync source files.\n" +
7203              "Would you like to compile all files and run the specified test?";
7204            int rc = JOptionPane.showConfirmDialog(MainFrame.this, msg, title, JOptionPane.YES_NO_OPTION);
7205            
7206            switch (rc) {
7207              case JOptionPane.YES_OPTION: // compile all open source files and test
7208
_model.getCompilerModel().addListener(testAfterCompile); // listener removes itself
7209
_compileAll();
7210                break;
7211              case JOptionPane.CLOSED_OPTION:
7212              case JOptionPane.NO_OPTION: // abort unit testing
7213
_model.getJUnitModel().nonTestCase(true); // cleans up
7214
break;
7215              default:
7216                throw new UnexpectedException("Invalid returnCode from showConfirmDialog: " + rc);
7217            }
7218          }
7219        });
7220      }
7221    }
7222                              
7223    public void saveBeforeJavadoc() {
7224      Utilities.invokeLater(new Runnable JavaDoc() {
7225        public void run() {
7226          _saveAllBeforeProceeding
7227            ("To run Javadoc, you must first save ALL modified files.\n" +
7228             "Would you like to save and then run Javadoc?", ALWAYS_SAVE_BEFORE_JAVADOC,
7229             "Always save before running Javadoc");
7230        }
7231      });
7232    }
7233    
7234    /** Helper method shared by all "saveBeforeX" methods. In JUnit tests, YES option is automatically selected
7235      * @param message a prompt message to be displayed to the user
7236      * @param option the BooleanOption for the prompt dialog checkbox
7237      * @param checkMsg the description of the checkbox ("Always save before X")
7238      */

7239    private void _saveAllBeforeProceeding(String JavaDoc message, BooleanOption option, String JavaDoc checkMsg) {
7240// new ScrollableDialog(null, "saveBeforeProceeding called in MainFrame", "", "").show();
7241
if (_model.hasModifiedDocuments()) {
7242        if (! DrJava.getConfig().getSetting(option).booleanValue() && ! Utilities.TEST_MODE) {
7243          ConfirmCheckBoxDialog dialog =
7244            new ConfirmCheckBoxDialog(MainFrame.this, "Must Save All Files to Continue", message, checkMsg);
7245          int rc = dialog.show();
7246          
7247          switch (rc) {
7248            case JOptionPane.YES_OPTION:
7249              _saveAll();
7250              // Only remember checkbox if they say yes
7251
if (dialog.getCheckBoxValue()) DrJava.getConfig().setSetting(option, Boolean.TRUE);
7252              break;
7253            case JOptionPane.NO_OPTION:
7254            case JOptionPane.CANCEL_OPTION:
7255            case JOptionPane.CLOSED_OPTION:
7256              // do nothing
7257
break;
7258            default:
7259              throw new RuntimeException JavaDoc("Invalid rc from showConfirmDialog: " + rc);
7260          }
7261        }
7262        else _saveAll();
7263      }
7264    }
7265    
7266    /** Saves the active document which is untitled. */
7267    public void saveUntitled() { _saveAs(); }
7268    
7269    public void filePathContainsPound() {
7270      Utilities.invokeLater(new Runnable JavaDoc() {
7271        public void run() {
7272          if (DrJava.getConfig().getSetting(WARN_PATH_CONTAINS_POUND).booleanValue()) {
7273            String JavaDoc msg =
7274              "Files whose paths contain the '#' symbol cannot be used in the\n" +
7275              "Interactions Pane due to a bug in Java's file to URL conversion.\n" +
7276              "It is suggested that you change the name of the directory\n" +
7277              "containing the '#' symbol.";
7278            
7279            String JavaDoc title = "Path Contains Pound Sign";
7280            
7281            ConfirmCheckBoxDialog dialog =
7282              new ConfirmCheckBoxDialog(MainFrame.this, title, msg,
7283                                        "Do not show this message again",
7284                                        JOptionPane.WARNING_MESSAGE,
7285                                        JOptionPane.DEFAULT_OPTION);
7286            if (dialog.show() == JOptionPane.OK_OPTION && dialog.getCheckBoxValue()) {
7287              DrJava.getConfig().setSetting(WARN_PATH_CONTAINS_POUND, Boolean.FALSE);
7288            }
7289          }
7290        }
7291      });
7292    }
7293    
7294    /** Event that is fired with there is nothing to test. JUnit is never started. */
7295    public void nonTestCase(boolean isTestAll) {
7296      
7297// Utilities.showStackTrace(new UnexpectedException("We should not have called nonTestCase"));
7298

7299      final String JavaDoc message = isTestAll ?
7300        "There are no compiled JUnit TestCases available for execution.\n" +
7301        "Perhaps you have not yet compiled your test files."
7302        :
7303        "The current document is not a valid JUnit test case.\n" +
7304        "Please make sure that:\n" +
7305        "- it has been compiled and\n" +
7306        "- it is a subclass of junit.framework.TestCase.\n";
7307
7308      // Not necessarily invoked from event-handling thread!
7309

7310      Utilities.invokeLater(new Runnable JavaDoc() {
7311        public void run() {
7312          JOptionPane.showMessageDialog(MainFrame.this, message,
7313                                        "Test Only Executes JUnit test cases",
7314                                        JOptionPane.ERROR_MESSAGE);
7315          // clean up as in JUnitEnded
7316
try {
7317            showTab(_junitErrorPanel);
7318            _junitAction.setEnabled(true);
7319            _junitAllAction.setEnabled(true);
7320            _junitProjectAction.setEnabled(_model.isProjectActive());
7321            _junitErrorPanel.reset();
7322          }
7323          finally {
7324            hourglassOff();
7325            _restoreJUnitActionsEnabled();
7326          }
7327        }});
7328    }
7329    
7330    /** Event that is fired when testing encounters an illegal class file. JUnit is never started. */
7331    public void classFileError(ClassFileError e) {
7332      
7333      final String JavaDoc message =
7334        "The class file for class " + e.getClassName() + " in source file " + e.getCanonicalPath() + " cannot be loaded.\n "
7335        + "When DrJava tries to load it, the following error is generated:\n" + e.getError();
7336      
7337      // Not necessarily invoked from event-handling thread!
7338

7339      Utilities.invokeLater(new Runnable JavaDoc() {
7340        public void run() {
7341          JOptionPane.showMessageDialog(MainFrame.this, message,
7342                                        "Testing works only on valid class files",
7343                                        JOptionPane.ERROR_MESSAGE);
7344          // clean up as junitEnded except hourglassOff (should factored into a private method)
7345
showTab(_junitErrorPanel);
7346          _junitAction.setEnabled(true);
7347          _junitAllAction.setEnabled(true);
7348          _junitProjectAction.setEnabled(_model.isProjectActive());
7349          _junitErrorPanel.reset();
7350        }});
7351    }
7352   
7353    /** Only callable from within the event-handling thread */
7354    public void currentDirectoryChanged(final File dir) { _setCurrentDirectory(dir); }
7355    
7356    /** Check if the specified document has been modified. If it has, ask the user if he would like to save it
7357      * and save the document if yes. Also give the user a "cancel" option to cancel doing the operation
7358      * that got us here in the first place.
7359      *
7360      * @return A boolean indicating whether the user cancelled the save process. False means cancel.
7361      */

7362    public boolean canAbandonFile(OpenDefinitionsDocument doc) {
7363      return _fileSaveHelper(doc, JOptionPane.YES_NO_CANCEL_OPTION);
7364    }
7365    
7366    private boolean _fileSaveHelper(OpenDefinitionsDocument doc, int paneOption) {
7367      String JavaDoc text,fname;
7368      OpenDefinitionsDocument lastActive = _model.getActiveDocument();
7369      if (lastActive != doc) {
7370        _model.setActiveDocument(doc);
7371      }
7372      boolean notFound = false;
7373      try {
7374        File file = doc.getFile();
7375        if (file == null) {
7376          fname = "Untitled file";
7377          text = "Untitled file has been modified. Would you like to save it?";
7378        }
7379        else {
7380          fname = file.getName();
7381          text = fname + " has been modified. Would you like to save it?";
7382        }
7383      }
7384      catch (FileMovedException fme) {
7385        // File was deleted, but use the same name anyway
7386
fname = fme.getFile().getName();
7387        text = fname + " not found on disk. Would you like to save to another file?";
7388        notFound = true;
7389      }
7390      
7391      int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "Save " + fname + "?", paneOption);
7392      switch (rc) {
7393        case JOptionPane.YES_OPTION:
7394          boolean saved = false;
7395          if (notFound) saved = _saveAs();
7396          else saved = _save();
7397          if (doc != lastActive) {
7398            _model.setActiveDocument(lastActive); // breaks when "if" clause omitted
7399
}
7400          return saved;
7401        case JOptionPane.NO_OPTION:
7402          if (doc != lastActive) {
7403          _model.setActiveDocument(lastActive); // breaks when "if" clause omitted
7404
}
7405          return true;
7406        case JOptionPane.CLOSED_OPTION:
7407        case JOptionPane.CANCEL_OPTION:
7408          return false;
7409        default: // never executed
7410
throw new RuntimeException JavaDoc("Invalid option: " + rc);
7411      }
7412    }
7413    
7414    /** Check if the current document has been modified. If it has, ask the user if he would like to save it
7415      * and save the document if yes.
7416      * @return true if quitting should continue, false if the user cancelled
7417      */

7418    public boolean quitFile(OpenDefinitionsDocument doc) { return _fileSaveHelper(doc, JOptionPane.YES_NO_CANCEL_OPTION); }
7419    
7420    /** Called to ask the listener if it is OK to revert the current document to a newer version saved on file. */
7421    public boolean shouldRevertFile(OpenDefinitionsDocument doc) {
7422      String JavaDoc fname;
7423      if (! _model.getActiveDocument().equals(doc)) {
7424        _model.setActiveDocument(doc);
7425      }
7426      try {
7427        File file = doc.getFile();
7428        if (file == null) fname = "Untitled file";
7429        else fname = file.getName();
7430      }
7431      catch (FileMovedException fme) { fname = fme.getFile().getName(); }
7432      // File was deleted, but use the same name anyway
7433

7434      String JavaDoc text = fname + " has changed on disk. Would you like to reload it?\n" +
7435        "This will discard any changes you have made.";
7436      int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, fname + " Modified on Disk",
7437                                             JOptionPane.YES_NO_OPTION);
7438      switch (rc) {
7439        case JOptionPane.YES_OPTION: return true;
7440        case JOptionPane.NO_OPTION: return false;
7441        case JOptionPane.CLOSED_OPTION:
7442        case JOptionPane.CANCEL_OPTION: return false;
7443        default: throw new RuntimeException JavaDoc("Invalid rc: " + rc);
7444      }
7445    }
7446    
7447    public void interactionIncomplete() { }
7448    
7449    /* Changes to the state */
7450    
7451    public void projectBuildDirChanged() {
7452      if (_model.getBuildDirectory() != null) {
7453        _cleanAction.setEnabled(true);
7454      }
7455      else _cleanAction.setEnabled(false);
7456    }
7457    
7458    public void projectWorkDirChanged() { }
7459      
7460    public void projectModified() {
7461// _saveProjectAction.setEnabled(_model.isProjectChanged());
7462
}
7463    
7464    public void projectClosed() {
7465      Utilities.invokeAndWait(new Runnable JavaDoc() { // Why the wait?
7466
public void run() {
7467          _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener);
7468          _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs);
7469          _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener);
7470// new ScrollableDialog(null, "Closing JUnit Error Panel in MainFrame", "", "").show();
7471
removeTab(_junitErrorPanel);
7472          _runButton = _updateToolbarButton(_runButton, _runAction);
7473          _compileButton = _updateToolbarButton(_compileButton, _compileAllAction);
7474          _junitButton = _updateToolbarButton(_junitButton, _junitAllAction);
7475          projectRunnableChanged();
7476        }
7477      });
7478    }
7479    
7480    public void projectOpened(File projectFile, FileOpenSelector files) {
7481      _setUpContextMenus();
7482      projectRunnableChanged();
7483      _compileButton = _updateToolbarButton(_compileButton, _compileProjectAction);
7484      _junitButton = _updateToolbarButton(_junitButton, _junitProjectAction);
7485      _recentProjectManager.updateOpenFiles(projectFile);
7486      open(files);
7487      _openProjectUpdate();
7488      _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener);
7489      _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs);
7490      _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener);
7491      _model.refreshActiveDocument();
7492    }
7493    
7494    public void projectRunnableChanged() {
7495      if (_model.getMainClass() != null && _model.getMainClass().exists()) {
7496        _runProjectAction.setEnabled(_model.isProjectActive());
7497        _runButton = _updateToolbarButton(_runButton, _runProjectAction);
7498      }
7499      else {
7500        _runProjectAction.setEnabled(false);
7501        _runButton = _updateToolbarButton(_runButton, _runAction);
7502      }
7503    }
7504    
7505    public void documentNotFound(OpenDefinitionsDocument d, File f) {
7506      
7507      _model.setProjectChanged(true);
7508     
7509      String JavaDoc text = "File " + f.getAbsolutePath() +
7510        "\ncould not be found on disk! It was probably moved\n" +
7511        "or deleted. Would you like to try to find it?";
7512      int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "File Moved or Deleted", JOptionPane.YES_NO_OPTION);
7513      if (rc == JOptionPane.NO_OPTION) return;
7514      if (rc == JOptionPane.YES_OPTION) {
7515        try {
7516          File[] opened = _openSelector.getFiles();
7517          d.setFile(opened[0]);
7518        }
7519        catch(OperationCanceledException oce) {
7520          // Interpret cancelled as "NO"
7521
}
7522      }
7523// The following line was commented out because it breaks when a user want to close but not save a deleted file
7524
// else throw new DocumentClosedException(d,"Document in " + f + "closed unexpectedly"); // misnamed exception
7525
}
7526  } // End of ModelListener class
7527

7528  public JViewport getDefViewport() {
7529    OpenDefinitionsDocument doc = _model.getActiveDocument();
7530// new ScrollableDialog(null, "Active Document is " + doc, "", "").show();
7531
JScrollPane defScroll = _defScrollPanes.get(doc);
7532    return defScroll.getViewport();
7533  }
7534  
7535  public void removeTab(final Component c) {
7536    Utilities.invokeLater(new Runnable JavaDoc() {
7537      public void run() {
7538        if(_tabbedPane.getTabCount() > 1) {
7539          if(_tabbedPane.getSelectedIndex() == _tabbedPane.getTabCount() - 1)
7540            _tabbedPane.setSelectedIndex(_tabbedPane.getSelectedIndex() - 1);
7541          else
7542            _tabbedPane.setSelectedIndex(_tabbedPane.getSelectedIndex() + 1);
7543        _tabbedPane.remove(c);
7544        ((TabbedPanel)c).setDisplayed(false);
7545        }
7546        _currentDefPane.requestFocusInWindow();
7547      }
7548    });
7549  }
7550  
7551  /** Shows the components passed in in the appropriate place in the tabbedPane depending on the position of
7552    * the component in the _tabs list.
7553    * @param c the component to show in the tabbedPane
7554    */

7555  public void showTab(final Component c) {
7556    
7557    // This retarded method doesn't work for our two always-on tabs, so here's a temporary kludge.
7558
Utilities.invokeLater(new Runnable JavaDoc() {
7559      public void run() {
7560        int numVisible = 0;
7561        if (c == _interactionsPane) _tabbedPane.setSelectedIndex(0);
7562        else if (c == _consolePane) _tabbedPane.setSelectedIndex(1);
7563        else {
7564          for (TabbedPanel tp: _tabs) {
7565            if (tp == c) {
7566              // 2 right now is a magic number for the number of tabs always visible
7567
// interactions & console
7568
if (! tp.isDisplayed()) {
7569                _tabbedPane.insertTab(tp.getName(), null, tp, null, numVisible + 2);
7570                tp.setDisplayed(true);
7571              }
7572              _tabbedPane.setSelectedIndex(numVisible + 2);
7573              
7574              c.requestFocusInWindow();
7575              return;
7576            }
7577            if (tp.isDisplayed()) numVisible++;
7578          }
7579        }
7580      }
7581    });
7582  }
7583  
7584  /**
7585   * Sets the location of the main divider.
7586   * (not currently used)
7587   private void _setDividerLocation() {
7588   int divLocation = _mainSplit.getHeight() -
7589   _mainSplit.getDividerSize() -
7590   (int)_tabbedPane.getMinimumSize().getHeight();
7591   if (_mainSplit.getDividerLocation() > divLocation)
7592   _mainSplit.setDividerLocation(divLocation);
7593   }*/

7594  
7595  /** Warns the user that the current file is open and query them if they wish to save over the currently open file. */
7596  private boolean _warnFileOpen(File f) {
7597    OpenDefinitionsDocument d = null;
7598    try { d = _model.getDocumentForFile(f); }
7599    catch(IOException ioe) { /* do nothing */ }
7600    Object JavaDoc[] options = {"Yes","No"};
7601    if (d == null) return false;
7602    boolean dMod = d.isModifiedSinceSave();
7603    String JavaDoc msg = "This file is already open in DrJava" + (dMod ? " and has been modified" : "") +
7604      ". Do you wish to overwrite it?";
7605    int choice = JOptionPane.showOptionDialog(MainFrame.this, msg, "File Open Warning", JOptionPane.YES_NO_OPTION,
7606                                              JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
7607    if (choice == JOptionPane.YES_OPTION) return _model.closeFileWithoutPrompt(d);
7608    return false;
7609  }
7610  
7611  /**
7612   * Confirms with the user that the file should be overwritten.
7613   * @return <code>true</code> iff the user accepts overwriting.
7614   */

7615  private boolean _verifyOverwrite() {
7616    Object JavaDoc[] options = {"Yes","No"};
7617    int n = JOptionPane.showOptionDialog(MainFrame.this,
7618                                         "This file already exists. Do you wish to overwrite the file?",
7619                                         "Confirm Overwrite",
7620                                         JOptionPane.YES_NO_OPTION,
7621                                         JOptionPane.QUESTION_MESSAGE,
7622                                         null,
7623                                         options,
7624                                         options[1]);
7625    return (n == JOptionPane.YES_OPTION);
7626  }
7627  
7628  /* Pops up a message and cleans up after unit testing has been interrupted. */
7629  private void _junitInterrupted(final UnexpectedException e) {
7630    Utilities.invokeLater(new Runnable JavaDoc() {
7631      public void run() {
7632        _showJUnitInterrupted(e);
7633        removeTab(_junitErrorPanel);
7634        _model.refreshActiveDocument();
7635        // hourglassOff();
7636
}
7637    });
7638  }
7639      
7640  boolean isDebuggerReady() { return _showDebugger && _model.getDebugger().isReady(); }
7641  
7642  /** Return the find replace dialog. Package protected for use in tests. */
7643  FindReplacePanel getFindReplaceDialog() { return _findReplace; }
7644  
7645  /** Builds the Hashtables in KeyBindingManager that are used to keep track of key-bindings and allows for live
7646    * updating, conflict resolution, and intelligent error messages (the ActionToNameMap).
7647    * IMPORTANT: Don't use this way to put actions into the KeyBindingManager if the action is a menu item. It will
7648    * already have been put in. Putting in again will cause bug #803304 "Uncomment lines wont rebind".
7649    */

7650  private void _setUpKeyBindingMaps() {
7651    final ActionMap _actionMap = _currentDefPane.getActionMap();
7652    
7653    KeyBindingManager.Singleton.put(KEY_BACKWARD, _actionMap.get(DefaultEditorKit.backwardAction), null, "Backward");
7654    KeyBindingManager.Singleton.addShiftAction(KEY_BACKWARD, DefaultEditorKit.selectionBackwardAction);
7655    
7656    KeyBindingManager.Singleton.put(KEY_BEGIN_DOCUMENT, _actionMap.get(DefaultEditorKit.beginAction), null,
7657                                    "Begin Document");
7658    KeyBindingManager.Singleton.addShiftAction(KEY_BEGIN_DOCUMENT, DefaultEditorKit.selectionBeginAction);
7659    
7660// KeyBindingManager.Singleton.put(KEY_BEGIN_LINE, _actionMap.get(DefaultEditorKit.beginLineAction), null,
7661
// "Begin Line");
7662
KeyBindingManager.Singleton.put(KEY_BEGIN_LINE, _beginLineAction, null, "Begin Line");
7663// KeyBindingManager.Singleton.addShiftAction(KEY_BEGIN_LINE,
7664
// DefaultEditorKit.selectionBeginLineAction);
7665
KeyBindingManager.Singleton.addShiftAction(KEY_BEGIN_LINE, _selectionBeginLineAction);
7666    
7667    KeyBindingManager.Singleton.put(KEY_PREVIOUS_WORD, _actionMap.get(DefaultEditorKit.previousWordAction), null,
7668                                    "Previous Word");
7669    KeyBindingManager.Singleton.addShiftAction(KEY_PREVIOUS_WORD, DefaultEditorKit.selectionPreviousWordAction);
7670    
7671    KeyBindingManager.Singleton.put(KEY_DOWN, _actionMap.get(DefaultEditorKit.downAction), null, "Down");
7672    KeyBindingManager.Singleton.addShiftAction(KEY_DOWN, DefaultEditorKit.selectionDownAction);
7673    
7674    KeyBindingManager.Singleton.put(KEY_END_DOCUMENT, _actionMap.get(DefaultEditorKit.endAction), null, "End Document");
7675    KeyBindingManager.Singleton.addShiftAction(KEY_END_DOCUMENT, DefaultEditorKit.selectionEndAction);
7676    
7677    KeyBindingManager.Singleton.put(KEY_END_LINE, _actionMap.get(DefaultEditorKit.endLineAction), null, "End Line");
7678    KeyBindingManager.Singleton.addShiftAction(KEY_END_LINE, DefaultEditorKit.selectionEndLineAction);
7679    
7680    KeyBindingManager.Singleton.put(KEY_NEXT_WORD, _actionMap.get(DefaultEditorKit.nextWordAction), null, "Next Word");
7681    KeyBindingManager.Singleton.addShiftAction(KEY_NEXT_WORD, DefaultEditorKit.selectionNextWordAction);
7682    
7683    KeyBindingManager.Singleton.put(KEY_FORWARD, _actionMap.get(DefaultEditorKit.forwardAction), null, "Forward");
7684    KeyBindingManager.Singleton.addShiftAction(KEY_FORWARD, DefaultEditorKit.selectionForwardAction);
7685    
7686    KeyBindingManager.Singleton.put(KEY_UP, _actionMap.get(DefaultEditorKit.upAction), null, "Up");
7687    KeyBindingManager.Singleton.addShiftAction(KEY_UP, DefaultEditorKit.selectionUpAction);
7688    
7689    // These last methods have no default selection methods
7690
KeyBindingManager.Singleton.put(KEY_PAGE_DOWN, _actionMap.get(DefaultEditorKit.pageDownAction), null, "Page Down");
7691    KeyBindingManager.Singleton.put(KEY_PAGE_UP, _actionMap.get(DefaultEditorKit.pageUpAction), null, "Page Up");
7692    KeyBindingManager.Singleton.put(KEY_CUT_LINE, _cutLineAction, null, "Cut Line");
7693    KeyBindingManager.Singleton.put(KEY_CLEAR_LINE, _clearLineAction, null, "Clear Line");
7694    KeyBindingManager.Singleton.put(KEY_SHIFT_DELETE_PREVIOUS, _actionMap.get(DefaultEditorKit.deletePrevCharAction),
7695                                    null, "Delete Previous");
7696    KeyBindingManager.Singleton.put(KEY_SHIFT_DELETE_NEXT, _actionMap.get(DefaultEditorKit.deleteNextCharAction),
7697                                    null, "Delete Next");
7698  }
7699  
7700  /** @param listener The ComponentListener to add to the open documents list
7701   * This method allows for testing of the dancing UI (See MainFrameTest.testDancingUI()).
7702   */

7703  public void addComponentListenerToOpenDocumentsList(ComponentListener listener) {
7704    _docSplitPane.getLeftComponent().addComponentListener(listener);
7705  }
7706  
7707  /**For test purposes only. Returns the text in the status bar. Is used to test brace matching*/
7708  public String JavaDoc getFileNameField() { return _fileNameField.getText(); }
7709  
7710  /**For test purposes only. Returns the edit menu*/
7711  public JMenu getEditMenu() { return _editMenu; }
7712  
7713  /** The OptionListener for FONT_MAIN */
7714  private class MainFontOptionListener implements OptionListener<Font> {
7715    public void optionChanged(OptionEvent<Font> oce) { _setMainFont(); }
7716  }
7717  
7718  /** The OptionListener for FONT_LINE_NUMBERS */
7719  private class LineNumbersFontOptionListener implements OptionListener<Font> {
7720    public void optionChanged(OptionEvent<Font> oce) { _updateLineNums(); }
7721  }
7722  
7723  /** The OptionListener for FONT_DOCLIST */
7724  private class DoclistFontOptionListener implements OptionListener<Font> {
7725    public void optionChanged(OptionEvent<Font> oce) {
7726      Font doclistFont = DrJava.getConfig().getSetting(FONT_DOCLIST);
7727      _model.getDocCollectionWidget().setFont(doclistFont);
7728    }
7729  }
7730  
7731  /** The OptionListener for FONT_TOOLBAR */
7732  private class ToolbarFontOptionListener implements OptionListener<Font> {
7733    public void optionChanged(OptionEvent<Font> oce) { _updateToolbarButtons(); }
7734  }
7735  
7736  /** The OptionListener for DEFINITIONS_NORMAL_COLOR */
7737  private class NormalColorOptionListener implements OptionListener<Color> {
7738    public void optionChanged(OptionEvent<Color> oce) { _updateNormalColor(); }
7739  }
7740  
7741  /** The OptionListener for DEFINITIONS_BACKGROUND_COLOR */
7742  private class BackgroundColorOptionListener implements OptionListener<Color> {
7743    public void optionChanged(OptionEvent<Color> oce) { _updateBackgroundColor(); }
7744  }
7745  
7746  /** The OptionListener for TOOLBAR options */
7747  private class ToolbarOptionListener implements OptionListener<Boolean JavaDoc> {
7748    public void optionChanged(OptionEvent<Boolean JavaDoc> oce) { _updateToolbarButtons(); }
7749  }
7750  
7751  /** The OptionListener for LINEENUM_ENABLED. */
7752  private class LineEnumOptionListener implements OptionListener<Boolean JavaDoc> {
7753    public void optionChanged(OptionEvent<Boolean JavaDoc> oce) { _updateDefScrollRowHeader(); }
7754  }
7755  
7756  /** The OptionListener for QUIT_PROMPT. */
7757  private class QuitPromptOptionListener implements OptionListener<Boolean JavaDoc> {
7758    public void optionChanged(OptionEvent<Boolean JavaDoc> oce) { _promptBeforeQuit = oce.value.booleanValue(); }
7759  }
7760  
7761  /** The OptionListener for RECENT_FILES_MAX_SIZE. */
7762  private class RecentFilesOptionListener implements OptionListener<Integer JavaDoc> {
7763    public void optionChanged(OptionEvent<Integer JavaDoc> oce) {
7764      _recentFileManager.updateMax(oce.value.intValue());
7765      _recentFileManager.numberItems();
7766      _recentProjectManager.updateMax(oce.value.intValue());
7767      _recentProjectManager.numberItems();
7768    }
7769  }
7770  
7771  private class LastFocusListener extends FocusAdapter {
7772    public void focusGained(FocusEvent e) { _lastFocusOwner = e.getComponent(); }
7773  };
7774  
7775  
7776  /** Wrapper for setPopupLoc(Window, Component) that uses the window's owner as the owner to center the popup on.
7777    * @param popup the Popup window
7778    */

7779  public void setPopupLoc(Window popup) {
7780    MainFrame.setPopupLoc(popup, (popup.getOwner()!=null)?popup.getOwner():this);
7781  }
7782  
7783  /** Sets the location of the popup in a consistant way. If the popup has an owner, the popup is centered over the
7784    * owner. If the popup has no owner(owner == null), the popup is centered over the first monitor. In either case,
7785    * the popup is moved and scaled if any part of it is not on the screen. This method should be called for all popups
7786    * to maintain consistancy.
7787    * @param popup the popup window
7788    * @param owner the parent component for the popup
7789    */

7790  public static void setPopupLoc(Window popup, Component owner) {
7791    Rectangle frameRect = popup.getBounds();
7792    
7793    Point ownerLoc = null;
7794    Dimension ownerSize = null;
7795    if(owner!=null) {
7796      ownerLoc = owner.getLocation();
7797      ownerSize = owner.getSize();
7798    }
7799    else {
7800      //for multi-monitor support
7801
//Question: do we want it to popup on the first monitor always?
7802
GraphicsDevice[] dev = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
7803      Rectangle rec = dev[0].getDefaultConfiguration().getBounds();
7804      ownerLoc = rec.getLocation();
7805      ownerSize = rec.getSize();
7806    }
7807    
7808    // center it on owner
7809
Point loc = new Point(ownerLoc.x + (ownerSize.width - frameRect.width) / 2,
7810                          ownerLoc.y + (ownerSize.height - frameRect.height) / 2);
7811    frameRect.setLocation(loc);
7812    
7813    // now find the GraphicsConfiguration the popup is on
7814
GraphicsConfiguration gcBest = null;
7815    int gcBestArea = -1;
7816    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
7817    GraphicsDevice[] gs = ge.getScreenDevices();
7818    for (GraphicsDevice gd: gs) {
7819      GraphicsConfiguration gc = gd.getDefaultConfiguration();
7820      Rectangle isect = frameRect.intersection(gc.getBounds());
7821      int gcArea = isect.width*isect.height;
7822      if (gcArea>gcBestArea) {
7823        gcBest = gc;
7824        gcBestArea = gcArea;
7825      }
7826    }
7827    
7828    // make it fit on the screen
7829
Rectangle screenRect = gcBest.getBounds();
7830    Dimension screenSize = screenRect.getSize();
7831    Dimension frameSize = popup.getSize();
7832
7833    if (frameSize.height > screenSize.height) frameSize.height = screenSize.height;
7834    if (frameSize.width > screenSize.width) frameSize.width = screenSize.width;
7835
7836    frameRect.setSize(frameSize);
7837    
7838    // center it on owner again
7839
loc = new Point(ownerLoc.x + (ownerSize.width - frameRect.width) / 2,
7840                    ownerLoc.y + (ownerSize.height - frameRect.height) / 2);
7841    frameRect.setLocation(loc);
7842    
7843    // now fit it on the screen
7844
if (frameRect.x < screenRect.x) frameRect.x = screenRect.x;
7845    if (frameRect.x + frameRect.width > screenRect.x + screenRect.width)
7846      frameRect.x = screenRect.x + screenRect.width - frameRect.width;
7847    
7848    if (frameRect.y < screenRect.y) frameRect.y = screenRect.y;
7849    if (frameRect.y + frameRect.height > screenRect.y + screenRect.height)
7850      frameRect.y = screenRect.y + screenRect.height - frameRect.height;
7851
7852    popup.setSize(frameRect.getSize());
7853    popup.setLocation(frameRect.getLocation());
7854  }
7855}
7856
Popular Tags