Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 10,614   Methods: 862
NCLOC: 7,736   Classes: 21
 
 Source file Conditionals Statements Methods TOTAL
MainFrame.java 17.3% 35.6% 25.4% 30.6%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.ui;
 38   
 39    import javax.swing.*;
 40    import javax.swing.border.*;
 41    import javax.swing.event.*;
 42    import javax.swing.tree.DefaultTreeModel;
 43    import javax.swing.text.*;
 44    import java.awt.event.*;
 45    import java.awt.*;
 46    import java.awt.print.*;
 47    import java.awt.dnd.*;
 48    import java.beans.*;
 49   
 50    import java.io.*;
 51    import java.util.AbstractMap;
 52    import java.util.ArrayList;
 53    import java.util.Collection;
 54    import java.util.Enumeration;
 55    import java.util.HashMap;
 56    import java.util.HashSet;
 57    import java.util.IdentityHashMap;
 58    import java.util.List;
 59    import java.util.LinkedList;
 60    import java.util.Map;
 61    import java.util.Set;
 62    import java.util.SortedSet;
 63    import java.util.StringTokenizer;
 64    import java.util.Vector;
 65    import java.util.concurrent.Executors;
 66    import java.util.concurrent.ExecutorService;
 67    import java.util.jar.JarEntry;
 68    import java.util.jar.JarFile;
 69    import java.net.URL;
 70    import java.net.MalformedURLException;
 71    import java.awt.datatransfer.*;
 72    import java.lang.ref.WeakReference;
 73   
 74    import edu.rice.cs.drjava.DrJava;
 75    import edu.rice.cs.drjava.DrJavaRoot;
 76    import edu.rice.cs.drjava.RemoteControlClient;
 77    import edu.rice.cs.drjava.RemoteControlServer;
 78    import edu.rice.cs.drjava.platform.*;
 79    import edu.rice.cs.drjava.config.FileConfiguration;
 80    import edu.rice.cs.drjava.config.*;
 81    import edu.rice.cs.drjava.model.*;
 82    import edu.rice.cs.drjava.model.compiler.CompilerListener;
 83    import edu.rice.cs.drjava.model.compiler.CompilerModel;
 84    import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException;
 85    import edu.rice.cs.drjava.model.definitions.DefinitionsDocument;
 86    import edu.rice.cs.drjava.model.definitions.DocumentUIListener;
 87    import edu.rice.cs.drjava.model.definitions.InvalidPackageException;
 88    import edu.rice.cs.drjava.model.definitions.NoSuchDocumentException;
 89    import edu.rice.cs.drjava.model.debug.*;
 90    import edu.rice.cs.drjava.model.repl.*;
 91    import edu.rice.cs.drjava.model.javadoc.JavadocModel;
 92    import edu.rice.cs.drjava.ui.config.ConfigFrame;
 93    import edu.rice.cs.drjava.ui.predictive.PredictiveInputFrame;
 94    import edu.rice.cs.drjava.ui.predictive.PredictiveInputModel;
 95    import edu.rice.cs.drjava.ui.avail.*;
 96    import edu.rice.cs.drjava.ui.ClipboardHistoryFrame;
 97    import edu.rice.cs.drjava.ui.RegionsTreePanel;
 98    import edu.rice.cs.drjava.project.*;
 99   
 100    import edu.rice.cs.plt.concurrent.JVMBuilder;
 101    import edu.rice.cs.plt.io.IOUtil;
 102    import edu.rice.cs.plt.iter.IterUtil;
 103    import edu.rice.cs.plt.lambda.DelayedThunk;
 104    import edu.rice.cs.plt.lambda.*;
 105    import edu.rice.cs.plt.reflect.JavaVersion;
 106    import edu.rice.cs.plt.tuple.Pair;
 107   
 108    import edu.rice.cs.util.classloader.ClassFileError;
 109    import edu.rice.cs.util.docnavigation.*;
 110    import edu.rice.cs.drjava.model.FileMovedException;
 111    import edu.rice.cs.util.FileOpenSelector;
 112    import edu.rice.cs.util.FileOps;
 113    import edu.rice.cs.util.Log;
 114    import edu.rice.cs.util.OperationCanceledException;
 115    import edu.rice.cs.util.StringOps;
 116    import edu.rice.cs.util.swing.Utilities;
 117    import edu.rice.cs.util.swing.*;
 118    import edu.rice.cs.util.swing.ProcessingDialog;
 119    import edu.rice.cs.util.text.ConsoleDocument;
 120    import edu.rice.cs.util.text.SwingDocument;
 121    import edu.rice.cs.util.UnexpectedException;
 122    import edu.rice.cs.util.XMLConfig;
 123   
 124    import static edu.rice.cs.drjava.config.OptionConstants.KEY_NEW_CLASS_FILE;
 125    import static edu.rice.cs.drjava.ui.RecentFileManager.*;
 126    import static edu.rice.cs.drjava.ui.predictive.PredictiveInputModel.*;
 127    import static edu.rice.cs.util.XMLConfig.XMLConfigException;
 128    import static edu.rice.cs.plt.object.ObjectUtil.hash;
 129    import static edu.rice.cs.drjava.ui.MainFrameStatics.*;
 130   
 131    /** DrJava's main window. */
 132    public class MainFrame extends SwingFrame implements ClipboardOwner, DropTargetListener {
 133    private static final Log _log = new Log("MainFrame.txt", false);
 134   
 135    private static final int INTERACTIONS_TAB = 0;
 136    private static final int CONSOLE_TAB = 1;
 137    private static final String ICON_PATH = "/edu/rice/cs/drjava/ui/icons/";
 138    private static final String DEBUGGER_OUT_OF_SYNC =
 139    " Current document is out of sync with the debugger and should be recompiled!";
 140   
 141    /** Number of milliseconds to wait before displaying "Stepping..." message after a step is requested in
 142    * the debugger.
 143    */
 144    private static final int DEBUG_STEP_TIMER_VALUE = 3000;
 145   
 146    // ------ Field Declarations -------
 147   
 148    /** The model which controls all logic in DrJava. */
 149    private volatile AbstractGlobalModel _model;
 150   
 151    /** The main model listener attached by the main frame to the global model */
 152    private volatile ModelListener _mainListener;
 153   
 154    /** Maps an OpenDefDoc to its JScrollPane. Why doesn't OpenDefDoc contain a defScrollPane field? */
 155    private HashMap<OpenDefinitionsDocument, JScrollPane> _defScrollPanes;
 156   
 157    /** The currently displayed DefinitionsPane. */
 158    private volatile DefinitionsPane _currentDefPane;
 159   
 160    /** The currently displayed DefinitionsDocument. */
 161    private volatile DefinitionsDocument _currentDefDoc;
 162   
 163    /** The filename currently being displayed. */
 164    private volatile String _fileTitle = "";
 165   
 166    // Tabbed panel fields
 167    public final LinkedList<TabbedPanel> _tabs = new LinkedList<TabbedPanel>();
 168    public final JTabbedPane _tabbedPane = new JTabbedPane();
 169    private final LinkedList<Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>>>
 170    _findResults = new LinkedList<Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>>>();
 171   
 172    // The following three fields are conceptually final, but were downgraded to volatile to allow initialization in
 173    // the event thread;
 174    private volatile DetachedFrame _tabbedPanesFrame;
 175    public volatile Component _lastFocusOwner;
 176   
 177    private volatile CompilerErrorPanel _compilerErrorPanel;
 178    private volatile JUnitPanel _junitPanel;
 179    private volatile JavadocErrorPanel _javadocErrorPanel;
 180    private volatile FindReplacePanel _findReplace;
 181    private volatile BreakpointsPanel _breakpointsPanel;
 182    private volatile BookmarksPanel _bookmarksPanel;
 183    private volatile DebugPanel _debugPanel;
 184   
 185    private volatile InteractionsPane _consolePane;
 186    private volatile JScrollPane _consoleScroll; // redirects focus to embedded _consolePane
 187    private volatile ConsoleController _consoleController;
 188   
 189    private volatile InteractionsPane _interactionsPane;
 190    private volatile JPanel _interactionsContainer; // redirects focus to embedded _interactionsPane
 191    private volatile InteractionsController _interactionsController;
 192    private volatile InteractionsScriptController _interactionsScriptController;
 193    private volatile InteractionsScriptPane _interactionsScriptPane;
 194   
 195    private volatile boolean _showDebugger; // whether the supporting context is debugger capable
 196   
 197   
 198    private volatile DetachedFrame _debugFrame;
 199   
 200    /** Panel to hold both InteractionsPane and its sync message. */
 201   
 202    // Status bar fields
 203    private final JPanel _statusBar = new JPanel(new BorderLayout()); //( layout );
 204    private final JLabel _statusField = new JLabel();
 205    private final JLabel _statusReport = new JLabel(); //("This is the text for the center message");
 206    private final JLabel _currLocationField = new JLabel();
 207    private final PositionListener _posListener = new PositionListener();
 208   
 209    // Split panes for layout
 210    private volatile JSplitPane _docSplitPane;
 211    private volatile JSplitPane _debugSplitPane;
 212    JSplitPane _mainSplit;
 213   
 214    // private Container _docCollectionWidget;
 215    private volatile JButton _compileButton;
 216    private volatile JButton _closeButton;
 217    private volatile JButton _undoButton;
 218    private volatile JButton _redoButton;
 219    private volatile JButton _runButton;
 220    private volatile JButton _junitButton;
 221    private volatile JButton _errorsButton;
 222   
 223    private final JToolBar _toolBar = new JToolBar();
 224    private final JFileChooser _interactionsHistoryChooser = new JFileChooser();
 225   
 226    // Menu fields
 227    private final JMenuBar _menuBar = new MenuBar(this);
 228    private volatile JMenu _fileMenu;
 229    private volatile JMenu _editMenu;
 230    private volatile JMenu _toolsMenu;
 231    private volatile JMenu _projectMenu;
 232    private volatile JMenu _languageLevelMenu;
 233    private volatile JMenu _helpMenu;
 234   
 235    private volatile JMenu _debugMenu;
 236    private volatile JMenuItem _debuggerEnabledMenuItem;
 237   
 238    // Popup menus
 239    private JPopupMenu _interactionsPanePopupMenu;
 240    private JPopupMenu _consolePanePopupMenu;
 241   
 242    // Cached frames and dialogs
 243    private volatile ConfigFrame _configFrame;
 244    private final HelpFrame _helpFrame = new HelpFrame();
 245    private final QuickStartFrame _quickStartFrame = new QuickStartFrame();
 246    private volatile AboutDialog _aboutDialog;
 247    private volatile RecentDocFrame _recentDocFrame; /** Holds/shows the history of documents for ctrl-tab. */
 248   
 249    // private ProjectPropertiesFrame _projectPropertiesFrame;
 250   
 251    /** Keeps track of the recent files list in the File menu. */
 252    private volatile RecentFileManager _recentFileManager;
 253   
 254    /** Keeps track of the recent projects list in the Project menu */
 255    private volatile RecentFileManager _recentProjectManager;
 256   
 257    private volatile File _currentProjFile;
 258   
 259    /** Timer to display "Stepping..." message if a step takes longer than a certain amount of time. All accesses
 260    * must be synchronized on it.
 261    */
 262    private volatile Timer _debugStepTimer;
 263   
 264    /** Timer to step into another line of code. The delay for each step is recorded in milliseconds. */
 265    private volatile Timer _automaticTraceTimer;
 266   
 267    /** The current highlight displaying the current location, used for FindAll and the of the debugger's thread,
 268    * if there is one. If there is none, this is null.
 269    */
 270    private volatile HighlightManager.HighlightInfo _currentLocationHighlight = null;
 271   
 272    /** Table to map breakpoints to their corresponding highlight objects. */
 273    private final IdentityHashMap<Breakpoint, HighlightManager.HighlightInfo> _documentBreakpointHighlights =
 274    new IdentityHashMap<Breakpoint, HighlightManager.HighlightInfo>();
 275   
 276    /** Table to map bookmarks to their corresponding highlight objects. */
 277    private final IdentityHashMap<OrderedDocumentRegion, HighlightManager.HighlightInfo> _documentBookmarkHighlights =
 278    new IdentityHashMap<OrderedDocumentRegion, HighlightManager.HighlightInfo>();
 279   
 280    /** The timestamp for the last change to any document. */
 281    private volatile long _lastChangeTime = 0;
 282   
 283    /** Whether to display a prompt message before quitting. */
 284    private volatile boolean _promptBeforeQuit;
 285   
 286    /** Listener for Interactions JVM */
 287    volatile private ConfigOptionListeners.SlaveJVMXMXListener _slaveJvmXmxListener;
 288   
 289    /** Listener for Main JVM */
 290    volatile private ConfigOptionListeners.MasterJVMXMXListener _masterJvmXmxListener;
 291   
 292    /** GUI component availability notifier. */
 293    final DefaultGUIAvailabilityNotifier _guiAvailabilityNotifier = new DefaultGUIAvailabilityNotifier();
 294   
 295    /** Window adapter for "pseudo-modal" dialogs, i.e. non-modal dialogs that insist on keeping the focus. */
 296    protected volatile java.util.HashMap<Window,WindowAdapter> _modalWindowAdapters
 297    = new java.util.HashMap<Window,WindowAdapter>();
 298   
 299    /** The owner of the modal window listener has already been taken by another window. */
 300    protected volatile Window _modalWindowAdapterOwner = null;
 301   
 302    /** For opening files. We have a persistent dialog to keep track of the last directory from which we opened. */
 303    private volatile JFileChooser _openChooser;
 304   
 305    /** For opening project files. */
 306    private volatile JFileChooser _openProjectChooser;
 307   
 308    /** For saving files. We have a persistent dialog to keep track of the last directory from which we saved. */
 309    private volatile JFileChooser _saveChooser;
 310   
 311    /** Filter for drjava project files (.drjava and .xml and .pjt) */
 312    private final javax.swing.filechooser.FileFilter _projectFilter = new javax.swing.filechooser.FileFilter() {
 313  2280 public boolean accept(File f) {
 314  2280 return f.isDirectory() || f.getPath().endsWith(PROJECT_FILE_EXTENSION) ||
 315    f.getPath().endsWith(PROJECT_FILE_EXTENSION2) || f.getPath().endsWith(OLD_PROJECT_FILE_EXTENSION);
 316    }
 317  38 public String getDescription() {
 318  38 return "DrJava Project Files (*" + PROJECT_FILE_EXTENSION + ", *" + PROJECT_FILE_EXTENSION2 + ", *" +
 319    OLD_PROJECT_FILE_EXTENSION + ")";
 320    }
 321    };
 322   
 323    /** Filter for text files (.txt) */
 324    private final javax.swing.filechooser.FileFilter _txtFileFilter = new javax.swing.filechooser.FileFilter() {
 325  0 public boolean accept(File f) { return f.isDirectory() || f.getPath().endsWith(TEXT_FILE_EXTENSION); }
 326  0 public String getDescription() { return "Text Files (*"+TEXT_FILE_EXTENSION+")"; }
 327    };
 328   
 329    /** Filter for any files (*.*) */
 330    private final javax.swing.filechooser.FileFilter _anyFileFilter = new javax.swing.filechooser.FileFilter() {
 331  0 public boolean accept(File f) { return true; }
 332  0 public String getDescription() { return "All files (*.*)"; }
 333    };
 334   
 335    /** Thread pool for executing asynchronous tasks. */
 336    private volatile ExecutorService _threadPool = Executors.newCachedThreadPool();
 337   
 338    // ------ End Field Declarations ------
 339   
 340    /** @return the source file filter as directed by the currently selected compiler. */
 341  76 private javax.swing.filechooser.FileFilter getSourceFileFilter() {
 342  76 CompilerModel cm = _model.getCompilerModel();
 343  0 if (cm == null) return new SmartSourceFilter();
 344  76 else return cm.getActiveCompiler().getFileFilter();
 345    }
 346   
 347    /** Return the suggested file extension that will be appended to a file without extension.
 348    * @return the suggested file extension */
 349  0 private String getSuggestedFileExtension() {
 350  0 CompilerModel cm = _model.getCompilerModel();
 351  0 if (cm == null) return DrJavaFileUtils.getSuggestedFileExtension();
 352  0 else return cm.getActiveCompiler().getSuggestedFileExtension();
 353    }
 354   
 355    /** Returns the files to open to the model (command pattern). */
 356    private final FileOpenSelector _openSelector = new FileOpenSelector() {
 357  0 public File[] getFiles() throws OperationCanceledException {
 358  0 _openChooser.resetChoosableFileFilters();
 359  0 _openChooser.setFileFilter(getSourceFileFilter());
 360  0 return getOpenFiles(_openChooser);
 361    }
 362    };
 363   
 364    /** Returns the files to open to the model (command pattern). */
 365    private final FileOpenSelector _openFileOrProjectSelector = new FileOpenSelector() {
 366  0 public File[] getFiles() throws OperationCanceledException {
 367  0 _openChooser.resetChoosableFileFilters();
 368  0 _openChooser.addChoosableFileFilter(_projectFilter);
 369  0 _openChooser.setFileFilter(getSourceFileFilter());
 370  0 return getOpenFiles(_openChooser);
 371    }
 372    };
 373   
 374    /** Returns the project file to open. */
 375    private final FileOpenSelector _openProjectSelector = new FileOpenSelector() {
 376  0 public File[] getFiles() throws OperationCanceledException { return getOpenFiles(_openProjectChooser); }
 377    };
 378   
 379    /** Returns the files to open. */
 380    private final FileOpenSelector _openAnyFileSelector = new FileOpenSelector() {
 381  0 public File[] getFiles() throws OperationCanceledException {
 382  0 _openChooser.resetChoosableFileFilters();
 383  0 _openChooser.setFileFilter(_anyFileFilter);
 384  0 return getOpenFiles(_openChooser);
 385    }
 386    };
 387   
 388    /** @return possibly renamed file, if it used an old LL extension and the user wanted it. */
 389  0 private File proposeBetterFileName(File f) {
 390  0 if (DrJavaFileUtils.isOldLLFile(f) && DrJava.getConfig().getSetting(PROMPT_RENAME_LL_FILES)) {
 391  0 File newFile = DrJavaFileUtils.getNewLLForOldLLFile(f);
 392  0 String newExt = DrJavaFileUtils.getExtension(newFile.getName());
 393  0 return proposeToChangeExtension(this,
 394    f,
 395    "Change Extension?",
 396    f.getPath() + "\nThis file still has an old Language Level extension."
 397    + "\nDo you want to change the file's extension to \""
 398    + newExt + "\"?",
 399    "Change to \"" + newExt + "\"",
 400    "Keep \"" + DrJavaFileUtils.getExtension(f.getName()) + "\"",
 401    newExt);
 402    }
 403  0 else return f;
 404    }
 405   
 406    /** Returns the file to save to the model (command pattern). */
 407    private final FileSaveSelector _saveSelector = new FileSaveSelector() {
 408  0 public File getFile() throws OperationCanceledException {
 409  0 return proposeBetterFileName(getSaveFile(_saveChooser));
 410    }
 411  0 public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
 412  0 public boolean verifyOverwrite(File f) { return MainFrameStatics.verifyOverwrite(MainFrame.this, f); }
 413  0 public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) {
 414  0 _model.setActiveDocument(doc);
 415  0 String text = "File " + oldFile.getAbsolutePath() +
 416    "\ncould not be found on disk! It was probably moved\nor deleted. Would you like to save it in a new file?";
 417  0 int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "File Moved or Deleted", JOptionPane.YES_NO_OPTION);
 418  0 return (rc == JOptionPane.YES_OPTION);
 419    }
 420  0 public boolean shouldUpdateDocumentState() { return true; }
 421    };
 422   
 423    /** Returns the file to save to the model (command pattern). */
 424    private final FileSaveSelector _saveAsSelector = new FileSaveSelector() {
 425  0 public File getFile() throws OperationCanceledException {
 426  0 return proposeBetterFileName(getSaveFile(_saveChooser));
 427    }
 428  0 public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
 429  0 public boolean verifyOverwrite(File f) { return MainFrameStatics.verifyOverwrite(MainFrame.this, f); }
 430  0 public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
 431  0 public boolean shouldUpdateDocumentState() { return true; }
 432    };
 433   
 434    /** Returns the file to save to the model (command pattern) without updating the document state. */
 435    private final FileSaveSelector _saveCopySelector = new FileSaveSelector() {
 436  0 public File getFile() throws OperationCanceledException {
 437  0 return proposeBetterFileName(getSaveFile(_saveChooser));
 438    }
 439  0 public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
 440  0 public boolean verifyOverwrite(File f) { return MainFrameStatics.verifyOverwrite(MainFrame.this, f); }
 441  0 public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
 442  0 public boolean shouldUpdateDocumentState() { return false; }
 443    };
 444   
 445    /** Provides the view's contribution to the Javadoc interaction. */
 446    private final JavadocDialog _javadocSelector = new JavadocDialog(this);
 447   
 448    /** Provides a chooser to open a directory */
 449    private volatile DirectoryChooser _folderChooser;
 450    private final JCheckBox _openRecursiveCheckBox = new JCheckBox("Open folders recursively");
 451   
 452    private final Action _moveToAuxiliaryAction = new AbstractAction("Include With Project") {
 453    { /* initalization block */
 454  38 String msg =
 455    "<html>Open this document each time this project is opened.<br>"+
 456    "This file would then be compiled and tested with the<br>"+
 457    "rest of the project.</html>";
 458  38 putValue(Action.LONG_DESCRIPTION, msg);
 459    }
 460  0 public void actionPerformed(ActionEvent ae) { _moveToAuxiliary(); }
 461    };
 462    private final Action _removeAuxiliaryAction = new AbstractAction("Do Not Include With Project") {
 463  38 { putValue(Action.LONG_DESCRIPTION, "Do not open this document next time this project is opened."); } // init
 464  0 public void actionPerformed(ActionEvent ae) { _removeAuxiliary(); }
 465    };
 466    private final Action _moveAllToAuxiliaryAction = new AbstractAction("Include All With Project") {
 467    { /* initalization block */
 468  38 String msg =
 469    "<html>Open these documents each time this project is opened.<br>"+
 470    "These files would then be compiled and tested with the<br>"+
 471    "rest of the project.</html>";
 472  38 putValue(Action.LONG_DESCRIPTION, msg);
 473    }
 474  0 public void actionPerformed(ActionEvent ae) { _moveAllToAuxiliary(); }
 475    };
 476   
 477    private final Action _removeAllAuxiliaryAction = new AbstractAction("Do Not Include Any With Project") {
 478  38 { putValue(Action.LONG_DESCRIPTION, "Do not open these documents next time this project is opened."); } // init
 479  0 public void actionPerformed(ActionEvent ae) { _removeAllAuxiliary(); }
 480    };
 481   
 482    /** Creates a new blank document and select it in the definitions pane. */
 483    private final Action _newAction = new AbstractAction("New") {
 484  0 public void actionPerformed(ActionEvent ae) { _new(); }
 485    };
 486   
 487    //newclass addition
 488    /** Creates a new Java class file. */
 489    private final Action _newClassAction = new AbstractAction("New Java Class...") {
 490  0 public void actionPerformed(ActionEvent ae) { _newJavaClass(); }
 491    };
 492  0 public void _newJavaClass() {
 493  0 NewJavaClassDialog njc = new NewJavaClassDialog(this);
 494  0 njc.setVisible(true);
 495    }
 496   
 497    private final Action _newProjectAction = new AbstractAction("New") {
 498  38 { putValue(Action.SHORT_DESCRIPTION, "New DrJava project"); } // init
 499  0 public void actionPerformed(ActionEvent ae) { _newProject(); }
 500    };
 501   
 502    private volatile AbstractAction _runProjectAction = new AbstractAction("Run Main Class of Project") {
 503    { /* initalization block */
 504  38 _addGUIAvailabilityListener(this,
 505    GUIAvailabilityListener.ComponentType.PROJECT,
 506    GUIAvailabilityListener.ComponentType.PROJECT_MAIN_CLASS,
 507    GUIAvailabilityListener.ComponentType.COMPILER,
 508    GUIAvailabilityListener.ComponentType.INTERACTIONS);
 509    }
 510  0 public void actionPerformed(ActionEvent ae) { _runProject(); }
 511    };
 512   
 513    /** The jar options dialog. */
 514    private volatile JarOptionsDialog _jarOptionsDialog;
 515   
 516    /** Initializes the "Create Jar from Project" dialog. */
 517  38 private void initJarOptionsDialog() {
 518  38 if (DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue())
 519  38 _jarOptionsDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STATE));
 520    }
 521   
 522    /** Reset the position of the "Create Jar from Project" dialog. */
 523  0 public void resetJarOptionsDialogPosition() {
 524  0 _jarOptionsDialog.setFrameState("default");
 525  0 if (DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue()) {
 526  0 DrJava.getConfig().setSetting(DIALOG_JAROPTIONS_STATE, "default");
 527    }
 528    }
 529    private final Action _jarProjectAction = new AbstractAction("Create Jar File from Project...") {
 530  38 { _addGUIAvailabilityListener(this,
 531    GUIAvailabilityListener.ComponentType.PROJECT,
 532    GUIAvailabilityListener.ComponentType.COMPILER); }
 533  0 public void actionPerformed(ActionEvent ae) { _jarOptionsDialog.setVisible(true); }
 534    };
 535   
 536    /** Initializes the "Tabbed Panes" frame. */
 537  38 private void initTabbedPanesFrame() {
 538  38 if (DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STORE_POSITION).booleanValue()) {
 539  38 _tabbedPanesFrame.setFrameState(DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STATE));
 540    }
 541    }
 542   
 543    /** Reset the position of the "Tabbed Panes" dialog. */
 544  0 public void resetTabbedPanesFrame() {
 545  0 _tabbedPanesFrame.setFrameState("default");
 546  0 if (DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STORE_POSITION).booleanValue()) {
 547  0 DrJava.getConfig().setSetting(DIALOG_TABBEDPANES_STATE, "default");
 548    }
 549    }
 550   
 551    /** Action that detaches the tabbed panes. Only runs in the event thread. */
 552    private final Action _detachTabbedPanesAction = new AbstractAction("Detach Tabbed Panes") {
 553  0 public void actionPerformed(ActionEvent ae) {
 554  0 JMenuItem m = (JMenuItem)ae.getSource();
 555  0 boolean b = m.isSelected();
 556  0 _detachTabbedPanesMenuItem.setSelected(b);
 557  0 DrJava.getConfig().setSetting(DETACH_TABBEDPANES, b);
 558  0 _tabbedPanesFrame.setDisplayInFrame(b);
 559    }
 560    };
 561   
 562    // menu item (checkbox menu) for detaching the tabbed panes
 563    private volatile JMenuItem _detachTabbedPanesMenuItem = null;
 564   
 565    /** Initializes the "Debugger" frame. */
 566  38 private void initDebugFrame() {
 567  0 if (_debugFrame == null) return; // debugger isn't used
 568  38 if (DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STORE_POSITION).booleanValue()) {
 569  38 _debugFrame.setFrameState(DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STATE));
 570    }
 571    }
 572   
 573    /** Reset the position of the "Debugger" dialog. */
 574  0 public void resetDebugFrame() {
 575  0 if (_debugFrame == null) return; // debugger isn't used
 576  0 _debugFrame.setFrameState("default");
 577  0 if (DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STORE_POSITION).booleanValue()) {
 578  0 DrJava.getConfig().setSetting(DIALOG_DEBUGFRAME_STATE, "default");
 579    }
 580    }
 581   
 582    /** Action that detaches the debugger pane. Only runs in the event thread. */
 583    private final Action _detachDebugFrameAction = new AbstractAction("Detach Debugger") {
 584  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.DEBUGGER); }
 585  0 public void actionPerformed(ActionEvent ae) {
 586  0 if (_debugFrame == null) return; // debugger isn't used
 587  0 JMenuItem m = (JMenuItem)ae.getSource();
 588  0 boolean b = m.isSelected();
 589  0 _detachDebugFrameMenuItem.setSelected(b);
 590  0 DrJava.getConfig().setSetting(DETACH_DEBUGGER, b);
 591  0 _debugFrame.setDisplayInFrame(b);
 592    }
 593    };
 594   
 595    // menu item (checkbox menu) for detaching the debugger pane
 596    private volatile JMenuItem _detachDebugFrameMenuItem;
 597   
 598    /** Sets the document in the definitions pane to a new templated junit test class. */
 599    private final Action _newJUnitTestAction = new AbstractAction("New JUnit Test Case...") {
 600  0 public void actionPerformed(ActionEvent ae) {
 601  0 String testName = JOptionPane.showInputDialog(MainFrame.this,
 602    "Please enter a name for the test class:",
 603    "New JUnit Test Case",
 604    JOptionPane.QUESTION_MESSAGE);
 605  0 if (testName != null) {
 606  0 String ext;
 607  0 for(int i = 0; i < OptionConstants.LANGUAGE_LEVEL_EXTENSIONS.length; i++) {
 608  0 ext = OptionConstants.LANGUAGE_LEVEL_EXTENSIONS[i];
 609  0 if (testName.endsWith(ext)) testName = testName.substring(0, testName.length() - ext.length());
 610    }
 611    // For now, don't include setUp and tearDown
 612  0 _model.newTestCase(testName, false, false);
 613    }
 614    }
 615    };
 616   
 617    /** Asks user for file name and and reads that file into the definitions pane. */
 618    private final Action _openAction = new AbstractAction("Open...") {
 619  0 public void actionPerformed(ActionEvent ae) {
 620  0 _open();
 621  0 _findReplace.updateFirstDocInSearch();
 622    }
 623    };
 624   
 625    /** Asks user for directory name and and reads it's files (and subdirectories files, on request) to
 626    * the definitions pane.
 627    */
 628    private final Action _openFolderAction = new AbstractAction("Open Folder...") {
 629  0 public void actionPerformed(ActionEvent ae) {
 630  0 _openFolder();
 631  0 _findReplace.updateFirstDocInSearch();
 632    }
 633    };
 634   
 635    /** Asks user for file name and and reads that file into the definitions pane. */
 636    private final Action _openFileOrProjectAction = new AbstractAction("Open...") {
 637  0 public void actionPerformed(ActionEvent ae) {
 638  0 _openFileOrProject();
 639  0 _findReplace.updateFirstDocInSearch();
 640    }
 641    };
 642   
 643    /** Asks user for project file name and and reads the associated files into the file navigator (and places the first
 644    * source file in the editor pane)
 645    */
 646    private final Action _openProjectAction = new AbstractAction("Open...") {
 647  38 { putValue(Action.SHORT_DESCRIPTION, "Open DrJava project"); }
 648  0 public void actionPerformed(ActionEvent ae) { _openProject(); }
 649    };
 650   
 651    private final Action _closeProjectAction = new AbstractAction("Close") {
 652  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.PROJECT);
 653  38 putValue(Action.SHORT_DESCRIPTION, "Close DrJava project"); }
 654  0 public void actionPerformed(ActionEvent ae) {
 655  0 closeProject();
 656  0 _findReplace.updateFirstDocInSearch();
 657    }
 658    };
 659   
 660   
 661    /** Closes the current active document, prompting to save if necessary. */
 662    private final Action _closeAction = new AbstractAction("Close") {
 663  1 public void actionPerformed(ActionEvent ae) {
 664  1 _close();
 665  1 _findReplace.updateFirstDocInSearch();
 666    }
 667    };
 668   
 669    /** Closes all open documents, prompting to save if necessary. */
 670    private final Action _closeAllAction = new AbstractAction("Close All") {
 671  0 public void actionPerformed(ActionEvent ae) {
 672  0 _closeAll();
 673  0 _findReplace.updateFirstDocInSearch();
 674    }
 675    };
 676   
 677    /** Closes all open documents, prompting to save if necessary. */
 678    private final Action _closeFolderAction = new AbstractAction("Close Folder") {
 679  0 public void actionPerformed(ActionEvent ae) {
 680  0 _closeFolder();
 681  0 _findReplace.updateFirstDocInSearch();
 682    // Set the document currently visible in the definitions pane as active document in the document navigator.
 683    // This action makes sure that something is selected in the navigator after the folder was closed.
 684  0 _model.getDocumentNavigator().selectDocument(_currentDefPane.getOpenDefDocument());
 685    }
 686    };
 687   
 688    /** Opens all the files in the current folder. */
 689    private final Action _openAllFolderAction = new AbstractAction("Open All Files") {
 690  0 public void actionPerformed(ActionEvent ae) {
 691    // now works with multiple selected folders
 692  0 List<File> l= _model.getDocumentNavigator().getSelectedFolders();
 693  0 for(File f: l) {
 694  0 File fAbs = new File(_model.getProjectRoot(), f.toString());
 695  0 _openFolder(fAbs, false, _model.getOpenAllFilesInFolderExtension());
 696    }
 697   
 698    // The following does not apply anymore:
 699    // Get the Folder that was clicked on by the user. When the user clicks on a directory component in the
 700    // navigation pane, the current directory is updated in the openChooser JFileChooser component. So the
 701    // clicked on directory is obtained in this way
 702    // File dir = _openChooser.getCurrentDirectory();
 703    // _openFolder(dir, false);
 704  0 _findReplace.updateFirstDocInSearch();
 705    }
 706    };
 707   
 708    /** Opens a files in the current folder. */
 709    private final Action _openOneFolderAction = new AbstractAction("Open File in Folder") {
 710  0 public void actionPerformed(ActionEvent ae) {
 711  0 _open();
 712  0 _findReplace.updateFirstDocInSearch();
 713    }
 714    };
 715   
 716    /** Creates a new untitled, empty file in the current folder. */
 717    public final Action _newFileFolderAction = new AbstractAction("Create New File in Folder") {
 718  0 public void actionPerformed(ActionEvent ae) {
 719    //make this new document the document in the document pane
 720  0 _new();
 721  0 _findReplace.updateFirstDocInSearch();
 722    }
 723    };
 724   
 725    /** Tests all the files in a folder. */
 726    private volatile AbstractAction _junitFolderAction = new AbstractAction("Test Folder") {
 727  38 { _addGUIAvailabilityListener(this,
 728    GUIAvailabilityListener.ComponentType.JUNIT,
 729    GUIAvailabilityListener.ComponentType.COMPILER,
 730    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 731  0 public final void actionPerformed(ActionEvent ae) { _junitFolder(); }
 732    };
 733   
 734    /** Saves the current document. */
 735    private final Action _saveAction = new AbstractAction("Save") {
 736  0 public final void actionPerformed(ActionEvent ae) { _save(); }
 737    };
 738   
 739    /** Returns the changed status of the MainFrame. */
 740  0 public long getLastChangeTime() { return _lastChangeTime; }
 741   
 742    /** Ensures that pack() is run in the event thread. Only used in test code */
 743  34 public void pack() {
 744  34 Utilities.invokeAndWait(new Runnable() { public void run() { packHelp(); } });
 745    }
 746   
 747    /** Helper method that provides access to super.pack() within the anonymous class new Runnable() {...} above */
 748  34 private void packHelp() { super.pack(); }
 749   
 750    /** Supports MainFrameTest.*/
 751  1 public boolean isSaveEnabled() { return _saveAction.isEnabled(); }
 752   
 753    /** Asks the user for a file name and saves the active document (in the definitions pane) to that file. */
 754    private final Action _saveAsAction = new AbstractAction("Save As...") {
 755  0 public void actionPerformed(ActionEvent ae) { _saveAs(); }
 756    };
 757   
 758    /** Asks the user for a file name and saves a copy of the active document (in the definitions pane) to
 759    * that file. DrJava's state is not modified (i.e. it does not set the document to 'unchanged'). */
 760    private final Action _saveCopyAction = new AbstractAction("Save Copy...") {
 761  0 public void actionPerformed(ActionEvent ae) { _saveCopy(); }
 762    };
 763   
 764    /** Asks the user for a file name and renames and saves the active document (in the definitions pane) to that file. */
 765    private final Action _renameAction = new AbstractAction("Rename") {
 766  0 public void actionPerformed(ActionEvent ae) { _rename(); }
 767    };
 768   
 769    private final Action _saveProjectAction = new AbstractAction("Save") {
 770  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.PROJECT); // init
 771  38 putValue(Action.SHORT_DESCRIPTION, "Save DrJava project"); }
 772  0 public void actionPerformed(ActionEvent ae) {
 773  0 _saveAll(); // saves project file and all modified project source files; does not save external files
 774    }
 775    };
 776   
 777    private final Action _saveProjectAsAction = new AbstractAction("Save As...") {
 778  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.PROJECT); // init
 779  38 putValue(Action.SHORT_DESCRIPTION, "Save DrJava project As");
 780  38 putValue(Action.LONG_DESCRIPTION, "Save DrJava project under different name"); }
 781  0 public void actionPerformed(ActionEvent ae) {
 782  0 if (_saveProjectAs()) { // asks user for new project file name; sets _projectFile in global model to this value
 783  0 _saveAll(); // performs saveAll operation using new project file name, assuming "Save as" was not cancelled
 784    }
 785    }
 786    };
 787   
 788    private final Action _exportProjectInOldFormatAction =
 789    new AbstractAction("Export Project In Old \"" + OLD_PROJECT_FILE_EXTENSION + "\" Format") {
 790  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.PROJECT); } // init
 791  0 public void actionPerformed(ActionEvent ae) {
 792  0 File cpf = _currentProjFile;
 793  0 _currentProjFile = FileOps.NULL_FILE;
 794  0 if (_saveProjectAs()) { // asks user for new project file name; sets _projectFile in global model to this value
 795  0 _saveAllOld(); // performs saveAll operation using new project file name, assuming "Save as" was not cancelled
 796    }
 797  0 _currentProjFile = cpf;
 798  0 _model.setProjectFile(cpf);
 799  0 _recentProjectManager.updateOpenFiles(cpf);
 800    }
 801    };
 802   
 803    /** Reverts the current document. */
 804    private final Action _revertAction = new AbstractAction("Revert to Saved") {
 805  0 public void actionPerformed(ActionEvent ae) {
 806  0 String title = "Revert to Saved?";
 807   
 808    // update message to reflect the number of files
 809  0 int count = _model.getDocumentNavigator().getDocumentSelectedCount();
 810  0 String message;
 811  0 if (count==1)
 812  0 message = "Are you sure you want to revert the current file to the version on disk?";
 813    else
 814  0 message = "Are you sure you want to revert the " + count + " selected files to the versions on disk?";
 815  0 int rc;
 816  0 Object[] options = {"Yes", "No"};
 817  0 rc = JOptionPane.showOptionDialog(MainFrame.this, message, title, JOptionPane.YES_NO_OPTION,
 818    JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
 819  0 if (rc == JOptionPane.YES_OPTION) _revert();
 820    }
 821    };
 822   
 823    /** Reverts all open documents.
 824    * (not working yet)
 825    private Action _revertAllAction = new AbstractAction("Revert All to Saved") {
 826    public void actionPerformed(ActionEvent ae) {
 827    String title = "Revert All to Saved?";
 828   
 829    String message = "Are you sure you want to revert all open " +
 830    "files to the versions on disk?";
 831   
 832    int rc = JOptionPane.showConfirmDialog(MainFrame.this,
 833    message,
 834    title,
 835    JOptionPane.YES_NO_OPTION);
 836    if (rc == JOptionPane.YES_OPTION) {
 837    _revertAll();
 838    }
 839    }
 840    };*/
 841   
 842    /** Saves all documents, prompting for file names as necessary. */
 843    final Action _saveAllAction = new AbstractAction("Save All") {
 844  0 public void actionPerformed(ActionEvent ae) { _saveAll(); }
 845    };
 846   
 847    /** Prints the current document. */
 848    private final Action _printDefDocAction = new AbstractAction("Print...") {
 849  0 public void actionPerformed(ActionEvent ae) { _printDefDoc(); }
 850    };
 851   
 852    /** Prints the console document. */
 853    private final Action _printConsoleAction = new AbstractAction("Print Console...") {
 854  0 public void actionPerformed(ActionEvent ae) { _printConsole(); }
 855    };
 856   
 857    /** Prints the interactions document. */
 858    private final Action _printInteractionsAction = new AbstractAction("Print Interactions...") {
 859  0 public void actionPerformed(ActionEvent ae) { _printInteractions(); }
 860    };
 861   
 862    /** Opens the print preview window. */
 863    private final Action _printDefDocPreviewAction = new AbstractAction("Print Preview...") {
 864  0 public void actionPerformed(ActionEvent ae) { _printDefDocPreview(); }
 865    };
 866   
 867    /** Opens the print preview window. */
 868    private final Action _printConsolePreviewAction = new AbstractAction("Print Preview...") {
 869  0 public void actionPerformed(ActionEvent ae) { _printConsolePreview(); }
 870    };
 871   
 872    /** Opens the print preview window. */
 873    private final Action _printInteractionsPreviewAction = new AbstractAction("Print Preview...") {
 874  0 public void actionPerformed(ActionEvent ae) { _printInteractionsPreview(); }
 875    };
 876   
 877    /** Opens the page setup window. */
 878    private final Action _pageSetupAction = new AbstractAction("Page Setup...") {
 879  0 public void actionPerformed(ActionEvent ae) { _pageSetup(); }
 880    };
 881   
 882    /** Compiles the document in the definitions pane. */
 883    private final Action _compileAction = new AbstractAction("Compile Current Document") {
 884  0 public void actionPerformed(ActionEvent ae) {
 885  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 886  0 _mainSplit.resetToPreferredSizes();
 887  0 updateStatusField("Compiling " + _fileTitle);
 888  0 _compile();
 889  0 updateStatusField("Compilation of current document completed");
 890    }
 891    };
 892   
 893    /** Compiles all the project. */
 894    private volatile AbstractAction _compileProjectAction = new AbstractAction("Compile Project") {
 895  38 { _addGUIAvailabilityListener(this, // init
 896    GUIAvailabilityListener.ComponentType.PROJECT,
 897    GUIAvailabilityListener.ComponentType.COMPILER); }
 898  0 public void actionPerformed(ActionEvent ae) {
 899  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 900  0 _mainSplit.resetToPreferredSizes();
 901  0 updateStatusField("Compiling all source files in open project");
 902  0 _compileProject();
 903  0 _findReplace.updateFirstDocInSearch();
 904  0 updateStatusField("Compilation of open project completed");
 905    }
 906    };
 907   
 908    /** Compiles all documents in the navigators active group. */
 909    private volatile AbstractAction _compileFolderAction = new AbstractAction("Compile Folder") {
 910  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.COMPILER); } // init
 911  0 public void actionPerformed(ActionEvent ae) {
 912  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 913  0 _mainSplit.resetToPreferredSizes();
 914  0 updateStatusField("Compiling all sources in current folder");
 915  0 _compileFolder();
 916  0 _findReplace.updateFirstDocInSearch();
 917  0 updateStatusField("Compilation of folder completed");
 918    }
 919    };
 920   
 921    /** Compiles all open documents. */
 922    private volatile AbstractAction _compileAllAction = new AbstractAction("Compile All Documents") {
 923  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.COMPILER); } // init
 924  1 public void actionPerformed(ActionEvent ae) {
 925  1 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 926  0 _mainSplit.resetToPreferredSizes();
 927  1 _compileAll();
 928  1 _findReplace.updateFirstDocInSearch();
 929    }
 930    };
 931   
 932    /** cleans the build directory */
 933    private volatile AbstractAction _cleanAction = new AbstractAction("Clean Build Directory") {
 934  38 { _addGUIAvailabilityListener(this, // init
 935    GUIAvailabilityListener.ComponentType.COMPILER,
 936    GUIAvailabilityListener.ComponentType.PROJECT,
 937    GUIAvailabilityListener.ComponentType.PROJECT_BUILD_DIR); }
 938  0 public void actionPerformed(ActionEvent ae) { _clean(); }
 939    };
 940   
 941    /** auto-refresh the project and open new files */
 942    private volatile AbstractAction _autoRefreshAction = new AbstractAction("Auto-Refresh Project") {
 943  38 { _addGUIAvailabilityListener(this, // init
 944    GUIAvailabilityListener.ComponentType.PROJECT,
 945    GUIAvailabilityListener.ComponentType.COMPILER); }
 946  0 public void actionPerformed(ActionEvent ae) { _model.autoRefreshProject(); }
 947    };
 948   
 949    /** Finds and runs the main method of the current document, if it exists. */
 950    private volatile AbstractAction _runAction = new AbstractAction("Run Document's Main Method") {
 951  38 { _addGUIAvailabilityListener(this, // init
 952    GUIAvailabilityListener.ComponentType.COMPILER,
 953    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 954  0 public void actionPerformed(ActionEvent ae) { _runMain(); }
 955    };
 956   
 957    /** Tries to run the current document as an applet. */
 958    private volatile AbstractAction _runAppletAction = new AbstractAction("Run Document as Applet") {
 959  38 { _addGUIAvailabilityListener(this, // init
 960    GUIAvailabilityListener.ComponentType.COMPILER,
 961    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 962  0 public void actionPerformed(ActionEvent ae) { _runApplet(); }
 963    };
 964   
 965    /** Runs JUnit on the document in the definitions pane. */
 966    private volatile AbstractAction _junitAction = new AbstractAction("Test Current Document") {
 967  38 { _addGUIAvailabilityListener(this, // init
 968    GUIAvailabilityListener.ComponentType.JUNIT,
 969    GUIAvailabilityListener.ComponentType.COMPILER,
 970    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 971  0 public void actionPerformed(ActionEvent ae) {
 972  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
 973  0 _junit();
 974    }
 975    };
 976   
 977    /** Runs JUnit over all open JUnit tests. */
 978    private volatile AbstractAction _junitAllAction = new AbstractAction("Test All Documents") {
 979  38 { _addGUIAvailabilityListener(this, // init
 980    GUIAvailabilityListener.ComponentType.JUNIT,
 981    GUIAvailabilityListener.ComponentType.COMPILER,
 982    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 983  0 public void actionPerformed(ActionEvent e) {
 984  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
 985  0 _junitAll();
 986  0 _findReplace.updateFirstDocInSearch();
 987    }
 988   
 989    };
 990   
 991    /** Runs JUnit over all open JUnit tests in the project directory. */
 992    private volatile AbstractAction _junitProjectAction = new AbstractAction("Test Project") {
 993  38 { _addGUIAvailabilityListener(this, // init
 994    GUIAvailabilityListener.ComponentType.PROJECT,
 995    GUIAvailabilityListener.ComponentType.JUNIT,
 996    GUIAvailabilityListener.ComponentType.COMPILER,
 997    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 998  0 public void actionPerformed(ActionEvent e) {
 999  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
 1000  0 _junitProject();
 1001  0 _findReplace.updateFirstDocInSearch();
 1002    }
 1003    };
 1004   
 1005    /** Runs Javadoc on all open documents (and the files in their packages). */
 1006    private volatile AbstractAction _javadocAllAction = new AbstractAction("Javadoc All Documents") {
 1007  38 { _addGUIAvailabilityListener(this, // init
 1008    GUIAvailabilityListener.ComponentType.JAVADOC,
 1009    GUIAvailabilityListener.ComponentType.COMPILER); }
 1010  0 public void actionPerformed(ActionEvent ae) {
 1011  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 1012  0 _mainSplit.resetToPreferredSizes();
 1013  0 try {
 1014  0 JavadocModel jm = _model.getJavadocModel();
 1015  0 File suggestedDir = jm.suggestJavadocDestination(_model.getActiveDocument());
 1016  0 _javadocSelector.setSuggestedDir(suggestedDir);
 1017  0 jm.javadocAll(_javadocSelector, _saveSelector);
 1018    }
 1019  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 1020    }
 1021    };
 1022   
 1023    /** Runs Javadoc on the current document. */
 1024    private volatile AbstractAction _javadocCurrentAction = new AbstractAction("Preview Javadoc for Current Document") {
 1025  38 { _addGUIAvailabilityListener(this, // init
 1026    GUIAvailabilityListener.ComponentType.JAVADOC,
 1027    GUIAvailabilityListener.ComponentType.COMPILER); }
 1028  0 public void actionPerformed(ActionEvent ae) {
 1029  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 1030  0 _mainSplit.resetToPreferredSizes();
 1031  0 try {
 1032  0 _model.getActiveDocument().generateJavadoc(_saveSelector);
 1033    }
 1034  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 1035    }
 1036    };
 1037   
 1038    /** Default cut action. Returns focus to the correct pane. */
 1039    final Action cutAction = new DefaultEditorKit.CutAction() {
 1040  0 public void actionPerformed(ActionEvent e) {
 1041  0 Component c = MainFrame.this.getFocusOwner();
 1042  0 super.actionPerformed(e);
 1043  0 if (_currentDefPane.hasFocus()) {
 1044  0 String s = Utilities.getClipboardSelection(c);
 1045  0 if (s != null && s.length() != 0) { ClipboardHistoryModel.singleton().put(s); }
 1046    }
 1047  0 if (c != null) c.requestFocusInWindow();
 1048    }
 1049    };
 1050   
 1051    /** Default copy action. Returns focus to the correct pane. */
 1052    final Action copyAction = new DefaultEditorKit.CopyAction() {
 1053  0 public void actionPerformed(ActionEvent e) {
 1054  0 Component c = MainFrame.this.getFocusOwner();
 1055  0 super.actionPerformed(e);
 1056  0 if (_currentDefPane.hasFocus() && _currentDefPane.getSelectedText() != null) {
 1057  0 String s = Utilities.getClipboardSelection(c);
 1058  0 if (s != null && s.length() != 0) { ClipboardHistoryModel.singleton().put(s); }
 1059    }
 1060  0 if (c != null) c.requestFocusInWindow();
 1061    }
 1062    };
 1063   
 1064    /** We lost ownership of what we put in the clipboard. */
 1065  1 public void lostOwnership(Clipboard clipboard, Transferable contents) {
 1066    // ignore
 1067    }
 1068   
 1069    /** Default paste action. Returns focus to the correct pane. */
 1070    final Action pasteAction = new DefaultEditorKit.PasteAction() {
 1071  0 public void actionPerformed(ActionEvent e) {
 1072    // remove unprintable characters before pasting
 1073  0 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
 1074  0 Transferable contents = clipboard.getContents(null);
 1075  0 if ((contents != null) && (contents.isDataFlavorSupported(DataFlavor.stringFlavor))) {
 1076  0 try {
 1077  0 String result = (String)contents.getTransferData(DataFlavor.stringFlavor);
 1078  0 StringBuilder sb = new StringBuilder();
 1079  0 for(int i = 0; i < result.length(); ++i) {
 1080  0 char ch = result.charAt(i);
 1081  0 if ((ch<32) && (ch!='\n')) sb.append(' ');
 1082  0 else sb.append(ch);
 1083    }
 1084  0 StringSelection stringSelection = new StringSelection(sb.toString());
 1085  0 clipboard.setContents(stringSelection, stringSelection);
 1086    }
 1087    catch (UnsupportedFlavorException ex) { /* just keep it the same */ }
 1088    catch (IOException ex) { /* just keep it the same */ }
 1089    }
 1090   
 1091  0 Component c = MainFrame.this.getFocusOwner();
 1092  0 if (_currentDefPane.hasFocus()) {
 1093  0 _currentDefPane.endCompoundEdit();
 1094    // CompoundUndoManager undoMan = _model.getActiveDocument().getUndoManager(); // French keyboard fix
 1095    // int key = undoMan.startCompoundEdit(); // French keyboard fix
 1096  0 super.actionPerformed(e);
 1097  0 _currentDefPane.endCompoundEdit(); // replaced line below for French keyboard fix
 1098    // undoMan.endCompoundEdit(key); // French keyboard fix
 1099    }
 1100  0 else if(_interactionsPane.hasFocus()){
 1101  0 _interactionsPane.endCompoundEdit();
 1102  0 super.actionPerformed(e);
 1103  0 _interactionsPane.endCompoundEdit();
 1104    }
 1105   
 1106  0 else super.actionPerformed(e);
 1107   
 1108  0 if (c != null) c.requestFocusInWindow();
 1109    }
 1110    };
 1111   
 1112    /** Reset the position of the "Clipboard History" dialog. */
 1113  0 public void resetClipboardHistoryDialogPosition() {
 1114  0 if (DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) {
 1115  0 DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, "default");
 1116    }
 1117    }
 1118   
 1119    /** The "Clipboard History" dialog. */
 1120    private volatile ClipboardHistoryFrame _clipboardHistoryDialog = null;
 1121   
 1122    /** Asks the user for a file name and goes there. */
 1123    private final Action _pasteHistoryAction = new AbstractAction("Paste from History...") {
 1124  0 public void actionPerformed(final ActionEvent ae) {
 1125  0 final ClipboardHistoryFrame.CloseAction cancelAction = new ClipboardHistoryFrame.CloseAction() {
 1126  0 public Object value(String s) {
 1127    // "Clipboard History" dialog position and size.
 1128  0 if ((DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue())
 1129    && (_clipboardHistoryDialog != null) && (_clipboardHistoryDialog.getFrameState() != null)) {
 1130  0 DrJava.getConfig().
 1131    setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, (_clipboardHistoryDialog.getFrameState().toString()));
 1132    }
 1133    else {
 1134    // Reset to defaults to restore pristine behavior.
 1135  0 DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, DIALOG_CLIPBOARD_HISTORY_STATE.getDefault());
 1136    }
 1137  0 return null;
 1138    }
 1139    };
 1140  0 ClipboardHistoryFrame.CloseAction okAction = new ClipboardHistoryFrame.CloseAction() {
 1141  0 public Object value(String s) {
 1142  0 cancelAction.value(null);
 1143   
 1144  0 StringSelection ssel = new StringSelection(s);
 1145  0 Clipboard cb = MainFrame.this.getToolkit().getSystemClipboard();
 1146  0 if (cb != null) {
 1147  0 cb.setContents(ssel, MainFrame.this);
 1148  0 pasteAction.actionPerformed(ae);
 1149    }
 1150  0 return null;
 1151    }
 1152    };
 1153   
 1154  0 _clipboardHistoryDialog = new ClipboardHistoryFrame(MainFrame.this,
 1155    "Clipboard History", ClipboardHistoryModel.singleton(),
 1156    okAction, cancelAction);
 1157  0 if (DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) {
 1158  0 _clipboardHistoryDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STATE));
 1159    }
 1160  0 _clipboardHistoryDialog.setVisible(true);
 1161    }
 1162    };
 1163   
 1164    /** Copies whatever is currently in the interactions pane at the prompt to the definitions pane. If the
 1165    * current string is empty, then it will attempt to return the last entry from the interactions pane's history.
 1166    */
 1167    private final Action _copyInteractionToDefinitionsAction =
 1168    new AbstractAction("Lift Current Interaction to Definitions") {
 1169  0 public void actionPerformed(ActionEvent a) {
 1170  0 String text = _interactionsController.getDocument().getCurrentInput();
 1171  0 if (! text.equals("")) {
 1172  0 _putTextIntoDefinitions(text + "\n");
 1173  0 return;
 1174    }
 1175  0 try { text = _interactionsController.getDocument().lastEntry(); }
 1176  0 catch(Exception e) { return; } // no entry to promote
 1177   
 1178    //It is assumed that empty strings are not put into the history
 1179  0 _putTextIntoDefinitions(text + "\n");
 1180  0 return;
 1181    }
 1182    };
 1183   
 1184    /** Action that copies the previous interaction to the definitions pane.
 1185    * Is there a good way to get the last history element without perturbing the current document?
 1186    Action copyPreviousInteractionToDefinitionsAction = new AbstractAction("Copy previous interaction to definitions") {
 1187    public void actionPerformed(ActionEvent e) {
 1188    _putTextIntoDefinitions(_interactionsController.getDocument().getCurrentInput() + "\n");
 1189    }
 1190    };*/
 1191   
 1192    /** Undoes the last change to the active definitions document. */
 1193    private final DelegatingAction _undoAction = new DelegatingAction() {
 1194  1 public void actionPerformed(ActionEvent e) {
 1195    // use whether the delegatee is the Interactions Pane's action instead of whether
 1196    // _interactionsPane.hasFocus(), because the focus will be lost when the user clicks
 1197    // on the menu bar.
 1198  1 final boolean intPaneFocused = (getDelegatee()==_interactionsController.getUndoAction());
 1199  0 if (intPaneFocused) _interactionsPane.endCompoundEdit();
 1200  1 else _currentDefPane.endCompoundEdit();
 1201   
 1202  1 super.actionPerformed(e);
 1203   
 1204  0 if (intPaneFocused) _interactionsPane.requestFocusInWindow();
 1205    else {
 1206  1 _currentDefPane.requestFocusInWindow();
 1207  1 OpenDefinitionsDocument doc = _model.getActiveDocument();
 1208  1 _saveAction.setEnabled(doc.isModifiedSinceSave() || doc.isUntitled());
 1209    }
 1210    }
 1211    };
 1212   
 1213    /** Redoes the last undo to the active definitions document. */
 1214    private final DelegatingAction _redoAction = new DelegatingAction() {
 1215  0 public void actionPerformed(ActionEvent e) {
 1216    // use whether the delegatee is the Interactions Pane's action instead of whether
 1217    // _interactionsPane.hasFocus(), because the focus will be lost when the user clicks
 1218    // on the menu bar.
 1219  0 final boolean intPaneFocused = (getDelegatee()==_interactionsController.getRedoAction());
 1220   
 1221  0 super.actionPerformed(e);
 1222  0 if (intPaneFocused)_interactionsPane.requestFocusInWindow();
 1223    else {
 1224  0 _currentDefPane.requestFocusInWindow();
 1225  0 OpenDefinitionsDocument doc = _model.getActiveDocument();
 1226  0 _saveAction.setEnabled(doc.isModifiedSinceSave() || doc.isUntitled());
 1227    }
 1228    }
 1229    };
 1230   
 1231    /** Quits DrJava. Optionally displays a prompt before quitting. */
 1232    private final Action _quitAction = new AbstractAction("Quit") {
 1233  0 public void actionPerformed(ActionEvent ae) { quit(); }
 1234    };
 1235   
 1236    /** Quits DrJava. Optionally displays a prompt before quitting. */
 1237    private final Action _forceQuitAction = new AbstractAction("Force Quit") {
 1238  0 public void actionPerformed(ActionEvent ae) { _forceQuit(); }
 1239    };
 1240   
 1241    /** Selects all text in window. */
 1242    private final Action _selectAllAction = new AbstractAction("Select All") {
 1243  0 public void actionPerformed(ActionEvent ae) { _selectAll(); }
 1244    };
 1245   
 1246    /** Shows the find/replace tab in the interactions pane. Only executes in the event thread. */
 1247  0 private void _showFindReplaceTab(boolean showDetachedWindow) {
 1248  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 1249  0 _mainSplit.resetToPreferredSizes();
 1250  0 final boolean wasDisplayed = isDisplayed(_findReplace);
 1251  0 showTab(_findReplace, showDetachedWindow);
 1252  0 if (!wasDisplayed) {
 1253  0 _findReplace.beginListeningTo(_currentDefPane);
 1254    }
 1255  0 _findReplace.setVisible(true);
 1256  0 _tabbedPane.setSelectedComponent(_findReplace);
 1257    }
 1258   
 1259    /** Action that shows the find/replace tab. Only executes in the event thread. */
 1260    private final Action _findReplaceAction = new AbstractAction("Find/Replace") {
 1261  0 public void actionPerformed(ActionEvent ae) {
 1262  0 _showFindReplaceTab(true);
 1263  0 _findReplace.requestFocusInWindow();
 1264    // Use EventQueue.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
 1265  0 EventQueue.invokeLater(new Runnable() { public void run() { _findReplace.requestFocusInWindow(); } });
 1266    }
 1267    };
 1268   
 1269    /** Find the next instance of the find word. */
 1270    private final Action _findNextAction = new AbstractAction("Find Next") {
 1271  0 public void actionPerformed(ActionEvent ae) {
 1272  0 _showFindReplaceTab(false);
 1273  0 if (!DrJava.getConfig().getSetting(FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
 1274    // Use EventQueue.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
 1275  0 EventQueue.invokeLater(new Runnable() { public void run() { _findReplace.requestFocusInWindow(); } });
 1276    }
 1277  0 _findReplace.findNext();
 1278    // _currentDefPane.requestFocusInWindow();
 1279    // atempt to fix intermittent bug where _currentDefPane listens but does not echo and won't undo!
 1280    }
 1281    };
 1282   
 1283    /** Does the find next in the opposite direction. If the direction is backward it searches forward. */
 1284    private final Action _findPrevAction = new AbstractAction("Find Previous") {
 1285  0 public void actionPerformed(ActionEvent ae) {
 1286  0 _showFindReplaceTab(false);
 1287  0 if (!DrJava.getConfig().getSetting(FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
 1288    // Use EventQueue.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
 1289  0 EventQueue.invokeLater(new Runnable() { public void run() { _findReplace.requestFocusInWindow(); } });
 1290    }
 1291  0 _findReplace.findPrevious();
 1292  0 _currentDefPane.requestFocusInWindow();
 1293    }
 1294    };
 1295   
 1296    /** Asks the user for a line number and goes there. */
 1297    private final Action _gotoLineAction = new AbstractAction("Go to Line...") {
 1298  0 public void actionPerformed(ActionEvent ae) {
 1299  0 int pos = _gotoLine();
 1300  0 _currentDefPane.requestFocusInWindow();
 1301  0 if (pos != -1) _currentDefPane.setCaretPosition(pos);
 1302    // The preceding is a brute force attempt to fix intermittent failure to display caret
 1303    }
 1304    };
 1305   
 1306    /** Reset the position of the "Go to File" dialog. */
 1307  0 public void resetGotoFileDialogPosition() {
 1308  0 initGotoFileDialog();
 1309  0 _gotoFileDialog.setFrameState("default");
 1310  0 if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) {
 1311  0 DrJava.getConfig().setSetting(DIALOG_GOTOFILE_STATE, "default");
 1312    }
 1313    }
 1314   
 1315    /** Initialize dialog if necessary. */
 1316  4 void initGotoFileDialog() {
 1317  4 if (_gotoFileDialog == null) {
 1318  3 PredictiveInputFrame.InfoSupplier<GoToFileListEntry> info =
 1319    new PredictiveInputFrame.InfoSupplier<GoToFileListEntry>() {
 1320  64 public String value(GoToFileListEntry entry) {
 1321  64 final StringBuilder sb = new StringBuilder();
 1322   
 1323  64 final OpenDefinitionsDocument doc = entry.getOpenDefinitionsDocument();
 1324  64 if (doc != null) {
 1325  28 try {
 1326  28 try { sb.append(FileOps.stringMakeRelativeTo(doc.getRawFile(), doc.getSourceRoot())); }
 1327  0 catch(IOException e) { sb.append(doc.getFile()); }
 1328    }
 1329  0 catch(FileMovedException e) { sb.append(entry + " was moved"); }
 1330    // catch(java.lang.IllegalStateException e) { sb.append(entry); }
 1331  0 catch(InvalidPackageException e) { sb.append(entry); }
 1332    }
 1333  36 else sb.append(entry);
 1334  64 return sb.toString();
 1335    }
 1336    };
 1337  3 PredictiveInputFrame.CloseAction<GoToFileListEntry> okAction =
 1338    new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
 1339  3 public String getName() { return "OK"; }
 1340  3 public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); }
 1341  3 public String getToolTipText() { return null; }
 1342  0 public Object value(PredictiveInputFrame<GoToFileListEntry> p) {
 1343  0 if (p.getItem() != null) {
 1344  0 final OpenDefinitionsDocument newDoc = p.getItem().getOpenDefinitionsDocument();
 1345  0 if (newDoc != null) {
 1346  0 final boolean docChanged = ! newDoc.equals(_model.getActiveDocument());
 1347  0 final boolean docSwitch = _model.getActiveDocument() != newDoc;
 1348  0 if (docSwitch) _model.setActiveDocument(newDoc);
 1349  0 final int curLine = newDoc.getCurrentLine();
 1350  0 final String t = p.getText();
 1351  0 final int last = t.lastIndexOf(':');
 1352  0 if (last >= 0) {
 1353  0 try {
 1354  0 String end = t.substring(last + 1);
 1355  0 int val = Integer.parseInt(end);
 1356   
 1357  0 final int lineNum = Math.max(1, val);
 1358  0 Runnable command = new Runnable() {
 1359  0 public void run() {
 1360  0 try { _jumpToLine(lineNum); } // adds this region to browser history
 1361  0 catch (RuntimeException e) { _jumpToLine(curLine); }
 1362    }
 1363    };
 1364  0 if (docSwitch) {
 1365    // postpone running command until after document switch, which is pending in the event queue
 1366  0 EventQueue.invokeLater(command);
 1367    }
 1368  0 else command.run();
 1369    }
 1370    catch(RuntimeException e) { /* ignore */ }
 1371    }
 1372  0 else if (docChanged) {
 1373    // defer executing this code until after active document switch (if any) is complete
 1374  0 addToBrowserHistory();
 1375    }
 1376    }
 1377    }
 1378  0 hourglassOff();
 1379  0 return null;
 1380    }
 1381    };
 1382  3 PredictiveInputFrame.CloseAction<GoToFileListEntry> cancelAction =
 1383    new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
 1384  3 public String getName() { return "Cancel"; }
 1385  3 public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); }
 1386  3 public String getToolTipText() { return null; }
 1387  0 public Object value(PredictiveInputFrame<GoToFileListEntry> p) {
 1388  0 hourglassOff();
 1389  0 return null;
 1390    }
 1391    };
 1392  3 ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>> strategies =
 1393    new ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>>();
 1394  3 strategies.add(new PredictiveInputModel.FragmentLineNumStrategy<GoToFileListEntry>());
 1395  3 strategies.add(new PredictiveInputModel.PrefixLineNumStrategy<GoToFileListEntry>());
 1396  3 strategies.add(new PredictiveInputModel.RegExLineNumStrategy<GoToFileListEntry>());
 1397  3 List<PredictiveInputFrame.CloseAction<GoToFileListEntry>> actions
 1398    = new ArrayList<PredictiveInputFrame.CloseAction<GoToFileListEntry>>();
 1399  3 actions.add(okAction);
 1400  3 actions.add(cancelAction);
 1401  3 _gotoFileDialog =
 1402    new PredictiveInputFrame<GoToFileListEntry>(MainFrame.this,
 1403    "Go to File",
 1404    true, // force
 1405    true, // ignore case
 1406    info,
 1407    strategies,
 1408    actions, 1, // cancel is action 1
 1409    new GoToFileListEntry(null, "dummyGoto")) {
 1410  0 public void setOwnerEnabled(boolean b) {
 1411  0 if (b) { hourglassOff(); } else { hourglassOn(); }
 1412    }
 1413    };
 1414    // putting one dummy entry in the list; it will be changed later anyway
 1415   
 1416  3 if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) {
 1417  3 _gotoFileDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STATE));
 1418    }
 1419    }
 1420    }
 1421   
 1422    /** The "Go to File" dialog instance. */
 1423    volatile PredictiveInputFrame<GoToFileListEntry> _gotoFileDialog = null;
 1424   
 1425    /** Action implementing "Go to file" command, which asks the user for a file name and goes there. */
 1426    private final Action _gotoFileAction = new AbstractAction("Go to File...") {
 1427  0 public void actionPerformed(ActionEvent ae) {
 1428  0 initGotoFileDialog();
 1429  0 List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments();
 1430  0 if (docs == null || docs.size() == 0) {
 1431  0 return; // do nothing
 1432    }
 1433  0 GoToFileListEntry currentEntry = null;
 1434  0 ArrayList<GoToFileListEntry> list;
 1435  0 if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) {
 1436  0 list = new ArrayList<GoToFileListEntry>(2 * docs.size());
 1437    }
 1438    else {
 1439  0 list = new ArrayList<GoToFileListEntry>(docs.size());
 1440    }
 1441  0 for(OpenDefinitionsDocument d: docs) {
 1442  0 GoToFileListEntry entry = new GoToFileListEntry(d, d.toString());
 1443  0 if (d.equals(_model.getActiveDocument())) currentEntry = entry;
 1444  0 list.add(entry);
 1445  0 if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) {
 1446  0 try {
 1447  0 try {
 1448  0 String relative = FileOps.stringMakeRelativeTo(d.getFile(), d.getSourceRoot());
 1449  0 if (!relative.equals(d.toString())) {
 1450  0 list.add(new GoToFileListEntry(d, d.getPackageName() + "." + d.toString()));
 1451    }
 1452    }
 1453    catch(IOException e) { /* ignore */ }
 1454    catch(InvalidPackageException e) { /* ignore */ }
 1455    }
 1456    catch(IllegalStateException e) { /* ignore */ }
 1457    }
 1458    }
 1459  0 _gotoFileDialog.setItems(true, list); // ignore case
 1460  0 if (currentEntry != null) _gotoFileDialog.setCurrentItem(currentEntry);
 1461  0 hourglassOn(); // Where is the corresponding hourglassOff()?
 1462    /* if (! Utilities.TEST_MODE) */
 1463  0 _gotoFileDialog.setVisible(true);
 1464    }
 1465    };
 1466   
 1467    /** Goes to the file specified by the word the cursor is on. */
 1468  5 void _gotoFileUnderCursor() {
 1469    // Utilities.show("Calling gotoFileUnderCursor()");
 1470  5 OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
 1471  5 String mask = "";
 1472  5 int loc = getCurrentDefPane().getCaretPosition();
 1473  5 String s = odd.getText();
 1474    // find start
 1475  5 int start = loc;
 1476  5 while(start > 0) {
 1477  0 if (! Character.isJavaIdentifierPart(s.charAt(start-1))) { break; }
 1478  0 --start;
 1479    }
 1480  5 while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start<loc)) {
 1481  0 ++start;
 1482    }
 1483    // find end
 1484  5 int end = loc-1;
 1485  5 while(end<s.length()-1) {
 1486  0 if (! Character.isJavaIdentifierPart(s.charAt(end+1))) { break; }
 1487  106 ++end;
 1488    }
 1489  5 if ((start>=0) && (end<s.length())) {
 1490  5 mask = s.substring(start, end + 1);
 1491    }
 1492  5 gotoFileMatchingMask(mask);
 1493    }
 1494   
 1495    /** Goes to the file matching the specified mask.
 1496    * @param mask word specifying the file to go to*/
 1497  5 public void gotoFileMatchingMask(String mask) {
 1498  5 List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments();
 1499  0 if ((docs == null) || (docs.size() == 0)) return; // do nothing
 1500   
 1501  5 GoToFileListEntry currentEntry = null;
 1502  5 ArrayList<GoToFileListEntry> list = new ArrayList<GoToFileListEntry>(docs.size());
 1503  5 for(OpenDefinitionsDocument d: docs) {
 1504  10 GoToFileListEntry entry = new GoToFileListEntry(d, d.toString());
 1505  5 if (d.equals(_model.getActiveDocument())) currentEntry = entry;
 1506  10 list.add(entry);
 1507    }
 1508   
 1509  5 PredictiveInputModel<GoToFileListEntry> pim =
 1510    new PredictiveInputModel<GoToFileListEntry>(true, new PrefixStrategy<GoToFileListEntry>(), list);
 1511  5 pim.setMask(mask);
 1512   
 1513    // Utilities.show("Matching items are: " + pim.getMatchingItems());
 1514   
 1515  5 if (pim.getMatchingItems().size() == 1) {
 1516    // exactly one match, go to file
 1517  3 if (pim.getCurrentItem() != null) {
 1518  3 final OpenDefinitionsDocument newDoc = pim.getCurrentItem().getOpenDefinitionsDocument();
 1519  3 if (newDoc != null) {
 1520  3 boolean docChanged = ! newDoc.equals(_model.getActiveDocument());
 1521    // if (docChanged) { addToBrowserHistory(); }
 1522  3 _model.setActiveDocument(newDoc);
 1523  3 if (docChanged) { // defer executing this code until after active document switch is complete
 1524  3 addToBrowserHistory();
 1525    }
 1526    }
 1527    }
 1528    }
 1529    else {
 1530    // try appending ".java" and the other file extensions and see if it's unique
 1531  2 boolean exact = false;
 1532  2 for(String attemptedExt: OptionConstants.LANGUAGE_LEVEL_EXTENSIONS) {
 1533  6 pim.setMask(mask);
 1534  6 pim.extendMask(attemptedExt);
 1535  6 if (pim.getMatchingItems().size() == 1) {
 1536  1 exact = true;
 1537    // exactly one match with ".java" appended, go to file
 1538  1 if (pim.getCurrentItem() != null) {
 1539  1 final OpenDefinitionsDocument newDoc = pim.getCurrentItem().getOpenDefinitionsDocument();
 1540  1 if (newDoc != null) {
 1541  1 boolean docChanged = !newDoc.equals(_model.getActiveDocument());
 1542    // if (docChanged) { addToBrowserHistory(); }
 1543  1 _model.setActiveDocument(newDoc);
 1544  1 if (docChanged) { // defer executing this code until after active document switch is complete
 1545  1 addToBrowserHistory();
 1546    }
 1547    }
 1548    }
 1549  1 break;
 1550    }
 1551    }
 1552  2 if (!exact) {
 1553    // not exactly one match
 1554  1 pim.setMask(mask);
 1555  1 if (pim.getMatchingItems().size() == 0) {
 1556    // if there are no matches, shorten the mask until there is at least one
 1557  0 mask = pim.getMask();
 1558  0 while (mask.length() > 0) {
 1559  0 mask = mask.substring(0, mask.length() - 1);
 1560  0 pim.setMask(mask);
 1561  0 if (pim.getMatchingItems().size() > 0) { break; }
 1562    }
 1563    }
 1564  1 initGotoFileDialog();
 1565  1 _gotoFileDialog.setModel(true, pim); // ignore case
 1566  1 if (currentEntry != null) _gotoFileDialog.setCurrentItem(currentEntry);
 1567  1 hourglassOn();
 1568    /* Following boolean flag suppresses display of the dialog during unit testing. If the unit test is revised
 1569    * to confirm that the dialog is displayed, this test must be removed. */
 1570  0 if (MainFrame.this.isVisible()) _gotoFileDialog.setVisible(true);
 1571    }
 1572    }
 1573    }
 1574   
 1575    /** Goes to the file specified by the word the cursor is on. */
 1576    final Action _gotoFileUnderCursorAction = new AbstractAction("Go to File Under Cursor") {
 1577  0 public void actionPerformed(ActionEvent ae) { _gotoFileUnderCursor(); }
 1578    };
 1579   
 1580    /** Reset the position of the "Open Javadoc" dialog. */
 1581  0 public void resetOpenJavadocDialogPosition() {
 1582  0 initOpenJavadocDialog();
 1583  0 _openJavadocDialog.setFrameState("default");
 1584  0 if (DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) {
 1585  0 DrJava.getConfig().setSetting(DIALOG_OPENJAVADOC_STATE, "default");
 1586    }
 1587    }
 1588   
 1589    /** Initialize dialog if necessary.
 1590    * Should NOT be called in the event thread. ???*/
 1591  0 void initOpenJavadocDialog() {
 1592    // assert (!EventQueue.isDispatchThread());
 1593  0 if (_openJavadocDialog == null) {
 1594  0 PredictiveInputFrame.InfoSupplier<JavaAPIListEntry> info =
 1595    new PredictiveInputFrame.InfoSupplier<JavaAPIListEntry>() {
 1596  0 public String value(JavaAPIListEntry entry) {
 1597  0 return entry.getFullString();
 1598    }
 1599    };
 1600  0 PredictiveInputFrame.CloseAction<JavaAPIListEntry> okAction =
 1601    new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() {
 1602  0 public String getName() { return "OK"; }
 1603  0 public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); }
 1604  0 public String getToolTipText() { return null; }
 1605  0 public Object value(PredictiveInputFrame<JavaAPIListEntry> p) {
 1606  0 if (p.getItem() != null) PlatformFactory.ONLY.openURL(p.getItem().getURL());
 1607  0 hourglassOff();
 1608  0 return null;
 1609    }
 1610    };
 1611  0 PredictiveInputFrame.CloseAction<JavaAPIListEntry> cancelAction =
 1612    new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() {
 1613  0 public String getName() { return "Cancel"; }
 1614  0 public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); }
 1615  0 public String getToolTipText() { return null; }
 1616  0 public Object value(PredictiveInputFrame<JavaAPIListEntry> p) {
 1617  0 hourglassOff();
 1618  0 return null;
 1619    }
 1620    };
 1621    // Note: PredictiveInputModel.* is statically imported
 1622  0 ArrayList<MatchingStrategy<JavaAPIListEntry>> strategies = new ArrayList<MatchingStrategy<JavaAPIListEntry>>();
 1623  0 strategies.add(new FragmentStrategy<JavaAPIListEntry>());
 1624  0 strategies.add(new PrefixStrategy<JavaAPIListEntry>());
 1625  0 strategies.add(new RegExStrategy<JavaAPIListEntry>());
 1626  0 List<PredictiveInputFrame.CloseAction<JavaAPIListEntry>> actions
 1627    = new ArrayList<PredictiveInputFrame.CloseAction<JavaAPIListEntry>>();
 1628  0 actions.add(okAction);
 1629  0 actions.add(cancelAction);
 1630  0 _openJavadocDialog =
 1631    new PredictiveInputFrame<JavaAPIListEntry>(MainFrame.this,
 1632    "Open Java API Javadoc Webpage",
 1633    true, // force
 1634    true, // ignore case
 1635    info,
 1636    strategies,
 1637    actions, 1, // cancel is action 1
 1638    new JavaAPIListEntry("dummyJavadoc", "dummyJavadoc", null)) {
 1639  0 public void setOwnerEnabled(boolean b) {
 1640  0 if (b) hourglassOff();
 1641  0 else hourglassOn();
 1642    }
 1643    };
 1644    // putting one dummy entry in the list; it will be changed later anyway
 1645   
 1646  0 if (DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) {
 1647  0 _openJavadocDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STATE));
 1648    }
 1649  0 generateJavaAPISet();
 1650    }
 1651    }
 1652   
 1653    /** Generate Java API class list. */
 1654  1 public static Set<JavaAPIListEntry> _generateJavaAPISet(String base, String stripPrefix, String suffix) {
 1655  1 URL url = MainFrame.class.getResource("/edu/rice/cs/drjava/docs/javaapi"+suffix);
 1656  1 return _generateJavaAPISet(base, stripPrefix, url);
 1657    }
 1658   
 1659    /** Generate Java API class list. */
 1660  1 public static Set<JavaAPIListEntry> _generateJavaAPISet(String base, String stripPrefix, URL url) {
 1661  1 Set<JavaAPIListEntry> s = new HashSet<JavaAPIListEntry>();
 1662  0 if (url==null) return s;
 1663  1 try {
 1664  1 InputStream urls = url.openStream();
 1665  1 InputStreamReader is = null;
 1666  1 BufferedReader br = null;
 1667  1 try {
 1668  1 is = new InputStreamReader(urls);
 1669  1 br = new BufferedReader(is);
 1670  1 String line = br.readLine();
 1671  1 while(line != null) {
 1672  6589 final String aText = "<a href=\"";
 1673  6589 int aPos = line.toLowerCase().indexOf(aText);
 1674  6589 int aEndPos = line.toLowerCase().indexOf(".html\" ",aPos);
 1675  6589 if ((aPos>=0) && (aEndPos>=0)) {
 1676  3279 String link = line.substring(aPos+aText.length(), aEndPos);
 1677  3279 String fullClassName = link.substring(stripPrefix.length()).replace('/', '.');
 1678  3279 String simpleClassName = fullClassName;
 1679  3279 int lastDot = fullClassName.lastIndexOf('.');
 1680  3279 if (lastDot>=0) { simpleClassName = fullClassName.substring(lastDot + 1); }
 1681  3279 try {
 1682  3279 URL pageURL = new URL(base + link + ".html");
 1683  3279 s.add(new JavaAPIListEntry(simpleClassName, fullClassName, pageURL));
 1684    }
 1685    catch(MalformedURLException mue) { /* ignore, we'll just not put this class in the list */ }
 1686    }
 1687  6589 line = br.readLine();
 1688    }
 1689    }
 1690    finally {
 1691  1 if (br != null) { br.close(); }
 1692  1 if (is != null) { is.close(); }
 1693  1 if (urls != null) { urls.close(); }
 1694    }
 1695    }
 1696    catch(IOException ioe) { /* ignore, we'll just have an incomplete list */ }
 1697  1 return s;
 1698    }
 1699   
 1700    /** @return the set of all classes, scanned after the last compile. */
 1701  0 public Set<GoToFileListEntry> getCompleteClassSet() { return _completeClassSet; }
 1702   
 1703    /** Clear the set of all classes. */
 1704  3 public void clearCompleteClassSet() { _completeClassSet.clear(); }
 1705   
 1706    /** Clears the Java API class set. */
 1707  0 public void clearJavaAPISet() { _javaAPISet.clear(); }
 1708   
 1709    /** @return the Java API class set. */
 1710  0 public Set<JavaAPIListEntry> getJavaAPISet() {
 1711  0 if (_javaAPISet.size() == 0) generateJavaAPISet();
 1712  0 return _javaAPISet;
 1713    }
 1714   
 1715    /** Generate Java API class list. */
 1716  0 public void generateJavaAPISet() {
 1717    // should NOT be called in the event thread
 1718    // otherwise the processing frame will not work correctly and the event thread will block
 1719    // assert (!EventQueue.isDispatchThread()); // Why is this commented out???
 1720  0 if (_javaAPISet.size() == 0) {
 1721  0 final ProcessingDialog pd =
 1722    new ProcessingDialog(this, "Java API Classes", "Loading, please wait.", false);
 1723  0 if (!EventQueue.isDispatchThread()) { pd.setVisible(true); }
 1724    // generate list
 1725  0 String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION);
 1726   
 1727    // the string that will be ADDED to the beginning of the link to form the full URL
 1728  0 String base = "";
 1729   
 1730    // the string that will be REMOVED from the beginning of the link to form the fully-qualified class name
 1731  0 String stripPrefix = "";
 1732   
 1733    // the HTML file name that contains all the links
 1734  0 String suffix = "";
 1735  0 if (linkVersion.equals(JAVADOC_AUTO_TEXT)) {
 1736    // use the compiler's version of the Java API Javadoc
 1737  0 JavaVersion ver = _model.getCompilerModel().getActiveCompiler().version();
 1738  0 if (ver == JavaVersion.JAVA_1_4) linkVersion = JAVADOC_1_4_TEXT;
 1739  0 else if (ver == JavaVersion.JAVA_5) linkVersion = JAVADOC_1_5_TEXT;
 1740  0 else if (ver == JavaVersion.JAVA_6) linkVersion = JAVADOC_1_6_TEXT;
 1741  0 else if (ver == JavaVersion.JAVA_7) linkVersion = JAVADOC_1_7_TEXT;
 1742  0 else linkVersion = JAVADOC_1_3_TEXT; // ???? This looks like the wrong default; I would version 7.
 1743    }
 1744  0 if (linkVersion.equals(JAVADOC_1_3_TEXT)) {
 1745  0 base = DrJava.getConfig().getSetting(JAVADOC_1_3_LINK) + "/";
 1746  0 stripPrefix = ""; // nothing needs to be stripped, links in 1.3 Javadoc are relative
 1747  0 suffix = "/allclasses-1.3.html";
 1748    }
 1749  0 else if (linkVersion.equals(JAVADOC_1_4_TEXT)) {
 1750  0 base = DrJava.getConfig().getSetting(JAVADOC_1_4_LINK) + "/";
 1751  0 stripPrefix = ""; // nothing needs to be stripped, links in 1.4 Javadoc are relative
 1752  0 suffix = "/allclasses-1.4.html";
 1753    }
 1754  0 else if (linkVersion.equals(JAVADOC_1_5_TEXT)) {
 1755  0 base = DrJava.getConfig().getSetting(JAVADOC_1_5_LINK) + "/";
 1756  0 stripPrefix = ""; // nothing needs to be stripped, links in 1.5 Javadoc are relative
 1757  0 suffix = "/allclasses-1.5.html";
 1758    }
 1759  0 else if (linkVersion.equals(JAVADOC_1_6_TEXT)) {
 1760    // at one point, the links in the 1.6 Javadoc were absolute, and this is how we dealt with that
 1761    // base = ""; // links in 1.6 Javadoc are absolute, so nothing needs to be added to get an absolute URL
 1762    // // but we do need to strip the absolute part to get correct fully-qualified class names
 1763    // // and we take the default string here, not what the user entered, because the links in
 1764    // // our allclasses-1.6.html file go to the original Sun website.
 1765    // stripPrefix = JAVADOC_1_6_LINK.getDefaultString() + "/";
 1766  0 base = DrJava.getConfig().getSetting(JAVADOC_1_6_LINK) + "/";
 1767  0 stripPrefix = ""; // nothing needs to be stripped, links in 1.6 Javadoc are relative
 1768  0 suffix = "/allclasses-1.6.html";
 1769    }
 1770  0 else if (linkVersion.equals(JAVADOC_1_7_TEXT)) {
 1771  0 base = DrJava.getConfig().getSetting(JAVADOC_1_7_LINK) + "/";
 1772  0 stripPrefix = ""; // nothing needs to be stripped, links in 1.7 Javadoc are relative
 1773  0 suffix = "/allclasses-1.7.html";
 1774    }
 1775   
 1776  0 if (!suffix.equals("")) {
 1777  0 _javaAPISet.addAll(_generateJavaAPISet(base, stripPrefix, suffix));
 1778    }
 1779    else {
 1780    // no valid Javadoc URL
 1781    }
 1782   
 1783    // add JUnit
 1784  0 Set<JavaAPIListEntry> junitAPIList = _generateJavaAPISet(DrJava.getConfig().getSetting(JUNIT_LINK) + "/",
 1785    "", // relative links
 1786    "/allclasses-concjunit4.7.html");
 1787  0 _javaAPISet.addAll(junitAPIList);
 1788   
 1789    // add additional Javadoc libraries
 1790  0 for(String url: DrJava.getConfig().getSetting(JAVADOC_ADDITIONAL_LINKS)) {
 1791  0 try {
 1792  0 Set<JavaAPIListEntry> additionalList = _generateJavaAPISet(url + "/",
 1793    "", // relative links
 1794    new URL(url+"/allclasses-frame.html"));
 1795  0 _javaAPISet.addAll(additionalList);
 1796    }
 1797    catch(MalformedURLException mue) { /* ignore, we'll just not put this class in the list */ }
 1798    }
 1799   
 1800  0 if (_javaAPISet.size() == 0) { clearJavaAPISet(); }
 1801   
 1802    // finished
 1803  0 if (!EventQueue.isDispatchThread()) {
 1804  0 pd.setVisible(false);
 1805  0 pd.dispose();
 1806    }
 1807    }
 1808    }
 1809   
 1810    /** The "Open Javadoc" dialog instance. */
 1811    volatile PredictiveInputFrame<JavaAPIListEntry> _openJavadocDialog = null;
 1812   
 1813    /** The list of Java API classes. */
 1814    volatile Set<JavaAPIListEntry> _javaAPISet = new HashSet<JavaAPIListEntry>();
 1815   
 1816    /** Action that asks the user for a file name and goes there. Only executes in the event thread. */
 1817    private volatile Action _openJavadocAction = new AbstractAction("Open Java API Javadoc...") {
 1818  0 public void actionPerformed(ActionEvent ae) {
 1819  0 hourglassOn();
 1820  0 new Thread() {
 1821  0 public void run() {
 1822    // run this in a thread other than the main thread
 1823  0 initOpenJavadocDialog();
 1824  0 Utilities.invokeLater(new Runnable() {
 1825  0 public void run() {
 1826    // but now run this in the event thread again
 1827  0 _openJavadocDialog.setItems(true, getJavaAPISet()); // ignore case
 1828  0 _openJavadocDialog.setVisible(true);
 1829    }
 1830    });
 1831    }
 1832    }.start();
 1833    }
 1834    };
 1835   
 1836    /** Opens the Javadoc specified by the word the cursor is on. Only executes in the event thread. */
 1837  0 private void _openJavadocUnderCursor() {
 1838  0 hourglassOn();
 1839  0 new Thread() {
 1840  0 public void run() {
 1841    // run this in a thread other than the main thread
 1842  0 final Set<JavaAPIListEntry> apiSet = getJavaAPISet();
 1843  0 if (apiSet == null) {
 1844    // Utilities.show("Cannot load Java API class list. No network connectivity?");
 1845  0 hourglassOff();
 1846  0 return;
 1847    }
 1848  0 Utilities.invokeLater(new Runnable() {
 1849  0 public void run() {
 1850    // but now run this in the event thread again
 1851  0 PredictiveInputModel<JavaAPIListEntry> pim =
 1852    new PredictiveInputModel<JavaAPIListEntry>(true, new PrefixStrategy<JavaAPIListEntry>(), apiSet);
 1853  0 OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
 1854  0 String mask = "";
 1855  0 int loc = getCurrentDefPane().getCaretPosition();
 1856  0 String s = odd.getText();
 1857    // find start
 1858  0 int start = loc;
 1859  0 while(start > 0) {
 1860  0 if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; }
 1861  0 --start;
 1862    }
 1863  0 while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start<loc)) {
 1864  0 ++start;
 1865    }
 1866    // find end
 1867  0 int end = loc-1;
 1868  0 while(end<s.length()-1) {
 1869  0 if (!Character.isJavaIdentifierPart(s.charAt(end+1))) { break; }
 1870  0 ++end;
 1871    }
 1872  0 if ((start>=0) && (end<s.length())) {
 1873  0 mask = s.substring(start, end + 1);
 1874  0 pim.setMask(mask);
 1875    }
 1876   
 1877    // Utilities.show("Matching items are: " + pim.getMatchingItems());
 1878   
 1879  0 if (pim.getMatchingItems().size() == 1) {
 1880    // exactly one match, go to file
 1881  0 if (pim.getCurrentItem() != null) {
 1882  0 PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL());
 1883  0 hourglassOff();
 1884    }
 1885    }
 1886    else {
 1887    // try appending ".java" and the other file extensions and see if it's unique
 1888  0 boolean exact = false;
 1889  0 for(String attemptedExt: OptionConstants.LANGUAGE_LEVEL_EXTENSIONS) {
 1890  0 pim.setMask(mask);
 1891  0 pim.extendMask(attemptedExt);
 1892  0 if (pim.getMatchingItems().size() == 1) {
 1893    // exactly one match with ".java" appended, go to file
 1894  0 exact = true;
 1895  0 if (pim.getCurrentItem() != null) {
 1896  0 PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL());
 1897  0 hourglassOff();
 1898    }
 1899  0 break;
 1900    }
 1901    }
 1902  0 if (!exact) {
 1903    // not exactly one match
 1904  0 pim.setMask(mask);
 1905  0 int found = 0;
 1906  0 if (pim.getMatchingItems().size() == 0) {
 1907    // if there are no matches, shorten the mask until there is at least one
 1908  0 mask = pim.getMask();
 1909  0 while(mask.length() > 0) {
 1910  0 mask = mask.substring(0, mask.length() - 1);
 1911  0 pim.setMask(mask);
 1912  0 if (pim.getMatchingItems().size() > 0) { break; }
 1913    }
 1914    }
 1915    else {
 1916    // there are several matches, see if there is an exact match
 1917  0 for(JavaAPIListEntry e: pim.getMatchingItems()) {
 1918  0 if (e.toString().equalsIgnoreCase(mask)) {
 1919  0 ++found;
 1920    }
 1921    }
 1922    }
 1923  0 if (found==1) {
 1924    // open unique item and return
 1925  0 PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL());
 1926  0 hourglassOff();
 1927    }
 1928    else {
 1929  0 initOpenJavadocDialog();
 1930  0 _openJavadocDialog.setModel(true, pim); // ignore case
 1931  0 _openJavadocDialog.setVisible(true);
 1932    }
 1933    }
 1934    }
 1935    }
 1936    });
 1937    }
 1938    }.start();
 1939    }
 1940   
 1941    /** Open Javadoc page specified by the word the cursor is on. */
 1942    final Action _openJavadocUnderCursorAction = new AbstractAction("Open Java API Javadoc for Word Under Cursor...") {
 1943  0 public void actionPerformed(ActionEvent ae) {
 1944  0 _openJavadocUnderCursor();
 1945    }
 1946    };
 1947   
 1948    /** Close input stream in the interactions pane. */
 1949    final Action _closeSystemInAction = new AbstractAction("Close System.in") {
 1950  0 public void actionPerformed(ActionEvent ae){
 1951  0 _interactionsController.setEndOfStream(true);
 1952  0 _interactionsController.interruptConsoleInput();
 1953    }
 1954    };
 1955   
 1956    /** The "Complete Word" dialog instance. */
 1957    private volatile AutoCompletePopup _completeWordDialog = null;
 1958   
 1959    /** Initialize the "Complete Word" dialog. */
 1960  0 private void initCompleteWordDialog() {
 1961  0 if (_completeWordDialog==null) {
 1962  0 _completeWordDialog = new AutoCompletePopup(this);
 1963    }
 1964    }
 1965   
 1966   
 1967    /** Complete the word the cursor is on. Only executes in the event thread. */
 1968  0 private void _completeWordUnderCursor() {
 1969  0 initCompleteWordDialog();
 1970  0 hourglassOn();
 1971   
 1972  0 final OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
 1973  0 final int loc = getCurrentDefPane().getCaretPosition();
 1974  0 try {
 1975  0 final String initial = odd.getText(0, loc);
 1976  0 _completeWordDialog.show(this,
 1977    "Complete Word",
 1978    initial,
 1979    loc,
 1980    IterUtil.make("OK", "Fully Qualified"),
 1981    IterUtil.make(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
 1982    KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, OptionConstants.MASK)),
 1983    0, // simple class name action if just one match
 1984    new Runnable() {
 1985  0 public void run() {
 1986    // canceled
 1987  0 hourglassOff();
 1988  0 MainFrame.this.toFront();
 1989    }
 1990    },
 1991    IterUtil.make(new Runnable3<AutoCompletePopupEntry,Integer,Integer>() {
 1992  0 public void run(AutoCompletePopupEntry entry, Integer from, Integer to) {
 1993    // accepted
 1994  0 try {
 1995  0 odd.remove(from, to-from);
 1996  0 odd.insertString(from, entry.getClassName(), null);
 1997    }
 1998    catch(BadLocationException ble) { /* just don't complete */ }
 1999   
 2000  0 hourglassOff();
 2001  0 MainFrame.this.toFront();
 2002    }
 2003    }, new Runnable3<AutoCompletePopupEntry,Integer,Integer>() {
 2004  0 public void run(AutoCompletePopupEntry entry,
 2005    Integer from,
 2006    Integer to) {
 2007    // accepted
 2008  0 try {
 2009  0 odd.remove(from, to-from);
 2010  0 odd.insertString(from, entry.getFullPackage()+entry.getClassName(), null);
 2011    }
 2012    catch(BadLocationException ble) { /* just don't complete */ }
 2013   
 2014  0 hourglassOff();
 2015  0 MainFrame.this.toFront();
 2016    }
 2017    }));
 2018    }
 2019    catch(BadLocationException ble) { /* just don't complete */ }
 2020    }
 2021   
 2022  0 public void resetCompleteWordDialogPosition() {
 2023  0 initCompleteWordDialog();
 2024  0 _completeWordDialog.setFrameState("default");
 2025  0 if (DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) {
 2026  0 DrJava.getConfig().setSetting(DIALOG_COMPLETE_WORD_STATE, "default");
 2027    }
 2028    }
 2029   
 2030    /** Auto-completes word the cursor is on. */
 2031    final Action completeWordUnderCursorAction = new AbstractAction("Auto-Complete Word Under Cursor") {
 2032  0 public void actionPerformed(ActionEvent ae) {
 2033  0 _completeWordUnderCursor();
 2034    }
 2035    };
 2036   
 2037    /** Indents the current selection. */
 2038    private final Action _indentLinesAction = new AbstractAction("Indent Line(s)") {
 2039  0 public void actionPerformed(ActionEvent ae) {
 2040  0 hourglassOn();
 2041  0 try {
 2042  0 _currentDefPane.endCompoundEdit();
 2043  0 _currentDefPane.indent();
 2044    } finally {
 2045  0 hourglassOff();
 2046    }
 2047    }
 2048    };
 2049   
 2050    /** Action for commenting out a block of text using wing comments. */
 2051    private final Action _commentLinesAction = new AbstractAction("Comment Line(s)") {
 2052  0 public void actionPerformed(ActionEvent ae) {
 2053  0 hourglassOn();
 2054  0 try{ commentLines(); }
 2055  0 finally{ hourglassOff(); }
 2056    }
 2057    };
 2058   
 2059    /** Action for un-commenting a block of commented text. */
 2060    private final Action _uncommentLinesAction = new AbstractAction("Uncomment Line(s)") {
 2061  0 public void actionPerformed(ActionEvent ae){
 2062  0 hourglassOn();
 2063  0 try{ uncommentLines(); }
 2064  0 finally{ hourglassOff(); }
 2065    }
 2066    };
 2067   
 2068    /** Saves a copy of DrJava's output console to a file. */
 2069    private final Action _saveConsoleCopyAction = new AbstractAction("Save Copy of Console...") {
 2070  0 public void actionPerformed(ActionEvent ae) {
 2071  0 updateStatusField("Saving Copy of Console");
 2072  0 _saveConsoleCopy(_model.getConsoleDocument());
 2073  0 _consolePane.requestFocusInWindow();
 2074    }
 2075    };
 2076   
 2077    /** Saves a copy of either the console or the interactions pane to a file. */
 2078  0 public void _saveConsoleCopy(ConsoleDocument doc) {
 2079  0 _saveChooser.resetChoosableFileFilters();
 2080  0 _saveChooser.setFileFilter(_txtFileFilter);
 2081  0 _saveChooser.setMultiSelectionEnabled(false);
 2082  0 _saveChooser.setSelectedFile(new File(""));
 2083  0 try {
 2084  0 _model.saveConsoleCopy(doc, new FileSaveSelector() {
 2085  0 public File getFile() throws OperationCanceledException {
 2086  0 int rc = _saveChooser.showSaveDialog(MainFrame.this);
 2087  0 switch (rc) {
 2088  0 case JFileChooser.CANCEL_OPTION:
 2089  0 case JFileChooser.ERROR_OPTION:
 2090  0 throw new OperationCanceledException();
 2091  0 case JFileChooser.APPROVE_OPTION:
 2092  0 File chosen = _saveChooser.getSelectedFile();
 2093  0 if (chosen != null) {
 2094    // append the .txt extension if no . written by user
 2095  0 if (chosen.getName().indexOf(".") == -1)
 2096  0 return new File(chosen.getAbsolutePath() + TEXT_FILE_EXTENSION);
 2097  0 return chosen;
 2098    }
 2099    else
 2100  0 throw new RuntimeException("Filechooser returned null file");
 2101    }
 2102    // impossible since rc must be one of these
 2103  0 throw new RuntimeException("Filechooser returned bad rc " + rc);
 2104    }
 2105  0 public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
 2106  0 public boolean verifyOverwrite(File f) { return MainFrameStatics.verifyOverwrite(MainFrame.this, f); }
 2107  0 public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
 2108  0 public boolean shouldUpdateDocumentState() { return false; }
 2109    });
 2110    }
 2111    catch (IOException ioe) {
 2112  0 MainFrameStatics.showIOError(MainFrame.this, new IOException("An error occured writing the contents to a file"));
 2113    }
 2114    }
 2115   
 2116    /** Saves a copy of an error pane to a file. */
 2117  0 public void _saveDocumentCopy(final SwingDocument doc) {
 2118  0 assert EventQueue.isDispatchThread();
 2119   
 2120  0 _saveChooser.resetChoosableFileFilters();
 2121  0 _saveChooser.setFileFilter(_txtFileFilter);
 2122  0 _saveChooser.setMultiSelectionEnabled(false);
 2123  0 _saveChooser.setSelectedFile(new File(""));
 2124  0 try {
 2125  0 FileSaveSelector selector = new FileSaveSelector() {
 2126  0 public File getFile() throws OperationCanceledException {
 2127  0 int rc = _saveChooser.showSaveDialog(MainFrame.this);
 2128  0 switch (rc) {
 2129  0 case JFileChooser.CANCEL_OPTION:
 2130  0 case JFileChooser.ERROR_OPTION:
 2131  0 throw new OperationCanceledException();
 2132  0 case JFileChooser.APPROVE_OPTION:
 2133  0 File chosen = _saveChooser.getSelectedFile();
 2134  0 if (chosen != null) {
 2135    // append the .txt extension if no . written by user
 2136  0 if (chosen.getName().indexOf(".") == -1)
 2137  0 return new File(chosen.getAbsolutePath() + TEXT_FILE_EXTENSION);
 2138  0 return chosen;
 2139    }
 2140    else
 2141  0 throw new RuntimeException("Filechooser returned null file");
 2142    }
 2143    // impossible since rc must be one of these
 2144  0 throw new RuntimeException("Filechooser returned bad rc " + rc);
 2145    }
 2146  0 public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
 2147  0 public boolean verifyOverwrite(File f) { return MainFrameStatics.verifyOverwrite(MainFrame.this, f); }
 2148  0 public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
 2149  0 public boolean shouldUpdateDocumentState() { return false; }
 2150    };
 2151   
 2152  0 try {
 2153  0 final File file = selector.getFile();
 2154    // by getting the canonical file, we make sure that we get an IOException if the filename is illegal
 2155  0 if (! file.getCanonicalFile().exists() || selector.verifyOverwrite(file)) { // confirm that existing file can be overwritten
 2156  0 FileOps.saveFile(new FileOps.DefaultFileSaver(file) {
 2157    /** Only runs in event thread so no read lock is necessary. */
 2158  0 public void saveTo(OutputStream os) throws IOException {
 2159  0 final String text = doc.getText();
 2160  0 OutputStreamWriter osw = new OutputStreamWriter(os);
 2161  0 osw.write(text,0,text.length());
 2162  0 osw.flush();
 2163    }
 2164    });
 2165    }
 2166    }
 2167    catch (OperationCanceledException oce) {
 2168    // Thrown by selector.getFile() if the user cancels.
 2169    // We don't do anything if this happens.
 2170  0 return;
 2171    }
 2172    }
 2173    catch (IOException ioe) {
 2174  0 MainFrameStatics.showIOError(MainFrame.this, new IOException("An error occured writing the contents to a file"));
 2175    }
 2176    }
 2177   
 2178    /** Clears DrJava's output console. */
 2179    private final Action _clearConsoleAction = new AbstractAction("Clear Console") {
 2180  0 public void actionPerformed(ActionEvent ae) { _model.resetConsole(); }
 2181    };
 2182   
 2183    /** Shows the DebugConsole. */
 2184    private final Action _showDebugConsoleAction = new AbstractAction("Show DrJava Debug Console") {
 2185  0 public void actionPerformed(ActionEvent e) { DrJavaRoot.showDrJavaDebugConsole(MainFrame.this); }
 2186    };
 2187   
 2188    /** Resets the Interactions pane. */
 2189    private final Action _resetInteractionsAction = new AbstractAction("Reset Interactions") {
 2190  0 public void actionPerformed(ActionEvent ae) {
 2191  0 if (! DrJava.getConfig().getSetting(INTERACTIONS_RESET_PROMPT).booleanValue()) {
 2192  0 _doResetInteractions();
 2193   
 2194  0 return;
 2195    }
 2196   
 2197  0 String title = "Confirm Reset Interactions";
 2198  0 String message = "Are you sure you want to reset the Interactions Pane?";
 2199  0 ConfirmCheckBoxDialog dialog =
 2200    new ConfirmCheckBoxDialog(MainFrame.this, title, message);
 2201  0 int rc = dialog.show();
 2202  0 if (rc == JOptionPane.YES_OPTION) {
 2203  0 _doResetInteractions();
 2204   
 2205  0 if (dialog.getCheckBoxValue()) {
 2206  0 DrJava.getConfig().setSetting(INTERACTIONS_RESET_PROMPT, Boolean.FALSE);
 2207    }
 2208    }
 2209    }
 2210    };
 2211   
 2212  0 private void _doResetInteractions() {
 2213  0 _tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
 2214  0 updateStatusField("Resetting Interactions");
 2215    // Lots of work, so use another thread
 2216  0 _interactionsPane.discardUndoEdits();
 2217  0 new Thread(new Runnable() {
 2218  0 public void run() {
 2219  0 _model.resetInteractions(_model.getWorkingDirectory(), true);
 2220  0 _closeSystemInAction.setEnabled(true);
 2221    }
 2222    }).start();
 2223    }
 2224   
 2225    /** Defines actions that displays the interactions classpath. */
 2226    private final Action _viewInteractionsClassPathAction = new AbstractAction("View Interactions Classpath...") {
 2227  0 public void actionPerformed(ActionEvent e) { viewInteractionsClassPath(); }
 2228    };
 2229   
 2230    /** Displays the interactions classpath. */
 2231  0 public void viewInteractionsClassPath() {
 2232  0 String cp = IterUtil.multilineToString(IterUtil.filter(_model.getInteractionsClassPath(),
 2233    new Predicate<File>() {
 2234    HashSet<File> alreadySeen = new HashSet<File>();
 2235  0 public boolean contains(File arg) {
 2236    // filter out empty strings and duplicates
 2237  0 return !("".equals(arg.toString().trim())) && alreadySeen.add(arg);
 2238    }
 2239    }));
 2240  0 new DrJavaScrollableDialog(this, "Interactions Classpath", "Current Interpreter Classpath", cp).show();
 2241    }
 2242   
 2243    /** Action that shows what help documentation is available. Only executes in the event thread. */
 2244    private final Action _helpAction = new AbstractAction("Help") {
 2245  0 public void actionPerformed(ActionEvent ae) {
 2246  0 _helpFrame.setVisible(true);
 2247    }
 2248    };
 2249   
 2250    /** Action that shows the quick start documentation. Only executes in the event thread. */
 2251    private final Action _quickStartAction = new AbstractAction("QuickStart") {
 2252  0 public void actionPerformed(ActionEvent ae) {
 2253  0 _quickStartFrame.setVisible(true);
 2254    }
 2255    };
 2256   
 2257    /** Action that pops up an info dialog. Only runs in the event thread. */
 2258    private final Action _aboutAction = new AbstractAction("About") {
 2259  0 public void actionPerformed(ActionEvent ae) {
 2260  0 _aboutDialog.setVisible(true);
 2261    }
 2262    };
 2263   
 2264    /** Action that pops up a dialog that checks for a new version. Only runs in the event thread. */
 2265    private final Action _checkNewVersionAction = new AbstractAction("Check for New Version") {
 2266  0 public void actionPerformed(ActionEvent ae) {
 2267  0 NewVersionPopup popup = new NewVersionPopup(MainFrame.this);
 2268  0 popup.setVisible(true);
 2269    }
 2270    };
 2271   
 2272    // /** Asks whether DrJava may contact the DrJava developers and send system information. */
 2273    // private final Action _drjavaSurveyAction = new AbstractAction("Send System Information") {
 2274    // public void actionPerformed(ActionEvent ae) {
 2275    // DrJavaSurveyPopup popup = new DrJavaSurveyPopup(MainFrame.this);
 2276    // popup.setVisible(true);
 2277    // }
 2278    // };
 2279   
 2280    /** Action that pops up the DrJava errors dialog. Only runs in the event thread. */
 2281    private final Action _errorsAction = new AbstractAction("DrJava Errors") {
 2282  0 public void actionPerformed(ActionEvent ae) {
 2283  0 setPopupLoc(DrJavaErrorWindow.singleton());
 2284  0 DrJavaErrorWindow.singleton().setVisible(true);
 2285    }
 2286    };
 2287   
 2288    /** Action that pops up the dialog to generate a custom drjava.jar file.
 2289    * Only runs in the event thread. */
 2290    private final Action _generateCustomDrJavaJarAction = new AbstractAction("Generate Custom drjava.jar...") {
 2291  0 public void actionPerformed(ActionEvent ae) {
 2292  0 GenerateCustomDrJavaJarFrame popup = new GenerateCustomDrJavaJarFrame(MainFrame.this);
 2293  0 popup.setVisible(true);
 2294    }
 2295    };
 2296   
 2297    /** Action that starts a new, blank, unconnected DrJava instance. */
 2298    private final Action _newDrJavaInstanceAction = new AbstractAction("New DrJava Instance...") {
 2299  0 public void actionPerformed(ActionEvent ae) {
 2300  0 try {
 2301  0 Process p = JVMBuilder.DEFAULT.classPath(FileOps.getDrJavaFile()).
 2302    start(DrJava.class.getName(), "-new");
 2303    }
 2304  0 catch(IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 2305    }
 2306    };
 2307   
 2308    /** Action that switches to next document. Only runs in the event thread. */
 2309    private final Action _switchToNextAction = new AbstractAction("Next Document") {
 2310  0 public void actionPerformed(ActionEvent ae) {
 2311  0 this.setEnabled(false);
 2312  0 if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
 2313  0 _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
 2314    //disables switching documents while the next one is opening up, in order to prevent out of control switching
 2315  0 _model.setActiveNextDocument();
 2316  0 _findReplace.updateFirstDocInSearch();
 2317  0 this.setEnabled(true);
 2318    // defer executing this code until after active document switch (if any) is complete
 2319  0 addToBrowserHistory();
 2320    }
 2321    };
 2322   
 2323    /** Switches to previous document. */
 2324    private final Action _switchToPrevAction = new AbstractAction("Previous Document") {
 2325  0 public void actionPerformed(ActionEvent ae) {
 2326  0 this.setEnabled(false);
 2327  0 if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
 2328  0 _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
 2329  0 _model.setActivePreviousDocument();
 2330  0 _findReplace.updateFirstDocInSearch();
 2331  0 this.setEnabled(true);
 2332    // defer executing this code until after active document switch (if any) is complete
 2333  0 addToBrowserHistory();
 2334    }
 2335    };
 2336   
 2337    /** Switches focus to next pane. */
 2338    private final Action _switchToNextPaneAction = new AbstractAction("Next Pane") {
 2339  0 public void actionPerformed(ActionEvent ae) {
 2340  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 2341  0 _mainSplit.resetToPreferredSizes();
 2342  0 this.setEnabled(false);
 2343  0 _switchPaneFocus(true);
 2344  0 this.setEnabled(true);
 2345    }
 2346    };
 2347   
 2348    /** Browse back in the browser history. */
 2349    private final Action _browseBackAction = new AbstractAction("Browse Back") {
 2350  0 public void actionPerformed(ActionEvent ae) {
 2351  0 updateStatusField("Browsing Back");
 2352  0 this.setEnabled(false);
 2353  0 if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
 2354  0 _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
 2355    //disables switching documents while the next one is opening up, in order to prevent out of control switching
 2356   
 2357    // add current location to history
 2358  0 BrowserHistoryManager rm = _model.getBrowserHistoryManager();
 2359  0 addToBrowserHistory();
 2360   
 2361    // then move back
 2362  0 BrowserDocumentRegion r = rm.prevCurrentRegion(_model.getNotifier());
 2363  0 if (r != null) scrollToDocumentAndOffset(r.getDocument(), r.getStartOffset(), false, false);
 2364  0 _configureBrowsing();
 2365    // MainFrame.MFLOG.log("browseBack: "+rm);
 2366    }
 2367    };
 2368   
 2369    /** Browse forward in the browser history. */
 2370    private final Action _browseForwardAction = new AbstractAction("Browse Forward") {
 2371  0 public void actionPerformed(ActionEvent ae) {
 2372  0 updateStatusField("Browsing Forward");
 2373  0 this.setEnabled(false);
 2374  0 if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation())
 2375  0 _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue());
 2376    //disables switching documents while the next one is opening up, in order to prevent out of control switching
 2377   
 2378    // add current location to history
 2379  0 BrowserHistoryManager rm = _model.getBrowserHistoryManager();
 2380  0 addToBrowserHistoryBefore();
 2381   
 2382    // then move forward
 2383  0 BrowserDocumentRegion r = rm.nextCurrentRegion(_model.getNotifier());
 2384  0 if (r != null) scrollToDocumentAndOffset(r.getDocument(), r.getStartOffset(), false, false);
 2385  0 _configureBrowsing();
 2386    // MainFrame.MFLOG.log("browseForward: "+rm);
 2387    }
 2388    };
 2389   
 2390    /** Jump to the next region in the tabbed pane. */
 2391    private final Action _nextRegionAction = new AbstractAction("Next Region") {
 2392  0 public void actionPerformed(ActionEvent ae) {
 2393  0 Component c = _tabbedPane.getComponentAt(_tabbedPane.getSelectedIndex());
 2394  0 if (c instanceof RegionsTreePanel) {
 2395  0 RegionsTreePanel<?> rtp = (RegionsTreePanel<?>)c;
 2396  0 rtp.goToNextRegion();
 2397    }
 2398    }
 2399    };
 2400   
 2401    /** Jump to the previous region in the tabbed pane. */
 2402    private final Action _prevRegionAction = new AbstractAction("Previous Region") {
 2403  0 public void actionPerformed(ActionEvent ae) {
 2404  0 Component c = _tabbedPane.getComponentAt(_tabbedPane.getSelectedIndex());
 2405  0 if (c instanceof RegionsTreePanel) {
 2406  0 RegionsTreePanel<?> rtp = (RegionsTreePanel<?>)c;
 2407  0 rtp.goToPreviousRegion();
 2408    }
 2409    }
 2410    };
 2411   
 2412    /** Switches focus to previous pane. */
 2413    private final Action _switchToPreviousPaneAction = new AbstractAction("Previous Pane") {
 2414  0 public void actionPerformed(ActionEvent ae) {
 2415  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 2416  0 _mainSplit.resetToPreferredSizes();
 2417  0 this.setEnabled(false);
 2418  0 _switchPaneFocus(false);
 2419  0 this.setEnabled(true);
 2420    }
 2421    };
 2422   
 2423    /** Go to the closing brace. */
 2424    private final Action _gotoClosingBraceAction = new AbstractAction("Go to Closing Brace") {
 2425  0 public void actionPerformed(ActionEvent ae) {
 2426  0 OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
 2427  0 try {
 2428  0 int pos = odd.findNextEnclosingBrace(getCurrentDefPane().getCaretPosition(), '{', '}');
 2429  0 if (pos != -1) { getCurrentDefPane().setCaretPosition(pos); }
 2430    }
 2431    catch(BadLocationException ble) { /* just ignore and don't move */ }
 2432    }
 2433    };
 2434   
 2435    /** Go to the opening brace. */
 2436    private final Action _gotoOpeningBraceAction = new AbstractAction("Go to Opening Brace") {
 2437  0 public void actionPerformed(ActionEvent ae) {
 2438  0 OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument();
 2439  0 try {
 2440  0 int pos = odd.findPrevEnclosingBrace(getCurrentDefPane().getCaretPosition(), '{', '}');
 2441  0 if (pos != -1) { getCurrentDefPane().setCaretPosition(pos); }
 2442    }
 2443    catch(BadLocationException ble) { /* just ignore and don't move */ }
 2444    }
 2445    };
 2446   
 2447    /** This takes a component and gives it focus, showing it if it's a tab. The interactionsPane and consolePane
 2448    * are wrapped in scrollpanes, so we have to specifically check for those and unwrap them.
 2449    * @param c the pane to switch focus to
 2450    */
 2451  0 private void _switchToPane(Component c) {
 2452  0 Component newC = c;
 2453    // if (c == _interactionsContainer) newC = _interactionsPane;
 2454    // if (c == _consoleScroll) newC = _consolePane;
 2455  0 showTab(newC, true);
 2456    }
 2457   
 2458    /** This method allows the user to cycle through the definitions pane and all of the open tabs.
 2459    * @param next true if we want to go to the next pane, false if the previous.
 2460    */
 2461  0 private void _switchPaneFocus(boolean next) {
 2462  0 int numTabs = _tabbedPane.getTabCount();
 2463   
 2464    /* If next, then we go to the next tab */
 2465  0 if (next) _switchToPane(_tabbedPane.getComponentAt((numTabs + _tabbedPane.getSelectedIndex() +1 ) % numTabs));
 2466  0 else _switchToPane(_tabbedPane.getComponentAt((numTabs + _tabbedPane.getSelectedIndex() - 1) % numTabs));
 2467    }
 2468   
 2469    /** Action that calls the ConfigFrame to edit preferences. Only runs in the event thread. */
 2470    private final Action _editPreferencesAction = new AbstractAction("Preferences ...") {
 2471  0 public void actionPerformed(ActionEvent ae) {
 2472  0 editPreferences();
 2473    }
 2474    };
 2475   
 2476  0 public void editPreferences() {
 2477  0 _configFrame.setUp();
 2478  0 setPopupLoc(_configFrame);
 2479  0 _configFrame.resetToCurrent();
 2480  0 _configFrame.setVisible(true);
 2481  0 _configFrame.toFront();
 2482    }
 2483   
 2484    private volatile AbstractAction _projectPropertiesAction = new AbstractAction("Project Properties") {
 2485  38 { _addGUIAvailabilityListener(this,
 2486    GUIAvailabilityListener.ComponentType.PROJECT,
 2487    GUIAvailabilityListener.ComponentType.COMPILER,
 2488    GUIAvailabilityListener.ComponentType.JUNIT); }
 2489  0 public void actionPerformed(ActionEvent ae) { _editProject(); }
 2490    };
 2491   
 2492    /** Action that enables the debugger. Only runs in the event thread. */
 2493    private final Action _toggleDebuggerAction = new AbstractAction("Debug Mode") {
 2494  38 { _addGUIAvailabilityListener(this,
 2495    GUIAvailabilityListener.ComponentType.INTERACTIONS); }
 2496  0 public void actionPerformed(ActionEvent ae) {
 2497  0 _guiAvailabilityNotifier.unavailable(GUIAvailabilityListener.ComponentType.INTERACTIONS);
 2498  0 debuggerToggle();
 2499  0 _guiAvailabilityNotifier.available(GUIAvailabilityListener.ComponentType.INTERACTIONS);
 2500    }
 2501    };
 2502   
 2503    /** Action that resumes debugging. Only runs in the event thread. */
 2504    private final Action _resumeDebugAction = new AbstractAction("Resume Debugger") {
 2505  38 { _addGUIAvailabilityListener(this,
 2506    GUIAvailabilityListener.ComponentType.DEBUGGER,
 2507    GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED); }
 2508  0 public void actionPerformed(ActionEvent ae) {
 2509  0 try { debuggerResume(); }
 2510  0 catch (DebugException de) { MainFrameStatics.showDebugError(MainFrame.this, de); }
 2511    }
 2512    };
 2513   
 2514    // menu item (checkbox menu) for automatic trace in the debugger
 2515    private volatile JMenuItem _automaticTraceMenuItem;
 2516   
 2517  38 public void setAutomaticTraceMenuItemStatus() {
 2518  38 if (_automaticTraceMenuItem != null) {
 2519  38 _automaticTraceMenuItem.setSelected(_model.getDebugger().isAutomaticTraceEnabled());
 2520    }
 2521    }
 2522   
 2523    /** Action that automatically traces through entire program*/
 2524    private final Action _automaticTraceDebugAction = new AbstractAction("Automatic Trace") {
 2525  38 { _addGUIAvailabilityListener(this,
 2526    GUIAvailabilityListener.ComponentType.DEBUGGER,
 2527    GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED); }
 2528  0 public void actionPerformed(ActionEvent ae) {
 2529  0 debuggerAutomaticTrace();
 2530    }
 2531    };
 2532   
 2533    /** Action that steps into the next method call. Only runs in the event thread. */
 2534    private final Action _stepIntoDebugAction = new AbstractAction("Step Into") {
 2535  38 { _addGUIAvailabilityListener(this,
 2536    GUIAvailabilityListener.ComponentType.DEBUGGER,
 2537    GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED); }
 2538  0 public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.StepType.STEP_INTO); }
 2539    };
 2540   
 2541    /** Action that executes the next line, without stepping into methods. Only runs in the event thread. */
 2542    private final Action _stepOverDebugAction = new AbstractAction("Step Over") {
 2543  38 { _addGUIAvailabilityListener(this,
 2544    GUIAvailabilityListener.ComponentType.DEBUGGER,
 2545    GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED); }
 2546  0 public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.StepType.STEP_OVER); }
 2547    };
 2548   
 2549    /** Action that steps out of the next method call. Only runs in the event thread. */
 2550    private final Action _stepOutDebugAction = new AbstractAction("Step Out") {
 2551  38 { _addGUIAvailabilityListener(this,
 2552    GUIAvailabilityListener.ComponentType.DEBUGGER,
 2553    GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED); }
 2554  0 public void actionPerformed(ActionEvent ae) {
 2555  0 debuggerStep(Debugger.StepType.STEP_OUT);
 2556    }
 2557    };
 2558   
 2559    /** Suspend debugging */
 2560    /*private Action _suspendDebugAction =
 2561    new AbstractAction("Suspend Debugger")
 2562    {
 2563    public void actionPerformed(ActionEvent ae) {
 2564    _debugSuspend();
 2565    }
 2566    };*/
 2567   
 2568    /** Toggles a breakpoint on the current line */
 2569    final Action _toggleBreakpointAction = new AbstractAction("Toggle Breakpoint on Current Line") {
 2570  0 public void actionPerformed(ActionEvent ae) { debuggerToggleBreakpoint(); }
 2571    };
 2572   
 2573    /** Clears all breakpoints */
 2574    private final Action _clearAllBreakpointsAction = new AbstractAction("Clear All Breakpoints") {
 2575  0 public void actionPerformed(ActionEvent ae) { debuggerClearAllBreakpoints(); }
 2576    };
 2577   
 2578   
 2579    /** Action that shows the breakpoints tab. Only runs in the event thread. */
 2580    private final Action _breakpointsPanelAction = new AbstractAction("Breakpoints") {
 2581  0 public void actionPerformed(ActionEvent ae) {
 2582  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 2583  0 _mainSplit.resetToPreferredSizes();
 2584  0 showTab(_breakpointsPanel, true);
 2585  0 _breakpointsPanel.setVisible(true);
 2586  0 _tabbedPane.setSelectedComponent(_breakpointsPanel);
 2587    // Use EventQueue.invokeLater to ensure that focus is set AFTER the _breakpointsPanel has been selected
 2588  0 EventQueue.invokeLater(new Runnable() { public void run() { _breakpointsPanel.requestFocusInWindow(); } });
 2589    }
 2590    };
 2591   
 2592    /** Action that shows the bookmarks tab. Only runs in the event thread. */
 2593    private final Action _bookmarksPanelAction = new AbstractAction("Bookmarks") {
 2594  0 public void actionPerformed(ActionEvent ae) {
 2595  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation())
 2596  0 _mainSplit.resetToPreferredSizes();
 2597  0 showTab(_bookmarksPanel, true);
 2598  0 _tabbedPane.setSelectedComponent(_bookmarksPanel);
 2599    // Use EventQueue.invokeLater to ensure that focus is set AFTER the _bookmarksPanel has been selected
 2600  0 EventQueue.invokeLater(new Runnable() { public void run() { _bookmarksPanel.requestFocusInWindow(); } });
 2601    }
 2602    };
 2603   
 2604    /** Toggles a bookmark. */
 2605    private final Action _toggleBookmarkAction = new AbstractAction("Toggle Bookmark") {
 2606  0 public void actionPerformed(ActionEvent ae) { toggleBookmark(); }
 2607    };
 2608   
 2609    /** Toggle a bookmark. */
 2610  0 public void toggleBookmark() {
 2611    // Utilities.show("MainFrame.toggleBookmark called");
 2612  0 assert EventQueue.isDispatchThread();
 2613  0 addToBrowserHistory();
 2614  0 _model._toggleBookmark(_currentDefPane.getSelectionStart(), _currentDefPane.getSelectionEnd());
 2615  0 showTab(_bookmarksPanel, true);
 2616    }
 2617   
 2618    /** Add the current location to the browser history. */
 2619  5 public void addToBrowserHistory() { _model.addToBrowserHistory(); }
 2620    /** Add the current location to the browser history before the current region. */
 2621  0 public void addToBrowserHistoryBefore() { _model.addToBrowserHistory(true); }
 2622   
 2623    /** Create a new find results tab.
 2624    * @param rm the region manager that will contain the regions
 2625    * @param title the title for the panel
 2626    * @return new find results tab.
 2627    * @param searchString string that was searched for
 2628    * @param searchAll whether all files were searched
 2629    * @param doc weak reference to document in which search occurred (or started, if all documents were searched)
 2630    * @param findReplace the FindReplacePanel that created this FindResultsPanel
 2631    */
 2632  0 public FindResultsPanel createFindResultsPanel(final RegionManager<MovingDocumentRegion> rm,
 2633    MovingDocumentRegion region, String title,
 2634    String searchString, boolean searchAll, boolean searchSelectionOnly,
 2635    boolean matchCase, boolean wholeWord, boolean noComments,
 2636    boolean noTestCases, WeakReference<OpenDefinitionsDocument> doc,
 2637    FindReplacePanel findReplace) {
 2638   
 2639  0 final FindResultsPanel panel = new FindResultsPanel(this, rm, region, title, searchString, searchAll,
 2640    searchSelectionOnly, matchCase, wholeWord, noComments,
 2641    noTestCases, doc, findReplace);
 2642   
 2643  0 final AbstractMap<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights =
 2644    new IdentityHashMap<MovingDocumentRegion, HighlightManager.HighlightInfo>();
 2645  0 final Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair =
 2646    new Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>>(panel, highlights);
 2647  0 _findResults.add(pair);
 2648   
 2649    // hook highlighting listener to find results manager
 2650  0 rm.addListener(new RegionManagerListener<MovingDocumentRegion>() {
 2651  0 public void regionAdded(MovingDocumentRegion r) {
 2652  0 DefinitionsPane pane = getDefPaneGivenODD(r.getDocument());
 2653    // if (pane == null) System.err.println("ODD " + r.getDocument() + " produced a null DefinitionsPane!");
 2654  0 highlights.put(r, pane.getHighlightManager().
 2655    addHighlight(r.getStartOffset(), r.getEndOffset(), panel.getSelectedPainter()));
 2656    }
 2657  0 public void regionChanged(MovingDocumentRegion r) {
 2658  0 regionRemoved(r);
 2659  0 regionAdded(r);
 2660    }
 2661  0 public void regionRemoved(MovingDocumentRegion r) {
 2662    // Utilities.show("Removing highlight for region " + r);
 2663  0 HighlightManager.HighlightInfo highlight = highlights.get(r);
 2664    // Utilities.show("The retrieved highlight is " + highlight);
 2665  0 if (highlight != null) highlight.remove();
 2666  0 highlights.remove(r);
 2667    // close the panel and dispose of its MainFrame resources when all regions have been removed.
 2668  0 if (rm.getDocuments().isEmpty()) {
 2669  0 panel._close(); // _close removes the panel from _tabs and pair from _findResults
 2670    }
 2671    }
 2672    });
 2673   
 2674    // attach a listener to the panel that removes pair from _findResults when the panel is closed
 2675  0 panel.addCloseListener(new ActionListener() {
 2676  0 public void actionPerformed(ActionEvent ae) { _findResults.remove(pair); }
 2677    });
 2678   
 2679  0 _tabs.addLast(panel);
 2680  0 panel.getMainPanel().addFocusListener(new FocusAdapter() {
 2681  0 public void focusGained(FocusEvent e) { _lastFocusOwner = panel; }
 2682    });
 2683   
 2684  0 return panel;
 2685    }
 2686   
 2687    /** Disable "Find Again" on "Find All" tabs that use a document that was closed. */
 2688  3 void disableFindAgainOnClose(List<OpenDefinitionsDocument> projDocs) {
 2689  3 for(TabbedPanel t: _tabs) {
 2690  18 if (t instanceof FindResultsPanel) {
 2691  0 FindResultsPanel p = (FindResultsPanel) t;
 2692  0 if (projDocs.contains(p.getDocument())) { p.disableFindAgain(); }
 2693    }
 2694    }
 2695    }
 2696   
 2697    /** Action that shows a find results tab. Only runs in event thread. */
 2698  0 public void showFindResultsPanel(final FindResultsPanel panel) {
 2699  0 assert EventQueue.isDispatchThread();
 2700  0 if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes();
 2701  0 showTab(panel, true);
 2702  0 panel.updatePanel();
 2703    // panel.setVisible(true);
 2704  0 _tabbedPane.setSelectedComponent(panel);
 2705    // Use EventQueue.invokeLater to ensure that focus is set AFTER the findResultsPanel has been selected
 2706  0 EventQueue.invokeLater(new Runnable() { public void run() { panel.requestFocusInWindow(); } });
 2707    };
 2708   
 2709    /** Cuts from the caret to the end of the current line to the clipboard. */
 2710    protected final Action _cutLineAction = new AbstractAction("Cut Line") {
 2711  0 public void actionPerformed(ActionEvent ae) {
 2712  0 ActionMap actionMap = _currentDefPane.getActionMap();
 2713  0 int oldCol = _model.getActiveDocument().getCurrentCol();
 2714  0 actionMap.get(DefaultEditorKit.selectionEndLineAction).actionPerformed(ae);
 2715    // if oldCol is equal to the current column, then selectionEndLine did
 2716    // nothing, so we're at the end of the line and should remove the newline
 2717    // character
 2718  0 if (oldCol == _model.getActiveDocument().getCurrentCol()) {
 2719    // Puts newline character on the clipboard also, not just content as before.
 2720  0 actionMap.get(DefaultEditorKit.selectionForwardAction).actionPerformed(ae);
 2721  0 cutAction.actionPerformed(ae);
 2722    }
 2723  0 else cutAction.actionPerformed(ae);
 2724    }
 2725    };
 2726   
 2727    /** Deletes text from the caret to the end of the current line. */
 2728    protected final Action _clearLineAction = new AbstractAction("Clear Line") {
 2729  1 public void actionPerformed(ActionEvent ae) {
 2730  1 ActionMap actionMap = _currentDefPane.getActionMap();
 2731  1 actionMap.get(DefaultEditorKit.selectionEndLineAction).actionPerformed(ae);
 2732  1 actionMap.get(DefaultEditorKit.deleteNextCharAction).actionPerformed(ae);
 2733    }
 2734    };
 2735   
 2736    /** Moves the caret to the "intelligent" beginning of the line.
 2737    * @see #_getBeginLinePos
 2738    */
 2739    private final Action _beginLineAction = new AbstractAction("Begin Line") {
 2740  0 public void actionPerformed(ActionEvent ae) {
 2741  0 int beginLinePos = _getBeginLinePos();
 2742  0 _currentDefPane.setCaretPosition(beginLinePos);
 2743    }
 2744    };
 2745   
 2746    /** Selects to the "intelligent" beginning of the line.
 2747    * @see #_getBeginLinePos
 2748    */
 2749    private final Action _selectionBeginLineAction = new AbstractAction("Select to Beginning of Line") {
 2750  0 public void actionPerformed(ActionEvent ae) {
 2751  0 int beginLinePos = _getBeginLinePos();
 2752  0 _currentDefPane.moveCaretPosition(beginLinePos);
 2753    }
 2754    };
 2755   
 2756    /** Returns the "intelligent" beginning of line. If the caret is to fhe right of the first non-whitespace character,
 2757    * the position of the first non-whitespace character is returned. If the caret is on or to the left of the first
 2758    * non-whitespace character, the beginning of the line is returned.
 2759    */
 2760  0 private int _getBeginLinePos() {
 2761  0 try {
 2762  0 int currPos = _currentDefPane.getCaretPosition();
 2763  0 OpenDefinitionsDocument openDoc = _model.getActiveDocument();
 2764  0 openDoc.setCurrentLocation(currPos);
 2765  0 return openDoc.getIntelligentBeginLinePos(currPos);
 2766    }
 2767    catch (BadLocationException ble) {
 2768    // Shouldn't happen: we're using a legal position
 2769  0 throw new UnexpectedException(ble);
 2770    }
 2771    }
 2772   
 2773    private final FileOpenSelector _interactionsHistoryFileSelector = new FileOpenSelector() {
 2774  0 public File[] getFiles() throws OperationCanceledException {
 2775  0 return getOpenFiles(_interactionsHistoryChooser);
 2776    }
 2777    };
 2778   
 2779    /** Interprets the commands in a file in the interactions window. */
 2780    private final Action _executeHistoryAction = new AbstractAction("Execute Interactions History...") {
 2781  0 public void actionPerformed(ActionEvent ae) {
 2782    // Show interactions tab
 2783  0 _tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
 2784   
 2785  0 _interactionsHistoryChooser.setDialogTitle("Execute Interactions History");
 2786  0 try { _model.loadHistory(_interactionsHistoryFileSelector); }
 2787  0 catch (FileNotFoundException fnf) { MainFrameStatics.showFileNotFoundError(MainFrame.this, fnf); }
 2788  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 2789  0 _interactionsPane.requestFocusInWindow();
 2790    }
 2791    };
 2792   
 2793    /** Closes the currently executing interactions script, if there is one. */
 2794  7 private void _closeInteractionsScript() {
 2795  7 if (_interactionsScriptController != null) {
 2796  0 _interactionsContainer.remove(_interactionsScriptPane);
 2797  0 _interactionsScriptController = null;
 2798  0 _interactionsScriptPane = null;
 2799  0 _tabbedPane.invalidate();
 2800  0 _tabbedPane.repaint();
 2801    }
 2802    }
 2803   
 2804    /** Action to load an interactions history as a replayable script. */
 2805    private final Action _loadHistoryScriptAction = new AbstractAction("Load Interactions History as Script...") {
 2806  0 public void actionPerformed(ActionEvent e) {
 2807  0 try {
 2808  0 _interactionsHistoryChooser.setDialogTitle("Load Interactions History");
 2809  0 InteractionsScriptModel ism = _model.loadHistoryAsScript(_interactionsHistoryFileSelector);
 2810  0 _interactionsScriptController = new InteractionsScriptController(ism, new AbstractAction("Close") {
 2811  0 public void actionPerformed(ActionEvent e) {
 2812  0 _closeInteractionsScript();
 2813  0 _interactionsPane.requestFocusInWindow();
 2814    }
 2815    }, _interactionsPane);
 2816  0 _interactionsScriptPane = _interactionsScriptController.getPane();
 2817  0 _interactionsContainer.add(_interactionsScriptPane, BorderLayout.EAST);
 2818  0 _tabbedPane.invalidate();
 2819  0 _tabbedPane.repaint();
 2820    }
 2821  0 catch (FileNotFoundException fnf) { MainFrameStatics.showFileNotFoundError(MainFrame.this, fnf); }
 2822  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 2823    catch (OperationCanceledException oce) {
 2824    }
 2825    }
 2826    };
 2827   
 2828    /** Save the contents of the interactions window to a file. */
 2829    private final Action _saveInteractionsCopyAction = new AbstractAction("Save Copy of Interactions...") {
 2830  0 public void actionPerformed(ActionEvent ae) {
 2831  0 updateStatusField("Saving Copy of Interactions");
 2832  0 _saveConsoleCopy(_model.getInteractionsDocument());
 2833  0 _interactionsPane.requestFocusInWindow();
 2834    }
 2835    };
 2836   
 2837    /** Save the commands in the interactions window's history to a file */
 2838    private final Action _saveHistoryAction = new AbstractAction("Save Interactions History...") {
 2839  0 public void actionPerformed(ActionEvent ae) {
 2840  0 String[] options = {"Yes","No","Cancel"};
 2841  0 int resp = JOptionPane.showOptionDialog(MainFrame.this,
 2842    "Edit interactions history before saving?",
 2843    "Edit History?",
 2844    JOptionPane.YES_NO_CANCEL_OPTION,
 2845    JOptionPane.QUESTION_MESSAGE,
 2846    null,options,
 2847    options[1]);
 2848    // Cancel
 2849  0 if (resp == 2 || resp == JOptionPane.CLOSED_OPTION) return;
 2850   
 2851  0 String history = _model.getHistoryAsStringWithSemicolons();
 2852   
 2853    // Edit the history
 2854  0 if (resp == 0)
 2855  0 history = (new HistorySaveDialog(MainFrame.this)).editHistory(history);
 2856  0 if (history == null) return; // save cancelled
 2857   
 2858  0 _interactionsHistoryChooser.setDialogTitle("Save Interactions History");
 2859  0 FileSaveSelector selector = new FileSaveSelector() {
 2860  0 public File getFile() throws OperationCanceledException {
 2861    // Don't try to set the fileName with getSaveFile;
 2862    // just display the dialog and get file with getChosenFile, otherwise
 2863    // the suggested file name will be whatever document is open.
 2864    // ED (8.14.03): Had to add this next block of code from getSaveFile to
 2865    // fix bug #788311 "NullPointer when saving history"
 2866  0 File selection = _interactionsHistoryChooser.getSelectedFile();//_saveChooser.getSelectedFile();
 2867  0 if (selection != null) {
 2868  0 _interactionsHistoryChooser.setSelectedFile(selection.getParentFile());
 2869  0 _interactionsHistoryChooser.setSelectedFile(selection);
 2870  0 _interactionsHistoryChooser.setSelectedFile(null);
 2871    }
 2872    // return getSaveFile(_interactionsHistoryChooser);
 2873  0 _interactionsHistoryChooser.setMultiSelectionEnabled(false);
 2874  0 int rc = _interactionsHistoryChooser.showSaveDialog(MainFrame.this);
 2875  0 File c = getChosenFile(_interactionsHistoryChooser, rc, null, false);
 2876    //Moved from history itself to here to account for bug #989232, non-existant default
 2877    //history file found
 2878  0 if ((c != null) && (c.getName().indexOf('.') == -1)) {
 2879  0 c = new File(c.getAbsolutePath() + "." + InteractionsHistoryFilter.HIST_EXTENSION);
 2880    }
 2881  0 _interactionsHistoryChooser.setSelectedFile(c);
 2882  0 return c;
 2883    }
 2884  0 public boolean warnFileOpen(File f) { return true; }
 2885  0 public boolean verifyOverwrite(File f) { return MainFrameStatics.verifyOverwrite(MainFrame.this, f); }
 2886  0 public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) {
 2887  0 return true;
 2888    }
 2889  0 public boolean shouldUpdateDocumentState() { return true; }
 2890    };
 2891   
 2892  0 try { _model.saveHistory(selector, history);}
 2893    catch (IOException ioe) {
 2894  0 MainFrameStatics.showIOError(MainFrame.this, new IOException("An error occured writing the history to a file"));
 2895    }
 2896  0 _interactionsPane.requestFocusInWindow();
 2897    }
 2898    };
 2899   
 2900    /** Clears the commands in the interaction history. */
 2901    private final Action _clearHistoryAction = new AbstractAction("Clear Interactions History") {
 2902  0 public void actionPerformed(ActionEvent ae) {
 2903  0 _model.clearHistory();
 2904  0 _interactionsPane.requestFocusInWindow();
 2905    }
 2906    };
 2907   
 2908    /** How DrJava responds to window events. */
 2909    private final WindowListener _windowCloseListener = new WindowAdapter() {
 2910  0 public void windowActivated(WindowEvent ev) { }
 2911  35 public void windowClosed(WindowEvent ev) { }
 2912  0 public void windowClosing(WindowEvent ev) { quit(); }
 2913  0 public void windowDeactivated(WindowEvent ev) { }
 2914  0 public void windowDeiconified(WindowEvent ev) {
 2915  0 try { _model.getActiveDocument().revertIfModifiedOnDisk(); }
 2916  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 2917  0 catch (IOException e) { MainFrameStatics.showIOError(MainFrame.this, e);}
 2918    }
 2919  0 public void windowIconified(WindowEvent ev) { }
 2920  0 public void windowOpened(WindowEvent ev) { _currentDefPane.requestFocusInWindow(); }
 2921    };
 2922   
 2923    private final MouseListener _resetFindReplaceListener = new MouseListener() {
 2924  0 public void mouseClicked(MouseEvent e) { }
 2925  0 public void mousePressed(MouseEvent e) { }
 2926    // As mouseReleased event so that it happens after the document has been set in the model and defPane
 2927  0 public void mouseReleased(MouseEvent e) {_findReplace.updateFirstDocInSearch();}
 2928  0 public void mouseEntered(MouseEvent e) { }
 2929  0 public void mouseExited(MouseEvent e) { }
 2930    };
 2931   
 2932    // ------------- File Display Managers for File Icons ------------
 2933   
 2934    private static final DJFileDisplayManager _djFileDisplayManager20;
 2935    private static final DJFileDisplayManager _djFileDisplayManager30;
 2936    private static final OddDisplayManager _oddDisplayManager20;
 2937    private static final OddDisplayManager _oddDisplayManager30;
 2938    private static final Icon _djProjectIcon;
 2939   
 2940    static {
 2941  9 Icon java, dj0, dj1, dj2, dj, other, star, jup, juf;
 2942   
 2943  9 java = MainFrame.getIcon("JavaIcon20.gif");
 2944  9 dj0 = MainFrame.getIcon("ElementaryIcon20.gif");
 2945  9 dj1 = MainFrame.getIcon("IntermediateIcon20.gif");
 2946  9 dj2 = MainFrame.getIcon("AdvancedIcon20.gif");
 2947  9 dj = MainFrame.getIcon("FunctionalIcon20.gif");
 2948  9 other = MainFrame.getIcon("OtherIcon20.gif");
 2949  9 _djFileDisplayManager20 = new DJFileDisplayManager(java,dj0,dj1,dj2,dj,other);
 2950   
 2951  9 java = MainFrame.getIcon("JavaIcon30.gif");
 2952  9 dj0 = MainFrame.getIcon("ElementaryIcon30.gif");
 2953  9 dj1 = MainFrame.getIcon("IntermediateIcon30.gif");
 2954  9 dj2 = MainFrame.getIcon("AdvancedIcon30.gif");
 2955  9 dj = MainFrame.getIcon("FunctionalIcon30.gif");
 2956  9 other = MainFrame.getIcon("OtherIcon30.gif");
 2957  9 _djFileDisplayManager30 = new DJFileDisplayManager(java,dj0,dj1,dj2,dj,other);
 2958   
 2959  9 star = MainFrame.getIcon("ModStar20.gif");
 2960  9 jup = MainFrame.getIcon("JUnitPass20.gif");
 2961  9 juf = MainFrame.getIcon("JUnitFail20.gif");
 2962  9 _oddDisplayManager20 = new OddDisplayManager(_djFileDisplayManager20,star,jup,juf);
 2963   
 2964  9 star = MainFrame.getIcon("ModStar30.gif");
 2965  9 jup = MainFrame.getIcon("JUnitPass30.gif");
 2966  9 juf = MainFrame.getIcon("JUnitFail30.gif");
 2967  9 _oddDisplayManager30 = new OddDisplayManager(_djFileDisplayManager30,star,jup,juf);
 2968   
 2969  9 _djProjectIcon = MainFrame.getIcon("ProjectIcon.gif");
 2970    }
 2971   
 2972   
 2973    /** This manager is meant to retrieve the correct icons for the given filename. The only files recognized
 2974    * are the files obviously listed below in the function (.java, .dj0, .dj1, .dj2, .dj). The icons that represent
 2975    * each filetype are given into the managers constructor upon instantiation. This class is static since
 2976    * it currently does not depend of the main frame for information.
 2977    */
 2978    private static class DJFileDisplayManager extends DefaultFileDisplayManager {
 2979    private final Icon _java;
 2980    private final Icon _dj0;
 2981    private final Icon _dj1;
 2982    private final Icon _dj2;
 2983    private final Icon _dj;
 2984    private final Icon _other;
 2985   
 2986  18 public DJFileDisplayManager(Icon java, Icon dj0, Icon dj1, Icon dj2, Icon dj, Icon other) {
 2987  18 _java = java;
 2988  18 _dj0 = dj0;
 2989  18 _dj1 = dj1;
 2990  18 _dj2 = dj2;
 2991  18 _dj = dj;
 2992  18 _other = other;
 2993    }
 2994    /** This method chooses the custom icon only for the known filetypes. If these filetypes are not receiving
 2995    * the correct icons, make sure the filenames are correct and that the icons are present in the ui/icons
 2996    * directory.
 2997    */
 2998  8 public Icon getIcon(File f) {
 2999  2 if (f == null) return _other;
 3000  6 Icon ret = null;
 3001  6 if (! f.isDirectory()) {
 3002  6 String name = f.getName().toLowerCase();
 3003  6 if (name.endsWith(OptionConstants.JAVA_FILE_EXTENSION)) ret = _java;
 3004  0 else if (name.endsWith(OptionConstants.DJ_FILE_EXTENSION)) ret = _dj;
 3005  0 else if (name.endsWith(OptionConstants.OLD_DJ0_FILE_EXTENSION)) ret = _dj0;
 3006  0 else if (name.endsWith(OptionConstants.OLD_DJ1_FILE_EXTENSION)) ret = _dj1;
 3007  0 else if (name.endsWith(OptionConstants.OLD_DJ2_FILE_EXTENSION)) ret = _dj2;
 3008    // TODO: What about Habanero Java extension?
 3009    }
 3010  6 if (ret == null) {
 3011  0 ret = super.getIcon(f);
 3012  0 if (ret.getIconHeight() < _java.getIconHeight()) {
 3013  0 ret = new CenteredIcon(ret, _java.getIconWidth(), _java.getIconHeight());
 3014    }
 3015    }
 3016  6 return ret;
 3017    }
 3018    }
 3019   
 3020    /** This class wraps the file display managers by superimposing any notification icons on top of the base
 3021    * file icon. Currently, only the modified star is allowed, but everything is set up to add notification
 3022    * icons for whether a document has passed the junit test (for display in the tree). This class is static
 3023    * for now. It may be necessary to make it dynamic when implementing the junit notifications.
 3024    */
 3025    private static class OddDisplayManager implements DisplayManager<OpenDefinitionsDocument> {
 3026    private final Icon _star;
 3027    // private Icon _juPass;
 3028    // private Icon _juFail;
 3029    private final FileDisplayManager _default;
 3030   
 3031    /** Standard constructor.
 3032    * @param star The star icon will be put flush to the left 1/4 the way down
 3033    * @param junitPass indicator of junit success, placed at bottom right
 3034    * @param junitFail indicator of junit failure, placed at bottom right
 3035    */
 3036  18 public OddDisplayManager(FileDisplayManager fdm, Icon star, Icon junitPass, Icon junitFail) {
 3037  18 _star = star;
 3038    // _juPass = junitPass;
 3039    // _juFail = junitFail;
 3040  18 _default = fdm;
 3041    }
 3042  8 public Icon getIcon(OpenDefinitionsDocument odd) {
 3043  8 File f = null;
 3044  8 try { f = odd.getFile(); }
 3045    catch(FileMovedException fme) { /* do nothing */ }
 3046   
 3047  0 if (odd.isModifiedSinceSave()) return makeLayeredIcon(_default.getIcon(f), _star);
 3048  8 return _default.getIcon(f);
 3049    }
 3050  0 public String getName(OpenDefinitionsDocument doc) { return doc.getFileName(); }
 3051  0 private LayeredIcon makeLayeredIcon(Icon base, Icon star) {
 3052  0 return new LayeredIcon(new Icon[]{base, star}, new int[]{0, 0},
 3053    new int[]{0, (base.getIconHeight() / 4)});
 3054    }
 3055    };
 3056   
 3057    /** This is what is given to the JTreeSortNavigator. This simply resolves the INavItem to an OpenDefDoc
 3058    * using the model and forwards it to the OddDisplayManager for size 20.
 3059    */
 3060    private final DisplayManager<INavigatorItem> _navPaneDisplayManager = new DisplayManager<INavigatorItem>() {
 3061  8 public Icon getIcon(INavigatorItem item) {
 3062  8 OpenDefinitionsDocument odd = (OpenDefinitionsDocument) item; // FIX THIS!
 3063  8 return _oddDisplayManager20.getIcon(odd);
 3064    }
 3065  8 public String getName(INavigatorItem name) { return name.getName(); }
 3066    };
 3067   
 3068    /** These listeners support the traversal operations that cycle through recent documents. */
 3069    public KeyListener _historyListener = new KeyListener() {
 3070  11 public void keyPressed(KeyEvent e) {
 3071  11 int backQuote = java.awt.event.KeyEvent.VK_BACK_QUOTE;
 3072  11 if (e.getKeyCode() == backQuote && e.isControlDown()) {
 3073  0 if (e.isShiftDown()) prevRecentDoc();
 3074  0 else nextRecentDoc();
 3075    }
 3076    }
 3077  11 public void keyReleased(KeyEvent e) {
 3078  0 if (e.getKeyCode() == java.awt.event.KeyEvent.VK_CONTROL) hideRecentDocFrame();
 3079    }
 3080  15 public void keyTyped(KeyEvent e) { /* noop */ }
 3081    };
 3082   
 3083    public FocusListener _focusListenerForRecentDocs = new FocusListener() {
 3084  0 public void focusLost(FocusEvent e) { hideRecentDocFrame(); }
 3085  0 public void focusGained(FocusEvent e) { }
 3086    };
 3087   
 3088    // adds Listener for undo/redo action for the definitions pane
 3089    public final FocusListener _undoRedoDefinitionsFocusListener = new FocusAdapter() {
 3090  0 public void focusGained(FocusEvent e){
 3091  0 _undoAction.setDelegatee(_currentDefPane.getUndoAction());
 3092  0 _redoAction.setDelegatee(_currentDefPane.getRedoAction());
 3093    }
 3094    };
 3095   
 3096  0 public static DJFileDisplayManager getFileDisplayManager20() { return _djFileDisplayManager20; }
 3097  0 public static DJFileDisplayManager getFileDisplayManager30() { return _djFileDisplayManager30; }
 3098  0 public static OddDisplayManager getOddDisplayManager20() { return _oddDisplayManager20; }
 3099  38 public static OddDisplayManager getOddDisplayManager30() { return _oddDisplayManager30; }
 3100  4 public DisplayManager<INavigatorItem> getNavPaneDisplayManager() { return _navPaneDisplayManager; }
 3101   
 3102    /* ----------------------- Constructor is here! --------------------------- */
 3103   
 3104    /** Creates the main window, and shows it. */
 3105  38 public MainFrame() {
 3106  38 Utilities.invokeAndWait(new Runnable() { public void run() {
 3107    // Cache the config object, since we use it many, many times.
 3108  38 final Configuration config = DrJava.getConfig();
 3109   
 3110    // _historyListener (declared and initialized above) required by new FindReplacePanel(...)
 3111  38 assert _historyListener != null;
 3112   
 3113    // create our model
 3114  38 _model = new DefaultGlobalModel();
 3115   
 3116  38 _showDebugger = _model.getDebugger().isAvailable();
 3117  38 _findReplace = new FindReplacePanel(MainFrame.this, _model);
 3118   
 3119    // add listeners to activate/deactivate the find/replace actions in MainFrame together with
 3120    // those in the Find/Replace panel
 3121  38 Utilities.enableDisableWith(_findReplace._findNextAction, _findNextAction);
 3122  38 Utilities.enableDisableWith(_findReplace._findPreviousAction, _findPrevAction);
 3123   
 3124  38 if (_showDebugger) {
 3125  38 _debugPanel = new DebugPanel(MainFrame.this);
 3126  38 _breakpointsPanel = new BreakpointsPanel(MainFrame.this, _model.getBreakpointManager());
 3127    }
 3128    else {
 3129  0 _debugPanel = null;
 3130  0 _breakpointsPanel = null;
 3131    }
 3132   
 3133  38 _compilerErrorPanel = new CompilerErrorPanel(_model, MainFrame.this);
 3134  38 _consoleController = new ConsoleController(_model.getConsoleDocument(), _model.getSwingConsoleDocument());
 3135  38 _consolePane = _consoleController.getPane();
 3136   
 3137  38 _consoleScroll = new BorderlessScrollPane(_consolePane) {
 3138  0 public boolean requestFocusInWindow() {
 3139  0 super.requestFocusInWindow();
 3140  0 return _consolePane.requestFocusInWindow();
 3141    }
 3142    };
 3143   
 3144  38 _interactionsController =
 3145    new InteractionsController(_model.getInteractionsModel(),
 3146    _model.getSwingInteractionsDocument(),
 3147    new Runnable() {
 3148  0 public void run() {
 3149  0 _closeSystemInAction.setEnabled(false);
 3150    }
 3151    });
 3152   
 3153  38 _interactionsPane = _interactionsController.getPane();
 3154   
 3155  38 _interactionsContainer = new JPanel(new BorderLayout());
 3156  38 _lastFocusOwner = _interactionsContainer;
 3157   
 3158  38 _junitPanel = new JUnitPanel(_model, MainFrame.this);
 3159  38 _javadocErrorPanel = new JavadocErrorPanel(_model, MainFrame.this);
 3160   
 3161  38 _bookmarksPanel = new BookmarksPanel(MainFrame.this, _model.getBookmarkManager());
 3162   
 3163    // Initialize the status bar
 3164  38 _setUpStatusBar();
 3165   
 3166    // Preliminary layout
 3167   
 3168    /* Definitions Pane */
 3169   
 3170    /* Ensure that DefinitionsPane uses the correct EditorKit! This has to be stored as a static field on
 3171    * DefinitionsPane because the JEditorPane constructor uses it before we get a chance to assign it to an instance
 3172    * field ... */
 3173  38 DefinitionsPane.setEditorKit(_model.getEditorKit());
 3174   
 3175  38 _defScrollPanes = new HashMap<OpenDefinitionsDocument, JScrollPane>();
 3176   
 3177    /* Set up tabbed pane and navigation pane. */
 3178  38 _tabbedPane.setFocusable(false);
 3179   
 3180  38 _tabbedPane.addFocusListener(_focusListenerForRecentDocs);
 3181  38 _tabbedPane.addKeyListener(_historyListener); // TODO: can this code be moved to the MainFrame keymap?
 3182   
 3183  38 if (Utilities.isPlasticLaf()) {
 3184  0 _tabbedPane.putClientProperty(com.jgoodies.looks.Options.EMBEDDED_TABS_KEY, Boolean.TRUE);
 3185    }
 3186   
 3187  38 JScrollPane defScroll = _createDefScrollPane(_model.getActiveDocument());
 3188   
 3189  38 _docSplitPane =
 3190    new BorderlessSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
 3191    new JScrollPane(_model.getDocumentNavigator().asContainer()), defScroll);
 3192  38 _debugSplitPane = new BorderlessSplitPane(JSplitPane.VERTICAL_SPLIT, true);
 3193  38 _mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, _docSplitPane, _tabbedPane);
 3194    // Lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
 3195    // // The OptionListener for LIGHTWEIGHT_PARSING_ENABLED.
 3196    // OptionListener<Boolean> parsingEnabledListener = new OptionListener<Boolean>() {
 3197    // public void optionChanged(OptionEvent<Boolean> oce) {
 3198    // if (oce.value) {
 3199    // _model.getParsingControl().addListener(new LightWeightParsingListener() {
 3200    // public void enclosingClassNameUpdated(OpenDefinitionsDocument doc, String old, String updated) {
 3201    // if (doc == _model.getActiveDocument()) { updateStatusField(); }
 3202    // }
 3203    // });
 3204    // }
 3205    // _model.getParsingControl().reset();
 3206    // _model.getParsingControl().setAutomaticUpdates(oce.value);
 3207    // updateStatusField();
 3208    // }
 3209    // };
 3210    // DrJava.getConfig().addOptionListener(LIGHTWEIGHT_PARSING_ENABLED, parsingEnabledListener);
 3211    // parsingEnabledListener.
 3212    // optionChanged(new OptionEvent<Boolean>(LIGHTWEIGHT_PARSING_ENABLED,
 3213    // DrJava.getConfig().
 3214    // getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()));
 3215    //
 3216    // Utilities.show("Global Model started");
 3217   
 3218  38 _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener);
 3219  38 _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs);
 3220   
 3221    /* Listens for clicks in the document navigator to reset the first document in an all-documents search for wrapping
 3222    * purposes. */
 3223  38 _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener);
 3224   
 3225  38 if (_showDebugger) _model.getDebugger().addListener(new UIDebugListener()); // add listener to debug manager
 3226   
 3227    // Timer to display a message if a debugging step takes a long time
 3228  38 _debugStepTimer = new Timer(DEBUG_STEP_TIMER_VALUE, new ActionListener() {
 3229  0 public void actionPerformed(ActionEvent e) {
 3230  0 if (!_model.getDebugger().isAutomaticTraceEnabled()) { _model.printDebugMessage("Stepping ..."); }
 3231    }
 3232    });
 3233  38 _debugStepTimer.setRepeats(false);
 3234   
 3235    // Working directory is default place to start (bug #895998).
 3236  38 File workDir = _model.getMasterWorkingDirectory();
 3237   
 3238    // Overrides JFileChooser to display the full path of the directory
 3239  38 _openChooser = new JFileChooser() {
 3240  120 public void setCurrentDirectory(File dir) {
 3241    //next two lines are order dependent!
 3242  120 super.setCurrentDirectory(dir);
 3243  120 setDialogTitle("Open: " + getCurrentDirectory());
 3244    }
 3245    };
 3246  38 _openChooser.setPreferredSize(new Dimension(650, 410));
 3247  38 _openChooser.setCurrentDirectory(workDir);
 3248  38 _openChooser.resetChoosableFileFilters();
 3249  38 _openChooser.setFileFilter(getSourceFileFilter());
 3250  38 _openChooser.setMultiSelectionEnabled(true);
 3251   
 3252  38 _openRecursiveCheckBox.setSelected(config.getSetting(OptionConstants.OPEN_FOLDER_RECURSIVE).booleanValue());
 3253   
 3254  38 _folderChooser = makeFolderChooser(workDir);
 3255   
 3256    //Get most recently opened project for filechooser
 3257  38 Vector<File> recentProjects = config.getSetting(RECENT_PROJECTS);
 3258  38 _openProjectChooser = new JFileChooser();
 3259  38 _openProjectChooser.setPreferredSize(new Dimension(650, 410));
 3260   
 3261  38 if (recentProjects.size() > 0 && recentProjects.elementAt(0).getParentFile() != null)
 3262  0 _openProjectChooser.setCurrentDirectory(recentProjects.elementAt(0).getParentFile());
 3263    else
 3264  38 _openProjectChooser.setCurrentDirectory(workDir);
 3265   
 3266  38 _openProjectChooser.resetChoosableFileFilters();
 3267  38 _openProjectChooser.setFileFilter(_projectFilter);
 3268  38 _openProjectChooser.setMultiSelectionEnabled(false);
 3269  38 _saveChooser = new JFileChooser() {
 3270  120 public void setCurrentDirectory(File dir) {
 3271    //next two lines are order dependent!
 3272  120 super.setCurrentDirectory(dir);
 3273  120 setDialogTitle("Save: " + getCurrentDirectory());
 3274    }
 3275    };
 3276  38 _saveChooser.setPreferredSize(new Dimension(650, 410));
 3277  38 _saveChooser.setCurrentDirectory(workDir);
 3278  38 _saveChooser.resetChoosableFileFilters();
 3279  38 _saveChooser.setFileFilter(getSourceFileFilter());
 3280   
 3281  38 _interactionsHistoryChooser.setPreferredSize(new Dimension(650, 410));
 3282  38 _interactionsHistoryChooser.setCurrentDirectory(workDir);
 3283  38 _interactionsHistoryChooser.resetChoosableFileFilters();
 3284  38 _interactionsHistoryChooser.setFileFilter(new InteractionsHistoryFilter());
 3285  38 _interactionsHistoryChooser.setMultiSelectionEnabled(true);
 3286   
 3287    //set up the hourglass cursor
 3288  38 setGlassPane(new GlassPane());
 3289  38 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
 3290   
 3291    // Set up listeners
 3292  38 addWindowListener(_windowCloseListener);
 3293   
 3294    // Create the main model listener and attach it to the global model
 3295  38 _mainListener = new ModelListener();
 3296  38 _model.addListener(_mainListener);
 3297   
 3298    // Initialize tabs before DefPane
 3299  38 _setUpTabs();
 3300   
 3301    // DefinitionsPane
 3302  38 _recentDocFrame = new RecentDocFrame(MainFrame.this);
 3303  38 OpenDefinitionsDocument activeDoc = _model.getActiveDocument();
 3304  38 _recentDocFrame.pokeDocument(activeDoc);
 3305  38 _currentDefDoc = activeDoc.getDocument();
 3306  38 _currentDefPane = (DefinitionsPane) defScroll.getViewport().getView();
 3307  38 _currentDefPane.notifyActive();
 3308  38 _currentDefPane.addFocusListener(_undoRedoDefinitionsFocusListener);
 3309   
 3310    // Get proper cross-platform mask.
 3311  38 int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
 3312   
 3313    // set up key-bindings
 3314  38 KeyBindingManager.ONLY.setMainFrame(MainFrame.this);
 3315  38 _setUpKeyBindingMaps();
 3316   
 3317  38 _posListener.updateLocation();
 3318   
 3319    // Need to set undo/redo actions to point to the initial def pane
 3320    // on switching documents later these pointers will also switch
 3321  38 _undoAction.setDelegatee(_currentDefPane.getUndoAction());
 3322  38 _redoAction.setDelegatee(_currentDefPane.getRedoAction());
 3323   
 3324  38 _compilerErrorPanel.reset();
 3325  38 _junitPanel.reset();
 3326  38 _javadocErrorPanel.reset();
 3327   
 3328    // Create menubar and menus
 3329  38 _fileMenu = _setUpFileMenu(mask, true);
 3330  38 _editMenu = _setUpEditMenu(mask, true);
 3331  38 _toolsMenu = _setUpToolsMenu(mask, true);
 3332  38 _projectMenu = _setUpProjectMenu(mask, true);
 3333  38 _debugMenu = null;
 3334  38 if (_showDebugger) _debugMenu = _setUpDebugMenu(mask, true);
 3335  38 _languageLevelMenu = _setUpLanguageLevelMenu(mask, true);
 3336  38 _helpMenu = _setUpHelpMenu(mask, true);
 3337   
 3338    // initialize menu bar and actions
 3339  38 _setUpActions();
 3340  38 _setUpMenuBar(_menuBar,
 3341    _fileMenu, _editMenu, _toolsMenu, _projectMenu, _debugMenu, _languageLevelMenu, _helpMenu);
 3342  38 setJMenuBar(_menuBar);
 3343   
 3344    // _setUpDocumentSelector();
 3345  38 _setUpContextMenus();
 3346   
 3347    // Create toolbar and buttons
 3348  38 _undoButton = _createManualToolbarButton(_undoAction);
 3349  38 _redoButton = _createManualToolbarButton(_redoAction);
 3350   
 3351    // initialize _toolBar
 3352  38 _setUpToolBar();
 3353   
 3354    // Set up GUI component availability
 3355  38 _setUpGUIComponentAvailability();
 3356   
 3357    // add recent file and project manager
 3358  38 RecentFileAction fileAct = new RecentFileManager.RecentFileAction() {
 3359  0 public void actionPerformed(FileOpenSelector selector) { open(selector); }
 3360    };
 3361  38 _recentFileManager = new RecentFileManager(_fileMenu.getItemCount() - 2, _fileMenu,
 3362    fileAct, OptionConstants.RECENT_FILES);
 3363   
 3364  38 RecentFileAction projAct = new RecentFileManager.RecentFileAction() {
 3365  0 public void actionPerformed(FileOpenSelector selector) { openProject(selector); }
 3366    };
 3367  38 _recentProjectManager = new RecentFileManager(_projectMenu.getItemCount() - 2, _projectMenu,
 3368    projAct, OptionConstants.RECENT_PROJECTS);
 3369   
 3370  38 _tabbedPanesFrame = new DetachedFrame("Tabbed Panes", MainFrame.this, new Runnable1<DetachedFrame>() {
 3371  0 public void run(DetachedFrame frame) {
 3372  0 frame.getContentPane().add(_tabbedPane);
 3373    }
 3374    }, new Runnable1<DetachedFrame>() {
 3375  38 public void run(DetachedFrame frame) {
 3376  38 _mainSplit.setBottomComponent(_tabbedPane);
 3377    }
 3378    });
 3379  38 _tabbedPanesFrame.addWindowListener(new WindowAdapter() {
 3380  0 public void windowClosing(WindowEvent we) {
 3381  0 _detachTabbedPanesMenuItem.setSelected(false);
 3382  0 DrJava.getConfig().setSetting(DETACH_TABBEDPANES, false);
 3383    }
 3384    });
 3385   
 3386    // set up the menu bars on other frames
 3387  38 _tabbedPanesFrame.setUpMenuBar();
 3388   
 3389    // Create detachable debug frame
 3390  38 if (_debugPanel != null) { // using debugger
 3391  38 _debugFrame = new DetachedFrame("Debugger", MainFrame.this, new Runnable1<DetachedFrame>() {
 3392  0 public void run(DetachedFrame frame) {
 3393  0 frame.getContentPane().add(_debugPanel);
 3394    }
 3395    }, new Runnable1<DetachedFrame>() {
 3396  0 public void run(DetachedFrame frame) {
 3397  0 _debugSplitPane.setTopComponent(_docSplitPane);
 3398  0 _debugSplitPane.setBottomComponent(_debugPanel);
 3399  0 _mainSplit.setTopComponent(_debugSplitPane);
 3400    }
 3401    });
 3402  38 _debugFrame.addWindowListener(new WindowAdapter() {
 3403  0 public void windowClosing(WindowEvent we) {
 3404  0 if (_debugFrame == null) return; // debugger not used
 3405  0 _detachDebugFrameMenuItem.setSelected(false);
 3406  0 DrJava.getConfig().setSetting(DETACH_DEBUGGER, false);
 3407    }
 3408    });
 3409  38 _debugFrame.setUpMenuBar();
 3410    }
 3411    else { // not using debugger
 3412  0 _debugFrame = null;
 3413    }
 3414   
 3415    // Set frame icon
 3416  38 setIconImage(getIcon("drjava64.png").getImage());
 3417   
 3418    // Size and position
 3419  38 int x = config.getSetting(WINDOW_X).intValue();
 3420  38 int y = config.getSetting(WINDOW_Y).intValue();
 3421  38 int width = config.getSetting(WINDOW_WIDTH).intValue();
 3422  38 int height = config.getSetting(WINDOW_HEIGHT).intValue();
 3423  38 int state = config.getSetting(WINDOW_STATE).intValue();
 3424   
 3425    // Bounds checking.
 3426    // suggested from zaq@nosi.com, to keep the frame on the screen!
 3427  38 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
 3428   
 3429  38 final int menubarHeight = 24;
 3430  0 if (height > screenSize.height - menubarHeight) height = screenSize.height - menubarHeight; // Too tall, so resize
 3431   
 3432  0 if (width > screenSize.width) width = screenSize.width; // Too wide, so resize
 3433   
 3434    // I assume that we want to be contained on the default screen.
 3435    // TODO: support spanning screens in multi-screen setups.
 3436  38 Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().
 3437    getDefaultConfiguration().getBounds();
 3438   
 3439  11 if (x == Integer.MAX_VALUE) x = (bounds.width - width + bounds.x) / 2; // magic value for "not set" - center.
 3440  11 if (y == Integer.MAX_VALUE) y = (bounds.height - height + bounds.y) / 2; // magic value for "not set" - center.
 3441  0 if (x < bounds.x) x = bounds.x; // Too far left, move to left edge.
 3442  0 if (y < bounds.y) y = bounds.y; // Too far up, move to top edge.
 3443  27 if ((x + width) > (bounds.x + bounds.width)) x = bounds.width - width + bounds.x;
 3444    // Too far right, move to right edge.
 3445  0 if ((y + height) > (bounds.y + bounds.height)) y = bounds.height - height + bounds.y;
 3446    // Too far down, move to bottom edge.
 3447   
 3448    //ensure that we don't set window state to minimized
 3449  38 state &= ~Frame.ICONIFIED;
 3450   
 3451  38 if (!Toolkit.getDefaultToolkit().isFrameStateSupported(state)) {
 3452    //we have a bad state, so reset to default
 3453  0 state = WINDOW_STATE.getDefault();
 3454    }
 3455   
 3456    // Set to the new correct size and location
 3457  38 setBounds(x, y, width, height);
 3458   
 3459    //Work-aroung for Java bug #6365898?
 3460    //setExtendedState does not work until the window in shown on Linux.
 3461  38 final int stateCopy = state;
 3462  38 addWindowListener(new WindowAdapter() {
 3463  0 public void windowOpened(WindowEvent e) {
 3464  0 setExtendedState(stateCopy);
 3465    //this is a one-off listener
 3466  0 removeWindowListener(this);
 3467    }
 3468    });
 3469   
 3470  38 _setUpPanes();
 3471  38 updateStatusField();
 3472   
 3473  38 _promptBeforeQuit = config.getSetting(QUIT_PROMPT).booleanValue();
 3474   
 3475    // Set the fonts
 3476  38 _setMainFont();
 3477  38 Font doclistFont = config.getSetting(FONT_DOCLIST);
 3478  38 _model.getDocCollectionWidget().setFont(doclistFont);
 3479   
 3480    // Set the colors
 3481  38 _updateNormalColor();
 3482  38 _updateBackgroundColor();
 3483   
 3484    // Add OptionListeners for the colors.
 3485  38 config.addOptionListener(DEFINITIONS_NORMAL_COLOR, new NormalColorOptionListener());
 3486  38 config.addOptionListener(DEFINITIONS_BACKGROUND_COLOR, new BackgroundColorOptionListener());
 3487   
 3488    /* Add option listeners for changes to config options. NOTE: We should only add listeners to view-related (or view-
 3489    * dependent) config options here. Model options should go in DefaultGlobalModel._registerOptionListeners(). */
 3490  38 config.addOptionListener(FONT_MAIN, new MainFontOptionListener());
 3491  38 config.addOptionListener(FONT_LINE_NUMBERS, new LineNumbersFontOptionListener());
 3492  38 config.addOptionListener(FONT_DOCLIST, new DoclistFontOptionListener());
 3493  38 config.addOptionListener(FONT_TOOLBAR, new ToolbarFontOptionListener());
 3494  38 config.addOptionListener(TOOLBAR_ICONS_ENABLED, new ToolbarOptionListener());
 3495  38 config.addOptionListener(TOOLBAR_TEXT_ENABLED, new ToolbarOptionListener());
 3496  38 config.addOptionListener(TOOLBAR_ENABLED, new ToolbarOptionListener());
 3497  38 config.addOptionListener(LINEENUM_ENABLED, new LineEnumOptionListener());
 3498  38 config.addOptionListener(DEFINITIONS_LINE_NUMBER_COLOR, new LineEnumColorOptionListener());
 3499  38 config.addOptionListener(DEFINITIONS_LINE_NUMBER_BACKGROUND_COLOR, new LineEnumColorOptionListener());
 3500  38 config.addOptionListener(QUIT_PROMPT, new QuitPromptOptionListener());
 3501  38 config.addOptionListener(RECENT_FILES_MAX_SIZE, new RecentFilesOptionListener());
 3502   
 3503    // Add a listener to the main font to keep the right margin in the definitions pane at the right place.
 3504  38 OptionListener<Font> fontListener = new OptionListener<Font>() {
 3505  0 public void optionChanged(OptionEvent<Font> oce) {
 3506  0 FontMetrics metrics = getFontMetrics(oce.value);
 3507  0 DefinitionsPane.updateMaxCharWidth(metrics);
 3508    }
 3509    };
 3510  38 DrJava.getConfig().addOptionListener(OptionConstants.FONT_MAIN, fontListener);
 3511  38 DefinitionsPane.updateMaxCharWidth(getFontMetrics(DrJava.getConfig().getSetting(FONT_MAIN)));
 3512   
 3513  38 config.addOptionListener(FORCE_TEST_SUFFIX, new OptionListener<Boolean>() {
 3514  0 public void optionChanged(OptionEvent<Boolean> oce) {
 3515  0 _model.getJUnitModel().setForceTestSuffix(oce.value.booleanValue());
 3516    }
 3517    });
 3518   
 3519    // The OptionListener for JAVADOC_API_REF_VERSION.
 3520  38 OptionListener<String> choiceOptionListener = new OptionListener<String>() {
 3521  0 public void optionChanged(OptionEvent<String> oce) {
 3522  0 clearJavaAPISet();
 3523    }
 3524    };
 3525  38 DrJava.getConfig().addOptionListener(JAVADOC_API_REF_VERSION, choiceOptionListener);
 3526   
 3527    // The OptionListener for JAVADOC_XXX_LINK.
 3528  38 OptionListener<String> link13OptionListener = new OptionListener<String>() {
 3529  0 public void optionChanged(OptionEvent<String> oce) {
 3530  0 String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION);
 3531  0 if (linkVersion.equals(JAVADOC_1_3_TEXT) ||
 3532    linkVersion.equals(JAVADOC_AUTO_TEXT)) {
 3533  0 clearJavaAPISet();
 3534    }
 3535    }
 3536    };
 3537  38 DrJava.getConfig().addOptionListener(JAVADOC_1_3_LINK, link13OptionListener);
 3538  38 OptionListener<String> link14OptionListener = new OptionListener<String>() {
 3539  0 public void optionChanged(OptionEvent<String> oce) {
 3540  0 String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION);
 3541  0 if (linkVersion.equals(JAVADOC_1_4_TEXT) ||
 3542    linkVersion.equals(JAVADOC_AUTO_TEXT)) {
 3543  0 clearJavaAPISet();
 3544    }
 3545    }
 3546    };
 3547  38 DrJava.getConfig().addOptionListener(JAVADOC_1_4_LINK, link14OptionListener);
 3548  38 OptionListener<String> link15OptionListener = new OptionListener<String>() {
 3549  0 public void optionChanged(OptionEvent<String> oce) {
 3550  0 String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION);
 3551  0 if (linkVersion.equals(JAVADOC_1_5_TEXT) ||
 3552    linkVersion.equals(JAVADOC_AUTO_TEXT)) {
 3553  0 clearJavaAPISet();
 3554    }
 3555    }
 3556    };
 3557  38 DrJava.getConfig().addOptionListener(JAVADOC_1_5_LINK, link15OptionListener);
 3558  38 OptionListener<String> link16OptionListener = new OptionListener<String>() {
 3559  0 public void optionChanged(OptionEvent<String> oce) {
 3560  0 String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION);
 3561  0 if (linkVersion.equals(JAVADOC_1_6_TEXT) ||
 3562    linkVersion.equals(JAVADOC_AUTO_TEXT)) {
 3563  0 clearJavaAPISet();
 3564    }
 3565    }
 3566    };
 3567  38 DrJava.getConfig().addOptionListener(JAVADOC_1_6_LINK, link16OptionListener);
 3568  38 OptionListener<String> linkJUnitOptionListener = new OptionListener<String>() {
 3569  0 public void optionChanged(OptionEvent<String> oce) {
 3570  0 clearJavaAPISet();
 3571    }
 3572    };
 3573  38 DrJava.getConfig().addOptionListener(JUNIT_LINK, linkJUnitOptionListener);
 3574  38 OptionListener<Vector<String>> additionalLinkOptionListener = new OptionListener<Vector<String>>() {
 3575  0 public void optionChanged(OptionEvent<Vector<String>> oce) {
 3576  0 clearJavaAPISet();
 3577    }
 3578    };
 3579  38 DrJava.getConfig().addOptionListener(JAVADOC_ADDITIONAL_LINKS, additionalLinkOptionListener);
 3580  38 OptionListener<Boolean> scanClassesOptionListener = new OptionListener<Boolean>() {
 3581  0 public void optionChanged(OptionEvent<Boolean> oce) {
 3582  0 clearCompleteClassSet();
 3583    }
 3584    };
 3585  38 DrJava.getConfig().addOptionListener(DIALOG_COMPLETE_SCAN_CLASS_FILES, scanClassesOptionListener);
 3586   
 3587    // Initialize cached frames and dialogs
 3588  38 _configFrame = new ConfigFrame(MainFrame.this);
 3589  38 _aboutDialog = new AboutDialog(MainFrame.this);
 3590  38 _interactionsScriptController = null;
 3591  38 _executeExternalDialog = new ExecuteExternalDialog(MainFrame.this);
 3592  38 _editExternalDialog = new EditExternalDialog(MainFrame.this);
 3593  38 _jarOptionsDialog = new JarOptionsDialog(MainFrame.this);
 3594   
 3595  38 initTabbedPanesFrame();
 3596  38 initDebugFrame();
 3597  38 initJarOptionsDialog();
 3598  38 initExecuteExternalProcessDialog();
 3599    // _projectPropertiesFrame = null;
 3600   
 3601  38 config.addOptionListener(DISPLAY_ALL_COMPILER_VERSIONS,
 3602    new ConfigOptionListeners.DisplayAllCompilerVersionsListener(_configFrame));
 3603  38 config.addOptionListener(LOOK_AND_FEEL, new ConfigOptionListeners.LookAndFeelListener(_configFrame));
 3604  38 config.addOptionListener(PLASTIC_THEMES, new ConfigOptionListeners.PlasticThemeListener(_configFrame));
 3605  38 OptionListener<String> slaveJVMArgsListener = new ConfigOptionListeners.SlaveJVMArgsListener(_configFrame);
 3606  38 config.addOptionListener(SLAVE_JVM_ARGS, slaveJVMArgsListener);
 3607  38 _slaveJvmXmxListener = new ConfigOptionListeners.SlaveJVMXMXListener(_configFrame);
 3608  38 config.addOptionListener(SLAVE_JVM_XMX, _slaveJvmXmxListener);
 3609  38 OptionListener<String> masterJVMArgsListener = new ConfigOptionListeners.MasterJVMArgsListener(_configFrame);
 3610  38 config.addOptionListener(MASTER_JVM_ARGS, masterJVMArgsListener);
 3611  38 _masterJvmXmxListener = new ConfigOptionListeners.MasterJVMXMXListener(_configFrame);
 3612  38 config.addOptionListener(MASTER_JVM_XMX, _masterJvmXmxListener);
 3613  38 config.addOptionListener(JAVADOC_CUSTOM_PARAMS,
 3614    new ConfigOptionListeners.JavadocCustomParamsListener(_configFrame));
 3615  38 ConfigOptionListeners.sanitizeSlaveJVMArgs(MainFrame.this, config.getSetting(SLAVE_JVM_ARGS), slaveJVMArgsListener);
 3616  38 ConfigOptionListeners.sanitizeSlaveJVMXMX(MainFrame.this, config.getSetting(SLAVE_JVM_XMX));
 3617  38 ConfigOptionListeners.sanitizeMasterJVMArgs(MainFrame.this, config.getSetting(MASTER_JVM_ARGS), masterJVMArgsListener);
 3618  38 ConfigOptionListeners.sanitizeMasterJVMXMX(MainFrame.this, config.getSetting(MASTER_JVM_XMX));
 3619  38 ConfigOptionListeners.sanitizeJavadocCustomParams(MainFrame.this, config.getSetting(JAVADOC_CUSTOM_PARAMS));
 3620  38 config.addOptionListener(REMOTE_CONTROL_ENABLED, new ConfigOptionListeners.
 3621    RequiresDrJavaRestartListener<Boolean>(_configFrame, "Remote Control"));
 3622  38 config.addOptionListener(REMOTE_CONTROL_PORT, new ConfigOptionListeners.
 3623    RequiresDrJavaRestartListener<Integer>(_configFrame, "Remote Control Port"));
 3624  38 config.addOptionListener(DEFAULT_COMPILER_PREFERENCE, new ConfigOptionListeners.DefaultCompilerListener(_configFrame));
 3625    // If any errors occurred while parsing config file, show them
 3626  38 _showConfigException();
 3627   
 3628  38 KeyBindingManager.ONLY.setShouldCheckConflict(false);
 3629   
 3630    // Platform-specific UI setup.
 3631  38 PlatformFactory.ONLY.afterUISetup(_aboutAction, _editPreferencesAction, _quitAction);
 3632  38 setUpKeys();
 3633   
 3634    // discard ` character if it was used for the next/prev recent doc feature
 3635  38 KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
 3636  0 public boolean dispatchKeyEvent(KeyEvent e) {
 3637  0 boolean discardEvent = false;
 3638   
 3639  0 if ((e.getID() == KeyEvent.KEY_TYPED) &&
 3640    (e.getKeyChar() == '`') &&
 3641    (((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) ||
 3642    ((e.getModifiersEx() & (InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK))
 3643    == (InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK))) &&
 3644    (e.getComponent().getClass().equals(DefinitionsPane.class))) {
 3645    // System.out.println("discarding `, modifiers = "+e.getModifiersEx()+": "+e.getComponent());
 3646  0 discardEvent = true;
 3647    }
 3648  0 return discardEvent;
 3649    }
 3650    });
 3651   
 3652  38 if (DrJava.getConfig().getSetting(OptionConstants.REMOTE_CONTROL_ENABLED)) {
 3653    // start remote control server if no server is running
 3654  38 try {
 3655  38 if (! RemoteControlClient.isServerRunning()) {
 3656  11 new RemoteControlServer(MainFrame.this);
 3657    }
 3658    }
 3659    catch(IOException ioe) {
 3660  5 try { RemoteControlClient.openFile(null); }
 3661    catch(IOException ignored) { /* ignore */ }
 3662  5 if (!Utilities.TEST_MODE && !System.getProperty("user.name").equals(RemoteControlClient.getServerUser())) {
 3663  0 Object[] options = {"Disable","Ignore"};
 3664  0 String msg = "<html>Could not start DrJava's remote control server";
 3665  0 if (RemoteControlClient.getServerUser() != null) {
 3666  0 msg += "<br>because user "+RemoteControlClient.getServerUser()+" is already using the same port";
 3667    }
 3668  0 msg += ".<br>Please select an unused port in the Preferences dialog.<br>"+
 3669    "In the meantime, do you want to disable the remote control feature?";
 3670  0 int n = JOptionPane.showOptionDialog(MainFrame.this,
 3671    msg,
 3672    "Could Not Start Remote Control Server",
 3673    JOptionPane.YES_NO_OPTION,
 3674    JOptionPane.QUESTION_MESSAGE,
 3675    null,
 3676    options,
 3677    options[1]);
 3678  0 if (n==JOptionPane.YES_OPTION) {
 3679  0 DrJava.getConfig().setSetting(OptionConstants.REMOTE_CONTROL_ENABLED, false);
 3680    }
 3681    }
 3682    }
 3683    }
 3684   
 3685  38 setUpDrJavaProperties();
 3686   
 3687  38 DrJavaErrorHandler.setButton(_errorsButton);
 3688   
 3689    // check file associations if desired by user
 3690  38 boolean alreadyShowedDialog = false;
 3691  38 if (PlatformFactory.ONLY.canRegisterFileExtensions()) {
 3692    // only try to register file extensions if this platform supports it
 3693  0 if (DrJava.getConfig().getSetting(OptionConstants.FILE_EXT_REGISTRATION)
 3694    .equals(OptionConstants.FILE_EXT_REGISTRATION_CHOICES.get(2))) { // Always
 3695    // always set file associations
 3696  0 PlatformFactory.ONLY.registerDrJavaFileExtensions();
 3697  0 PlatformFactory.ONLY.registerJavaFileExtension();
 3698    }
 3699  0 else if (DrJava.getConfig().getSetting(OptionConstants.FILE_EXT_REGISTRATION)
 3700    .equals(OptionConstants.FileExtRegistrationChoices.ASK_ME) && // Ask me
 3701    ! Utilities.TEST_MODE &&
 3702    ((!PlatformFactory.ONLY.areDrJavaFileExtensionsRegistered()) ||
 3703    (!PlatformFactory.ONLY.isJavaFileExtensionRegistered()))) {
 3704  0 alreadyShowedDialog = true;
 3705  0 EventQueue.invokeLater(new Runnable() {
 3706  0 public void run() {
 3707  0 int rc;
 3708  0 Object[] options = {"Yes", "No", "Always", "Never"};
 3709  0 String text = "Do you want to associate .java, .drjava and .djapp files with DrJava?\n" +
 3710    "Double-clicking on those files will open them in DrJava.\n\n" +
 3711    "Select 'Always' to let DrJava do this automatically.\n"+
 3712    "Select 'Never' if you don't want to be asked again.\n\n"+
 3713    "You can change this setting in the Preferences dialog under\n"+
 3714    "Miscellaneous/File Types.";
 3715   
 3716  0 rc = JOptionPane.showOptionDialog(MainFrame.this, text, "Set File Associations?", JOptionPane.YES_NO_OPTION,
 3717    JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
 3718  0 if ((rc == 0) || (rc==2)) { // Yes or Always
 3719  0 PlatformFactory.ONLY.registerDrJavaFileExtensions();
 3720  0 PlatformFactory.ONLY.registerJavaFileExtension();
 3721    }
 3722  0 if (rc==2) { // Always
 3723  0 DrJava.getConfig().setSetting(OptionConstants.FILE_EXT_REGISTRATION,
 3724    OptionConstants.FILE_EXT_REGISTRATION_CHOICES.get(2));
 3725    }
 3726  0 if (rc==3) { // Never
 3727  0 DrJava.getConfig().setSetting(OptionConstants.FILE_EXT_REGISTRATION,
 3728    OptionConstants.FILE_EXT_REGISTRATION_CHOICES.get(0));
 3729    }
 3730    }
 3731    });
 3732    }
 3733    }
 3734   
 3735  38 if (!alreadyShowedDialog) {
 3736    // check for new version if desired by user
 3737    // but only if we haven't just asked if the user wants to download a new version
 3738    // two dialogs on program start is too much clutter
 3739  38 if (DrJava.getConfig().getSetting(OptionConstants.NEW_VERSION_ALLOWED) &&
 3740    !DrJava.getConfig().getSetting(OptionConstants.NEW_VERSION_NOTIFICATION)
 3741    .equals(OptionConstants.VersionNotificationChoices.DISABLED) && ! Utilities.TEST_MODE) {
 3742  0 int days = DrJava.getConfig().getSetting(NEW_VERSION_NOTIFICATION_DAYS);
 3743  0 java.util.Date nextCheck =
 3744    new java.util.Date(DrJava.getConfig().getSetting(OptionConstants.LAST_NEW_VERSION_NOTIFICATION)
 3745    + days * 24L * 60 * 60 * 1000); // x days after last check; 24L ensures long accumulation
 3746  0 if (new java.util.Date().after(nextCheck)) {
 3747  0 alreadyShowedDialog = true;
 3748  0 EventQueue.invokeLater(new Runnable() {
 3749  0 public void run() {
 3750  0 NewVersionPopup popup = new NewVersionPopup(MainFrame.this);
 3751  0 if (popup.checkNewVersion()) { popup.setVisible(true); }
 3752    }
 3753    });
 3754    }
 3755    }
 3756    }
 3757    // if (!alreadyShowedDialog) {
 3758    // // ask if the user wants to submit the survey
 3759    // // but only if we haven't just asked if the user wants to download a new version
 3760    // // two dialogs on program start is too much clutter
 3761    // if (DrJava.getConfig().getSetting(DIALOG_DRJAVA_SURVEY_ENABLED) &&
 3762    // ! edu.rice.cs.util.swing.Utilities.TEST_MODE) {
 3763    // if (DrJavaSurveyPopup.maySubmitSurvey()) {
 3764    // // either enough days have passed, or the configuration has changed
 3765    // alreadyShowedDialog = true;
 3766    // EventQueue.invokeLater(new Runnable() {
 3767    // public void run() {
 3768    // DrJavaSurveyPopup popup = new DrJavaSurveyPopup(MainFrame.this);
 3769    // popup.setVisible(true);
 3770    // }
 3771    // });
 3772    // }
 3773    // }
 3774    // }
 3775   
 3776  38 initDone(); // call mandated by SwingFrame contract
 3777   
 3778  38 EventQueue.invokeLater(new Runnable() {
 3779  38 public void run() {
 3780  38 _tabbedPanesFrame.setDisplayInFrame(DrJava.getConfig().getSetting(DETACH_TABBEDPANES));
 3781    }
 3782    });
 3783    } });
 3784    } // End of MainFrame constructor
 3785   
 3786  0 public void setVisible(boolean b) {
 3787  0 _updateToolBarVisible();
 3788  0 super.setVisible(b);
 3789    }
 3790   
 3791    /** This method sets up all the DrJava properties that can be used as variables
 3792    * in external process command lines. */
 3793  38 public void setUpDrJavaProperties() {
 3794  38 final String DEF_DIR = "${drjava.working.dir}";
 3795   
 3796  38 DrJavaPropertySetup.setup();
 3797   
 3798    // Files
 3799  38 PropertyMaps.TEMPLATE.
 3800    setProperty("DrJava",
 3801    new FileProperty("drjava.current.file", new Thunk<File>() {
 3802  0 public File value() { return _model.getActiveDocument().getRawFile(); }
 3803    },
 3804    "Returns the current document in DrJava.\n"+
 3805    "Optional attributes:\n"+
 3806    "\trel=\"<dir to which the output should be relative\"\n"+
 3807    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3808    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3809  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3810    });
 3811  38 PropertyMaps.TEMPLATE.setProperty("DrJava",
 3812    new DrJavaProperty("drjava.current.line",
 3813    "Returns the current line in the Definitions Pane.") {
 3814  0 public void update(PropertyMaps pm) { _value = String.valueOf(_posListener.lastLine()); }
 3815  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3816  0 public boolean isCurrent() { return false; }
 3817    });
 3818  38 PropertyMaps.TEMPLATE.
 3819    setProperty("DrJava", new DrJavaProperty("drjava.current.col",
 3820    "Returns the current column in the Definitions Pane.") {
 3821  0 public void update(PropertyMaps pm) {
 3822    // int line = _currentDefPane.getCurrentLine();
 3823    // int lineOffset = _currentDefPane.getLineStartOffset(line);
 3824    // int caretPos = _currentDefPane.getCaretPosition();
 3825  0 _value = String.valueOf(_posListener.lastCol());
 3826    }
 3827  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3828  0 public boolean isCurrent() { return false; }
 3829    });
 3830  38 PropertyMaps.TEMPLATE.
 3831    setProperty("DrJava",
 3832    new FileProperty("drjava.working.dir", new Thunk<File>() {
 3833  111 public File value() { return _model.getInteractionsModel().getWorkingDirectory(); }
 3834    },
 3835    "Returns the current working directory of DrJava.\n"+
 3836    "Optional attributes:\n"+
 3837    "\trel=\"<dir to which output should be relative\"\n"+
 3838    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3839    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3840  64 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3841    });
 3842  38 PropertyMaps.TEMPLATE.
 3843    setProperty("DrJava",
 3844    new FileProperty("drjava.master.working.dir", new Thunk<File>() {
 3845  0 public File value() { return _model.getMasterWorkingDirectory(); }
 3846    },
 3847    "Returns the working directory of the DrJava master JVM.\n"+
 3848    "Optional attributes:\n"+
 3849    "\trel=\"<dir to which output should be relative\"\n"+
 3850    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3851    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3852  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3853    });
 3854   
 3855    // Files
 3856  38 PropertyMaps.TEMPLATE.
 3857    setProperty("DrJava",
 3858    new FileListProperty("drjava.all.files", File.pathSeparator, DEF_DIR,
 3859    "Returns a list of all files open in DrJava.\n"+
 3860    "Optional attributes:\n"+
 3861    "\trel=\"<dir to which output should be relative\"\n"+
 3862    "\tsep=\"<separator between files>\"\n"+
 3863    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3864    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3865  32 protected List<File> getList(PropertyMaps pm) {
 3866  32 ArrayList<File> l = new ArrayList<File>();
 3867  32 for(OpenDefinitionsDocument odd: _model.getOpenDefinitionsDocuments()) {
 3868  47 l.add(odd.getRawFile());
 3869    }
 3870  32 return l;
 3871    }
 3872  32 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3873  32 public boolean isCurrent() { return false; }
 3874    });
 3875  38 PropertyMaps.TEMPLATE.
 3876    setProperty("DrJava",
 3877    new FileListProperty("drjava.project.files", File.pathSeparator, DEF_DIR,
 3878    "Returns a list of all files open in DrJava that belong " +
 3879    "to a project and are underneath the project root.\n" +
 3880    "Optional attributes:\n" +
 3881    "\trel=\"<dir to which output should be relative\"\n" +
 3882    "\tsep=\"<separator between files>\"\n"+
 3883    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3884    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3885  0 protected List<File> getList(PropertyMaps pm) {
 3886  0 ArrayList<File> l = new ArrayList<File>();
 3887  0 for(OpenDefinitionsDocument odd: _model.getProjectDocuments()) {
 3888  0 l.add(odd.getRawFile());
 3889    }
 3890  0 return l;
 3891    }
 3892  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3893  0 public boolean isCurrent() { return false; }
 3894    }).listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files"));
 3895  38 PropertyMaps.TEMPLATE.
 3896    setProperty("DrJava",
 3897    new FileListProperty("drjava.included.files", File.pathSeparator, DEF_DIR,
 3898    "Returns a list of all files open in DrJava that are " +
 3899    "not underneath the project root but are included in " +
 3900    "the project.\n" +
 3901    "Optional attributes:\n" +
 3902    "\trel=\"<dir to which output should be relative\"\n" +
 3903    "\tsep=\"<separator between files>\"\n"+
 3904    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3905    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3906  0 protected List<File> getList(PropertyMaps pm) {
 3907  0 ArrayList<File> l = new ArrayList<File>();
 3908  0 for(OpenDefinitionsDocument odd: _model.getAuxiliaryDocuments()) {
 3909  0 l.add(odd.getRawFile());
 3910    }
 3911  0 return l;
 3912    }
 3913  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3914  0 public boolean isCurrent() { return false; }
 3915    }).listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files"));
 3916  38 PropertyMaps.TEMPLATE.
 3917    setProperty("DrJava",
 3918    new FileListProperty("drjava.external.files", File.pathSeparator, DEF_DIR,
 3919    "Returns a list of all files open in DrJava that are "+
 3920    "not underneath the project root and are not included in "+
 3921    "the project.\n"+
 3922    "Optional attributes:\n"+
 3923    "\trel=\"<dir to which output should be relative\"\n"+
 3924    "\tsep=\"<separator between files>\"\n"+
 3925    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 3926    "\tdquote=\"<true to enclose file in double quotes>\"") {
 3927  0 protected List<File> getList(PropertyMaps pm) {
 3928  0 ArrayList<File> l = new ArrayList<File>();
 3929  0 for(OpenDefinitionsDocument odd: _model.getNonProjectDocuments()) {
 3930  0 l.add(odd.getRawFile());
 3931    }
 3932  0 return l;
 3933    }
 3934  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3935  0 public boolean isCurrent() { return false; }
 3936    }).listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files"));
 3937   
 3938  38 PropertyMaps.TEMPLATE.
 3939    setProperty("Misc",
 3940    new DrJavaProperty("input", "(User Input...)",
 3941    "Get an input string from the user.\n"+
 3942    "Optional attributes:\n"+
 3943    "\tprompt=\"<prompt to display>\"\n"+
 3944    "\tdefault=\"<suggestion to the user>\"") {
 3945  0 public String toString() {
 3946  0 return "(User Input...)";
 3947    }
 3948  0 public void update(PropertyMaps pm) {
 3949  0 String msg = _attributes.get("prompt");
 3950  0 if (msg == null) msg = "Please enter text for the external process.";
 3951  0 String input = _attributes.get("default");
 3952  0 if (input == null) input = "";
 3953  0 input = JOptionPane.showInputDialog(MainFrame.this, msg, input);
 3954  0 if (input == null) input = _attributes.get("default");
 3955  0 if (input == null) input = "";
 3956  0 _value = input;
 3957    }
 3958  0 public String getCurrent(PropertyMaps pm) {
 3959  0 invalidate();
 3960  0 return super.getCurrent(pm);
 3961    }
 3962  38 public void resetAttributes() {
 3963  38 _attributes.clear();
 3964  38 _attributes.put("prompt", null);
 3965  38 _attributes.put("default", null);
 3966    }
 3967  0 public boolean isCurrent() { return false; }
 3968    });
 3969   
 3970    // Project
 3971  38 PropertyMaps.TEMPLATE.
 3972    setProperty("Project",
 3973    new DrJavaProperty("project.mode",
 3974    "Evaluates to true if a project is loaded.") {
 3975  0 public void update(PropertyMaps pm) {
 3976  0 Boolean b = _model.isProjectActive();
 3977  0 String f = _attributes.get("fmt").toLowerCase();
 3978  0 if (f.equals("int")) _value = b ? "1" : "0";
 3979  0 else if (f.equals("yes")) _value = b ? "yes" : "no";
 3980  0 else _value = b.toString();
 3981    }
 3982  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 3983  38 public void resetAttributes() {
 3984  38 _attributes.clear();
 3985  38 _attributes.put("fmt", "boolean");
 3986    }
 3987  0 public boolean isCurrent() { return false; }
 3988    });
 3989  38 PropertyMaps.TEMPLATE.
 3990    setProperty("Project",
 3991    new DrJavaProperty("project.changed",
 3992    "Evaluates to true if the project has been "+
 3993    "changed since the last save.") { //TODO: factor out repeated code!
 3994  0 public void update(PropertyMaps pm) {
 3995    // long millis = System.currentTimeMillis();
 3996  0 String f = _attributes.get("fmt").toLowerCase();
 3997  0 Boolean b = _model.isProjectChanged();
 3998  0 if (f.equals("int")) _value = b ? "1" : "0";
 3999  0 else if (f.equals("yes")) _value = b ? "yes" : "no";
 4000  0 else _value = b.toString();
 4001    }
 4002  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4003  38 public void resetAttributes() {
 4004  38 _attributes.clear();
 4005  38 _attributes.put("fmt", "boolean");
 4006    }
 4007  0 public boolean isCurrent() { return false; }
 4008    });
 4009  38 PropertyMaps.TEMPLATE.
 4010    setProperty("Project",
 4011    new FileProperty("project.file",
 4012    new Thunk<File>() {
 4013  0 public File value() { return _model.getProjectFile(); }
 4014    },
 4015    "Returns the current project file in DrJava.\n"+
 4016    "Optional attributes:\n"+
 4017    "\trel=\"<dir to which the output should be relative\"\n"+
 4018    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4019    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4020  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4021    });
 4022   
 4023  38 PropertyMaps.TEMPLATE.
 4024    setProperty("Project",
 4025    new FileProperty("project.main.class",
 4026    new Thunk<File>() {
 4027  0 public File value() { return new File(_model.getMainClass()); }
 4028    },
 4029    "Returns the current project file in DrJava.\n"+
 4030    "Optional attributes:\n"+
 4031    "\trel=\"<dir to which the output should be relative\"\n"+
 4032    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4033    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4034  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4035    });
 4036  38 PropertyMaps.TEMPLATE.
 4037    setProperty("Project",
 4038    new FileProperty("project.root",
 4039    new Thunk<File>() {
 4040  0 public File value() { return _model.getProjectRoot(); }
 4041    },
 4042    "Returns the current project root in DrJava.\n"+
 4043    "Optional attributes:\n"+
 4044    "\trel=\"<dir to which the output should be relative\"\n"+
 4045    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4046    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4047  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4048    });
 4049  38 PropertyMaps.TEMPLATE.
 4050    setProperty("Project",
 4051    new FileProperty("project.build.dir",
 4052    new Thunk<File>() {
 4053  0 public File value() { return _model.getBuildDirectory(); }
 4054    },
 4055    "Returns the current build directory in DrJava.\n"+
 4056    "Optional attributes:\n"+
 4057    "\trel=\"<dir to which the output should be relative\"\n"+
 4058    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4059    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4060  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4061    });
 4062  38 RecursiveFileListProperty classFilesProperty =
 4063    new RecursiveFileListProperty("project.class.files", File.pathSeparator, DEF_DIR,
 4064    _model.getBuildDirectory().getAbsolutePath(),
 4065    "Returns the class files currently in the build directory.\n"+
 4066    "\trel=\"<dir to which the output should be relative\"\n"+
 4067    "\tsep=\"<string to separate files in the list>\"\n"+
 4068    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4069    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4070    /** Reset the attributes. */
 4071  114 public void resetAttributes() {
 4072  114 _attributes.clear();
 4073  114 _attributes.put("sep", _sep);
 4074  114 _attributes.put("rel", _dir);
 4075  114 _attributes.put("dir", _model.getBuildDirectory().getAbsolutePath());
 4076  114 _attributes.put("filter", "*.class");
 4077  114 _attributes.put("dirfilter", "*");
 4078    }
 4079    };
 4080  38 PropertyMaps.TEMPLATE.setProperty("Project", classFilesProperty);
 4081  38 PropertyMaps.TEMPLATE.
 4082    setProperty("Project",
 4083    new DrJavaProperty("project.auto.refresh",
 4084    "Evaluates to true if project auto-refresh is enabled.") {
 4085  32 public void update(PropertyMaps pm) {
 4086  32 Boolean b = _model.getAutoRefreshStatus();
 4087  32 String f = _attributes.get("fmt").toLowerCase();
 4088  0 if (f.equals("int")) _value = b ? "1" : "0";
 4089  0 else if (f.equals("yes")) _value = b ? "yes" : "no";
 4090  32 else _value = b.toString();
 4091    }
 4092  32 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4093  38 public void resetAttributes() {
 4094  38 _attributes.clear();
 4095  38 _attributes.put("fmt", "boolean");
 4096    }
 4097  32 public boolean isCurrent() { return false; }
 4098    });
 4099  38 PropertyMaps.TEMPLATE.
 4100    setProperty("Project",
 4101    new FileListProperty("project.excluded.files", File.pathSeparator, DEF_DIR,
 4102    "Returns a list of files that are excluded from DrJava's "+
 4103    "project auto-refresh.\n"+
 4104    "Optional attributes:\n"+
 4105    "\trel=\"<dir to which output should be relative\"\n"+
 4106    "\tsep=\"<separator between files>\"\n"+
 4107    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4108    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4109  0 protected List<File> getList(PropertyMaps pm) {
 4110  0 ArrayList<File> l = new ArrayList<File>();
 4111  0 for(File f: _model.getExclFiles()) { l.add(f); }
 4112  0 return l;
 4113    }
 4114  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4115  0 public boolean isCurrent() { return false; }
 4116    });
 4117  38 PropertyMaps.TEMPLATE.
 4118    setProperty("Project",
 4119    new FileListProperty("project.extra.class.path", File.pathSeparator, DEF_DIR,
 4120    "Returns a list of files in the project's extra "+
 4121    "class path.\n"+
 4122    "Optional attributes:\n"+
 4123    "\trel=\"<dir to which output should be relative\"\n"+
 4124    "\tsep=\"<separator between files>\"\n"+
 4125    "\tsquote=\"<true to enclose file in single quotes>\"\n"+
 4126    "\tdquote=\"<true to enclose file in double quotes>\"") {
 4127  0 protected List<File> getList(PropertyMaps pm) {
 4128  0 ArrayList<File> l = new ArrayList<File>();
 4129  0 for(File f: _model.getExtraClassPath()) { l.add(f); }
 4130  0 return l;
 4131    }
 4132  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 4133  0 public boolean isCurrent() { return false; }
 4134    });
 4135   
 4136    // Actions
 4137  38 PropertyMaps.TEMPLATE.setProperty("Action", new DrJavaActionProperty("action.save.all", "(Save All...)",
 4138    "Execute a \"Save All\" action.") {
 4139  0 public void update(PropertyMaps pm) { _saveAll(); }
 4140  0 public boolean isCurrent() { return false; }
 4141    });
 4142  38 PropertyMaps.TEMPLATE.
 4143    setProperty("Action", new DrJavaActionProperty("action.compile.all", "(Compile All...)",
 4144    "Execute a \"Compile All\" action.") {
 4145  0 public void update(PropertyMaps pm) { _compileAll(); }
 4146  0 public boolean isCurrent() { return false; }
 4147    });
 4148  38 PropertyMaps.TEMPLATE.
 4149    setProperty("Action",
 4150    new DrJavaActionProperty("action.clean", "(Clean Build Directory...)",
 4151    "Execute a \"Clean Build Directory\" action.") {
 4152  0 public void update(PropertyMaps pm) {
 4153    // could not use _clean(), since ProjectFileGroupingState.cleanBuildDirectory()
 4154    // is implemented as an asynchronous task, and DrJava would not wait for its completion
 4155  0 IOUtil.deleteRecursively(_model.getBuildDirectory());
 4156    }
 4157  0 public boolean isCurrent() { return false; }
 4158    });
 4159  38 PropertyMaps.TEMPLATE.setProperty("Action", new DrJavaActionProperty("action.open.file", "(Open File...)",
 4160    "Execute an \"Open File\" action.\n"+
 4161    "Required attributes:\n"+
 4162    "\tfile=\"<file to open>\"\n"+
 4163    "Optional attributes:\n"+
 4164    "\tline=\"<line number to display>") {
 4165  0 public void update(PropertyMaps pm) {
 4166  0 if (_attributes.get("file") != null) {
 4167  0 final String dir = StringOps.
 4168    unescapeFileName(StringOps.replaceVariables(DEF_DIR, pm, PropertyMaps.GET_CURRENT));
 4169  0 final String fil = StringOps.
 4170    unescapeFileName(StringOps.replaceVariables(_attributes.get("file"), pm, PropertyMaps.GET_CURRENT));
 4171  0 FileOpenSelector fs = new FileOpenSelector() {
 4172  0 public File[] getFiles() {
 4173  0 if (fil.startsWith("/")) { return new File[] { new File(fil) }; }
 4174  0 else { return new File[] { new File(dir, fil) }; }
 4175    }
 4176    };
 4177  0 open(fs);
 4178  0 int lineNo = -1;
 4179  0 if (_attributes.get("line") != null) {
 4180  0 try { lineNo = Integer.valueOf(_attributes.get("line")); }
 4181  0 catch(NumberFormatException nfe) { lineNo = -1; }
 4182    }
 4183  0 if (lineNo >= 0) {
 4184  0 final int l = lineNo;
 4185  0 Utilities.invokeLater(new Runnable() { public void run() { _jumpToLine(l); } });
 4186    }
 4187    }
 4188    }
 4189    /** Reset the attributes. */
 4190  38 public void resetAttributes() {
 4191  38 _attributes.clear();
 4192  38 _attributes.put("file", null);
 4193  38 _attributes.put("line", null);
 4194    }
 4195  0 public boolean isCurrent() { return false; }
 4196    });
 4197  38 PropertyMaps.TEMPLATE.
 4198    setProperty("Action",
 4199    new DrJavaActionProperty("action.auto.refresh", "(Auto-Refresh...)",
 4200    "Execute an \"Auto-Refresh Project\" action.") {
 4201  0 public void update(PropertyMaps pm) {
 4202  0 _model.autoRefreshProject();
 4203    }
 4204  0 public boolean isCurrent() { return false; }
 4205    });
 4206    }
 4207   
 4208    /** Sets up new painters for existing breakpoint highlights. */
 4209  0 void refreshBreakpointHighlightPainter() {
 4210  0 for(Map.Entry<Breakpoint,HighlightManager.HighlightInfo> pair: _documentBreakpointHighlights.entrySet()) {
 4211  0 if (pair.getKey().isEnabled()) pair.getValue().refresh(DefinitionsPane.BREAKPOINT_PAINTER);
 4212  0 else pair.getValue().refresh(DefinitionsPane.DISABLED_BREAKPOINT_PAINTER);
 4213    }
 4214    }
 4215   
 4216    /** Sets new painters for existing bookmark highlights. */
 4217  0 void refreshBookmarkHighlightPainter() {
 4218  0 for(HighlightManager.HighlightInfo hi: _documentBookmarkHighlights.values()) {
 4219  0 hi.refresh(DefinitionsPane.BOOKMARK_PAINTER);
 4220    }
 4221    }
 4222   
 4223    /** Set new painter for existing find results highlights. */
 4224  0 void refreshFindResultsHighlightPainter(FindResultsPanel panel, LayeredHighlighter.LayerPainter painter) {
 4225  0 for(Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair: _findResults) {
 4226  0 if (pair.first() == panel) {
 4227  0 Map<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights = pair.second();
 4228  0 for(HighlightManager.HighlightInfo hi: highlights.values()) { hi.refresh(painter); }
 4229    }
 4230    }
 4231    }
 4232   
 4233    /** Creates the folder chooser during MainFrame initialization which does not run in event thread. */
 4234  38 private DirectoryChooser makeFolderChooser(final File workDir) {
 4235  38 assert duringInit() || EventQueue.isDispatchThread();
 4236  38 final DirectoryChooser dc = new DirectoryChooser(this);
 4237    /* The following code fragement was moved to the event thread because setSelectedFile occasionally generates an
 4238    * ArrayOutOfBoundsException otherwise. */
 4239  38 dc.setSelectedFile(workDir);
 4240  38 dc.setApproveButtonText("Select");
 4241  38 dc.setDialogTitle("Open Folder");
 4242  38 dc.setAccessory(_openRecursiveCheckBox);
 4243  38 return dc;
 4244    }
 4245   
 4246    /** Sets up the ctrl-tab listener. */
 4247  38 private void setUpKeys() { setFocusTraversalKeysEnabled(false); }
 4248   
 4249    /** Clean up model and Swing resources. */
 4250  36 public void dispose() {
 4251  36 _model.dispose();
 4252  36 super.dispose();
 4253    }
 4254   
 4255    /** @return The model providing the logic for this view. */
 4256  375 public SingleDisplayModel getModel() { return _model; }
 4257   
 4258    /** Returns the frame's interactions pane. (Package private accessor) */
 4259  3 InteractionsPane getInteractionsPane() { return _interactionsPane; }
 4260   
 4261    /** Returns the frame's interactions controller. (Package private accessor) */
 4262  0 InteractionsController getInteractionsController() { return _interactionsController; }
 4263   
 4264    /** @return The frame's close button (Package private accessor). */
 4265  1 JButton getCloseButton() { return _closeButton; }
 4266   
 4267    /** For testing purposes.
 4268    * @return The frame's compileAll button (Package private accessor)
 4269    */
 4270  1 JButton getCompileAllButton() { return _compileButton; }
 4271   
 4272    private volatile int _hourglassNestLevel = 0;
 4273   
 4274    /** Make the cursor an hourglass. Only runs in the event thread. */
 4275  16 public void hourglassOn() {
 4276  16 assert EventQueue.isDispatchThread();
 4277  16 _hourglassNestLevel++;
 4278  16 if (_hourglassNestLevel == 1) {
 4279  15 getGlassPane().setVisible(true);
 4280  15 _currentDefPane.setEditable(false);
 4281  15 setAllowKeyEvents(false);
 4282    // _menuBar.setEnabled(false); // causes problems on Mac OS 10.6; make sure this runs in the event thread?
 4283  15 _interactionsPane.setEnabled(false);
 4284    }
 4285    }
 4286   
 4287    /** Return the cursor to normal. Only runs in the event thread. */
 4288  15 public void hourglassOff() {
 4289  15 assert EventQueue.isDispatchThread();
 4290  15 _hourglassNestLevel--;
 4291  15 if (_hourglassNestLevel == 0) {
 4292  14 getGlassPane().setVisible(false);
 4293  14 _currentDefPane.setEditable(true);
 4294  14 setAllowKeyEvents(true);
 4295    // _menuBar.setEnabled(true); // causes problems on Mac OS 10.6; make sure this runs in the event thread?
 4296  14 _interactionsPane.setEnabled(true);
 4297    }
 4298    }
 4299   
 4300    private volatile boolean _allowKeyEvents = true;
 4301   
 4302  29 public void setAllowKeyEvents(boolean a) { _allowKeyEvents = a; }
 4303   
 4304  37 public boolean getAllowKeyEvents() { return _allowKeyEvents; }
 4305   
 4306    /** Toggles whether the debugger is enabled or disabled, and updates the display accordingly. Only runs in the
 4307    * event thread. */
 4308  0 public void debuggerToggle() {
 4309  0 assert EventQueue.isDispatchThread();
 4310    // Make sure the debugger is available
 4311  0 Debugger debugger = _model.getDebugger();
 4312  0 if (! debugger.isAvailable()) return;
 4313   
 4314  0 updateStatusField("Toggling Debugger Mode");
 4315  0 try {
 4316  0 if (isDebuggerReady()) {
 4317  0 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.DEBUGGER);
 4318  0 debugger.shutdown();
 4319    }
 4320    else {
 4321    // Turn on debugger
 4322  0 hourglassOn();
 4323  0 try {
 4324  0 debugger.startUp(); // may kick active document (if unmodified) out of memory!
 4325    // System.err.println("Trying to start debugger");
 4326  0 _model.refreshActiveDocument();
 4327  0 _updateDebugStatus();
 4328    }
 4329  0 finally { hourglassOff(); }
 4330    }
 4331    }
 4332    catch (DebugException de) {
 4333  0 MainFrameStatics.showError(MainFrame.this, de, "Debugger Error", "Could not start the debugger.");
 4334    }
 4335    catch (NoClassDefFoundError err) {
 4336  0 MainFrameStatics.showError(MainFrame.this, err, "Debugger Error",
 4337    "Unable to find the JPDA package for the debugger.\n" +
 4338    "Please make sure either tools.jar or jpda.jar is\n" +
 4339    "in your classpath when you start DrJava.");
 4340  0 _setDebugMenuItemsEnabled(false);
 4341    }
 4342    }
 4343   
 4344    /** Display the debugger tab and update the Debug menu accordingly. */
 4345  0 public void showDebugger() {
 4346  0 assert EventQueue.isDispatchThread();
 4347  0 _setDebugMenuItemsEnabled(true);
 4348  0 _showDebuggerPanel();
 4349    }
 4350   
 4351    /** Hide the debugger tab and update the Debug menu accordingly. */
 4352  0 public void hideDebugger() {
 4353  0 _setDebugMenuItemsEnabled(false);
 4354  0 _hideDebuggerPanel();
 4355    }
 4356   
 4357  0 private void _showDebuggerPanel() {
 4358  0 if (_debugFrame == null) return; // debugger isn't used
 4359  0 if (_detachDebugFrameMenuItem.isSelected()) {
 4360  0 _debugFrame.setDisplayInFrame(true);
 4361    }
 4362    else {
 4363  0 _debugSplitPane.setTopComponent(_docSplitPane);
 4364  0 _mainSplit.setTopComponent(_debugSplitPane);
 4365    }
 4366  0 _debugPanel.updateData();
 4367  0 _lastFocusOwner.requestFocusInWindow();
 4368    }
 4369   
 4370  0 private void _hideDebuggerPanel() {
 4371  0 if (_debugFrame == null) return; // debugger isn't used
 4372  0 if (_detachDebugFrameMenuItem.isSelected()) {
 4373  0 _debugFrame.setVisible(false);
 4374    }
 4375    else {
 4376  0 _mainSplit.setTopComponent(_docSplitPane);
 4377    }
 4378  0 _lastFocusOwner.requestFocusInWindow();
 4379    }
 4380   
 4381    /** ONLY executes in event thread. */
 4382  8 public void updateStatusField(String text) {
 4383  8 assert EventQueue.isDispatchThread();
 4384  8 _statusField.setText(text);
 4385  8 _statusField.paint(getGraphics()); // force an immediate repaint
 4386    }
 4387   
 4388    /** Updates the status field with the current status of the Definitions Pane. */
 4389  191 public void updateStatusField() {
 4390  191 OpenDefinitionsDocument doc = _model.getActiveDocument();
 4391  191 String fileName = doc.getCompletePath();
 4392  191 if (! fileName.equals(_fileTitle)) {
 4393  88 _fileTitle = fileName;
 4394  88 setTitle(fileName);
 4395  88 _tabbedPanesFrame.setTitle("Tabbed Panes - "+fileName);
 4396  88 if (_debugFrame!=null) _debugFrame.setTitle("Debugger - "+fileName);
 4397  88 _model.getDocCollectionWidget().repaint();
 4398    }
 4399  191 String path = doc.getCompletePath();
 4400   
 4401  191 String text = "Editing " + path;
 4402   
 4403    // Lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
 4404    // if (DrJava.getConfig().getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()) {
 4405    // String temp = _model.getParsingControl().getEnclosingClassName(doc);
 4406    // if ((temp != null) && (temp.length() > 0)) { text = text + " - " + temp; }
 4407   
 4408    // _statusField.setToolTipText("Full path for file: " + path);
 4409   
 4410  191 if (! _statusField.getText().equals(text)) {
 4411  88 _statusField.setText(text);
 4412  88 _statusField.paint(getGraphics()); // force immediate painting of the _statusField
 4413    }
 4414    }
 4415   
 4416    /** Prompt the user to select a place to open files from, then load them. Ask the user if they'd like to save
 4417    * previous changes (if the current document has been modified) before opening.
 4418    * @param jfc the open dialog from which to extract information
 4419    * @return an array of the files that were chosen
 4420    */
 4421  0 public File[] getOpenFiles(JFileChooser jfc) throws OperationCanceledException {
 4422  0 int rc = jfc.showOpenDialog(this);
 4423  0 return getChosenFiles(jfc, rc);
 4424    }
 4425   
 4426    /** Prompt the user to select a place to save the current document. */
 4427  0 public File getSaveFile(JFileChooser jfc) throws OperationCanceledException {
 4428    // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X!
 4429    // File selection = jfc.getSelectedFile();//_saveChooser.getSelectedFile();
 4430    // if (selection != null) {
 4431    // jfc.setSelectedFile(selection.getParentFile());
 4432    // jfc.setSelectedFile(selection);
 4433    // jfc.setSelectedFile(null);
 4434    // }
 4435   
 4436  0 OpenDefinitionsDocument active = _model.getActiveDocument();
 4437  0 File previous = null;
 4438   
 4439    // Fill in class name
 4440  0 if (active.isUntitled()) {
 4441  0 try {
 4442  0 String className = active.getFirstTopLevelClassName();
 4443  0 if (!className.equals("")) {
 4444  0 jfc.setSelectedFile(new File(jfc.getCurrentDirectory(), className));
 4445    }
 4446    }
 4447    catch (ClassNameNotFoundException e) {
 4448    // Don't set selected file
 4449    }
 4450    }
 4451    else {
 4452    // not untitled, select previous name
 4453  0 previous = active.getRawFile();
 4454  0 jfc.setSelectedFile(previous);
 4455    }
 4456   
 4457  0 jfc.resetChoosableFileFilters();
 4458  0 jfc.setFileFilter(getSourceFileFilter());
 4459  0 jfc.setMultiSelectionEnabled(false);
 4460  0 int rc = jfc.showSaveDialog(this);
 4461  0 return getChosenFile(jfc, rc, previous, true);
 4462    }
 4463   
 4464    /** Returns the current DefinitionsPane. */
 4465  165 public DefinitionsPane getCurrentDefPane() { return _currentDefPane; }
 4466   
 4467    /** Returns the compiler error panel. */
 4468  0 public CompilerErrorPanel getCompilerErrorPanel() { return _compilerErrorPanel; }
 4469   
 4470    /** Returns the JUnit error panel. */
 4471  0 public JUnitPanel getJUnitPanel() { return _junitPanel; }
 4472   
 4473    /** Returns the javadoc error panel. */
 4474  0 public JavadocErrorPanel getJavadocErrorPanel() { return _javadocErrorPanel; }
 4475   
 4476    /** Returns the currently shown error panel if there is one. Otherwise returns null. */
 4477  176 public CompilerErrorPanel getSelectedCompilerErrorPanel() {
 4478  176 Component c = _tabbedPane.getSelectedComponent();
 4479  11 if (c instanceof CompilerErrorPanel) return (CompilerErrorPanel) c;
 4480  165 return null;
 4481    }
 4482   
 4483    /** Returns whether the compiler output tab is currently showing. */
 4484  0 public boolean isCompilerTabSelected() {
 4485  0 return _tabbedPane.getSelectedComponent() == _compilerErrorPanel;
 4486    }
 4487   
 4488    /** Returns whether the test output tab is currently showing. */
 4489  0 public boolean isTestTabSelected() {
 4490  0 return _tabbedPane.getSelectedComponent() == _junitPanel;
 4491    }
 4492   
 4493    /** Returns whether the JavaDoc output tab is currently showing. */
 4494  0 public boolean isJavadocTabSelected() {
 4495  0 return _tabbedPane.getSelectedComponent() == _javadocErrorPanel;
 4496    }
 4497   
 4498    /** Makes sure save and compile buttons and menu items are enabled and disabled appropriately after document
 4499    * modifications.
 4500    */
 4501  93 private void _installNewDocumentListener(final OpenDefinitionsDocument d) {
 4502  93 d.addDocumentListener(new DocumentUIListener() {
 4503  106 public void changedUpdate(DocumentEvent e) { }
 4504  49 public void insertUpdate(DocumentEvent e) {
 4505  49 assert EventQueue.isDispatchThread();
 4506  49 _saveAction.setEnabled(true);
 4507  49 if (isDebuggerEnabled() && _debugPanel.getStatusText().equals(""))
 4508  12 _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
 4509    }
 4510  35 public void removeUpdate(DocumentEvent e) {
 4511  35 assert EventQueue.isDispatchThread();
 4512  35 _saveAction.setEnabled(true);
 4513  35 if (isDebuggerEnabled() && _debugPanel.getStatusText().equals(""))
 4514  0 _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
 4515    }
 4516    });
 4517    }
 4518   
 4519    /** Changes the message text toward the right of the status bar
 4520    * @param msg The message to place in the status bar
 4521    */
 4522  0 public void setStatusMessage(String msg) { _statusReport.setText(msg); }
 4523   
 4524    /** Sets the message text in the status bar to the null string. */
 4525  39 public void clearStatusMessage() { _statusReport.setText(""); }
 4526   
 4527    /** Sets the font of the status bar message
 4528    * @param f The new font of the status bar message
 4529    */
 4530  0 public void setStatusMessageFont(Font f) { _statusReport.setFont(f); }
 4531   
 4532    /** Sets the color of the text in the status bar message
 4533    * @param c The color of the text
 4534    */
 4535  0 public void setStatusMessageColor(Color c) { _statusReport.setForeground(c); }
 4536   
 4537    /** Performs op on each document in docs and invalidates the various project file collection properties. */
 4538  1 private void _processDocs(Collection<OpenDefinitionsDocument> docs, Runnable1<OpenDefinitionsDocument> op) {
 4539  1 for (OpenDefinitionsDocument doc: docs) {
 4540  1 if (doc != null && ! doc.isUntitled()) {
 4541  1 op.run(doc);
 4542  1 try {
 4543  1 String path = _model.fixPathForNavigator(doc.getFile().getCanonicalPath());
 4544  1 _model.getDocumentNavigator().refreshDocument(doc, path);
 4545    }
 4546    catch(IOException e) { /* do nothing */ }
 4547    }
 4548    }
 4549  1 PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.project.files").invalidate();
 4550  1 PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.included.files").invalidate();
 4551  1 PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.external.files").invalidate();
 4552    }
 4553   
 4554    /* Converts the selected files to auxiliary files. Access is ackage protected rather than private to support access
 4555    * by ProjectMenuTest.testSaveProject.
 4556    */
 4557  1 void _moveToAuxiliary() {
 4558  1 Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() {
 4559  1 public void run(OpenDefinitionsDocument d) { _model.addAuxiliaryFile(d); }
 4560    };
 4561  1 _processDocs(_model.getDocumentNavigator().getSelectedDocuments(), op);
 4562    }
 4563   
 4564    /** Removes selected auxiliary files. */
 4565  0 private void _removeAuxiliary() {
 4566  0 Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() {
 4567  0 public void run(OpenDefinitionsDocument d) { _model.removeAuxiliaryFile(d); }
 4568    };
 4569  0 _processDocs(_model.getDocumentNavigator().getSelectedDocuments(), op);
 4570    }
 4571   
 4572    /** Converts all external files to auxiliary files. */
 4573  0 void _moveAllToAuxiliary() {
 4574  0 assert EventQueue.isDispatchThread();
 4575  0 Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() {
 4576  0 public void run(OpenDefinitionsDocument d) { _model.addAuxiliaryFile(d); }
 4577    };
 4578  0 _processDocs(_model.getDocumentNavigator().getDocumentsInBin(_model.getExternalBinTitle()), op);
 4579    }
 4580   
 4581    /** Converts all auxiliary files to external files. */
 4582  0 private void _removeAllAuxiliary() {
 4583  0 assert EventQueue.isDispatchThread();
 4584  0 Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() {
 4585  0 public void run(OpenDefinitionsDocument d) { _model.removeAuxiliaryFile(d); }
 4586    };
 4587  0 _processDocs(_model.getDocumentNavigator().getDocumentsInBin(_model.getAuxiliaryBinTitle()), op);
 4588    }
 4589   
 4590  0 private void _new() {
 4591  0 updateStatusField("Creating a new Untitled Document");
 4592  0 _model.newFile();
 4593    }
 4594   
 4595  0 private void _open() {
 4596  0 updateStatusField("Opening File");
 4597  0 open(_openSelector);
 4598    }
 4599   
 4600  0 private void _openFolder() {
 4601  0 openFolder(_folderChooser);
 4602    }
 4603   
 4604  0 private void _openFileOrProject() {
 4605  0 try {
 4606  0 final File[] fileList = _openFileOrProjectSelector.getFiles();
 4607   
 4608  0 FileOpenSelector fos = new FileOpenSelector() { public File[] getFiles() { return fileList; } };
 4609   
 4610  0 if (_openChooser.getFileFilter().equals(_projectFilter)) openProject(fos);
 4611  0 else open(fos);
 4612    }
 4613    catch(OperationCanceledException oce) { /* do nothing */ }
 4614    }
 4615   
 4616    /** Puts the given text into the current definitions pane at the current caret position. */
 4617  0 private void _putTextIntoDefinitions(String text) {
 4618  0 int caretPos = _currentDefPane.getCaretPosition();
 4619   
 4620  0 try { _model.getActiveDocument().insertString(caretPos, text, null); }
 4621  0 catch (BadLocationException ble) { throw new UnexpectedException(ble); }
 4622    }
 4623   
 4624    /** Sets the left navigator pane to the correct component as dictated by the model. */
 4625  6 private void _resetNavigatorPane() {
 4626  6 if (_model.getDocumentNavigator() instanceof JTreeSortNavigator<?>) {
 4627  4 JTreeSortNavigator<?> nav = (JTreeSortNavigator<?>)_model.getDocumentNavigator();
 4628  4 nav.setDisplayManager(getNavPaneDisplayManager());
 4629  4 nav.setRootIcon(_djProjectIcon);
 4630    }
 4631  6 _docSplitPane.remove(_docSplitPane.getLeftComponent());
 4632  6 _docSplitPane.setLeftComponent(new JScrollPane(_model.getDocumentNavigator().asContainer()));
 4633  6 Font doclistFont = DrJava.getConfig().getSetting(FONT_DOCLIST);
 4634  6 _model.getDocCollectionWidget().setFont(doclistFont);
 4635  6 _updateNormalColor();
 4636  6 _updateBackgroundColor();
 4637    }
 4638   
 4639    /** Asks the user to select the project file to open and starts the process of opening the project. */
 4640  0 private void _openProject() { openProject(_openProjectSelector); }
 4641   
 4642  1 public void openProject(FileOpenSelector projectSelector) {
 4643   
 4644  1 try {
 4645  1 final File[] files = projectSelector.getFiles();
 4646  1 if (files.length < 1)
 4647  0 throw new IllegalStateException("Open project file selection not canceled but no project file was selected.");
 4648  1 final File file = files[0];
 4649   
 4650  1 updateStatusField("Opening project " + file);
 4651   
 4652  1 try {
 4653  1 hourglassOn();
 4654    // make sure there are no open projects
 4655  1 if (! _model.isProjectActive() || (_model.isProjectActive() && _closeProject())) _openProjectHelper(file);
 4656    }
 4657  0 catch(Exception e) { e.printStackTrace(System.out); }
 4658  1 finally { hourglassOff(); }
 4659    }
 4660    catch(OperationCanceledException oce) { /* do nothing, we just won't open anything */ }
 4661   
 4662    }
 4663   
 4664    /** Oversees the opening of the project by delegating to the model to parse and initialize the project
 4665    * while resetting the navigator pane and opening up the files itself.
 4666    * @param projectFile the file of the project to open
 4667    */
 4668  1 private void _openProjectHelper(File projectFile) {
 4669  1 _currentProjFile = projectFile;
 4670  1 try {
 4671  1 _mainListener.resetFNFCount();
 4672  1 _model.openProject(projectFile);
 4673  1 _setUpProjectButtons(projectFile);
 4674  1 _openProjectUpdate();
 4675   
 4676  0 if (_mainListener.someFilesNotFound()) _model.setProjectChanged(true);
 4677  1 clearCompleteClassSet(); // reset auto-completion list
 4678  1 addToBrowserHistory();
 4679    }
 4680    catch(MalformedProjectFileException e) {
 4681  0 MainFrameStatics.showProjectFileParseError(MainFrame.this, e); // add to an error adapter
 4682  0 return;
 4683    }
 4684    catch(FileNotFoundException e) {
 4685  0 MainFrameStatics.showFileNotFoundError(MainFrame.this, e); // add to an error adapter
 4686  0 return;
 4687    }
 4688    catch(IOException e) {
 4689  0 MainFrameStatics.showIOError(MainFrame.this, e); // add to an error adapter
 4690  0 return;
 4691    }
 4692    }
 4693   
 4694  4 private void _setUpProjectButtons(File projectFile) {
 4695  4 _compileButton = _updateToolbarButton(_compileButton, _compileProjectAction);
 4696  4 _junitButton = _updateToolbarButton(_junitButton, _junitProjectAction);
 4697  4 _recentProjectManager.updateOpenFiles(projectFile);
 4698    }
 4699   
 4700  4 private void _openProjectUpdate() {
 4701  4 if (_model.isProjectActive()) {
 4702  4 _guiAvailabilityNotifier.available(GUIAvailabilityListener.ComponentType.PROJECT);
 4703  4 _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener);
 4704  4 _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs);
 4705  4 _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener);
 4706  4 _resetNavigatorPane();
 4707  4 _model.refreshActiveDocument();
 4708    }
 4709    }
 4710   
 4711    /** Closes project when DrJava is not in the process of quitting.
 4712    * @return true if the project is closed, false if cancelled.
 4713    */
 4714  0 boolean closeProject() {
 4715  0 updateStatusField("Closing current project");
 4716  0 return _closeProject();
 4717    }
 4718   
 4719  2 boolean _closeProject() { return _closeProject(false); }
 4720   
 4721    /** Saves the project file; closes all open project files; and calls _model.closeProject(quitting) the
 4722    * clean up the state of the global model. It also restores the list view navigator
 4723    * @param quitting whether the project is being closed as part of quitting DrJava
 4724    * @return true if the project is closed, false if cancelled
 4725    */
 4726  2 boolean _closeProject(boolean quitting) {
 4727    // TODO: in some cases, it is possible to see the documents being removed in the navigation pane
 4728    // this can cause errors. fix this.
 4729  2 clearCompleteClassSet(); // reset auto-completion list
 4730  2 _autoImportClassSet = new HashSet<JavaAPIListEntry>(); // reset auto-import list
 4731   
 4732  2 if (_checkProjectClose()) {
 4733  2 List<OpenDefinitionsDocument> projDocs = _model.getProjectDocuments();
 4734    // System.err.println("projDocs = " + projDocs);
 4735  2 _cleanUpDebugger();
 4736  2 boolean couldClose = _model.closeFiles(projDocs);
 4737  0 if (! couldClose) return false;
 4738   
 4739  2 disableFindAgainOnClose(projDocs); // disable "Find Again" for documents that are closed
 4740   
 4741    // project file has been saved and all files closed
 4742  0 if (quitting) return true;
 4743  2 _model.closeProject(quitting);
 4744   
 4745  2 Component renderer = _model.getDocumentNavigator().getRenderer();
 4746  2 new ForegroundColorListener(renderer);
 4747  2 new BackgroundColorListener(renderer);
 4748  2 _resetNavigatorPane();
 4749  2 if (_model.getDocumentCount() == 1) _model.setActiveFirstDocument();
 4750  2 _guiAvailabilityNotifier.unavailable(GUIAvailabilityListener.ComponentType.PROJECT);
 4751  2 _setUpContextMenus();
 4752  2 _currentProjFile = FileOps.NULL_FILE;
 4753  2 return true;
 4754    }
 4755  0 else return false; // Project closing cancelled in _checkProjectClose dialog
 4756    }
 4757   
 4758  19 private void _configureBrowsing() {
 4759  19 BrowserHistoryManager bm = _model.getBrowserHistoryManager();
 4760  19 _browseBackAction.setEnabled(!bm.isCurrentRegionFirst());
 4761  19 _browseForwardAction.setEnabled(!bm.isCurrentRegionLast());
 4762    }
 4763   
 4764  2 private boolean _checkProjectClose() {
 4765  2 _log.log("is changed? "+_model.isProjectChanged()+" based on "+_model);
 4766   
 4767  2 if (_model.isProjectChanged()) {
 4768  0 String fname = _model.getProjectFile().getName();
 4769  0 String text = fname + " has been modified. Would you like to save it?";
 4770  0 int rc =
 4771    JOptionPane.showConfirmDialog(MainFrame.this, text, "Save " + fname + "?", JOptionPane.YES_NO_CANCEL_OPTION);
 4772  0 switch (rc) {
 4773  0 case JOptionPane.YES_OPTION:
 4774  0 _saveProject();
 4775  0 return true;
 4776  0 case JOptionPane.NO_OPTION:
 4777  0 return true;
 4778  0 case JOptionPane.CLOSED_OPTION:
 4779  0 case JOptionPane.CANCEL_OPTION:
 4780  0 return false;
 4781  0 default:
 4782  0 throw new RuntimeException("Invalid rc: " + rc);
 4783    }
 4784    }
 4785  2 return true;
 4786    }
 4787   
 4788  0 public File getCurrentProject() { return _currentProjFile; }
 4789   
 4790    /** Opens all the files returned by the FileOpenSelector prompting the user to handle the cases where files are
 4791    * already open, files are missing, or the action was canceled by the user
 4792    * @param openSelector the selector that returns the files to open
 4793    */
 4794  10 public void open(FileOpenSelector openSelector) {
 4795  10 try {
 4796  10 hourglassOn();
 4797  10 _model.openFiles(openSelector);
 4798    }
 4799    catch (AlreadyOpenException aoe) {
 4800  0 OpenDefinitionsDocument[] openDocs = aoe.getOpenDocuments();
 4801  0 for(OpenDefinitionsDocument openDoc : openDocs) {
 4802  0 try {
 4803  0 File f = openDoc.getFile();
 4804  0 if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f);
 4805    }
 4806    catch (IllegalStateException ise) {
 4807    // Impossible: saved => has a file
 4808  0 throw new UnexpectedException(ise);
 4809    }
 4810    catch (FileMovedException fme) {
 4811  0 File f = fme.getFile();
 4812    // Recover, show it in the list anyway
 4813  0 if (! _model.inProject(f))
 4814  0 _recentFileManager.updateOpenFiles(f);
 4815    }
 4816    }
 4817    }
 4818    catch (OperationCanceledException oce) { /* do not open file */ }
 4819    catch (FileNotFoundException fnf) {
 4820  0 MainFrameStatics.showFileNotFoundError(MainFrame.this, fnf);
 4821    }
 4822  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 4823  10 finally { hourglassOff(); }
 4824    }
 4825   
 4826    /** Opens all the files in the directory returned by the FolderSelector.
 4827    * @param chooser the selector that returns the files to open
 4828    * TODO: change the dialog title to give the current path rather than "..."
 4829    */
 4830  0 public void openFolder(DirectoryChooser chooser) {
 4831  0 String ext = _model.getOpenAllFilesInFolderExtension();
 4832  0 final String type = "'" + ext + "' ";
 4833  0 chooser.setDialogTitle("Open All " + type + "Files in ...");
 4834  0 javax.swing.filechooser.FileFilter ff = new javax.swing.filechooser.FileFilter() {
 4835  0 public boolean accept(File f) { return true; }
 4836  0 public String getDescription() { return "All "+type+" Files in Folder Selected"; }
 4837    };
 4838  0 chooser.resetChoosableFileFilters();
 4839  0 chooser.setAcceptAllFileFilterUsed(false);
 4840  0 chooser.setFileFilter(ff);
 4841   
 4842  0 File openDir = FileOps.NULL_FILE;
 4843  0 try {
 4844  0 File activeFile = _model.getActiveDocument().getFile();
 4845  0 if (activeFile != null) openDir = activeFile.getParentFile();
 4846  0 else openDir = _model.getProjectRoot();
 4847    }
 4848    catch(FileMovedException e) { /* do nothing */ }
 4849   
 4850  0 int result = chooser.showDialog(openDir);
 4851  0 File dir = chooser.getSelectedDirectory();
 4852  0 chooser.removeChoosableFileFilter(ff);
 4853  0 if (result != DirectoryChooser.APPROVE_OPTION) return; // canceled or error
 4854   
 4855  0 boolean rec = _openRecursiveCheckBox.isSelected();
 4856  0 DrJava.getConfig().setSetting(OptionConstants.OPEN_FOLDER_RECURSIVE, Boolean.valueOf(rec));
 4857  0 updateStatusField("Opening folder " + dir);
 4858  0 _openFolder(dir, rec, ext);
 4859    }
 4860   
 4861    /** Opens all the files in the specified directory; it opens all files in nested folders if rec is true.
 4862    * @param dir the specified directory
 4863    * @param rec true if files in nested folders should be opened
 4864    * @param ext extension
 4865    */
 4866  0 private void _openFolder(File dir, boolean rec, String ext) {
 4867  0 hourglassOn();
 4868  0 try { _model.openFolder(dir, rec, ext); }
 4869    catch(AlreadyOpenException e) { /* do nothing */ }
 4870  0 catch(IOException e) { MainFrameStatics.showIOError(MainFrame.this, e); }
 4871    catch(OperationCanceledException oce) { /* do nothing */ }
 4872  0 finally { hourglassOff(); }
 4873    }
 4874   
 4875    /** Closes the active document. The user is queried in some cases. */
 4876  1 private void _close() {
 4877   
 4878    // this works with multiple selected files now
 4879  1 List<OpenDefinitionsDocument> l = _model.getDocumentNavigator().getSelectedDocuments();
 4880  1 boolean queryNecessary = false; // is a query necessary because the files are project or auxiliary files?
 4881  1 for (OpenDefinitionsDocument doc: l) {
 4882  1 if ((_model.isProjectActive() && doc.inProjectPath()) || doc.isAuxiliaryFile()) {
 4883  0 queryNecessary = true;
 4884  0 break;
 4885    }
 4886    }
 4887  1 if (queryNecessary) {
 4888  0 int rc;
 4889  0 String fileName = null;
 4890  0 Object[] options = {"Yes", "No"};
 4891  0 if (l.size() == 1) {
 4892  0 OpenDefinitionsDocument doc = l.get(0);
 4893  0 try {
 4894  0 if (doc.isUntitled()) fileName = "File";
 4895  0 else fileName = _model.getActiveDocument().getFile().getName();
 4896    }
 4897  0 catch(FileMovedException e) { fileName = e.getFile().getName(); }
 4898  0 String text = "Closing this file will permanently remove it from the current project." +
 4899    "\nAre you sure that you want to close this file?";
 4900   
 4901  0 rc = JOptionPane.showOptionDialog(MainFrame.this, text,"Close " + fileName + "?", JOptionPane.YES_NO_OPTION,
 4902    JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
 4903    }
 4904    else {
 4905  0 fileName = l.size()+" files";
 4906  0 String text = "Closing these "+fileName+" will permanently remove them from the current project." +
 4907    "\nAre you sure that you want to close these files?";
 4908   
 4909  0 rc = JOptionPane.showOptionDialog(MainFrame.this, text, "Close "+l.size()+" files?", JOptionPane.YES_NO_OPTION,
 4910    JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
 4911    }
 4912  0 if (rc != JOptionPane.YES_OPTION) return;
 4913   
 4914  0 updateStatusField("Closing " + fileName);
 4915  0 _model.setProjectChanged(true);
 4916    }
 4917   
 4918  1 disableFindAgainOnClose(l); // disable "Find Again" for documents that are closed
 4919   
 4920    // Either this is an external file or user actually wants to close it
 4921  1 for(OpenDefinitionsDocument doc: l) {
 4922  1 _model.closeFile(doc);
 4923    }
 4924    }
 4925   
 4926  0 private void _closeFolder() {
 4927  0 ArrayList<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments();
 4928  0 final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
 4929   
 4930  0 if (_model.getDocumentNavigator().isGroupSelected()) {
 4931  0 for (OpenDefinitionsDocument doc: docs) {
 4932  0 if (_model.getDocumentNavigator().isSelectedInGroup(doc)) { l.add(doc); }
 4933    }
 4934  0 disableFindAgainOnClose(l); // disable "Find Again" for documents that are closed
 4935  0 _model.closeFiles(l);
 4936  0 if (! l.isEmpty()) _model.setProjectChanged(true);
 4937    }
 4938    }
 4939   
 4940  0 private void _printDefDoc() {
 4941  0 try {
 4942  0 _model.getActiveDocument().print();
 4943    }
 4944    catch (FileMovedException fme) {
 4945  0 _showFileMovedError(fme);
 4946    }
 4947    catch (PrinterException e) {
 4948  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while printing.");
 4949    }
 4950    catch (BadLocationException e) {
 4951  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while printing.");
 4952    }
 4953    }
 4954   
 4955  0 private void _printConsole() {
 4956  0 try {
 4957  0 _model.getConsoleDocument().print();
 4958    }
 4959    catch (PrinterException e) {
 4960  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while printing.");
 4961    }
 4962    }
 4963   
 4964  0 private void _printInteractions() {
 4965  0 try {
 4966  0 _model.getInteractionsDocument().print();
 4967    }
 4968    catch (PrinterException e) {
 4969  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while printing.");
 4970    }
 4971    }
 4972   
 4973    /** Opens a new PrintPreview frame. */
 4974  0 private void _printDefDocPreview() {
 4975  0 try {
 4976  0 _model.getActiveDocument().preparePrintJob();
 4977  0 new PreviewDefDocFrame(_model, this);
 4978    }
 4979    catch (FileMovedException fme) {
 4980  0 _showFileMovedError(fme);
 4981    }
 4982    catch (BadLocationException e) {
 4983  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while preparing the print preview.");
 4984    }
 4985    catch (IllegalStateException e) {
 4986  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while preparing the print preview.");
 4987    }
 4988    }
 4989   
 4990  0 private void _printConsolePreview() {
 4991  0 try {
 4992  0 _model.getConsoleDocument().preparePrintJob();
 4993  0 new PreviewConsoleFrame(_model, this, false);
 4994    }
 4995    catch (IllegalStateException e) {
 4996  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while preparing the print preview.");
 4997    }
 4998    }
 4999   
 5000  0 private void _printInteractionsPreview() {
 5001  0 try {
 5002  0 _model.getInteractionsDocument().preparePrintJob();
 5003  0 new PreviewConsoleFrame(_model, this, true);
 5004    }
 5005    catch (IllegalStateException e) {
 5006  0 MainFrameStatics.showError(MainFrame.this, e, "Print Error", "An error occured while preparing the print preview.");
 5007    }
 5008    }
 5009   
 5010  0 private void _pageSetup() {
 5011  0 PrinterJob job = PrinterJob.getPrinterJob();
 5012  0 _model.setPageFormat(job.pageDialog(_model.getPageFormat()));
 5013    }
 5014   
 5015    // Called by testCases
 5016  1 void closeAll() { _closeAll(); }
 5017   
 5018  1 private void _closeAll() {
 5019  1 updateStatusField("Closing All Files");
 5020  1 if (!_model.isProjectActive() || _model.isProjectActive() && _closeProject()) _model.closeAllFiles();
 5021    }
 5022   
 5023  0 private boolean _save() {
 5024  0 updateStatusField("Saving File");
 5025  0 try {
 5026    // now works with multiple files
 5027  0 List<OpenDefinitionsDocument> l = _model.getDocumentNavigator().getSelectedDocuments();
 5028  0 boolean success = false;
 5029  0 for(OpenDefinitionsDocument doc: l) {
 5030  0 if (doc.saveFile(_saveSelector)) {
 5031  0 getDefPaneGivenODD(doc).hasWarnedAboutModified(false);
 5032  0 success = true;
 5033    }
 5034    }
 5035    // Is _model.refreshActiveDocument() sufficient here? Before this action selected the document in navigator
 5036    // it was not in flat-file mode
 5037  0 _model.refreshActiveDocument();
 5038  0 return success;
 5039    }
 5040    catch (IOException ioe) {
 5041  0 MainFrameStatics.showIOError(MainFrame.this, ioe);
 5042  0 return false;
 5043    }
 5044    }
 5045   
 5046  0 private boolean _saveAs() {
 5047  0 updateStatusField("Saving File Under New Name");
 5048  0 try {
 5049  0 boolean toReturn = _model.getActiveDocument().saveFileAs(_saveAsSelector);
 5050  0 _model.refreshActiveDocument(); // highlights the document in the navigator
 5051  0 return toReturn;
 5052    }
 5053    catch (IOException ioe) {
 5054  0 MainFrameStatics.showIOError(MainFrame.this, ioe);
 5055  0 return false;
 5056    }
 5057    }
 5058   
 5059  0 private boolean _saveCopy() {
 5060  0 updateStatusField("Saving Copy of File");
 5061  0 try {
 5062  0 boolean toReturn = _model.getActiveDocument().saveFileAs(_saveCopySelector);
 5063  0 _model.refreshActiveDocument(); // highlights the document in the navigator
 5064  0 return toReturn;
 5065    }
 5066    catch (IOException ioe) {
 5067  0 MainFrameStatics.showIOError(MainFrame.this, ioe);
 5068  0 return false;
 5069    }
 5070    }
 5071   
 5072  0 private boolean _rename() {
 5073  0 try {
 5074  0 if (!_model.getActiveDocument().fileExists()) return _saveAs();
 5075    else {
 5076  0 File fileToDelete;
 5077  0 try { fileToDelete = _model.getActiveDocument().getFile(); }
 5078  0 catch (FileMovedException fme) { return _saveAs(); }
 5079  0 boolean toReturn = _model.getActiveDocument().saveFileAs(_saveAsSelector);
 5080    /** Delete the old file if save was successful. */
 5081    // TODO: what if delete() fails? (mgricken)
 5082  0 if (toReturn && ! _model.getActiveDocument().getFile().equals(fileToDelete)) fileToDelete.delete();
 5083    /** this highlights the document in the navigator */
 5084  0 _model.refreshActiveDocument();
 5085  0 return toReturn;
 5086    }
 5087    }
 5088    catch (IOException ioe) {
 5089  0 MainFrameStatics.showIOError(MainFrame.this, ioe);
 5090  0 return false;
 5091    }
 5092    }
 5093   
 5094    /* Package private to allow use in MainFrameTest. */
 5095  1 void _saveAll() {
 5096  1 hourglassOn();
 5097  1 try {
 5098  0 if (_model.isProjectActive()) _saveProject();
 5099  1 _model.saveAllFiles(_saveSelector);
 5100    }
 5101  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5102  1 finally { hourglassOff(); }
 5103    }
 5104   
 5105  0 void _saveAllOld() {
 5106  0 hourglassOn();
 5107  0 File file = _currentProjFile;
 5108  0 try {
 5109  0 if (_model.isProjectActive()) {
 5110  0 if (file.getName().indexOf(".") == -1) file = new File (file.getAbsolutePath() + OLD_PROJECT_FILE_EXTENSION);
 5111  0 _model.exportOldProject(file, gatherProjectDocInfo());
 5112    }
 5113  0 _model.saveAllFiles(_saveSelector);
 5114    }
 5115  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5116  0 finally { hourglassOff(); }
 5117    }
 5118   
 5119    // Called by the ProjectPropertiesFrame
 5120  1 void saveProject() { _saveProject(); }
 5121   
 5122  1 private void _saveProject() {
 5123    //File file = _model.getProjectFile();
 5124  1 _saveProjectHelper(_currentProjFile);
 5125    }
 5126   
 5127    /** Edits project frame. Only runs in the event thread. */
 5128  0 private void _editProject() {
 5129  0 ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(this);
 5130  0 ppf.setVisible(true);
 5131  0 ppf.reset();
 5132  0 ppf.toFront(); // ppf actions save state of ppf in global model
 5133    }
 5134   
 5135    /** Closes all files and makes a new project. */
 5136  0 private void _newProject() {
 5137   
 5138  0 _closeProject(true); // suppress resetting interactions; it will be done in _model.newProject() below
 5139  0 _saveChooser.resetChoosableFileFilters();
 5140  0 _saveChooser.setFileFilter(_projectFilter);
 5141  0 _saveChooser.setMultiSelectionEnabled(false);
 5142  0 int rc = _saveChooser.showSaveDialog(this);
 5143  0 if (rc == JFileChooser.APPROVE_OPTION) {
 5144  0 File projectFile = _saveChooser.getSelectedFile();
 5145   
 5146  0 if (projectFile == null || projectFile.getParentFile() == null) { return; }
 5147  0 String fileName = projectFile.getName();
 5148    // ensure that saved file has extension ".drjava"
 5149  0 if (! fileName.endsWith(OptionConstants.PROJECT_FILE_EXTENSION)) {
 5150  0 int lastIndex = fileName.lastIndexOf(".");
 5151  0 if (lastIndex == -1) projectFile = new File (projectFile.getAbsolutePath() +
 5152    OptionConstants.PROJECT_FILE_EXTENSION);
 5153  0 else projectFile = new File(projectFile.getParentFile(), fileName.substring(0, lastIndex) +
 5154    OptionConstants.PROJECT_FILE_EXTENSION);
 5155    }
 5156  0 try {
 5157    // by getting the canonical file, we make sure that we get an IOException if the filename is illegal
 5158  0 if (projectFile == null ||
 5159    projectFile.getParentFile() == null ||
 5160  0 (projectFile.getCanonicalFile().exists() && ! MainFrameStatics.verifyOverwrite(MainFrame.this, projectFile))) { return; }
 5161  0 _model.createNewProject(projectFile); // sets model to a new FileGroupingState for project file pf
 5162    // ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(MainFrame.this, file);
 5163    // ppf.saveSettings(); // Saves new project profile in global model
 5164  0 _model.configNewProject(); // configures the new project in the model
 5165  0 _editProject(); // edits the properties of the new FileGroupingState
 5166  0 _setUpProjectButtons(projectFile);
 5167  0 _currentProjFile = projectFile;
 5168    }
 5169    catch(IOException e) {
 5170  0 MainFrameStatics.showIOError(MainFrame.this, e);
 5171    }
 5172    }
 5173    }
 5174   
 5175    /** Pops up the _saveChooser dialog, asks the user for a new project file name, and sets the project file to the
 5176    * specified file. Nothing is written in the file system; this action is performed by a subsequent _saveAll().
 5177    * @return false if the user canceled the action */
 5178  0 private boolean _saveProjectAs() {
 5179  0 _saveChooser.resetChoosableFileFilters();
 5180  0 _saveChooser.setFileFilter(_projectFilter);
 5181   
 5182  0 if (_currentProjFile != FileOps.NULL_FILE) _saveChooser.setSelectedFile(_currentProjFile);
 5183  0 _saveChooser.setMultiSelectionEnabled(false);
 5184  0 int rc = _saveChooser.showSaveDialog(this);
 5185  0 if (rc == JFileChooser.APPROVE_OPTION) {
 5186  0 File file = _saveChooser.getSelectedFile();
 5187  0 try {
 5188    // by getting the canonical file, we make sure that we get an IOException if the filename is illegal
 5189  0 if ((file != null) && (! file.getCanonicalFile().exists() || MainFrameStatics.verifyOverwrite(MainFrame.this, file))) {
 5190  0 _model.setProjectFile(file);
 5191  0 _currentProjFile = file;
 5192    }
 5193    }
 5194    catch(IOException e) {
 5195  0 MainFrameStatics.showIOError(MainFrame.this, e);
 5196  0 return false;
 5197    }
 5198    }
 5199   
 5200  0 return (rc == JFileChooser.APPROVE_OPTION);
 5201    }
 5202   
 5203  1 void _saveProjectHelper(File file) {
 5204  1 try {
 5205  1 String fileName = file.getAbsolutePath();
 5206  1 if (!fileName.endsWith(PROJECT_FILE_EXTENSION) &&
 5207    !fileName.endsWith(PROJECT_FILE_EXTENSION2) &&
 5208    !fileName.endsWith(OLD_PROJECT_FILE_EXTENSION)) {
 5209    // doesn't end in .drjava or .xml or .pjt
 5210  0 String text = "The file name does not end with a DrJava project file "+
 5211    "extension ("+PROJECT_FILE_EXTENSION+" or "+PROJECT_FILE_EXTENSION2+" or "+OLD_PROJECT_FILE_EXTENSION+"):\n"+
 5212    file.getName()+"\n"+
 5213    "Do you want to append "+PROJECT_FILE_EXTENSION+" at the end?";
 5214   
 5215  0 Object[] options = {"Append "+PROJECT_FILE_EXTENSION, "Don't Change File Name"};
 5216  0 int rc = 0;
 5217  0 if (!Utilities.TEST_MODE) {
 5218  0 rc = JOptionPane.showOptionDialog(MainFrame.this, text, "Append Extension?", JOptionPane.YES_NO_OPTION,
 5219    JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
 5220    }
 5221  0 if (rc == 0) {
 5222  0 int lastDot = fileName.lastIndexOf('.');
 5223  0 if (lastDot == -1) {
 5224  0 file = new File(fileName + PROJECT_FILE_EXTENSION);
 5225    }
 5226    else {
 5227  0 file = new File(fileName.substring(0,lastDot) + PROJECT_FILE_EXTENSION);
 5228    }
 5229    }
 5230    }
 5231    // by getting the canonical file, we make sure that we get an IOException if the filename is illegal
 5232  1 fileName = file.getCanonicalPath();
 5233  1 if (fileName.endsWith(OLD_PROJECT_FILE_EXTENSION)) {
 5234  1 file = proposeToChangeExtension(MainFrame.this, file,
 5235    "Change Extension?",
 5236    "The project will be saved in XML format."
 5237    + "\nDo you want to change the project file's extension to \""
 5238    + PROJECT_FILE_EXTENSION+ "\"?",
 5239    "Change to \"" + PROJECT_FILE_EXTENSION + "\"",
 5240    "Keep \"" + DrJavaFileUtils.getExtension(fileName) + "\"",
 5241    PROJECT_FILE_EXTENSION);
 5242  1 _model.setProjectFile(file);
 5243  1 _currentProjFile = file;
 5244    }
 5245  1 _model.saveProject(file, gatherProjectDocInfo());
 5246    // if (!(_model.getDocumentNavigator() instanceof JTreeSortNavigator)) {
 5247    // _openProjectHelper(file);
 5248    // }
 5249    }
 5250  0 catch(IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5251  1 _recentProjectManager.updateOpenFiles(file);
 5252  1 _model.setProjectChanged(false);
 5253    }
 5254   
 5255  1 public HashMap<OpenDefinitionsDocument,DocumentInfoGetter> gatherProjectDocInfo() {
 5256  1 HashMap<OpenDefinitionsDocument,DocumentInfoGetter> map =
 5257    new HashMap<OpenDefinitionsDocument,DocumentInfoGetter>();
 5258  1 List<OpenDefinitionsDocument> docs = _model.getProjectDocuments();
 5259  1 for(OpenDefinitionsDocument doc: docs) {
 5260  3 map.put(doc, _makeInfoGetter(doc));
 5261    }
 5262  1 return map;
 5263    }
 5264    /** Gets the information to be saved for a project document.
 5265    * Implementation may change if the scroll/selection information is later stored in a place other than the
 5266    * definitions pane. Hopefully this info will eventually be backed up in the OpenDefinitionsDocument in which
 5267    * case all this code should be refactored into the model's _saveProject method
 5268    */
 5269  3 private DocumentInfoGetter _makeInfoGetter(final OpenDefinitionsDocument doc) {
 5270  3 JScrollPane s = _defScrollPanes.get(doc);
 5271  1 if (s == null) s = _createDefScrollPane(doc);
 5272   
 5273  3 final DefinitionsPane pane = _currentDefPane; // rhs was (DefinitionsPane)scroller.getViewport().getView();
 5274  3 return new DocumentInfoGetter() {
 5275  3 public Pair<Integer,Integer> getSelection() {
 5276  3 Integer selStart = Integer.valueOf(pane.getSelectionStart());
 5277  3 Integer selEnd = Integer.valueOf(pane.getSelectionEnd());
 5278  3 if ( selStart == 0 && selEnd == 0)
 5279  3 return new Pair<Integer,Integer>(pane.getCaretPosition(),pane.getCaretPosition());
 5280  0 if (pane.getCaretPosition() == selStart) return new Pair<Integer,Integer>(selEnd,selStart);
 5281  0 return new Pair<Integer,Integer>(selStart,selEnd);
 5282    }
 5283  3 public Pair<Integer,Integer> getScroll() {
 5284  3 Integer scrollv = Integer.valueOf(pane.getVerticalScroll());
 5285  3 Integer scrollh = Integer.valueOf(pane.getHorizontalScroll());
 5286  3 return new Pair<Integer,Integer>(scrollv,scrollh);
 5287    }
 5288  3 public File getFile() { return doc.getRawFile(); }
 5289  3 public String getPackage() { return doc.getPackageName(); }
 5290  3 public boolean isActive() { return _model.getActiveDocument() == doc; }
 5291  3 public boolean isUntitled() { return doc.isUntitled(); }
 5292    };
 5293    }
 5294   
 5295  0 private void _revert() {
 5296    // this works with multiple selected files now
 5297  0 List<OpenDefinitionsDocument> l = _model.getDocumentNavigator().getSelectedDocuments();
 5298  0 for(OpenDefinitionsDocument d: l) { _revert(d); }
 5299    }
 5300   
 5301  0 private void _revert(OpenDefinitionsDocument doc) {
 5302  0 try {
 5303  0 doc.revertFile();
 5304    }
 5305    catch (FileMovedException fme) {
 5306  0 _showFileMovedError(fme);
 5307    }
 5308    catch (IOException ioe) {
 5309  0 MainFrameStatics.showIOError(MainFrame.this, ioe);
 5310    }
 5311    }
 5312   
 5313    /**
 5314    private void _revertAll() {
 5315    try {
 5316    _model.revertAllFiles();
 5317    }
 5318    catch (FileMovedException fme) {
 5319    _showFileMovedError(fme);
 5320    }
 5321    catch (IOException ioe) {
 5322    MainFrameStatics.showIOError(MainFrame.this, ioe);
 5323    }
 5324    }
 5325    */
 5326   
 5327  0 void quit() {
 5328    // AbstractGlobalModel._log.log("MainFrame.quit() called");
 5329  0 if (_promptBeforeQuit) {
 5330  0 String title = "Quit DrJava?";
 5331  0 String message = "Are you sure you want to quit DrJava?";
 5332  0 ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, title, message);
 5333  0 int rc = dialog.show();
 5334  0 if (rc != JOptionPane.YES_OPTION) return;
 5335    else {
 5336    // Only remember the checkbox if they say yes
 5337  0 if (dialog.getCheckBoxValue() == true) {
 5338  0 DrJava.getConfig().setSetting(QUIT_PROMPT, Boolean.FALSE);
 5339    }
 5340    }
 5341    }
 5342  0 _executeExternalDialog.setVisible(false);
 5343    // tried passing false here. seemed to help with bug
 5344    // [ 1478796 ] DrJava Does Not Shut Down With Project Open
 5345    // on HP tc1100 and Toshiba Portege tablet PCs, but did not help in all cases
 5346  0 if (! _closeProject(true)) { return; /* if user pressed cancel, do not quit */ }
 5347   
 5348  0 _updateSavedConfiguration();
 5349   
 5350    //DrJava.consoleOut().println("Quitting DrJava...");
 5351  0 dispose(); // Free GUI elements of this frame
 5352  0 _model.quit();
 5353    }
 5354   
 5355  0 void _updateSavedConfiguration() {
 5356  0 _recentFileManager.saveRecentFiles();
 5357  0 _recentProjectManager.saveRecentFiles();
 5358  0 if (! _model.closeAllFilesOnQuit()) { return; /* if user pressed cancel, do not quit */ }
 5359  0 _storePositionInfo();
 5360   
 5361    // Save recent files, but only if there wasn't a problem at startUp
 5362    // (Don't want to overwrite a custom config file with a simple typo.)
 5363  0 if (! DrJava.getConfig().hadStartupException()) {
 5364  0 try { DrJava.getConfig().saveConfiguration(); }
 5365  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5366    }
 5367    }
 5368   
 5369  0 private void _forceQuit() { _model.forceQuit(); }
 5370   
 5371    /** Stores the current position and size info for window and panes to the config framework. Only runs in the event
 5372    * thread.
 5373    */
 5374  0 private void _storePositionInfo() {
 5375  0 assert EventQueue.isDispatchThread();
 5376  0 Configuration config = DrJava.getConfig();
 5377   
 5378    // Window bounds.
 5379  0 if (config.getSetting(WINDOW_STORE_POSITION).booleanValue()) {
 5380  0 Rectangle bounds = getBounds();
 5381  0 config.setSetting(WINDOW_HEIGHT, Integer.valueOf(bounds.height));
 5382  0 config.setSetting(WINDOW_WIDTH, Integer.valueOf(bounds.width));
 5383  0 config.setSetting(WINDOW_X, Integer.valueOf(bounds.x));
 5384  0 config.setSetting(WINDOW_Y, Integer.valueOf(bounds.y));
 5385  0 config.setSetting(WINDOW_STATE, Integer.valueOf(getExtendedState()));
 5386    }
 5387    else {
 5388    // Reset to defaults to restore pristine behavior.
 5389  0 config.setSetting(WINDOW_HEIGHT, WINDOW_HEIGHT.getDefault());
 5390  0 config.setSetting(WINDOW_WIDTH, WINDOW_WIDTH.getDefault());
 5391  0 config.setSetting(WINDOW_X, WINDOW_X.getDefault());
 5392  0 config.setSetting(WINDOW_Y, WINDOW_Y.getDefault());
 5393  0 config.setSetting(WINDOW_STATE, WINDOW_STATE.getDefault());
 5394    }
 5395   
 5396    // "Go to File" dialog position and size.
 5397  0 if ((DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue())
 5398    && (_gotoFileDialog != null) && (_gotoFileDialog.getFrameState() != null)) {
 5399  0 config.setSetting(DIALOG_GOTOFILE_STATE, (_gotoFileDialog.getFrameState().toString()));
 5400    }
 5401    else {
 5402    // Reset to defaults to restore pristine behavior.
 5403  0 config.setSetting(DIALOG_GOTOFILE_STATE, DIALOG_GOTOFILE_STATE.getDefault());
 5404    }
 5405   
 5406    // "Open Javadoc" dialog position and size.
 5407  0 if ((DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue())
 5408    && (_openJavadocDialog != null) && (_openJavadocDialog.getFrameState() != null)) {
 5409  0 config.setSetting(DIALOG_OPENJAVADOC_STATE, (_openJavadocDialog.getFrameState().toString()));
 5410    }
 5411    else {
 5412    // Reset to defaults to restore pristine behavior.
 5413  0 config.setSetting(DIALOG_OPENJAVADOC_STATE, DIALOG_OPENJAVADOC_STATE.getDefault());
 5414    }
 5415   
 5416    // "Complete Word" dialog position and size.
 5417  0 if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue())
 5418    && (_completeWordDialog != null) && (_completeWordDialog.getFrameState() != null)) {
 5419  0 config.setSetting(DIALOG_COMPLETE_WORD_STATE, (_completeWordDialog.getFrameState().toString()));
 5420    }
 5421    else {
 5422    // Reset to defaults to restore pristine behavior.
 5423  0 config.setSetting(DIALOG_COMPLETE_WORD_STATE, DIALOG_COMPLETE_WORD_STATE.getDefault());
 5424    }
 5425   
 5426    // "Create Jar from Project" dialog position and size.
 5427  0 if ((DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue())
 5428    && (_jarOptionsDialog != null) && (_jarOptionsDialog.getFrameState() != null)) {
 5429  0 config.setSetting(DIALOG_JAROPTIONS_STATE, (_jarOptionsDialog.getFrameState().toString()));
 5430    }
 5431    else {
 5432    // Reset to defaults to restore pristine behavior.
 5433  0 config.setSetting(DIALOG_JAROPTIONS_STATE, DIALOG_JAROPTIONS_STATE.getDefault());
 5434    }
 5435   
 5436    // "Tabbed Panes" frame position and size.
 5437  0 if ((DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STORE_POSITION).booleanValue())
 5438    && (_tabbedPanesFrame != null) && (_tabbedPanesFrame.getFrameState() != null)) {
 5439  0 config.setSetting(DIALOG_TABBEDPANES_STATE, (_tabbedPanesFrame.getFrameState().toString()));
 5440    }
 5441    else {
 5442    // Reset to defaults to restore pristine behavior.
 5443  0 config.setSetting(DIALOG_TABBEDPANES_STATE, DIALOG_TABBEDPANES_STATE.getDefault());
 5444    }
 5445   
 5446    // "Debugger" frame position and size.
 5447  0 if ((DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STORE_POSITION).booleanValue())
 5448    && (_debugFrame != null) && (_debugFrame.getFrameState() != null)) {
 5449  0 config.setSetting(DIALOG_DEBUGFRAME_STATE, (_debugFrame.getFrameState().toString()));
 5450    }
 5451    else {
 5452    // Reset to defaults to restore pristine behavior.
 5453  0 config.setSetting(DIALOG_DEBUGFRAME_STATE, DIALOG_DEBUGFRAME_STATE.getDefault());
 5454    }
 5455   
 5456    // Panel heights.
 5457  0 if (_showDebugger) config.setSetting(DEBUG_PANEL_HEIGHT, Integer.valueOf(_debugPanel.getHeight()));
 5458   
 5459    // Doc list width.
 5460  0 config.setSetting(DOC_LIST_WIDTH, Integer.valueOf(_docSplitPane.getDividerLocation()));
 5461    }
 5462   
 5463  0 private void _cleanUpDebugger() { if (isDebuggerReady()) _model.getDebugger().shutdown(); }
 5464   
 5465  0 private void _compile() {
 5466    // now works with multiple files
 5467  0 _cleanUpDebugger();
 5468  0 hourglassOn();
 5469  0 try {
 5470    // final OpenDefinitionsDocument doc = _model.getActiveDocument();
 5471  0 try { _model.getCompilerModel().compile(_model.getDocumentNavigator().getSelectedDocuments()); }
 5472  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5473  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5474    }
 5475  0 finally { hourglassOff();}
 5476    // update(getGraphics());
 5477    }
 5478   
 5479  0 private void _compileFolder() {
 5480  0 _cleanUpDebugger();
 5481  0 hourglassOn();
 5482  0 try {
 5483  0 ArrayList<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments();
 5484  0 final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
 5485  0 if (_model.getDocumentNavigator().isGroupSelected()) {
 5486  0 for (OpenDefinitionsDocument doc: docs) {
 5487  0 if (_model.getDocumentNavigator().isSelectedInGroup(doc)) l.add(doc);
 5488    }
 5489   
 5490    // new Thread("Compile Folder") {
 5491    // public void run() {
 5492  0 try { _model.getCompilerModel().compile(l); }
 5493  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5494  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5495    // }
 5496    // }.start();
 5497    }
 5498    }
 5499  0 finally { hourglassOff(); }
 5500    // update(getGraphics());
 5501    }
 5502   
 5503  0 private void _compileProject() {
 5504  0 _cleanUpDebugger();
 5505    // new Thread("Compile All") {
 5506    // public void run() {
 5507  0 hourglassOn();
 5508  0 try { _model.getCompilerModel().compileProject(); }
 5509  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5510  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5511  0 finally { hourglassOff(); }
 5512    // }
 5513    // }.start();
 5514    // update(getGraphics());
 5515    }
 5516   
 5517  1 private void _compileAll() {
 5518  1 _cleanUpDebugger();
 5519  1 hourglassOn();
 5520  1 try { _model.getCompilerModel().compileAll(); }
 5521  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5522  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5523  1 finally{ hourglassOff(); }
 5524    }
 5525   
 5526  0 private boolean showCleanWarning() {
 5527  0 if (DrJava.getConfig().getSetting(PROMPT_BEFORE_CLEAN).booleanValue()) {
 5528  0 String buildDirTxt = "";
 5529  0 try { buildDirTxt = _model.getBuildDirectory().getCanonicalPath(); }
 5530  0 catch (Exception e) { buildDirTxt = _model.getBuildDirectory().getPath(); }
 5531  0 ConfirmCheckBoxDialog dialog =
 5532    new ConfirmCheckBoxDialog(MainFrame.this,
 5533    "Clean Build Directory?",
 5534    "Cleaning your build directory will delete all\n" +
 5535    "class files and empty folders within that directory.\n" +
 5536    "Are you sure you want to clean\n" +
 5537    buildDirTxt + "?",
 5538    "Do not show this message again");
 5539  0 int rc = dialog.show();
 5540  0 switch (rc) {
 5541  0 case JOptionPane.YES_OPTION:
 5542  0 _saveAll();
 5543    // Only remember checkbox if they say yes
 5544  0 if (dialog.getCheckBoxValue()) DrJava.getConfig().setSetting(PROMPT_BEFORE_CLEAN, Boolean.FALSE);
 5545  0 return true;
 5546  0 case JOptionPane.NO_OPTION: return false;
 5547  0 case JOptionPane.CANCEL_OPTION: return false;
 5548  0 case JOptionPane.CLOSED_OPTION: return false;
 5549  0 default: throw new RuntimeException("Invalid rc from showConfirmDialog: " + rc);
 5550    }
 5551    }
 5552  0 return true;
 5553    }
 5554   
 5555  0 private void _clean() { _model.cleanBuildDirectory(); } // The model performs this as an AsyncTask
 5556   
 5557    /** List with entries for the complete dialog. */
 5558    HashSet<GoToFileListEntry> _completeClassSet = new HashSet<GoToFileListEntry>();
 5559   
 5560    /** List with entries for the auto-import dialog. */
 5561    HashSet<JavaAPIListEntry> _autoImportClassSet = new HashSet<JavaAPIListEntry>();
 5562   
 5563    /** Scan the build directory for class files and update the auto-completion list. */
 5564  0 private void _scanClassFiles() {
 5565  0 Thread t = new Thread(new Runnable() {
 5566  0 public void run() {
 5567  0 File buildDir = _model.getBuildDirectory();
 5568  0 HashSet<GoToFileListEntry> hs = new HashSet<GoToFileListEntry>();
 5569  0 HashSet<JavaAPIListEntry> hs2 = new HashSet<JavaAPIListEntry>();
 5570  0 if (buildDir != null) {
 5571  0 List<File> classFiles = _model.getClassFiles();
 5572  0 DummyOpenDefDoc dummyDoc = new DummyOpenDefDoc();
 5573  0 for(File f: classFiles) {
 5574  0 String s = f.toString();
 5575  0 if (s.lastIndexOf(File.separatorChar) >= 0) {
 5576  0 s = s.substring(s.lastIndexOf(File.separatorChar)+1);
 5577    }
 5578  0 s = s.substring(0, s.lastIndexOf(".class"));
 5579  0 s = s.replace('$', '.');
 5580  0 int pos = 0;
 5581  0 boolean ok = true;
 5582  0 while ((pos=s.indexOf('.', pos)) >= 0) {
 5583  0 if (s.length() <= pos + 1 || Character.isDigit(s.charAt(pos + 1))) {
 5584  0 ok = false;
 5585  0 break;
 5586    }
 5587  0 ++pos;
 5588    }
 5589  0 if (ok) {
 5590  0 if (s.lastIndexOf('.') >= 0) {
 5591  0 s = s.substring(s.lastIndexOf('.') + 1);
 5592    }
 5593  0 GoToFileListEntry entry = new GoToFileListEntry(dummyDoc, s);
 5594  0 hs.add(entry);
 5595  0 try {
 5596  0 String rel = FileOps.stringMakeRelativeTo(f, buildDir);
 5597  0 String full = rel.replace(File.separatorChar, '.');
 5598  0 full = full.substring(0, full.lastIndexOf(".class"));
 5599  0 if (full.indexOf('$') < 0) {
 5600    // No '$' in the name means not an inner class. we do not support inner classes, because that would
 5601    // mean having to determine public static scope
 5602  0 hs2.add(new JavaAPIListEntry(s, full, null));
 5603    }
 5604    }
 5605    catch(IOException ioe) { /* ignore, just don't add this one */ }
 5606    catch(SecurityException se) { /* ignore, just don't add this one */ }
 5607    }
 5608    }
 5609    }
 5610  0 clearCompleteClassSet();
 5611  0 _completeClassSet.addAll(hs);
 5612  0 _autoImportClassSet = new HashSet<JavaAPIListEntry>(hs2);
 5613    }
 5614    });
 5615  0 t.setPriority(Thread.MIN_PRIORITY);
 5616  0 t.start();
 5617    }
 5618   
 5619  0 private void _runProject() {
 5620  0 if (_model.isProjectActive()) {
 5621  0 try {
 5622  0 final File f = _model.getMainClassContainingFile();
 5623  0 if (f != null) {
 5624  0 updateStatusField("Running Open Project");
 5625  0 OpenDefinitionsDocument doc = _model.getDocumentForFile(f);
 5626  0 boolean smart = DrJava.getConfig().getSetting(OptionConstants.SMART_RUN_FOR_APPLETS_AND_PROGRAMS);
 5627  0 if (smart) {
 5628  0 doc.runSmart(_model.getMainClass());
 5629    }
 5630    else {
 5631  0 doc.runMain(_model.getMainClass());
 5632    }
 5633    }
 5634    }
 5635    catch (ClassNameNotFoundException e) {
 5636    // Display a warning message if a class name can't be found.
 5637  0 String msg =
 5638    "DrJava could not find the top level class name in the\n" +
 5639    "current document, so it could not run the class. Please\n" +
 5640    "make sure that the class is properly defined first.";
 5641   
 5642  0 JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE);
 5643    }
 5644  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5645  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5646    }
 5647  0 else _runMain();
 5648    }
 5649   
 5650    /** Internal helper method to run the main method of the current document in the interactions pane. */
 5651  0 private void _runMain() {
 5652  0 try {
 5653  0 boolean smart = DrJava.getConfig().getSetting(OptionConstants.SMART_RUN_FOR_APPLETS_AND_PROGRAMS);
 5654  0 if (smart) {
 5655  0 updateStatusField("Running main Method of Current Document");
 5656  0 _model.getActiveDocument().runSmart(null);
 5657    }
 5658    else {
 5659  0 updateStatusField("Running Current Document");
 5660  0 _model.getActiveDocument().runMain(null);
 5661    }
 5662    }
 5663   
 5664    catch (ClassNameNotFoundException e) {
 5665    // Display a warning message if a class name can't be found.
 5666  0 String msg =
 5667    "DrJava could not find the top level class name in the\n" +
 5668    "current document, so it could not run the class. Please\n" +
 5669    "make sure that the class is properly defined first.";
 5670   
 5671  0 JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE);
 5672    }
 5673  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5674  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5675    }
 5676   
 5677    /** Internal helper method to run the current document as applet in the interactions pane. */
 5678  0 private void _runApplet() {
 5679  0 updateStatusField("Running Current Document as Applet");
 5680   
 5681  0 try { _model.getActiveDocument().runApplet(null); }
 5682   
 5683    catch (ClassNameNotFoundException e) {
 5684    // Display a warning message if a class name can't be found.
 5685  0 String msg =
 5686    "DrJava could not find the top level class name in the\n" +
 5687    "current document, so it could not run the class. Please\n" +
 5688    "make sure that the class is properly defined first.";
 5689   
 5690  0 JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE);
 5691    }
 5692  0 catch (FileMovedException fme) { _showFileMovedError(fme); }
 5693  0 catch (IOException ioe) { MainFrameStatics.showIOError(MainFrame.this, ioe); }
 5694    }
 5695   
 5696  0 private void _junit() {
 5697  0 /* */ assert Utilities.TEST_MODE || EventQueue.isDispatchThread();
 5698   
 5699  0 hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted
 5700    // moved this back into the event thread to fix bug 2848696
 5701    // this code doesn't have to run in an auxiliary thread
 5702    // the actual unit testing later is done in a separate thread
 5703  0 _guiAvailabilityNotifier.junitStarted(); // JUNIT and COMPILER
 5704   
 5705    // now also works with multiple documents
 5706    // hourglassOn(); // moved into the prelude before this thread start
 5707  0 try { _model.getJUnitModel().junitDocs(_model.getDocumentNavigator().getSelectedDocuments()); }
 5708  0 catch(UnexpectedException e) { _junitInterrupted(e); }
 5709  0 catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); }
 5710    }
 5711   
 5712  0 private void _junitFolder() {
 5713  0 updateStatusField("Running Unit Tests in Current Folder");
 5714  0 hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted
 5715    // moved this back into the event thread to fix bug 2848696
 5716    // this code doesn't have to run in an auxiliary thread
 5717    // the actual unit testing later is done in a separate thread
 5718  0 _guiAvailabilityNotifier.junitStarted(); // JUNIT and COMPILER
 5719   
 5720    // hourglassOn(); // turned off when JUnitStarted event is fired
 5721  0 if (_model.getDocumentNavigator().isGroupSelected()) {
 5722  0 ArrayList<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments();
 5723  0 final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
 5724  0 for (OpenDefinitionsDocument doc: docs) {
 5725  0 if (_model.getDocumentNavigator().isSelectedInGroup(doc)) l.add(doc);
 5726    }
 5727  0 try { _model.getJUnitModel().junitDocs(l); } // hourglassOn executed by junitStarted()
 5728  0 catch(UnexpectedException e) { _junitInterrupted(e); }
 5729  0 catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); }
 5730    }
 5731    }
 5732   
 5733    /** Tests the documents in the project source tree. Assumes that DrJava is in project mode. */
 5734  0 private void _junitProject() {
 5735  0 updateStatusField("Running JUnit Tests in Project");
 5736  0 hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted
 5737  0 _guiAvailabilityNotifier.junitStarted(); // JUNIT and COMPILER
 5738  0 try { _model.getJUnitModel().junitProject(); }
 5739  0 catch(UnexpectedException e) { _junitInterrupted(e); }
 5740  0 catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); }
 5741    }
 5742   
 5743    /** Tests all open documents. */
 5744  0 private void _junitAll() {
 5745  0 updateStatusField("Running All Open Unit Tests");
 5746  0 hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted
 5747  0 _guiAvailabilityNotifier.junitStarted(); // JUNIT and COMPILER
 5748  0 try { _model.getJUnitModel().junitAll(); }
 5749  0 catch(UnexpectedException e) { _junitInterrupted(e); }
 5750  0 catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); }
 5751    }
 5752   
 5753    // /**
 5754    // * Suspends the current execution of the debugger
 5755    // */
 5756    // private void debuggerSuspend() throws DebugException {
 5757    // if (isDebuggerReady())
 5758    // _model.getDebugger().suspend();
 5759    // }
 5760   
 5761    /** Resumes the debugger's current execution. */
 5762  0 void debuggerResume() throws DebugException {
 5763  0 if (isDebuggerReady()) {
 5764  0 _model.getDebugger().resume();
 5765  0 removeCurrentLocationHighlight();
 5766    }
 5767    }
 5768   
 5769    /** Automatically traces through the entire program with a defined rate for stepping into each line of code*/
 5770  0 void debuggerAutomaticTrace() {
 5771  0 _log.log("debuggerAutomaticTrace(): isDebuggerReady() = "+isDebuggerReady());
 5772  0 if (isDebuggerReady()) {
 5773  0 if(!_model.getDebugger().isAutomaticTraceEnabled()) {
 5774  0 enableAutomaticTrace();
 5775    }
 5776    else {
 5777  0 disableAutomaticTrace();
 5778    }
 5779    }
 5780    }
 5781   
 5782    /** Enable automatic trace. Assumes that the debugger is ready. */
 5783  0 private void enableAutomaticTrace() {
 5784  0 if (!isDebuggerEnabled()) return; // debugger isn't used
 5785  0 try {
 5786  0 int rate = DrJava.getConfig().getSetting(OptionConstants.AUTO_STEP_RATE);
 5787   
 5788  0 _automaticTraceTimer = new Timer(rate, new ActionListener() {
 5789  0 public void actionPerformed(ActionEvent e) {
 5790  0 _debugStepTimer.stop();
 5791  0 if (_model.getDebugger().isAutomaticTraceEnabled()) {
 5792    // hasn't been disabled in the meantime
 5793  0 debuggerStep(Debugger.StepType.STEP_INTO);
 5794    // _debugStepTimer.restart(); // _debugStepTimer prints "Stepping..." when timer expires
 5795    }
 5796    }
 5797    });
 5798  0 _automaticTraceTimer.setRepeats(false);
 5799  0 _model.getDebugger().setAutomaticTraceEnabled(true);
 5800  0 _debugPanel.setAutomaticTraceButtonText();
 5801  0 debuggerStep(Debugger.StepType.STEP_INTO);
 5802  0 _debugStepTimer.stop();
 5803    }
 5804    catch (IllegalStateException ise) {
 5805    /* This may happen if the user if stepping very frequently, and is even more likely if they are using both
 5806    * hotkeys and UI buttons. Ignore it in this case. Hopefully, there are no other situations where the user
 5807    * can be trying to step while there are no suspended threads. */
 5808    }
 5809    }
 5810   
 5811    /** Disable the automatic trace. Assumes that the debugger is ready. */
 5812  0 private void disableAutomaticTrace() {
 5813  0 if (!isDebuggerEnabled()) return; // debugger isn't used
 5814  0 _log.log("disableAutomaticTrace(): isDebuggerReady() = "+isDebuggerReady());
 5815  0 _model.getDebugger().setAutomaticTraceEnabled(false);
 5816  0 _debugPanel.setAutomaticTraceButtonText();
 5817  0 if (_automaticTraceTimer != null) _automaticTraceTimer.stop();
 5818    }
 5819   
 5820    /** Steps in the debugger. */
 5821  0 void debuggerStep(Debugger.StepType type) {
 5822  0 if (isDebuggerReady()) {
 5823  0 try { _model.getDebugger().step(type); }
 5824    catch (IllegalStateException ise) {
 5825    /* This may happen if the user if stepping very frequently,and is even more likely if they are using both
 5826    * hotkeys and UI buttons. Ignore it in this case. Hopefully, there are no other situations where the user
 5827    * can be trying to step while there are no suspended threads. */
 5828    }
 5829    catch (DebugException de) {
 5830  0 MainFrameStatics.showError(MainFrame.this, de, "Debugger Error",
 5831    "Could not create a step request.");
 5832    }
 5833    }
 5834    }
 5835   
 5836    /** Toggles a breakpoint on the current line. */
 5837  0 void debuggerToggleBreakpoint() {
 5838  0 addToBrowserHistory();
 5839  0 OpenDefinitionsDocument doc = _model.getActiveDocument();
 5840   
 5841  0 boolean isUntitled = doc.isUntitled();
 5842  0 if (isUntitled) {
 5843  0 JOptionPane.showMessageDialog(this,
 5844    "You must save and compile this document before you can\n" +
 5845    "set a breakpoint in it.",
 5846    "Must Save and Compile",
 5847    JOptionPane.ERROR_MESSAGE);
 5848  0 return;
 5849    }
 5850   
 5851  0 boolean isModified = doc.isModifiedSinceSave();
 5852  0 if (isDebuggerReady() && isModified && !_currentDefPane.hasWarnedAboutModified() &&
 5853    DrJava.getConfig().getSetting(WARN_BREAKPOINT_OUT_OF_SYNC).booleanValue()) {
 5854  0 String message =
 5855    "This document has been modified and may be out of sync\n" +
 5856    "with the debugger. It is recommended that you first\n" +
 5857    "save and recompile before continuing to use the debugger,\n" +
 5858    "to avoid any unexpected errors. Would you still like to\n" +
 5859    "toggle the breakpoint on the specified line?";
 5860  0 String title = "Toggle breakpoint on modified file?";
 5861   
 5862  0 ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(this, title, message);
 5863  0 int rc = dialog.show();
 5864  0 switch (rc) {
 5865  0 case JOptionPane.YES_OPTION:
 5866  0 _currentDefPane.hasWarnedAboutModified(true);
 5867  0 if (dialog.getCheckBoxValue()) {
 5868  0 DrJava.getConfig().setSetting(WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE);
 5869    }
 5870  0 break;
 5871   
 5872  0 case JOptionPane.NO_OPTION:
 5873  0 if (dialog.getCheckBoxValue()) DrJava.getConfig().setSetting(WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE);
 5874  0 return;
 5875   
 5876  0 case JOptionPane.CANCEL_OPTION:
 5877  0 case JOptionPane.CLOSED_OPTION:
 5878    // do nothing
 5879  0 return;
 5880   
 5881  0 default:
 5882  0 throw new RuntimeException("Invalid rc from showConfirmDialog: " + rc);
 5883    }
 5884    }
 5885   
 5886  0 try {
 5887  0 Debugger debugger = _model.getDebugger();
 5888  0 boolean breakpointSet =
 5889    debugger.toggleBreakpoint(doc, _currentDefPane.getCaretPosition(), true);
 5890  0 if (breakpointSet) showBreakpoints();
 5891    }
 5892    catch (DebugException de) {
 5893  0 MainFrameStatics.showError(MainFrame.this, de, "Debugger Error", "Could not set a breakpoint at the current line.");
 5894    }
 5895    }
 5896   
 5897   
 5898    // private void _getText(String name) { _field = name; }
 5899   
 5900    // /** Adds a watch to a given variable or field. */
 5901    // void debuggerAddWatch() {
 5902    // if (isDebuggerReady()) {
 5903    // //final String field;
 5904    // OpenDefinitionsDocument doc = _model.getActiveDocument();
 5905    // final JDialog getFieldDialog = new JDialog(this, "Choose Field to be Watched", true);
 5906    // //getFieldDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
 5907    // final JTextField fieldName = new JTextField();
 5908    // getFieldDialog.setSize(new Dimension(150, 60));
 5909    // getFieldDialog.getContentPane().add(fieldName);
 5910    // fieldName.addActionListener(new ActionListener() {
 5911    // public void actionPerformed(ActionEvent ae) {
 5912    // _getText(fieldName.getText());
 5913    // getFieldDialog.dispose();
 5914    // }
 5915    // });
 5916    // getFieldDialog.setLocation(300,300);
 5917    // getFieldDialog.show();
 5918    // Debugger debugger = _model.getDebugger();
 5919    // debugger.addWatch(_field);
 5920    // }
 5921    // }
 5922   
 5923    // /** Displays all breakpoints currently set in the debugger. */
 5924    // void _printBreakpoints() { _model.getDebugger().printBreakpoints(); }
 5925   
 5926   
 5927    /** Clears all breakpoints from the debugger. */
 5928  0 void debuggerClearAllBreakpoints() {
 5929  0 _model.getBreakpointManager().clearRegions();
 5930    }
 5931   
 5932  0 void _showFileMovedError(FileMovedException fme) {
 5933  0 try {
 5934  0 File f = fme.getFile();
 5935  0 OpenDefinitionsDocument doc = _model.getDocumentForFile(f);
 5936  0 if (doc != null && _saveSelector.shouldSaveAfterFileMoved(doc, f)) _saveAs();
 5937    }
 5938    catch (IOException ioe) { /* Couldn't find the document, so ignore the FME */ }
 5939    }
 5940   
 5941  0 void _showProjectFileParseError(MalformedProjectFileException mpfe) {
 5942  0 showProjectFileParseError(this, mpfe);
 5943    }
 5944   
 5945  0 void _showFileNotFoundError(FileNotFoundException fnf) {
 5946  0 showFileNotFoundError(this, fnf);
 5947    }
 5948   
 5949  0 void _showIOError(IOException ioe) {
 5950  0 showIOError(this, ioe);
 5951    }
 5952   
 5953  0 void _showClassNotFoundError(ClassNotFoundException cnfe) {
 5954  0 showClassNotFoundError(this, cnfe);
 5955    }
 5956   
 5957  0 void _showNoClassDefError(NoClassDefFoundError ncde) {
 5958  0 showNoClassDefError(this, ncde);
 5959    }
 5960   
 5961  0 void _showDebugError(DebugException de) {
 5962  0 showDebugError(this, de);
 5963    }
 5964   
 5965  0 void _showJUnitInterrupted(UnexpectedException e) {
 5966  0 showJUnitInterrupted(this, e);
 5967    }
 5968   
 5969  0 void _showJUnitInterrupted(String message) {
 5970  0 showJUnitInterrupted(this, message);
 5971    }
 5972   
 5973  0 void _showError(Throwable e, String title, String message) {
 5974  0 showError(this, e, title, message);
 5975    }
 5976   
 5977  0 void _showWarning(Throwable e, String title, String message) {
 5978  0 showWarning(this, e, title, message);
 5979    }
 5980   
 5981    /** Check if any errors occurred while parsing the config file, and display a message if necessary. */
 5982  38 private void _showConfigException() {
 5983  38 if (DrJava.getConfig().hadStartupException()) {
 5984  0 try {
 5985  0 DrJava.getConfig().saveConfiguration();
 5986    }
 5987    catch(IOException ioe) { /* ignore */ }
 5988  0 Exception e = DrJava.getConfig().getStartupException();
 5989  0 MainFrameStatics.showError(this, e, "Error in Config File",
 5990    "Could not read the '.drjava' configuration file\n" +
 5991    "in your home directory. Starting with default\n" +
 5992    "values instead.\n\n" + "The problem was:\n");
 5993    }
 5994    }
 5995   
 5996    /** Returns the File selected by the JFileChooser.
 5997    * @param fc File chooser presented to the user
 5998    * @param choice return value from fc
 5999    * @param previous previous file (or null if none)
 6000    * @param addSourceFileExtension whether .java (or another appropriate extension) should be added to files without extension
 6001    * @return Selected File
 6002    * @throws OperationCanceledException if file choice canceled
 6003    * @throws RuntimeException if fc returns a bad file or choice
 6004    */
 6005  0 private File getChosenFile(JFileChooser fc, int choice, File previous,
 6006    boolean addSourceFileExtension) throws OperationCanceledException {
 6007  0 switch (choice) {
 6008  0 case JFileChooser.CANCEL_OPTION:
 6009  0 case JFileChooser.ERROR_OPTION:
 6010  0 throw new OperationCanceledException();
 6011  0 case JFileChooser.APPROVE_OPTION:
 6012  0 File chosen = fc.getSelectedFile();
 6013  0 if (chosen != null) {
 6014    //append the appropriate language level extension if not written by user
 6015  0 if (addSourceFileExtension) {
 6016  0 if (chosen.getName().indexOf(".") == -1) {
 6017    // no file extension
 6018  0 String previousName = (previous!=null)?previous.getName():"";
 6019  0 if (!DrJavaFileUtils.isSourceFile(previousName)) {
 6020    // previous file name doesn't have a file extension either
 6021  0 File newFile = new File(chosen.getAbsolutePath() + getSuggestedFileExtension());
 6022  0 return newFile;
 6023    }
 6024    else {
 6025    // use previous file's extension
 6026  0 int previousLastDotPos = previousName.lastIndexOf(".");
 6027  0 String previousExt = previousName.substring(previousLastDotPos);
 6028  0 File newFile = new File(chosen.getAbsolutePath() + previousExt);
 6029  0 return newFile;
 6030    }
 6031    }
 6032    }
 6033  0 return chosen;
 6034    }
 6035    else
 6036  0 throw new RuntimeException("Filechooser returned null file");
 6037  0 default: // impossible since rc must be one of these
 6038  0 throw new RuntimeException("Filechooser returned bad rc " + choice);
 6039    }
 6040    }
 6041    /** Returns the Files selected by the JFileChooser.
 6042    * @param fc File chooser presented to the user
 6043    * @param choice return value from fc
 6044    * @return Selected Files - this array will be size 1 for single-selection dialogs.
 6045    * @throws OperationCanceledException if file choice canceled
 6046    * @throws RuntimeException if fc returns a bad file or choice
 6047    */
 6048  0 private File[] getChosenFiles(JFileChooser fc, int choice) throws OperationCanceledException {
 6049  0 switch (choice) {
 6050  0 case JFileChooser.CANCEL_OPTION:
 6051  0 case JFileChooser.ERROR_OPTION:
 6052  0 throw new OperationCanceledException();
 6053  0 case JFileChooser.APPROVE_OPTION:
 6054  0 File[] chosen = fc.getSelectedFiles();
 6055  0 if (chosen == null)
 6056  0 throw new UnexpectedException(new OperationCanceledException(), "filechooser returned null file");
 6057   
 6058    // Following code reviewed for bug 70902-- JVF
 6059    // If this is a single-selection dialog, getSelectedFiles() will always
 6060    // return a zero-size array -- handle it differently.
 6061  0 if (chosen.length == 0) {
 6062  0 if (!fc.isMultiSelectionEnabled()) {
 6063  0 return new File[] { fc.getSelectedFile() };
 6064    }
 6065    else {
 6066    /* This is the workaround for bug 70902: sometimes Mac OS X will return
 6067    * APPROVE_OPTION when the user clicks the close (x) control button
 6068    * on the dialog window, even though nothing is selected.
 6069    */
 6070  0 throw new OperationCanceledException();
 6071    }
 6072    }
 6073    else {
 6074  0 return chosen;
 6075    }
 6076   
 6077  0 default: // impossible since rc must be one of these
 6078  0 throw new UnexpectedException(new OperationCanceledException(), "filechooser returned bad rc " + choice);
 6079    }
 6080    }
 6081   
 6082  0 private void _selectAll() { _currentDefPane.selectAll(); }
 6083   
 6084    /** Jump to the specified line and return the offset. Only runs in event thread.
 6085    * @return offset */
 6086  0 public int _jumpToLine(int lineNum) {
 6087  0 int pos = _model.getActiveDocument().gotoLine(lineNum);
 6088  0 addToBrowserHistory();
 6089  0 _currentDefPane.setCaretPosition(pos);
 6090  0 _currentDefPane.centerViewOnOffset(pos);
 6091  0 return pos;
 6092    }
 6093   
 6094    /** Ask the user what line they'd like to jump to, then go there. */
 6095  0 private int _gotoLine() {
 6096  0 final String msg = "What line would you like to go to?";
 6097  0 final String title = "Go to Line";
 6098  0 String lineStr = JOptionPane.showInputDialog(this, msg, title, JOptionPane.QUESTION_MESSAGE);
 6099  0 try {
 6100  0 if (lineStr != null) {
 6101  0 int lineNum = Integer.parseInt(lineStr);
 6102  0 return _jumpToLine(lineNum); }
 6103    }
 6104    catch (NumberFormatException nfe) {
 6105    // invalid input for line number
 6106  0 Toolkit.getDefaultToolkit().beep();
 6107    // Do nothing.
 6108    }
 6109    //catch (BadLocationException ble) { }
 6110  0 return -1;
 6111    }
 6112   
 6113    /** Removes the ErrorCaretListener corresponding to the given document, after that document has been closed.
 6114    * (Allows pane and listener to be garbage collected...)
 6115    */
 6116  38 private void _removeErrorListener(OpenDefinitionsDocument doc) {
 6117  38 JScrollPane scroll = _defScrollPanes.get(doc);
 6118  38 if (scroll != null) {
 6119  37 DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView();
 6120  37 pane.removeCaretListener(pane.getErrorCaretListener());
 6121    }
 6122    }
 6123   
 6124  1102 void _addGUIAvailabilityListener(Action a, GUIAvailabilityListener.ComponentType... components) {
 6125  1102 _guiAvailabilityNotifier.
 6126    addListener(new AndGUIAvailabilityActionAdapter(a, _guiAvailabilityNotifier, components));
 6127    }
 6128   
 6129  190 void _addGUIAvailabilityListener(Component a, GUIAvailabilityListener.ComponentType... components) {
 6130  190 _guiAvailabilityNotifier.
 6131    addListener(new AndGUIAvailabilityComponentAdapter(a, _guiAvailabilityNotifier, components));
 6132    }
 6133   
 6134  0 void _displayGUIComponentAvailabilityFrame() {
 6135  0 JFrame frame = new JFrame("GUI Availability");
 6136  0 frame.setAlwaysOnTop(true );
 6137  0 frame.setLocationByPlatform(true);
 6138  0 frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS));
 6139  0 for(final GUIAvailabilityListener.ComponentType c: GUIAvailabilityListener.ComponentType.values()) {
 6140  0 final DelayedThunk<JButton> buttonThunk = DelayedThunk.make();
 6141  0 final JButton button = new JButton(new AbstractAction(c.toString()+" "+_guiAvailabilityNotifier.getCount(c)) {
 6142  0 public void actionPerformed(ActionEvent e) {
 6143  0 _guiAvailabilityNotifier.availabilityChanged(c, !buttonThunk.value().getText().endsWith(" 0"));
 6144    }
 6145    });
 6146  0 buttonThunk.set(button);
 6147  0 _guiAvailabilityNotifier.addListener(new AndGUIAvailabilityListener(_guiAvailabilityNotifier, c) {
 6148  0 public void availabilityChanged(boolean available) {
 6149  0 button.setText(c.toString()+" "+_guiAvailabilityNotifier.getCount(c));
 6150  0 button.setSelected(available);
 6151    }
 6152    });
 6153  0 button.setSelected(_guiAvailabilityNotifier.isAvailable(c));
 6154  0 frame.add(button);
 6155    }
 6156  0 frame.pack();
 6157  0 frame.setVisible(true);
 6158    }
 6159   
 6160    /** Initialize the availability of GUI components.
 6161    *
 6162    * When JUnit is running, the compiler or Javadoc should not be invoked (Javadoc may invoke the compiler).
 6163    */
 6164  38 private void _setUpGUIComponentAvailability() {
 6165    // _displayGUIComponentAvailabilityFrame();
 6166   
 6167  38 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.PROJECT);
 6168  38 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.PROJECT_BUILD_DIR);
 6169  38 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.PROJECT_MAIN_CLASS);
 6170  38 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.DEBUGGER);
 6171  38 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED);
 6172  38 _guiAvailabilityNotifier.ensureAvailable(GUIAvailabilityListener.ComponentType.JUNIT);
 6173  38 _guiAvailabilityNotifier.ensureAvailable(GUIAvailabilityListener.ComponentType.COMPILER);
 6174  38 _guiAvailabilityNotifier.ensureAvailabilityIs(GUIAvailabilityListener.ComponentType.JAVADOC,
 6175    _model.getJavadocModel().isAvailable());
 6176    }
 6177   
 6178    /** Initializes all action objects. Adds icons and descriptions to several of the actions. Note: this
 6179    * initialization will later be done in the constructor of each action, which will subclass AbstractAction.
 6180    */
 6181  38 private void _setUpActions() {
 6182  38 _setUpAction(_newAction, "New", "Create a new document");
 6183  38 _setUpAction(_newClassAction, "New", "Create a new Java Class");
 6184  38 _setUpAction(_newJUnitTestAction, "New", "Create a new JUnit test case class");
 6185  38 _setUpAction(_newProjectAction, "New", "Make a new project");
 6186  38 _setUpAction(_openAction, "Open", "Open an existing file");
 6187  38 _setUpAction(_openFolderAction, "Open Folder", "OpenAll", "Open all files within a directory");
 6188  38 _setUpAction(_openFileOrProjectAction, "Open", "Open an existing file or project");
 6189  38 _setUpAction(_openProjectAction, "Open", "Open an existing project");
 6190  38 _setUpAction(_saveAction, "Save", "Save the current document");
 6191  38 _setUpAction(_saveAsAction, "Save As", "SaveAs", "Save the current document with a new name");
 6192  38 _setUpAction(_saveCopyAction, "Save Copy", "SaveAs", "Save a copy of the current document");
 6193  38 _setUpAction(_renameAction, "Rename", "Rename", "Rename the current document");
 6194  38 _setUpAction(_saveProjectAction, "Save", "Save", "Save the current project");
 6195  38 _setUpAction(_saveProjectAsAction, "Save As", "SaveAs", "Save current project to new project file");
 6196  38 _setUpAction(_exportProjectInOldFormatAction, "Export Project In Old \"" + OLD_PROJECT_FILE_EXTENSION +
 6197    "\" Format", "SaveAs", "Export Project In Old \"" + OLD_PROJECT_FILE_EXTENSION + "\" Format");
 6198  38 _setUpAction(_revertAction, "Revert", "Revert the current document to the saved version");
 6199    // Not yet working
 6200    // _setUpAction(_revertAllAction, "Revert All", "RevertAll",
 6201    // "Revert all open documents to the saved versions");
 6202   
 6203  38 _setUpAction(_closeAction, "Close", "Close the current document");
 6204  38 _setUpAction(_closeAllAction, "Close All", "CloseAll", "Close all documents");
 6205  38 _setUpAction(_closeProjectAction, "Close", "CloseAll", "Close the current project");
 6206  38 _setUpAction(_projectPropertiesAction, "Project Properties", "Preferences", "Edit Project Properties");
 6207  38 _setUpAction(_junitProjectAction, "Test Project", "Test the documents in the project source tree");
 6208  38 _setUpAction(_compileProjectAction, "Compile Project", "Compile the documents in the project source tree");
 6209  38 _setUpAction(_runProjectAction, "Run Project", "Run the project's main method");
 6210  38 _setUpAction(_jarProjectAction, "Jar", "Create a jar archive from this project");
 6211  38 _setUpAction(_saveAllAction, "Save All", "SaveAll", "Save all open documents");
 6212  38 _setUpAction(_cleanAction, "Clean", "Clean Build directory");
 6213  38 _setUpAction(_autoRefreshAction, "Auto-Refresh", "Auto-refresh project");
 6214  38 _setUpAction(_compileAction, "Compile Current Document", "Compile the current document");
 6215  38 _setUpAction(_compileAllAction, "Compile", "Compile all open documents");
 6216  38 _setUpAction(_printDefDocAction, "Print", "Print the current document");
 6217  38 _setUpAction(_printConsoleAction, "Print", "Print the Console pane");
 6218  38 _setUpAction(_printInteractionsAction, "Print", "Print the Interactions pane");
 6219  38 _setUpAction(_pageSetupAction, "Page Setup", "PageSetup", "Change the printer settings");
 6220  38 _setUpAction(_printDefDocPreviewAction, "Print Preview", "PrintPreview",
 6221    "Preview how the document will be printed");
 6222  38 _setUpAction(_printConsolePreviewAction, "Print Preview", "PrintPreview",
 6223    "Preview how the console document will be printed");
 6224  38 _setUpAction(_printInteractionsPreviewAction, "Print Preview", "PrintPreview",
 6225    "Preview how the interactions document will be printed");
 6226   
 6227  38 _setUpAction(_quitAction, "Quit", "Quit", "Quit DrJava");
 6228   
 6229  38 _setUpAction(_undoAction, "Undo", "Undo previous command");
 6230  38 _setUpAction(_redoAction, "Redo", "Redo last undo");
 6231  38 _undoAction.putValue(Action.NAME, "Undo previous command");
 6232  38 _redoAction.putValue(Action.NAME, "Redo last undo");
 6233   
 6234  38 _setUpAction(cutAction, "Cut", "Cut selected text to the clipboard");
 6235  38 _setUpAction(copyAction, "Copy", "Copy selected text to the clipboard");
 6236  38 _setUpAction(pasteAction, "Paste", "Paste text from the clipboard");
 6237  38 _setUpAction(_pasteHistoryAction, "Paste from History", "Paste text from the clipboard history");
 6238  38 _setUpAction(_selectAllAction, "Select All", "Select all text");
 6239   
 6240  38 cutAction.putValue(Action.NAME, "Cut");
 6241  38 copyAction.putValue(Action.NAME, "Copy");
 6242  38 pasteAction.putValue(Action.NAME, "Paste");
 6243  38 _pasteHistoryAction.putValue(Action.NAME, "Paste from History");
 6244   
 6245  38 _setUpAction(_indentLinesAction, "Indent Lines", "Indent all selected lines");
 6246  38 _setUpAction(_commentLinesAction, "Comment Lines", "Comment out all selected lines");
 6247  38 _setUpAction(_uncommentLinesAction, "Uncomment Lines", "Uncomment all selected lines");
 6248   
 6249  38 _setUpAction(completeWordUnderCursorAction, "Auto-Complete Word Under Cursor",
 6250    "Auto-complete the word the cursor is currently located on");
 6251  38 _setUpAction(_bookmarksPanelAction, "Bookmarks", "Display the bookmarks panel");
 6252  38 _setUpAction(_toggleBookmarkAction, "Toggle Bookmark", "Toggle the bookmark at the current cursor location");
 6253  38 _setUpAction(_followFileAction, "Follow File", "Follow a file's updates");
 6254  38 _setUpAction(_executeExternalProcessAction, "Execute External", "Execute external process");
 6255  38 _setUpAction(_editExternalProcessesAction, "Preferences", "Edit saved external processes");
 6256   
 6257  38 _setUpAction(_findReplaceAction, "Find", "Find or replace text in the document");
 6258  38 _setUpAction(_findNextAction, "Find Next", "Repeats the last find");
 6259  38 _setUpAction(_findPrevAction, "Find Previous", "Repeats the last find in the opposite direction");
 6260  38 _setUpAction(_gotoLineAction, "Go to line", "Go to a line number in the document");
 6261  38 _setUpAction(_gotoFileAction, "Go to File", "Go to a file specified by its name");
 6262  38 _setUpAction(_gotoFileUnderCursorAction, "Go to File Under Cursor",
 6263    "Go to the file specified by the word the cursor is located on");
 6264   
 6265  38 _setUpAction(_switchToPrevAction, "Previous Document", "Up", "Switch to the previous document");
 6266  38 _setUpAction(_switchToNextAction, "Next Document", "Down", "Switch to the next document");
 6267   
 6268  38 _setUpAction(_browseBackAction, "Back", "Back", "Move back in the browser history");
 6269  38 _setUpAction(_browseForwardAction, "Forward", "Forward", "Move forward in the browser history");
 6270   
 6271  38 _setUpAction(_prevRegionAction, "Previous Region", "Move to previous region in tabbed pane");
 6272  38 _setUpAction(_nextRegionAction, "Next Region", "Move to next region in tabbed pane");
 6273   
 6274  38 _setUpAction(_switchToPreviousPaneAction, "Previous Pane", "Switch focus to the previous pane");
 6275  38 _setUpAction(_switchToNextPaneAction, "Next Pane", "Switch focus to the next pane");
 6276  38 _setUpAction(_gotoOpeningBraceAction, "Go to Opening Brace",
 6277    "Go th the opening brace of the block enclosing the cursor");
 6278  38 _setUpAction(_gotoClosingBraceAction, "Go to Closing Brace",
 6279    "Go th the closing brace of the block enclosing the cursor");
 6280   
 6281  38 _setUpAction(_editPreferencesAction, "Preferences", "Edit configurable settings in DrJava");
 6282   
 6283  38 _setUpAction(_junitAction, "Test Current", "Run JUnit over the current document");
 6284  38 _setUpAction(_junitAllAction, "Test", "Run JUnit over all open JUnit tests");
 6285  38 if (_model.getJavadocModel().isAvailable()) {
 6286  38 _setUpAction(_javadocAllAction, "Javadoc", "Create and save Javadoc for the packages of all open documents");
 6287  38 _setUpAction(_javadocCurrentAction, "Preview Javadoc Current", "Preview the Javadoc for the current document");
 6288    }
 6289    else {
 6290  0 _setUpAction(_javadocAllAction, "Javadoc",
 6291    "Note: DrJava cannot run Javadoc because no JDK was found. Please install a JDK.");
 6292  0 _setUpAction(_javadocCurrentAction, "Preview Javadoc Current",
 6293    "Note: DrJava cannot run Javadoc because no JDK was found. Please install a JDK.");
 6294    }
 6295  38 _setUpAction(_runAction, "Run", "Run the main method of the current document");
 6296  38 _setUpAction(_runAppletAction, "Run", "Run the current document as applet");
 6297   
 6298  38 _setUpAction(_openJavadocAction, "Open Java API Javadoc...", "Open the Java API Javadoc Web page for a class");
 6299  38 _setUpAction(_openJavadocUnderCursorAction, "Open Java API Javadoc for Word Under Cursor...", "Open the Java API " +
 6300    "Javadoc Web page for the word under the cursor");
 6301   
 6302  38 _setUpAction(_saveInteractionsCopyAction, "Save Copy of Interactions...",
 6303    "SaveAs", "Save copy of interactions contents to a file");
 6304  38 _setUpAction(_executeHistoryAction, "Execute History", "Load and execute a history of interactions from a file");
 6305  38 _setUpAction(_loadHistoryScriptAction, "Load History as Script",
 6306    "Load a history from a file as a series of interactions");
 6307  38 _setUpAction(_saveHistoryAction, "Save History", "Save the history of interactions to a file");
 6308  38 _setUpAction(_clearHistoryAction, "Clear History", "Clear the current history of interactions");
 6309   
 6310  38 _setUpAction(_resetInteractionsAction, "Reset", "Reset the Interactions Pane");
 6311  38 _setUpAction(_closeSystemInAction, "Close System.in", "Close System.in Stream in Interactions Pane");
 6312   
 6313  38 _setUpAction(_viewInteractionsClassPathAction, "View Interactions Classpath",
 6314    "Display the classpath in use by the Interactions Pane");
 6315  38 _setUpAction(_copyInteractionToDefinitionsAction, "Lift Current Interaction",
 6316    "Copy the current interaction into the Definitions Pane");
 6317   
 6318  38 _setUpAction(_saveConsoleCopyAction, "Save Copy of Console...",
 6319    "SaveAs", "Save copy of console contents to a file");
 6320  38 _setUpAction(_clearConsoleAction, "Clear Console", "Clear all text in the Console Pane");
 6321  38 _setUpAction(_showDebugConsoleAction, "Show DrJava Debug Console", "<html>Show a console for debugging DrJava<br>" +
 6322    "(with \"mainFrame\", \"model\", and \"config\" variables defined)</html>");
 6323   
 6324  38 if (_model.getDebugger().isAvailable()) {
 6325  38 _setUpAction(_toggleDebuggerAction, "Debug Mode", "Enable or disable DrJava's debugger");
 6326  38 _setUpAction(_toggleBreakpointAction, "Toggle Breakpoint", "Set or clear a breakpoint on the current line");
 6327  38 _setUpAction(_clearAllBreakpointsAction, "Clear Breakpoints", "Clear all breakpoints in all classes");
 6328  38 _setUpAction(_resumeDebugAction, "Resume", "Resume the current suspended thread");
 6329  38 _setUpAction(_automaticTraceDebugAction, "Automatic Trace", "Automatically trace through entire program");
 6330  38 _setUpAction(_stepIntoDebugAction, "Step Into", "Step into the current line or method call");
 6331  38 _setUpAction(_stepOverDebugAction, "Step Over", "Step over the current line or method call");
 6332  38 _setUpAction(_stepOutDebugAction, "Step Out", "Step out of the current method");
 6333  38 _setUpAction(_breakpointsPanelAction, "Breakpoints", "Display the breakpoints panel");
 6334    }
 6335   
 6336  38 _setUpAction(_helpAction, "Help", "Show documentation on how to use DrJava");
 6337  38 _setUpAction(_quickStartAction, "Help", "View Quick Start Guide for DrJava");
 6338  38 _setUpAction(_aboutAction, "About", "About DrJava");
 6339  38 _setUpAction(_checkNewVersionAction, "Check for New Version", "Find", "Check for New Version");
 6340  38 _checkNewVersionAction.setEnabled(DrJava.getConfig().getSetting(OptionConstants.NEW_VERSION_ALLOWED));
 6341    // _setUpAction(_drjavaSurveyAction, "Send System Information", "About",
 6342    // "Send anonymous system information to DrJava developers");
 6343  38 _setUpAction(_errorsAction, "DrJava Errors", "drjavaerror", "Show a window with internal DrJava errors");
 6344  38 _setUpAction(_forceQuitAction, "Force Quit", "Stop", "Force DrJava to quit without cleaning up");
 6345  38 _setUpAction(_generateCustomDrJavaJarAction, "Generate Custom drjava.jar...",
 6346    "<html>Generate a custom drjava.jar file that includes additional files,<br>"+
 6347    "e.g. libraries or resources.</html>");
 6348    }
 6349   
 6350  4028 private void _setUpAction(Action a, String name, String icon, String longDesc) {
 6351  4028 a.putValue(Action.SMALL_ICON, _getIcon(icon + "16.gif"));
 6352  4028 a.putValue(Action.DEFAULT, name);
 6353  4028 a.putValue(Action.LONG_DESCRIPTION, longDesc);
 6354    }
 6355   
 6356  3078 private void _setUpAction(Action a, String icon, String shortDesc) { _setUpAction(a, icon, icon, shortDesc); }
 6357   
 6358   
 6359    /** Returns the icon with the given name. All icons are assumed to reside in the /edu/rice/cs/drjava/ui/icons
 6360    * directory.
 6361    * @param name Name of icon image file
 6362    * @return ImageIcon object constructed from the file
 6363    */
 6364  4028 private ImageIcon _getIcon(String name) { return getIcon(name); }
 6365   
 6366  29284 public static ImageIcon getIcon(String name) {
 6367  29284 URL url = MainFrame.class.getResource(ICON_PATH + name);
 6368  26968 if (url != null) return new ImageIcon(url);
 6369   
 6370  2316 return null;
 6371    }
 6372   
 6373    /** This allows us to intercept key events when compiling testing and turn them off when the glass pane is up. */
 6374    static class MenuBar extends JMenuBar {
 6375    private final MainFrame _mf;
 6376  38 public MenuBar(MainFrame mf) { _mf = mf; }
 6377  0 public boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
 6378  0 if (_mf.getAllowKeyEvents()) return super.processKeyBinding(ks, e, condition, pressed);
 6379  0 return false;
 6380    }
 6381    }
 6382   
 6383  0 public void addMenuBarInOtherFrame(JMenuBar menuBar) {
 6384  0 JMenu fileMenu = menuBar.getMenu(Utilities.getComponentIndex(_fileMenu));
 6385  0 _recentFileManager.addMirroredMenu(fileMenu);
 6386  0 JMenu projectMenu = menuBar.getMenu(Utilities.getComponentIndex(_projectMenu));
 6387  0 _recentProjectManager.addMirroredMenu(projectMenu);
 6388    }
 6389   
 6390  0 public void removeMenuBarInOtherFrame(JMenuBar menuBar) {
 6391  0 JMenu fileMenu = menuBar.getMenu(Utilities.getComponentIndex(_fileMenu));
 6392  0 _recentFileManager.removeMirroredMenu(fileMenu);
 6393  0 JMenu projectMenu = menuBar.getMenu(Utilities.getComponentIndex(_projectMenu));
 6394  0 _recentProjectManager.removeMirroredMenu(projectMenu);
 6395    }
 6396   
 6397    /** Sets up the components of the menu bar and links them to the private fields within MainFrame. This method
 6398    * serves to make the code more legible on the higher calling level, i.e., the constructor.
 6399    */
 6400  0 void _setUpMenuBar(JMenuBar menuBar) {
 6401  0 int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
 6402  0 _setUpMenuBar(menuBar,
 6403    _setUpFileMenu(mask, false), _setUpEditMenu(mask, false), _setUpToolsMenu(mask, false),
 6404  0 _setUpProjectMenu(mask, false), _showDebugger?_setUpDebugMenu(mask, false):null,
 6405    _setUpLanguageLevelMenu(mask, false), _setUpHelpMenu(mask, false));
 6406    }
 6407   
 6408  38 void _setUpMenuBar(JMenuBar menuBar,
 6409    JMenu fileMenu,
 6410    JMenu editMenu,
 6411    JMenu toolsMenu,
 6412    JMenu projectMenu,
 6413    JMenu debugMenu,
 6414    JMenu languageLevelMenu,
 6415    JMenu helpMenu) {
 6416  38 menuBar.add(fileMenu);
 6417  38 menuBar.add(editMenu);
 6418  38 menuBar.add(toolsMenu);
 6419  38 menuBar.add(projectMenu);
 6420  38 if (_showDebugger && (debugMenu!=null)) menuBar.add(debugMenu);
 6421  38 menuBar.add(languageLevelMenu);
 6422  38 menuBar.add(helpMenu);
 6423    // Plastic-specific style hints
 6424  38 if(Utilities.isPlasticLaf()) {
 6425  0 menuBar.putClientProperty(com.jgoodies.looks.Options.HEADER_STYLE_KEY, com.jgoodies.looks.HeaderStyle.BOTH);
 6426    }
 6427    }
 6428   
 6429    /** Adds an Action as a menu item to the given menu, using the specified configurable keystroke.
 6430    * @param menu Menu to add item to
 6431    * @param a Action for the menu item
 6432    * @param opt Configurable keystroke for the menu item
 6433    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6434    * @return the added menu item
 6435    */
 6436  3762 private JMenuItem _addMenuItem(JMenu menu, Action a, VectorOption<KeyStroke> opt, boolean updateKeyboardManager) {
 6437  3762 JMenuItem item;
 6438  3762 item = menu.add(a);
 6439  3762 _setMenuShortcut(item, a, opt, updateKeyboardManager);
 6440  3762 return item;
 6441    }
 6442   
 6443    /** Inserts an Action as a menu item to the given menu, at the specified index,
 6444    * using the specified configurable keystroke.
 6445    * @param menu Menu to add item to
 6446    * @param a Action for the menu item
 6447    * @param opt Configurable keystroke for the menu item
 6448    * @param index Index at which the action is inserted
 6449    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6450    * @return the added menu item
 6451    */
 6452  0 private JMenuItem _addMenuItem(JMenu menu, Action a, VectorOption<KeyStroke> opt, int index,
 6453    boolean updateKeyboardManager) {
 6454  0 JMenuItem item;
 6455  0 item = menu.insert(a, index);
 6456  0 _setMenuShortcut(item, a, opt, updateKeyboardManager);
 6457  0 return item;
 6458    }
 6459   
 6460    /** Sets the given menu item to have the specified configurable keystroke.
 6461    * @param item Menu item containing the action
 6462    * @param a Action for the menu item
 6463    * @param opt Configurable keystroke for the menu item
 6464    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6465    */
 6466  3914 private void _setMenuShortcut(JMenuItem item, Action a, VectorOption<KeyStroke> opt, boolean updateKeyboardManager) {
 6467  3914 Vector<KeyStroke> keys = DrJava.getConfig().getSetting(opt);
 6468    // Checks that "a" is the action associated with the keystroke.
 6469    // Need to check in case two actions were assigned to the same
 6470    // key in the config file.
 6471    // Also check that the keystroke isn't the NULL_KEYSTROKE, which
 6472    // can strangely be triggered by certain keys in Windows.
 6473  3914 if (updateKeyboardManager) { KeyBindingManager.ONLY.put(opt, a, item, item.getText()); }
 6474  3914 if ((keys.size() > 0) && KeyBindingManager.ONLY.get(keys.get(0)) == a) {
 6475  2622 item.setAccelerator(keys.get(0));
 6476    }
 6477    }
 6478   
 6479    /** Creates and returns a file menu. Side effects: sets values for _saveMenuItem.
 6480    * @param mask the keystroke modifier to be used
 6481    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6482    */
 6483  38 private JMenu _setUpFileMenu(int mask, boolean updateKeyboardManager) {
 6484  38 JMenu fileMenu = new JMenu("File");
 6485  38 PlatformFactory.ONLY.setMnemonic(fileMenu,KeyEvent.VK_F);
 6486    // New, open
 6487  38 _addMenuItem(fileMenu, _newAction, KEY_NEW_FILE, updateKeyboardManager);
 6488  38 _addMenuItem(fileMenu, _newClassAction, KEY_NEW_CLASS_FILE, updateKeyboardManager);
 6489   
 6490  38 _addMenuItem(fileMenu, _newJUnitTestAction, KEY_NEW_TEST, updateKeyboardManager);
 6491  38 _addMenuItem(fileMenu, _openAction, KEY_OPEN_FILE, updateKeyboardManager);
 6492  38 _addMenuItem(fileMenu, _openFolderAction, KEY_OPEN_FOLDER, updateKeyboardManager);
 6493   
 6494  38 fileMenu.addSeparator();
 6495   
 6496  38 _addMenuItem(fileMenu, _saveAction, KEY_SAVE_FILE, updateKeyboardManager);
 6497  38 _saveAction.setEnabled(true);
 6498  38 _addMenuItem(fileMenu, _saveAsAction, KEY_SAVE_FILE_AS, updateKeyboardManager);
 6499  38 _addMenuItem(fileMenu, _saveCopyAction, KEY_SAVE_FILE_COPY, updateKeyboardManager);
 6500  38 _addMenuItem(fileMenu, _saveAllAction, KEY_SAVE_ALL_FILES, updateKeyboardManager);
 6501  38 _addMenuItem(fileMenu, _renameAction, KEY_RENAME_FILE, updateKeyboardManager);
 6502  38 _renameAction.setEnabled(false);
 6503   
 6504  38 _addMenuItem(fileMenu, _revertAction, KEY_REVERT_FILE, updateKeyboardManager);
 6505  38 _revertAction.setEnabled(false);
 6506    //tmpItem = fileMenu.add(_revertAllAction);
 6507   
 6508    // Close, Close all
 6509  38 fileMenu.addSeparator();
 6510  38 _addMenuItem(fileMenu, _closeAction, KEY_CLOSE_FILE, updateKeyboardManager);
 6511  38 _addMenuItem(fileMenu, _closeAllAction, KEY_CLOSE_ALL_FILES, updateKeyboardManager);
 6512   
 6513    // Page setup, print preview, print
 6514  38 fileMenu.addSeparator();
 6515  38 _addMenuItem(fileMenu, _pageSetupAction, KEY_PAGE_SETUP, updateKeyboardManager);
 6516  38 _addMenuItem(fileMenu, _printDefDocPreviewAction, KEY_PRINT_PREVIEW, updateKeyboardManager);
 6517  38 _addMenuItem(fileMenu, _printDefDocAction, KEY_PRINT, updateKeyboardManager);
 6518   
 6519    // Quit
 6520  38 fileMenu.addSeparator();
 6521  38 _addMenuItem(fileMenu, _quitAction, KEY_QUIT, updateKeyboardManager);
 6522   
 6523  38 return fileMenu;
 6524    }
 6525   
 6526    /** Creates and returns a edit menu.
 6527    * @param mask the keystroke modifier to be used
 6528    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6529    */
 6530  38 private JMenu _setUpEditMenu(int mask, boolean updateKeyboardManager) {
 6531  38 JMenu editMenu = new JMenu("Edit");
 6532  38 PlatformFactory.ONLY.setMnemonic(editMenu,KeyEvent.VK_E);
 6533    // Undo, redo
 6534  38 final JMenuItem undoItem = _addMenuItem(editMenu, _undoAction, KEY_UNDO, updateKeyboardManager);
 6535  38 _undoAction.addPropertyChangeListener(new PropertyChangeListener() {
 6536  318 public void propertyChange(PropertyChangeEvent evt) {
 6537  318 if ("enabled".equals(evt.getPropertyName())) {
 6538  79 boolean val = (Boolean) evt.getNewValue();
 6539  79 undoItem.setEnabled(val);
 6540    }
 6541    }
 6542    });
 6543   
 6544  38 final JMenuItem redoItem = _addMenuItem(editMenu, _redoAction, KEY_REDO, updateKeyboardManager);
 6545  38 _redoAction.addPropertyChangeListener(new PropertyChangeListener() {
 6546  301 public void propertyChange(PropertyChangeEvent evt) {
 6547  301 if ("enabled".equals(evt.getPropertyName())) {
 6548  68 boolean val = (Boolean) evt.getNewValue();
 6549  68 redoItem.setEnabled(val);
 6550    }
 6551    }
 6552    });
 6553   
 6554    // Cut, copy, paste, select all
 6555  38 editMenu.addSeparator();
 6556  38 _addMenuItem(editMenu, cutAction, KEY_CUT, updateKeyboardManager);
 6557  38 _addMenuItem(editMenu, copyAction, KEY_COPY, updateKeyboardManager);
 6558  38 _addMenuItem(editMenu, pasteAction, KEY_PASTE, updateKeyboardManager);
 6559  38 _addMenuItem(editMenu, _pasteHistoryAction, KEY_PASTE_FROM_HISTORY, updateKeyboardManager);
 6560  38 _addMenuItem(editMenu, _selectAllAction, KEY_SELECT_ALL, updateKeyboardManager);
 6561   
 6562    // Indent lines, comment lines
 6563  38 editMenu.addSeparator();
 6564    //_addMenuItem(editMenu, _indentLinesAction, KEY_INDENT, updateKeyboardManager);
 6565  38 JMenuItem editItem = editMenu.add(_indentLinesAction);
 6566  38 editItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
 6567  38 _addMenuItem(editMenu, _commentLinesAction, KEY_COMMENT_LINES, updateKeyboardManager);
 6568  38 _addMenuItem(editMenu, _uncommentLinesAction, KEY_UNCOMMENT_LINES, updateKeyboardManager);
 6569  38 _addMenuItem(editMenu, completeWordUnderCursorAction, KEY_COMPLETE_FILE, updateKeyboardManager);
 6570   
 6571    // Find/replace
 6572  38 editMenu.addSeparator();
 6573  38 _addMenuItem(editMenu, _findReplaceAction, KEY_FIND_REPLACE, updateKeyboardManager);
 6574  38 _addMenuItem(editMenu, _findNextAction, KEY_FIND_NEXT, updateKeyboardManager);
 6575  38 _addMenuItem(editMenu, _findPrevAction, KEY_FIND_PREV, updateKeyboardManager);
 6576   
 6577    // Next, prev doc
 6578  38 editMenu.addSeparator();
 6579  38 _addMenuItem(editMenu, _switchToPrevAction, KEY_PREVIOUS_DOCUMENT, updateKeyboardManager);
 6580  38 _addMenuItem(editMenu, _switchToNextAction, KEY_NEXT_DOCUMENT, updateKeyboardManager);
 6581  38 _addMenuItem(editMenu, _browseBackAction, KEY_BROWSE_BACK, updateKeyboardManager);
 6582  38 _addMenuItem(editMenu, _browseForwardAction, KEY_BROWSE_FORWARD, updateKeyboardManager);
 6583  38 editMenu.addSeparator();
 6584   
 6585    // Go to
 6586  38 final JMenu goToMenu = new JMenu("Go To");
 6587  38 _addMenuItem(goToMenu, _gotoLineAction, KEY_GOTO_LINE, updateKeyboardManager);
 6588  38 _addMenuItem(goToMenu, _gotoFileAction, KEY_GOTO_FILE, updateKeyboardManager);
 6589  38 _addMenuItem(goToMenu, _gotoFileUnderCursorAction, KEY_GOTO_FILE_UNDER_CURSOR, updateKeyboardManager);
 6590  38 _addMenuItem(goToMenu, _gotoOpeningBraceAction, KEY_OPENING_BRACE, updateKeyboardManager);
 6591  38 _addMenuItem(goToMenu, _gotoClosingBraceAction, KEY_CLOSING_BRACE, updateKeyboardManager);
 6592  38 editMenu.add(goToMenu);
 6593   
 6594    // Panes
 6595  38 final JMenu panesMenu = new JMenu("Tabbed Panes");
 6596  38 _addMenuItem(panesMenu, _switchToPreviousPaneAction, KEY_PREVIOUS_PANE, updateKeyboardManager);
 6597  38 _addMenuItem(panesMenu, _switchToNextPaneAction, KEY_NEXT_PANE, updateKeyboardManager);
 6598  38 panesMenu.addSeparator();
 6599  38 _addMenuItem(panesMenu, _prevRegionAction, KEY_TABBED_PREV_REGION, updateKeyboardManager);
 6600  38 _addMenuItem(panesMenu, _nextRegionAction, KEY_TABBED_NEXT_REGION, updateKeyboardManager);
 6601  38 panesMenu.addSeparator();
 6602   
 6603  38 JMenuItem tempDetachTabbedPanesMenuItem = MainFrameStatics.newCheckBoxMenuItem(_detachTabbedPanesAction);
 6604  38 tempDetachTabbedPanesMenuItem.setSelected(DrJava.getConfig().getSetting(DETACH_TABBEDPANES));
 6605  38 _setMenuShortcut(tempDetachTabbedPanesMenuItem, _detachTabbedPanesAction, KEY_DETACH_TABBEDPANES,
 6606    updateKeyboardManager);
 6607  38 panesMenu.add(tempDetachTabbedPanesMenuItem);
 6608  38 if (_detachTabbedPanesMenuItem==null) {
 6609    // assign the first time
 6610  38 _detachTabbedPanesMenuItem = tempDetachTabbedPanesMenuItem;
 6611    }
 6612    else {
 6613    // otherwise link this item to the first item
 6614  0 final WeakReference<JMenuItem> weakRef = new WeakReference<JMenuItem>(tempDetachTabbedPanesMenuItem);
 6615  0 _detachTabbedPanesMenuItem.addItemListener(new ItemListener() {
 6616  0 public void itemStateChanged(ItemEvent e) {
 6617  0 JMenuItem temp = weakRef.get();
 6618  0 if (temp!=null) {
 6619  0 temp.setSelected(_detachTabbedPanesMenuItem.isSelected());
 6620    }
 6621    else {
 6622    // weak reference cleared, remove this listener
 6623  0 _detachTabbedPanesMenuItem.removeItemListener(this);
 6624    }
 6625    }
 6626    });
 6627    }
 6628   
 6629  38 editMenu.add(panesMenu);
 6630   
 6631    // access to configurations GUI
 6632  38 editMenu.addSeparator();
 6633  38 _addMenuItem(editMenu, _editPreferencesAction, KEY_PREFERENCES, updateKeyboardManager);
 6634   
 6635    // Add the menus to the menu bar
 6636  38 return editMenu;
 6637    }
 6638   
 6639    /** Creates and returns a tools menu.
 6640    * @param mask the keystroke modifier to be used
 6641    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6642    */
 6643  38 private JMenu _setUpToolsMenu(int mask, boolean updateKeyboardManager) {
 6644  38 final JMenu toolsMenu = new JMenu("Tools");
 6645  38 PlatformFactory.ONLY.setMnemonic(toolsMenu,KeyEvent.VK_T);
 6646   
 6647    // Compile, Test, Javadoc
 6648  38 _addMenuItem(toolsMenu, _compileAllAction, KEY_COMPILE_ALL, updateKeyboardManager);
 6649  38 _addMenuItem(toolsMenu, _compileAction, KEY_COMPILE, updateKeyboardManager);
 6650  38 _addMenuItem(toolsMenu, _junitAllAction, KEY_TEST_ALL, updateKeyboardManager);
 6651  38 _addMenuItem(toolsMenu, _junitAction, KEY_TEST, updateKeyboardManager);
 6652  38 toolsMenu.addSeparator();
 6653   
 6654    // Run
 6655  38 final int runActionIndex = toolsMenu.getItemCount();
 6656  38 _addMenuItem(toolsMenu, _runAction, KEY_RUN, updateKeyboardManager);
 6657  38 _addMenuItem(toolsMenu, _runAppletAction, KEY_RUN_APPLET, updateKeyboardManager);
 6658  38 _addMenuItem(toolsMenu, _resetInteractionsAction, KEY_RESET_INTERACTIONS, updateKeyboardManager);
 6659  38 toolsMenu.addSeparator();
 6660   
 6661    // Javadoc
 6662  38 final JMenu javadocMenu = new JMenu("Javadoc");
 6663  38 _addMenuItem(javadocMenu, _javadocAllAction, KEY_JAVADOC_ALL, updateKeyboardManager);
 6664  38 _addMenuItem(javadocMenu, _javadocCurrentAction, KEY_JAVADOC_CURRENT, updateKeyboardManager);
 6665  38 javadocMenu.addSeparator();
 6666  38 _addMenuItem(javadocMenu, _openJavadocAction, KEY_OPEN_JAVADOC, updateKeyboardManager);
 6667  38 _addMenuItem(javadocMenu, _openJavadocUnderCursorAction, KEY_OPEN_JAVADOC_UNDER_CURSOR, updateKeyboardManager);
 6668  38 toolsMenu.add(javadocMenu);
 6669   
 6670  38 final JMenu historyMenu = new JMenu("History");
 6671  38 _addMenuItem(historyMenu, _executeHistoryAction, KEY_EXECUTE_HISTORY, updateKeyboardManager);
 6672  38 _addMenuItem(historyMenu, _loadHistoryScriptAction, KEY_LOAD_HISTORY_SCRIPT, updateKeyboardManager);
 6673  38 _addMenuItem(historyMenu, _saveHistoryAction, KEY_SAVE_HISTORY, updateKeyboardManager);
 6674  38 _addMenuItem(historyMenu, _clearHistoryAction, KEY_CLEAR_HISTORY, updateKeyboardManager);
 6675  38 toolsMenu.add(historyMenu);
 6676   
 6677    // Interactions, console
 6678  38 final JMenu interMenu = new JMenu("Interactions & Console");
 6679  38 _addMenuItem(interMenu, _saveInteractionsCopyAction, KEY_SAVE_INTERACTIONS_COPY, updateKeyboardManager);
 6680  38 _addMenuItem(interMenu, _viewInteractionsClassPathAction, KEY_VIEW_INTERACTIONS_CLASSPATH, updateKeyboardManager);
 6681  38 _addMenuItem(interMenu, _copyInteractionToDefinitionsAction, KEY_LIFT_CURRENT_INTERACTION, updateKeyboardManager);
 6682  38 _addMenuItem(interMenu, _printInteractionsAction, KEY_PRINT_INTERACTIONS, updateKeyboardManager);
 6683  38 interMenu.addSeparator();
 6684  38 _addMenuItem(interMenu, _clearConsoleAction, KEY_CLEAR_CONSOLE, updateKeyboardManager);
 6685  38 _addMenuItem(interMenu, _saveConsoleCopyAction, KEY_SAVE_CONSOLE_COPY, updateKeyboardManager);
 6686  38 _addMenuItem(interMenu, _printConsoleAction, KEY_PRINT_CONSOLE, updateKeyboardManager);
 6687  38 _addMenuItem(interMenu, _closeSystemInAction, KEY_CLOSE_SYSTEM_IN, updateKeyboardManager);
 6688  38 if (DrJava.getConfig().getSetting(SHOW_DEBUG_CONSOLE).booleanValue()) {
 6689  0 toolsMenu.add(_showDebugConsoleAction);
 6690    }
 6691  38 toolsMenu.add(interMenu);
 6692   
 6693  38 final JMenu extMenu = new JMenu("External Processes");
 6694  38 _addMenuItem(extMenu, _executeExternalProcessAction, KEY_EXEC_PROCESS, updateKeyboardManager);
 6695  38 final JMenuItem execItem = extMenu.getItem(0);
 6696  38 extMenu.addSeparator();
 6697  38 extMenu.add(_editExternalProcessesAction);
 6698  38 toolsMenu.add(extMenu);
 6699   
 6700  38 final int savedCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_COUNT);
 6701  38 final int namesCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_NAMES).size();
 6702  38 final int cmdlinesCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_CMDLINES).size();
 6703  38 final int workdirsCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_WORKDIRS).size();
 6704  38 final int enclosingFileCount =
 6705    DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_ENCLOSING_DJAPP_FILES).size();
 6706  38 if ((savedCount!=namesCount) ||
 6707    (savedCount!=cmdlinesCount) ||
 6708    (savedCount!=workdirsCount) ||
 6709    (savedCount!=enclosingFileCount)) {
 6710  0 DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_COUNT, 0);
 6711  0 DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_NAMES, new Vector<String>());
 6712  0 DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_CMDLINES, new Vector<String>());
 6713  0 DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_WORKDIRS, new Vector<String>());
 6714  0 DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_ENCLOSING_DJAPP_FILES, new Vector<String>());
 6715    }
 6716   
 6717  38 OptionListener<Integer> externalSavedCountListener =
 6718    new OptionListener<Integer>() {
 6719  38 public void optionChanged(final OptionEvent<Integer> oce) {
 6720  38 extMenu.removeAll();
 6721  38 extMenu.add(execItem);
 6722  38 extMenu.addSeparator();
 6723  38 for (int count=0; count<oce.value; ++count) {
 6724  0 final int i = count;
 6725  0 final Vector<String> names = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_NAMES);
 6726  0 final Vector<String> cmdlines = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_CMDLINES);
 6727  0 final Vector<String> workdirs = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_WORKDIRS);
 6728  0 final Vector<String> enclosingfiles =
 6729    DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_ENCLOSING_DJAPP_FILES);
 6730   
 6731  0 extMenu.insert(new AbstractAction(names.get(i)) {
 6732  0 public void actionPerformed(ActionEvent ae) {
 6733  0 try {
 6734  0 PropertyMaps pm = PropertyMaps.TEMPLATE.clone();
 6735  0 String s = enclosingfiles.get(i).trim();
 6736  0 ((MutableFileProperty) pm.getProperty("enclosing.djapp.file")).
 6737  0 setFile(s.length() > 0 ? new File(s) : null);
 6738  0 _executeExternalDialog.
 6739    runCommand(names.get(i),cmdlines.get(i),workdirs.get(i),enclosingfiles.get(i),pm);
 6740    }
 6741  0 catch(CloneNotSupportedException e) { throw new UnexpectedException(e); }
 6742    }
 6743    },i+2);
 6744    }
 6745  0 if (oce.value > 0) { extMenu.addSeparator(); }
 6746  38 extMenu.add(_editExternalProcessesAction);
 6747  38 _editExternalProcessesAction.setEnabled(true); // always keep enabled, because it allows import
 6748    }
 6749    };
 6750  38 DrJava.getConfig().addOptionListener(OptionConstants.EXTERNAL_SAVED_COUNT, externalSavedCountListener);
 6751  38 externalSavedCountListener.
 6752    optionChanged(new OptionEvent<Integer>(OptionConstants.EXTERNAL_SAVED_COUNT,
 6753    DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_COUNT)));
 6754  38 final JMenu advancedMenu = new JMenu("Advanced");
 6755  38 _addMenuItem(advancedMenu, _generateCustomDrJavaJarAction, KEY_GENERATE_CUSTOM_DRJAVA, updateKeyboardManager);
 6756  38 _addMenuItem(advancedMenu, _newDrJavaInstanceAction, KEY_NEW_DRJAVA_INSTANCE, updateKeyboardManager);
 6757  38 toolsMenu.add(advancedMenu);
 6758   
 6759  38 toolsMenu.addSeparator();
 6760   
 6761  38 _addMenuItem(toolsMenu, _bookmarksPanelAction, KEY_BOOKMARKS_PANEL, updateKeyboardManager);
 6762  38 _addMenuItem(toolsMenu, _toggleBookmarkAction, KEY_BOOKMARKS_TOGGLE, updateKeyboardManager);
 6763   
 6764  38 toolsMenu.addSeparator();
 6765  38 _addMenuItem(toolsMenu, _followFileAction, KEY_FOLLOW_FILE, updateKeyboardManager);
 6766   
 6767    // Add the listener that changes the "Run Main" menu item
 6768  38 OptionListener<Boolean> runMainListener = new OptionListener<Boolean>() {
 6769  38 public void optionChanged(final OptionEvent<Boolean> oce) {
 6770  38 JMenuItem mi = toolsMenu.getItem(runActionIndex);
 6771   
 6772    // change
 6773  38 if (oce.value) {
 6774  38 mi.setText("Run Document");
 6775  38 mi.setToolTipText("Run the current document, regardless of whether it is an applet, an ACM " +
 6776    "Java Task Force program, or a regular Java program with a main method.");
 6777    }
 6778    else {
 6779  0 mi.setText("Run Document's Main Method");
 6780  0 mi.setToolTipText("Run the main method of the current document");
 6781    }
 6782    }
 6783    };
 6784  38 DrJava.getConfig().addOptionListener(OptionConstants.SMART_RUN_FOR_APPLETS_AND_PROGRAMS, runMainListener);
 6785  38 runMainListener.optionChanged(new OptionEvent<Boolean>
 6786    (OptionConstants.SMART_RUN_FOR_APPLETS_AND_PROGRAMS,
 6787    DrJava.getConfig().getSetting(OptionConstants.SMART_RUN_FOR_APPLETS_AND_PROGRAMS)));
 6788   
 6789    // Add the menus to the menu bar
 6790  38 return toolsMenu;
 6791    }
 6792   
 6793    /** Creates and returns a project menu
 6794    * @param mask the keystroke modifier to be used
 6795    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6796    */
 6797  38 private JMenu _setUpProjectMenu(int mask, boolean updateKeyboardManager) {
 6798  38 JMenu projectMenu = new JMenu("Project");
 6799  38 PlatformFactory.ONLY.setMnemonic(projectMenu,KeyEvent.VK_P);
 6800    // New, open
 6801  38 _addMenuItem(projectMenu, _newProjectAction, KEY_NEW_PROJECT, updateKeyboardManager);
 6802  38 _addMenuItem(projectMenu, _openProjectAction, KEY_OPEN_PROJECT, updateKeyboardManager);
 6803   
 6804    //Save
 6805  38 _addMenuItem(projectMenu, _saveProjectAction, KEY_SAVE_PROJECT, updateKeyboardManager);
 6806    //SaveAs
 6807  38 _addMenuItem(projectMenu, _saveProjectAsAction, KEY_SAVE_AS_PROJECT, updateKeyboardManager);
 6808   
 6809    // Close
 6810  38 _addMenuItem(projectMenu, _closeProjectAction, KEY_CLOSE_PROJECT, updateKeyboardManager);
 6811   
 6812  38 projectMenu.addSeparator();
 6813    // run project
 6814  38 _addMenuItem(projectMenu, _compileProjectAction, KEY_COMPILE_PROJECT, updateKeyboardManager);
 6815  38 _addMenuItem(projectMenu, _junitProjectAction, KEY_JUNIT_PROJECT, updateKeyboardManager);
 6816  38 _addMenuItem(projectMenu, _runProjectAction, KEY_RUN_PROJECT, updateKeyboardManager);
 6817  38 _addMenuItem(projectMenu, _cleanAction, KEY_CLEAN_PROJECT, updateKeyboardManager);
 6818  38 _addMenuItem(projectMenu, _autoRefreshAction, KEY_AUTO_REFRESH_PROJECT, updateKeyboardManager);
 6819  38 _addMenuItem(projectMenu, _jarProjectAction, KEY_JAR_PROJECT, updateKeyboardManager);
 6820   
 6821  38 projectMenu.addSeparator();
 6822    // eventually add project options
 6823  38 _addMenuItem(projectMenu, _projectPropertiesAction, KEY_PROJECT_PROPERTIES, updateKeyboardManager);
 6824   
 6825  38 return projectMenu;
 6826    }
 6827   
 6828    /** Creates and returns a debug menu.
 6829    * @param mask the keystroke modifier to be used
 6830    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6831    */
 6832  38 private JMenu _setUpDebugMenu(int mask, boolean updateKeyboardManager) {
 6833  38 JMenu debugMenu = new JMenu("Debugger");
 6834  38 PlatformFactory.ONLY.setMnemonic(debugMenu,KeyEvent.VK_D);
 6835    // Enable debugging item
 6836  38 JMenuItem tempDebuggerEnabledMenuItem = MainFrameStatics.newCheckBoxMenuItem(_toggleDebuggerAction);
 6837  38 tempDebuggerEnabledMenuItem.setSelected(false);
 6838  38 _setMenuShortcut(tempDebuggerEnabledMenuItem, _toggleDebuggerAction, KEY_DEBUG_MODE_TOGGLE, updateKeyboardManager);
 6839  38 debugMenu.add(tempDebuggerEnabledMenuItem);
 6840  38 if (_debuggerEnabledMenuItem==null) {
 6841    // assign the first time
 6842  38 _debuggerEnabledMenuItem = tempDebuggerEnabledMenuItem;
 6843    }
 6844    else {
 6845    // otherwise link this item to the first item
 6846  0 final WeakReference<JMenuItem> weakRef = new WeakReference<JMenuItem>(tempDebuggerEnabledMenuItem);
 6847  0 _debuggerEnabledMenuItem.addItemListener(new ItemListener() {
 6848  0 public void itemStateChanged(ItemEvent e) {
 6849  0 JMenuItem temp = weakRef.get();
 6850  0 if (temp!=null) {
 6851  0 temp.setSelected(_debuggerEnabledMenuItem.isSelected());
 6852    }
 6853    else {
 6854    // weak reference cleared, remove this listener
 6855  0 _debuggerEnabledMenuItem.removeItemListener(this);
 6856    }
 6857    }
 6858    });
 6859    }
 6860   
 6861  38 debugMenu.addSeparator();
 6862   
 6863  38 _addMenuItem(debugMenu, _toggleBreakpointAction, KEY_DEBUG_BREAKPOINT_TOGGLE, updateKeyboardManager);
 6864    //_printBreakpointsMenuItem = debugMenu.add(_printBreakpointsAction);
 6865    //_clearAllBreakpointsMenuItem =
 6866  38 _addMenuItem(debugMenu, _clearAllBreakpointsAction, KEY_DEBUG_CLEAR_ALL_BREAKPOINTS, updateKeyboardManager);
 6867  38 _addMenuItem(debugMenu, _breakpointsPanelAction, KEY_DEBUG_BREAKPOINT_PANEL, updateKeyboardManager);
 6868  38 debugMenu.addSeparator();
 6869   
 6870    //_addMenuItem(debugMenu, _suspendDebugAction, KEY_DEBUG_SUSPEND, updateKeyboardManager);
 6871  38 _addMenuItem(debugMenu, _resumeDebugAction, KEY_DEBUG_RESUME, updateKeyboardManager);
 6872  38 _addMenuItem(debugMenu, _stepIntoDebugAction, KEY_DEBUG_STEP_INTO, updateKeyboardManager);
 6873  38 _addMenuItem(debugMenu, _stepOverDebugAction, KEY_DEBUG_STEP_OVER, updateKeyboardManager);
 6874  38 _addMenuItem(debugMenu, _stepOutDebugAction, KEY_DEBUG_STEP_OUT, updateKeyboardManager);
 6875   
 6876  38 JMenuItem tempAutomaticTraceMenuItem = MainFrameStatics.newCheckBoxMenuItem(_automaticTraceDebugAction);
 6877  38 _setMenuShortcut(tempAutomaticTraceMenuItem, _automaticTraceDebugAction, KEY_DEBUG_AUTOMATIC_TRACE,
 6878    updateKeyboardManager);
 6879  38 debugMenu.add(tempAutomaticTraceMenuItem);
 6880  38 if (_automaticTraceMenuItem==null) {
 6881    // assign the first time
 6882  38 _automaticTraceMenuItem = tempAutomaticTraceMenuItem;
 6883    }
 6884    else {
 6885    // otherwise link this item to the first item
 6886  0 final WeakReference<JMenuItem> weakRef = new WeakReference<JMenuItem>(tempAutomaticTraceMenuItem);
 6887  0 _automaticTraceMenuItem.addItemListener(new ItemListener() {
 6888  0 public void itemStateChanged(ItemEvent e) {
 6889  0 JMenuItem temp = weakRef.get();
 6890  0 if (temp!=null) {
 6891  0 temp.setSelected(_automaticTraceMenuItem.isSelected());
 6892    }
 6893    else {
 6894    // weak reference cleared, remove this listener
 6895  0 _automaticTraceMenuItem.removeItemListener(this);
 6896    }
 6897    }
 6898    });
 6899    }
 6900   
 6901  38 debugMenu.addSeparator();
 6902  38 JMenuItem tempDetachDebugFrameMenuItem = MainFrameStatics.newCheckBoxMenuItem(_detachDebugFrameAction);
 6903  38 tempDetachDebugFrameMenuItem.setSelected(DrJava.getConfig().getSetting(DETACH_DEBUGGER));
 6904  38 _setMenuShortcut(tempDetachDebugFrameMenuItem, _detachDebugFrameAction, KEY_DETACH_DEBUGGER, updateKeyboardManager);
 6905  38 debugMenu.add(tempDetachDebugFrameMenuItem);
 6906  38 if (_detachDebugFrameMenuItem==null) {
 6907    // assign the first time
 6908  38 _detachDebugFrameMenuItem = tempDetachDebugFrameMenuItem;
 6909    }
 6910    else {
 6911    // otherwise link this item to the first item
 6912  0 final WeakReference<JMenuItem> weakRef = new WeakReference<JMenuItem>(tempDetachDebugFrameMenuItem);
 6913  0 _detachDebugFrameMenuItem.addItemListener(new ItemListener() {
 6914  0 public void itemStateChanged(ItemEvent e) {
 6915  0 JMenuItem temp = weakRef.get();
 6916  0 if (temp!=null) {
 6917  0 temp.setSelected(_detachDebugFrameMenuItem.isSelected());
 6918    }
 6919    else {
 6920    // weak reference cleared, remove this listener
 6921  0 _detachDebugFrameMenuItem.removeItemListener(this);
 6922    }
 6923    }
 6924    });
 6925    }
 6926   
 6927    // Start off disabled
 6928  38 _setDebugMenuItemsEnabled(false);
 6929   
 6930    // Add the menu to the menu bar
 6931  38 return debugMenu;
 6932    }
 6933   
 6934    /** Called every time the debug mode checkbox is toggled. The resume and step
 6935    * functions should always be disabled.
 6936    */
 6937  38 private void _setDebugMenuItemsEnabled(boolean isEnabled) {
 6938  38 _debuggerEnabledMenuItem.setSelected(isEnabled);
 6939  38 _guiAvailabilityNotifier.ensureUnavailable(GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED);
 6940  38 if (_showDebugger) { _debugPanel.setAutomaticTraceButtonText(); }
 6941    }
 6942   
 6943    /** Enables and disables the appropriate menu items in the debug menu depending upon the state of the current thread.
 6944    * @param isSuspended is true when the current thread has just been suspended
 6945    * false if the current thread has just been resumed
 6946    */
 6947  0 private void _setThreadDependentDebugMenuItems(boolean isSuspended) {
 6948  0 _guiAvailabilityNotifier.ensureAvailabilityIs(GUIAvailabilityListener.ComponentType.DEBUGGER_SUSPENDED,
 6949    isSuspended);
 6950  0 if (_showDebugger) { _debugPanel.setAutomaticTraceButtonText(); }
 6951    }
 6952   
 6953    /** Creates and returns the language levels menu.
 6954    * @param mask the keystroke modifier to be used
 6955    * @param updateKeyboardManager true if the keyboard manager should be updated; pass true only for MainFrame!
 6956    */
 6957  38 private JMenu _setUpLanguageLevelMenu(int mask, boolean updateKeyboardManager) {
 6958  38 JMenu languageLevelMenu = new JMenu("Language Level");
 6959  38 PlatformFactory.ONLY.setMnemonic(languageLevelMenu,KeyEvent.VK_L);
 6960  38 ButtonGroup group = new ButtonGroup();
 6961   
 6962  38 final Configuration config = DrJava.getConfig();
 6963  38 int currentLanguageLevel = config.getSetting(LANGUAGE_LEVEL);
 6964   
 6965  38 final AbstractAction rbFullJavaAction = new AbstractAction("Full Java") {
 6966  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.LANGUAGE_LEVELS); }
 6967  0 public void actionPerformed(ActionEvent e) {
 6968  0 config.setSetting(LANGUAGE_LEVEL, OptionConstants.FULL_JAVA);
 6969    }
 6970    };
 6971  38 final JRadioButtonMenuItem rbFullJavaMenuItem = new JRadioButtonMenuItem(rbFullJavaAction);
 6972  38 rbFullJavaMenuItem.setToolTipText("Use full Java syntax");
 6973  38 if (currentLanguageLevel != OptionConstants.FUNCTIONAL_JAVA_LEVEL) { rbFullJavaMenuItem.setSelected(true); }
 6974  38 group.add(rbFullJavaMenuItem);
 6975  38 languageLevelMenu.add(rbFullJavaMenuItem);
 6976  38 languageLevelMenu.addSeparator();
 6977   
 6978  38 final AbstractAction rbFunctionalAction = new AbstractAction("Functional Java") {
 6979  38 { _addGUIAvailabilityListener(this, GUIAvailabilityListener.ComponentType.LANGUAGE_LEVELS); }
 6980  0 public void actionPerformed(ActionEvent e) {
 6981  0 config.setSetting(LANGUAGE_LEVEL, OptionConstants.FUNCTIONAL_JAVA_LEVEL);
 6982    <