MainFrame.java

Index Score
edu.rice.cs.drjava.ui
DrJava

View: Reasons, Metrics, Source Code

These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.

MetricDescription
EXEC_COMMENTSComments in executable code
LINE_COMMENTNumber of line comments
SIZESize of the file in bytes
DECL_COMMENTSComments in declarations
CYCLOMATICCyclomatic complexity
FUNCTIONSNumber of function declarations
OPERATORSNumber of operators
PROGRAM_LENGTHHalstead program length
LOGICAL_LINESNumber of statements
OPERANDSNumber of operands
BLOCKSNumber of blocks
EXITSProcedure exits
ELOCEffective lines of code
RETURNSNumber of return points from functions
UNIQUE_OPERANDSNumber of unique operands
LOCLines of code
INTERFACE_COMPLEXITYInterface complexity
LINESNumber of lines in the source file
PROGRAM_VOCABHalstead program vocabulary
PARAMSNumber of formal parameter declarations
COMPARISONSNumber of comparison operators
COMMENTSComment lines
JAVA0034JAVA0034 Missing braces in if statement
WHITESPACENumber of whitespace lines
JAVA0020JAVA0020 Field name does not have required form
DOC_COMMENTNumber of javadoc comment lines
JAVA0018JAVA0018 Method name does not have required form
JAVA0049JAVA0049 Nested block at depth N (maximum: M)
JAVA0108JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
LOOPSNumber of loops
JAVA0177JAVA0177 Variable declaration missing initializer
JAVA0110JAVA0110 Incorrect javadoc: no @return tag
JAVA0077JAVA0077 Private field not used in declaring class
JAVA0117JAVA0117 Missing javadoc: method 'method'
JAVA0173JAVA0173 Unused method parameter
JAVA0171JAVA0171 Unused local variable
JAVA0166JAVA0166 Generic exception caught
JAVA0130JAVA0130 Non-static method does not use instance fields
BLOCK_COMMENTNumber of block comment lines
JAVA0128JAVA0128 Public constructor in non-public class
JAVA0025JAVA0025 Method override is empty
UNIQUE_OPERATORSNumber of unique operators
JAVA0031JAVA0031 Case statement not properly closed
JAVA0076JAVA0076 Use of magic number
JAVA0115JAVA0115 Incorrect javadoc: no @throws or @exception tag for 'exception'
JAVA0265JAVA0265 Use of Throwable.printStackTrace()
JAVA0270JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
JAVA0116JAVA0116 Missing javadoc: field 'field'
JAVA0068JAVA0068 Modifiers not declared in recommended order
JAVA0136JAVA0136 N methods defined in class (maximum: M)
NEST_DEPTHMaximum nesting depth
JAVA0081JAVA0081 Boolean literal in comparison
JAVA0174JAVA0174 Assigned local variable never used
JAVA0106JAVA0106 Unnecessary import from current package
JAVA0080JAVA0080 Import declaration not used
JAVA0022JAVA0022 Static final field name does not have required form
JAVA0287JAVA0287 Unnecessary null check
JAVA0029JAVA0029 Private method not used
JAVA0109JAVA0109 Incorrect javadoc: no parameter 'parameter'
JAVA0061JAVA0061 Inaccessible member in anonymous class
JAVA0170JAVA0170 Caught exception not derived from java.lang.Exception
JAVA0006JAVA0006 Empty finally block
JAVA0111JAVA0111 Incorrect javadoc: @return tag for void method
PROGRAM_VOLUMEHalstead program volume
JAVA0126JAVA0126 Method declares unchecked exception in throws
JAVA0285JAVA0285 Dereference of potentially null variable
JAVA0007JAVA0007 Should not declare public field
JAVA0100JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0254JAVA0254 Use enhanced for loop construct instead of Iterator
JAVA0145JAVA0145 Tab character used in source file
/*BEGIN_COPYRIGHT_BLOCK * * Copyright (c) 2001-2008, JavaPLT group at Rice University (drjava@rice.edu) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software is Open Source Initiative approved Open Source Software. * Open Source Initative Approved is a trademark of the Open Source Initiative. * * This file is part of DrJava. Download the current version of this project * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/ * * END_COPYRIGHT_BLOCK*/ package edu.rice.cs.drjava.ui; import javax.swing.*; import javax.swing.text.*; import javax.swing.event.*; import javax.swing.border.*; import java.awt.event.*; import java.awt.*; import java.awt.print.*; import java.awt.dnd.*; import java.beans.*; import java.io.*; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.LinkedList; import java.util.Map; import java.util.TreeMap; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.net.URL; import java.net.MalformedURLException; import java.awt.datatransfer.*; import java.lang.ref.WeakReference; import edu.rice.cs.drjava.DrJava; import edu.rice.cs.drjava.DrJavaRoot; import edu.rice.cs.drjava.RemoteControlClient; import edu.rice.cs.drjava.platform.*; import edu.rice.cs.drjava.config.*; import edu.rice.cs.drjava.model.*; import edu.rice.cs.drjava.model.ClipboardHistoryModel; import edu.rice.cs.drjava.model.FileSaveSelector; import edu.rice.cs.drjava.model.compiler.CompilerListener; import edu.rice.cs.drjava.model.definitions.NoSuchDocumentException; import edu.rice.cs.drjava.model.definitions.DefinitionsDocument; import edu.rice.cs.drjava.model.definitions.DocumentUIListener; import edu.rice.cs.drjava.model.definitions.CompoundUndoManager; import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException; import edu.rice.cs.drjava.model.definitions.InvalidPackageException; import edu.rice.cs.drjava.model.definitions.reducedmodel.*; import edu.rice.cs.drjava.model.debug.*; import edu.rice.cs.drjava.model.repl.*; import edu.rice.cs.drjava.model.javadoc.JavadocModel; import edu.rice.cs.drjava.ui.config.ConfigFrame; import edu.rice.cs.drjava.ui.predictive.PredictiveInputFrame; import edu.rice.cs.drjava.ui.predictive.PredictiveInputModel; import edu.rice.cs.drjava.ui.ClipboardHistoryFrame; import edu.rice.cs.drjava.ui.RegionsTreePanel; import edu.rice.cs.drjava.project.*; import edu.rice.cs.plt.tuple.Pair; import edu.rice.cs.plt.iter.IterUtil; import edu.rice.cs.plt.io.IOUtil; import edu.rice.cs.plt.lambda.Runnable1; import edu.rice.cs.plt.lambda.Thunk; import edu.rice.cs.util.XMLConfig; import edu.rice.cs.util.FileOpenSelector; import edu.rice.cs.util.FileOps; import edu.rice.cs.util.OperationCanceledException; import edu.rice.cs.util.StringOps; import edu.rice.cs.util.UnexpectedException; import edu.rice.cs.util.classloader.ClassFileError; import edu.rice.cs.util.docnavigation.*; import edu.rice.cs.util.swing.AsyncTask; import edu.rice.cs.util.swing.AsyncTaskLauncher; import edu.rice.cs.util.swing.BorderlessScrollPane; import edu.rice.cs.util.swing.BorderlessSplitPane; import edu.rice.cs.util.swing.ConfirmCheckBoxDialog; import edu.rice.cs.util.swing.DelegatingAction; import edu.rice.cs.util.swing.DirectoryChooser; import edu.rice.cs.util.swing.FileDisplayManager; import edu.rice.cs.util.swing.HighlightManager; import edu.rice.cs.util.swing.RightClickMouseAdapter; import edu.rice.cs.util.swing.SwingFrame; import edu.rice.cs.util.swing.SwingWorker; import edu.rice.cs.util.swing.Utilities; import edu.rice.cs.util.swing.*; import edu.rice.cs.util.text.AbstractDocumentInterface; import static edu.rice.cs.drjava.ui.RecentFileManager.*; import static edu.rice.cs.drjava.config.OptionConstants.*; import static edu.rice.cs.drjava.ui.predictive.PredictiveInputModel.*; import static edu.rice.cs.util.XMLConfig.XMLConfigException; import static edu.rice.cs.plt.object.ObjectUtil.hash; /** DrJava's main window. */ public class MainFrame extends SwingFrame implements ClipboardOwner, DropTargetListener { private static final int INTERACTIONS_TAB = 0; private static final int CONSOLE_TAB = 1; private static final String ICON_PATH = "/edu/rice/cs/drjava/ui/icons/"; private static final String DEBUGGER_OUT_OF_SYNC = " Current document is out of sync with the debugger and should be recompiled!"; /** Number of milliseconds to wait before displaying "Stepping..." message after a step is requested in * the debugger. */ private static final int DEBUG_STEP_TIMER_VALUE = 2000; /** The model which controls all logic in DrJava. */ private final AbstractGlobalModel _model; /** The main model listener attached by the main frame to the global model */ private final ModelListener _mainListener; /** Maps an OpenDefDoc to its JScrollPane. Why doesn't OpenDefDoc contain a defScrollPane field? */ private final HashMap<OpenDefinitionsDocument, JScrollPane> _defScrollPanes; /** The currently displayed DefinitionsPane. */ private volatile DefinitionsPane _currentDefPane; /** The currently displayed DefinitionsDocument. */ private volatile DefinitionsDocument _currentDefDoc; /** The filename currently being displayed. */ private volatile String _fileTitle = ""; // Tabbed panel fields public final LinkedList<TabbedPanel> _tabs = new LinkedList<TabbedPanel>(); public final JTabbedPane _tabbedPane; private final DetachedFrame _tabbedPanesFrame; public volatile Component _lastFocusOwner; private final CompilerErrorPanel _compilerErrorPanel; private final InteractionsPane _consolePane; private final JScrollPane _consoleScroll; // redirects focus to embedded _consolePane private final ConsoleController _consoleController; // move to controller private final InteractionsPane _interactionsPane; private final JPanel _interactionsContainer; // redirects focus to embedded _interactionsPane private final InteractionsController _interactionsController; // move to controller private final JUnitPanel _junitErrorPanel; private final JavadocErrorPanel _javadocErrorPanel; private final FindReplacePanel _findReplace; private final BreakpointsPanel _breakpointsPanel; final BookmarksPanel _bookmarksPanel; private final LinkedList<Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>>> _findResults = new LinkedList<Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>>>(); private volatile boolean _showDebugger; // whether the supporting context is debugger capable private volatile InteractionsScriptController _interactionsScriptController; private volatile InteractionsScriptPane _interactionsScriptPane; private volatile DebugPanel _debugPanel; private final DetachedFrame _debugFrame; /** Panel to hold both InteractionsPane and its sync message. */ // Status bar fields private final JPanel _statusBar = new JPanel(new BorderLayout()); //( layout ); private final JLabel _statusField = new JLabel(); private final JLabel _statusReport = new JLabel(); //("This is the text for the center message"); private final JLabel _currLocationField = new JLabel(); private final PositionListener _posListener = new PositionListener(); // Split panes for layout private final JSplitPane _docSplitPane; private final JSplitPane _debugSplitPane; final JSplitPane _mainSplit; // private Container _docCollectionWidget; private volatile JButton _compileButton; private volatile JButton _closeButton; private volatile JButton _undoButton; private volatile JButton _redoButton; private volatile JButton _runButton; private volatile JButton _junitButton; private JButton _errorsButton; private final JToolBar _toolBar; private final JFileChooser _interactionsHistoryChooser; // Menu fields private final JMenuBar _menuBar; private final JMenu _fileMenu; private final JMenu _editMenu; private final JMenu _toolsMenu; private final JMenu _projectMenu; private final JMenu _languageLevelMenu; private final JMenu _helpMenu; private volatile JMenu _debugMenu; private volatile JMenuItem _debuggerEnabledMenuItem; // Popup menus private JPopupMenu _interactionsPanePopupMenu; private JPopupMenu _consolePanePopupMenu; // Cached frames and dialogs private final ConfigFrame _configFrame; private final HelpFrame _helpFrame; private final QuickStartFrame _quickStartFrame; private final AboutDialog _aboutDialog; private final RecentDocFrame _recentDocFrame; /** Holds/shows the history of documents for ctrl-tab. */ // private ProjectPropertiesFrame _projectPropertiesFrame; /** Keeps track of the recent files list in the File menu. */ private final RecentFileManager _recentFileManager; /** Keeps track of the recent projects list in the Project menu */ private final RecentFileManager _recentProjectManager; private volatile File _currentProjFile; /** Timer to display "Stepping..." message if a step takes longer than a certain amount of time. All accesses * must be synchronized on it. */ private final Timer _debugStepTimer; /** The current highlight displaying the current location, used for FindAll and the of the debugger's thread, * if there is one. If there is none, this is null. */ private volatile HighlightManager.HighlightInfo _currentLocationHighlight = null; /** Table to map breakpoints to their corresponding highlight objects. */ private final IdentityHashMap<Breakpoint, HighlightManager.HighlightInfo> _documentBreakpointHighlights; /** Table to map bookmarks to their corresponding highlight objects. */ private final IdentityHashMap<OrderedDocumentRegion, HighlightManager.HighlightInfo> _documentBookmarkHighlights; /** The timestamp for the last change to any document. */ private volatile long _lastChangeTime = 0; /** Whether to display a prompt message before quitting. */ private volatile boolean _promptBeforeQuit; /** Listener for Interactions JVM */ final private ConfigOptionListeners.SlaveJVMXMXListener _slaveJvmXmxListener; /** Listener for Main JVM */ final private ConfigOptionListeners.MasterJVMXMXListener _masterJvmXmxListener; /** Window adapter for "pseudo-modal" dialogs, i.e. non-modal dialogs that insist on keeping the focus. */ protected java.util.HashMap<Window,WindowAdapter> _modalWindowAdapters = new java.util.HashMap<Window,WindowAdapter>(); /** The owner of the modal window listener has already been taken by another window. */ protected volatile Window _modalWindowAdapterOwner = null; /** For opening files. We have a persistent dialog to keep track of the last directory from which we opened. */ private final JFileChooser _openChooser; /** For opening project files. */ private final JFileChooser _openProjectChooser; /** For saving files. We have a persistent dialog to keep track of the last directory from which we saved. */ private final JFileChooser _saveChooser; /** Filter for regular java files (.java and .j). */ private final javax.swing.filechooser.FileFilter _javaSourceFilter = new JavaSourceFilter(); /** Filter for drjava project files (.xml and .pjt) */ private final javax.swing.filechooser.FileFilter _projectFilter = new javax.swing.filechooser.FileFilter() { public boolean accept(File f) { return f.isDirectory() || f.getPath().endsWith(PROJECT_FILE_EXTENSION) || f.getPath().endsWith(OLD_PROJECT_FILE_EXTENSION); } public String getDescription() { return "DrJava Project Files (*"+PROJECT_FILE_EXTENSION+", *"+OLD_PROJECT_FILE_EXTENSION+")"; } }; /** Filter for any files (*.*) */ private final javax.swing.filechooser.FileFilter _anyFileFilter = new javax.swing.filechooser.FileFilter() { public boolean accept(File f) { return true; } public String getDescription() { return "All files (*.*)"; } }; /** Returns the files to open to the model (command pattern). */ private final FileOpenSelector _openSelector = new FileOpenSelector() { public File[] getFiles() throws OperationCanceledException { //_openChooser.removeChoosableFileFilter(_projectFilter); _openChooser.resetChoosableFileFilters(); _openChooser.setFileFilter(_javaSourceFilter); return getOpenFiles(_openChooser); } }; /** Returns the files to open to the model (command pattern). */ private final FileOpenSelector _openFileOrProjectSelector = new FileOpenSelector() { public File[] getFiles() throws OperationCanceledException { //_openChooser.removeChoosableFileFilter(_projectFilter); _openChooser.resetChoosableFileFilters(); _openChooser.addChoosableFileFilter(_projectFilter); _openChooser.setFileFilter(_javaSourceFilter); return getOpenFiles(_openChooser); } }; /** Returns the project file to open. */ private final FileOpenSelector _openProjectSelector = new FileOpenSelector() { public File[] getFiles() throws OperationCanceledException { File[] retFiles = getOpenFiles(_openProjectChooser); return retFiles; } }; /** Returns the files to open. */ private final FileOpenSelector _openAnyFileSelector = new FileOpenSelector() { public File[] getFiles() throws OperationCanceledException { _openChooser.resetChoosableFileFilters(); _openChooser.setFileFilter(_anyFileFilter); return getOpenFiles(_openChooser); } }; /** Returns the file to save to the model (command pattern). */ private final FileSaveSelector _saveSelector = new FileSaveSelector() { public File getFile() throws OperationCanceledException { return getSaveFile(_saveChooser); } public boolean warnFileOpen(File f) { return _warnFileOpen(f); } public boolean verifyOverwrite() { return _verifyOverwrite(); } public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { _model.setActiveDocument(doc); String text = "File " + oldFile.getAbsolutePath() + "\ncould not be found on disk! It was probably moved\n" + "or deleted. Would you like to save it in a new file?"; int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "File Moved or Deleted", JOptionPane.YES_NO_OPTION); return (rc == JOptionPane.YES_OPTION); } }; /** Returns the file to save to the model (command pattern). */ private final FileSaveSelector _saveAsSelector = new FileSaveSelector() { public File getFile() throws OperationCanceledException { return getSaveFile(_saveChooser); } public boolean warnFileOpen(File f) { return _warnFileOpen(f); } public boolean verifyOverwrite() { return _verifyOverwrite(); } public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; } }; /** Provides the view's contribution to the Javadoc interaction. */ private final JavadocDialog _javadocSelector = new JavadocDialog(this); /** Provides a chooser to open a directory */ private final DirectoryChooser _folderChooser; private final JCheckBox _openRecursiveCheckBox; private final Action _moveToAuxiliaryAction = new AbstractAction("Include With Project") { { /* initalization block */ String msg = "<html>Open this document each time this project is opened.<br>"+ "This file would then be compiled and tested with the<br>"+ "rest of the project.</html>"; putValue(Action.SHORT_DESCRIPTION, msg); } public void actionPerformed(ActionEvent ae) { _moveToAuxiliary(); } }; private final Action _removeAuxiliaryAction = new AbstractAction("Do Not Include With Project") { { putValue(Action.SHORT_DESCRIPTION, "Do not open this document next time this project is opened."); } public void actionPerformed(ActionEvent ae) { _removeAuxiliary(); } }; private final Action _moveAllToAuxiliaryAction = new AbstractAction("Include All With Project") { { /* initalization block */ String msg = "<html>Open these documents each time this project is opened.<br>"+ "These files would then be compiled and tested with the<br>"+ "rest of the project.</html>"; putValue(Action.SHORT_DESCRIPTION, msg); } public void actionPerformed(ActionEvent ae) { _moveAllToAuxiliary(); } }; private final Action _removeAllAuxiliaryAction = new AbstractAction("Do Not Include Any With Project") { { putValue(Action.SHORT_DESCRIPTION, "Do not open these documents next time this project is opened."); } public void actionPerformed(ActionEvent ae) { _removeAllAuxiliary(); } }; /** Creates a new blank document and select it in the definitions pane. */ private final Action _newAction = new AbstractAction("New") { public void actionPerformed(ActionEvent ae) { // System.out.println("------------------new----------------------"); _new(); } }; private final Action _newProjectAction = new AbstractAction("New") { public void actionPerformed(ActionEvent ae) { _newProject(); } }; private volatile AbstractAction _runProjectAction = new AbstractAction("Run Main Document of Project") { public void actionPerformed(ActionEvent ae) { _runProject(); } }; /** The jar options dialog. */ private final JarOptionsDialog _jarOptionsDialog; /** Initializes the "Create Jar from Project" dialog. */ private void initJarOptionsDialog() { if (DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue()) _jarOptionsDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STATE)); } /** Reset the position of the "Create Jar from Project" dialog. */ public void resetJarOptionsDialogPosition() { _jarOptionsDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_JAROPTIONS_STATE, "default"); } } private final Action _jarProjectAction = new AbstractAction("Create Jar File from Project...") { public void actionPerformed(ActionEvent ae) { _jarOptionsDialog.setVisible(true); } }; /** Initializes the "Tabbed Panes" frame. */ private void initTabbedPanesFrame() { if (DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STORE_POSITION).booleanValue()) { _tabbedPanesFrame.setFrameState(DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STATE)); } } /** Reset the position of the "Tabbed Panes" dialog. */ public void resetTabbedPanesFrame() { _tabbedPanesFrame.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_TABBEDPANES_STATE, "default"); } } /** Action that detaches the tabbed panes. Only runs in the event thread. */ private final Action _detachTabbedPanesAction = new AbstractAction("Detach Tabbed Panes") { public void actionPerformed(ActionEvent ae) { JMenuItem m = (JMenuItem)ae.getSource(); boolean b = m.isSelected(); DrJava.getConfig().setSetting(DETACH_TABBEDPANES, b); _tabbedPanesFrame.setDisplayInFrame(b); } }; // menu item (checkbox menu) for detaching the tabbed panes private JMenuItem _detachTabbedPanesMenuItem; /** Initializes the "Debugger" frame. */ private void initDebugFrame() { if (_debugFrame==null) return; // debugger isn't used if (DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STORE_POSITION).booleanValue()) { _debugFrame.setFrameState(DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STATE)); } } /** Reset the position of the "Debugger" dialog. */ public void resetDebugFrame() { if (_debugFrame==null) return; // debugger isn't used _debugFrame.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_DEBUGFRAME_STATE, "default"); } } /** Action that detaches the debugger pane. Only runs in the event thread. */ private final Action _detachDebugFrameAction = new AbstractAction("Detach Debugger") { public void actionPerformed(ActionEvent ae) { if (_debugFrame==null) return; // debugger isn't used JMenuItem m = (JMenuItem)ae.getSource(); boolean b = m.isSelected(); DrJava.getConfig().setSetting(DETACH_DEBUGGER, b); _debugFrame.setDisplayInFrame(b); } }; // menu item (checkbox menu) for detaching the debugger pane private JMenuItem _detachDebugFrameMenuItem; /** Sets the document in the definitions pane to a new templated junit test class. */ private final Action _newJUnitTestAction = new AbstractAction("New JUnit Test Case...") { public void actionPerformed(ActionEvent ae) { String testName = JOptionPane.showInputDialog(MainFrame.this, "Please enter a name for the test class:", "New JUnit Test Case", JOptionPane.QUESTION_MESSAGE); if (testName != null) { String ext; for(int i=0; i < DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS.length; i++) { ext = "." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[i]; if (testName.endsWith(ext)) testName = testName.substring(0, testName.length() - ext.length()); } // For now, don't include setUp and tearDown _model.newTestCase(testName, false, false); } } }; /** Asks user for file name and and reads that file into the definitions pane. */ private final Action _openAction = new AbstractAction("Open...") { public void actionPerformed(ActionEvent ae) { _open(); _findReplace.updateFirstDocInSearch(); } }; /** Asks user for directory name and and reads it's files (and subdirectories files, on request) to * the definitions pane. */ private final Action _openFolderAction = new AbstractAction("Open Folder...") { public void actionPerformed(ActionEvent ae) { _openFolder(); _findReplace.updateFirstDocInSearch(); } }; /** Asks user for file name and and reads that file into the definitions pane. */ private final Action _openFileOrProjectAction = new AbstractAction("Open...") { public void actionPerformed(ActionEvent ae) { _openFileOrProject(); _findReplace.updateFirstDocInSearch(); } }; /** Asks user for project file name and and reads the associated files into the file navigator (and places the first * source file in the editor pane) */ private final Action _openProjectAction = new AbstractAction("Open...") { public void actionPerformed(ActionEvent ae) { _openProject(); } }; private final Action _closeProjectAction = new AbstractAction("Close") { public void actionPerformed(ActionEvent ae) { closeProject(); _findReplace.updateFirstDocInSearch(); } }; /** Closes the current active document, prompting to save if necessary. */ private final Action _closeAction = new AbstractAction("Close") { public void actionPerformed(ActionEvent ae) { _close(); _findReplace.updateFirstDocInSearch(); } }; /** Closes all open documents, prompting to save if necessary. */ private final Action _closeAllAction = new AbstractAction("Close All") { public void actionPerformed(ActionEvent ae) { _closeAll(); _findReplace.updateFirstDocInSearch(); } }; /** Closes all open documents, prompting to save if necessary. */ private final Action _closeFolderAction = new AbstractAction("Close Folder") { public void actionPerformed(ActionEvent ae) { _closeFolder(); _findReplace.updateFirstDocInSearch(); // set the document currently visible in the definitions pane as active // document in the document navigator // this makes sure that something is selected in the navigator after the // folder was closed _model.getDocumentNavigator().setActiveDoc(_currentDefPane.getOpenDefDocument()); } }; /** Opens all the files in the current folder. */ private final Action _openAllFolderAction = new AbstractAction("Open All Files") { public void actionPerformed(ActionEvent ae) { // now works with multiple selected folders java.util.List<File> l= _model.getDocumentNavigator().getSelectedFolders(); for(File f: l) { File fAbs = new File(_model.getProjectRoot(), f.toString()); _openFolder(fAbs, false); } // The following does not apply anymore: // Get the Folder that was clicked on by the user. When the user clicks on a directory component in the // navigation pane, the current directory is updated in the openChooser JFileChooser component. So the // clicked on directory is obtained in this way // File dir = _openChooser.getCurrentDirectory(); // _openFolder(dir, false); _findReplace.updateFirstDocInSearch(); } }; /** Opens a files in the current folder. */ private final Action _openOneFolderAction = new AbstractAction("Open File in Folder") { public void actionPerformed(ActionEvent ae) { _open(); _findReplace.updateFirstDocInSearch(); } }; /** Creates a new untitled, empty file in the current folder. */ public final Action _newFileFolderAction = new AbstractAction("Create New File in Folder") { public void actionPerformed(ActionEvent ae) { //make this new document the document in the document pane _new(); _findReplace.updateFirstDocInSearch(); } }; /** Tests all the files in a folder. */ private volatile AbstractAction _junitFolderAction = new AbstractAction("Test Folder") { public final void actionPerformed(ActionEvent ae) { _junitFolder(); } }; /** Saves the current document. */ private final Action _saveAction = new AbstractAction("Save") { public final void actionPerformed(ActionEvent ae) { _save(); } }; /** Returns the changed status of the MainFrame. */ public long getLastChangeTime() { return _lastChangeTime; } /** Ensures that pack() is run in the event thread. Only used in test code */ public void pack() { Utilities.invokeAndWait(new Runnable() { public void run() { packHelp(); } }); } /** Helper method that provides access to super.pack() within the anonymous class new Runnable() {...} above */ private void packHelp() { super.pack(); } /** Supports MainFrameTest.*/ public boolean saveEnabledHuh() { return _saveAction.isEnabled(); } /** Asks the user for a file name and saves the active document (in the definitions pane) to that file. */ private final Action _saveAsAction = new AbstractAction("Save As...") { public void actionPerformed(ActionEvent ae) { _saveAs(); } }; /** Asks the user for a file name and renames and saves the active document (in the definitions pane) to that file. */ private final Action _renameAction = new AbstractAction("Rename") { public void actionPerformed(ActionEvent ae) { _rename(); } }; private final Action _saveProjectAction = new AbstractAction("Save") { public void actionPerformed(ActionEvent ae) { _saveAll(); // saves project file and all modified project source files; does not save external files } }; private final Action _saveProjectAsAction = new AbstractAction("Save As...") { public void actionPerformed(ActionEvent ae) { if (_saveProjectAs()) { // asks user for new project file name; sets _projectFile in global model to this value _saveAll(); // performs saveAll operation using new project file name, assuming "Save as" was not cancelled } } }; private final Action _exportProjectInOldFormatAction = new AbstractAction("Export Project In Old \"" + OLD_PROJECT_FILE_EXTENSION + "\" Format") { public void actionPerformed(ActionEvent ae) { File cpf = _currentProjFile; _currentProjFile = FileOps.NULL_FILE; if (_saveProjectAs()) { // asks user for new project file name; sets _projectFile in global model to this value _saveAllOld(); // performs saveAll operation using new project file name, assuming "Save as" was not cancelled } _currentProjFile = cpf; _model.setProjectFile(cpf); _recentProjectManager.updateOpenFiles(cpf); } }; /** Reverts the current document. */ private final Action _revertAction = new AbstractAction("Revert to Saved") { public void actionPerformed(ActionEvent ae) { String title = "Revert to Saved?"; // update message to reflect the number of files int count = _model.getDocumentNavigator().getDocumentSelectedCount(); String message; if (count==1) { message = "Are you sure you want to revert the current " + "file to the version on disk?"; } else { message = "Are you sure you want to revert the " + count + " selected files to the versions on disk?"; } int rc; String fileName = null; Object[] options = {"Yes", "No"}; rc = JOptionPane.showOptionDialog(MainFrame.this, message, title, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (rc == JOptionPane.YES_OPTION) { _revert(); } } }; /** Reverts all open documents. * (not working yet) private Action _revertAllAction = new AbstractAction("Revert All to Saved") { public void actionPerformed(ActionEvent ae) { String title = "Revert All to Saved?"; String message = "Are you sure you want to revert all open " + "files to the versions on disk?"; int rc = JOptionPane.showConfirmDialog(MainFrame.this, message, title, JOptionPane.YES_NO_OPTION); if (rc == JOptionPane.YES_OPTION) { _revertAll(); } } };*/ /** Saves all documents, prompting for file names as necessary. */ final Action _saveAllAction = new AbstractAction("Save All") { public void actionPerformed(ActionEvent ae) { _saveAll(); } }; /** Prints the current document. */ private final Action _printDefDocAction = new AbstractAction("Print...") { public void actionPerformed(ActionEvent ae) { _printDefDoc(); } }; /** Prints the console document. */ private final Action _printConsoleAction = new AbstractAction("Print Console...") { public void actionPerformed(ActionEvent ae) { _printConsole(); } }; /** Prints the interactions document. */ private final Action _printInteractionsAction = new AbstractAction("Print Interactions...") { public void actionPerformed(ActionEvent ae) { _printInteractions(); } }; /** Opens the print preview window. */ private final Action _printDefDocPreviewAction = new AbstractAction("Print Preview...") { public void actionPerformed(ActionEvent ae) { _printDefDocPreview(); } }; /** Opens the print preview window. */ private final Action _printConsolePreviewAction = new AbstractAction("Print Preview...") { public void actionPerformed(ActionEvent ae) { _printConsolePreview(); } }; /** Opens the print preview window. */ private final Action _printInteractionsPreviewAction = new AbstractAction("Print Preview...") { public void actionPerformed(ActionEvent ae) { _printInteractionsPreview(); } }; /** Opens the page setup window. */ private final Action _pageSetupAction = new AbstractAction("Page Setup...") { public void actionPerformed(ActionEvent ae) { _pageSetup(); } }; // /** Compiles all the project. */ // private Action _compileOpenProjectAction = new AbstractAction("Compile Open Project Files") { // public void actionPerformed(ActionEvent ae) { _compileAll(); } // right now, it's the same as compile all // }; /** Compiles the document in the definitions pane. */ private final Action _compileAction = new AbstractAction("Compile Current Document") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); updateStatusField("Compiling " + _fileTitle); _compile(); updateStatusField("Compilation of current document completed"); } }; /** Compiles all the project. */ private volatile AbstractAction _compileProjectAction = new AbstractAction("Compile Project") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); updateStatusField("Compiling all source files in open project"); _compileProject(); _findReplace.updateFirstDocInSearch(); updateStatusField("Compilation of open project completed"); } }; /** Compiles all documents in the navigators active group. */ private volatile AbstractAction _compileFolderAction = new AbstractAction("Compile Folder") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); updateStatusField("Compiling all sources in current folder"); _compileFolder(); _findReplace.updateFirstDocInSearch(); updateStatusField("Compilation of folder completed"); } }; /** Compiles all open documents. */ private volatile AbstractAction _compileAllAction = new AbstractAction("Compile All Documents") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); _compileAll(); _findReplace.updateFirstDocInSearch(); } }; /** cleans the build directory */ private volatile AbstractAction _cleanAction = new AbstractAction("Clean Build Directory") { public void actionPerformed(ActionEvent ae) { _clean(); } }; /** auto-refresh the project and open new files */ private volatile AbstractAction _autoRefreshAction = new AbstractAction("Auto-Refresh Project") { public void actionPerformed(ActionEvent ae) { _model.autoRefreshProject(); } }; /** Finds and runs the main method of the current document, if it exists. */ private volatile AbstractAction _runAction = new AbstractAction("Run Document's Main Method") { public void actionPerformed(ActionEvent ae) { _runMain(); } }; /** Runs JUnit on the document in the definitions pane. */ private volatile AbstractAction _junitAction = new AbstractAction("Test Current Document") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); _junit(); } }; /** Runs JUnit over all open JUnit tests. */ private volatile AbstractAction _junitAllAction = new AbstractAction("Test All Documents") { public void actionPerformed(ActionEvent e) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); _junitAll(); _findReplace.updateFirstDocInSearch(); } }; /** Runs JUnit over all open JUnit tests in the project directory. */ private volatile AbstractAction _junitProjectAction = new AbstractAction("Test Project") { public void actionPerformed(ActionEvent e) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); _junitProject(); _findReplace.updateFirstDocInSearch(); } }; // /** JUnit a directory. */ // private final Action _junitProjectAction = new AbstractAction("Test Project") { // public void actionPerformed(ActionEvent e) { // new Thread("Running JUnit Tests") { // public void run() { // if (_model.isProjectActive()) { // try { // // hourglassOn(); // also done in junitStarted // _model.junitAll(); // } // finally { // // hourglassOff(); // also done in junitEnded // } // } // } // }.start(); // } // }; /** Runs Javadoc on all open documents (and the files in their packages). */ private final Action _javadocAllAction = new AbstractAction("Javadoc All Documents") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); try { // hourglassOn(); JavadocModel jm = _model.getJavadocModel(); File suggestedDir = jm.suggestJavadocDestination(_model.getActiveDocument()); _javadocSelector.setSuggestedDir(suggestedDir); jm.javadocAll(_javadocSelector, _saveSelector); } catch (IOException ioe) { _showIOError(ioe); } finally { // hourglassOff(); } } }; /** Runs Javadoc on the current document. */ private final Action _javadocCurrentAction = new AbstractAction("Preview Javadoc for Current Document") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); try { _model.getActiveDocument().generateJavadoc(_saveSelector); } catch (IOException ioe) { _showIOError(ioe); } } }; /** Default cut action. Returns focus to the correct pane. */ final Action cutAction = new DefaultEditorKit.CutAction() { public void actionPerformed(ActionEvent e) { Component c = MainFrame.this.getFocusOwner(); super.actionPerformed(e); if (_currentDefPane.hasFocus()) { String s = Utilities.getClipboardSelection(c); if (s != null && s.length() != 0) { ClipboardHistoryModel.singleton().put(s); } } if (c != null) c.requestFocusInWindow(); } }; /** Default copy action. Returns focus to the correct pane. */ final Action copyAction = new DefaultEditorKit.CopyAction() { public void actionPerformed(ActionEvent e) { Component c = MainFrame.this.getFocusOwner(); super.actionPerformed(e); if (_currentDefPane.hasFocus() && _currentDefPane.getSelectedText() != null) { String s = Utilities.getClipboardSelection(c); if (s != null && s.length() != 0) { ClipboardHistoryModel.singleton().put(s); } } if (c != null) c.requestFocusInWindow(); } }; /** We lost ownership of what we put in the clipboard. */ public void lostOwnership(Clipboard clipboard, Transferable contents) { // ignore } /** Default paste action. Returns focus to the correct pane. */ final Action pasteAction = new DefaultEditorKit.PasteAction() { public void actionPerformed(ActionEvent e) { Component c = MainFrame.this.getFocusOwner(); if (_currentDefPane.hasFocus()) { _currentDefPane.endCompoundEdit(); // CompoundUndoManager undoMan = _model.getActiveDocument().getUndoManager(); // French keyboard fix // int key = undoMan.startCompoundEdit(); // French keyboard fix super.actionPerformed(e); _currentDefPane.endCompoundEdit(); // replaced line below for French keyboard fix // undoMan.endCompoundEdit(key); // French keyboard fix } else super.actionPerformed(e); if (c != null) c.requestFocusInWindow(); } }; /** Reset the position of the "Clipboard History" dialog. */ public void resetClipboardHistoryDialogPosition() { if (DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, "default"); } } /** The "Clipboard History" dialog. */ private ClipboardHistoryFrame _clipboardHistoryDialog = null; /** Asks the user for a file name and goes there. */ private final Action _pasteHistoryAction = new AbstractAction("Paste from History...") { public void actionPerformed(final ActionEvent ae) { final ClipboardHistoryFrame.CloseAction cancelAction = new ClipboardHistoryFrame.CloseAction() { public Object value(String s) { // "Clipboard History" dialog position and size. if ((DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) && (_clipboardHistoryDialog != null) && (_clipboardHistoryDialog.getFrameState() != null)) { DrJava.getConfig(). setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, (_clipboardHistoryDialog.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. DrJava.getConfig().setSetting(DIALOG_CLIPBOARD_HISTORY_STATE, DIALOG_CLIPBOARD_HISTORY_STATE.getDefault()); } return null; } }; ClipboardHistoryFrame.CloseAction okAction = new ClipboardHistoryFrame.CloseAction() { public Object value(String s) { cancelAction.value(null); StringSelection ssel = new StringSelection(s); Clipboard cb = MainFrame.this.getToolkit().getSystemClipboard(); if (cb != null) { cb.setContents(ssel, MainFrame.this); pasteAction.actionPerformed(ae); } return null; } }; _clipboardHistoryDialog = new ClipboardHistoryFrame(MainFrame.this, "Clipboard History", ClipboardHistoryModel.singleton(), okAction, cancelAction); if (DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) { _clipboardHistoryDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_CLIPBOARD_HISTORY_STATE)); } _clipboardHistoryDialog.setVisible(true); } }; /** Copies whatever is currently in the interactions pane at the prompt to the definitions pane. If the * current string is empty, then it will attempt to return the last entry from the interactions pane's history. */ private final Action _copyInteractionToDefinitionsAction = new AbstractAction("Lift Current Interaction to Definitions") { public void actionPerformed(ActionEvent a) { String text = _interactionsController.getDocument().getCurrentInput(); if (! text.equals("")) { _putTextIntoDefinitions(text + "\n"); return; } try { text = _interactionsController.getDocument().lastEntry(); } catch(Exception e) { return; } // no entry to promote //It is assumed that empty strings are not put into the history _putTextIntoDefinitions(text + "\n"); return; } }; /** Action that copies the previous interaction to the definitions pane. * Is there a good way to get the last history element without perturbing the current document? Action copyPreviousInteractionToDefinitionsAction = new AbstractAction("Copy previous interaction to definitions") { public void actionPerformed(ActionEvent e) { _putTextIntoDefinitions(_interactionsController.getDocument().getCurrentInput() + "\n"); } };*/ /** Undoes the last change to the active definitions document. */ private final DelegatingAction _undoAction = new DelegatingAction() { public void actionPerformed(ActionEvent e) { _currentDefPane.endCompoundEdit(); super.actionPerformed(e); _currentDefPane.requestFocusInWindow(); OpenDefinitionsDocument doc = _model.getActiveDocument(); // Utilities.showDebug("isModifiedSinceSave() = " + doc.isModifiedSinceSave()); _saveAction.setEnabled(doc.isModifiedSinceSave() || doc.isUntitled()); // Utilities.showDebug("check status"); } }; /** Redoes the last undo to the active definitions document. */ private final DelegatingAction _redoAction = new DelegatingAction() { public void actionPerformed(ActionEvent e) { super.actionPerformed(e); _currentDefPane.requestFocusInWindow(); OpenDefinitionsDocument doc = _model.getActiveDocument(); _saveAction.setEnabled(doc.isModifiedSinceSave() || doc.isUntitled()); } }; /** Quits DrJava. Optionally displays a prompt before quitting. */ private final Action _quitAction = new AbstractAction("Quit") { public void actionPerformed(ActionEvent ae) { _quit(); } }; /** Quits DrJava. Optionally displays a prompt before quitting. */ private final Action _forceQuitAction = new AbstractAction("Force Quit") { public void actionPerformed(ActionEvent ae) { _forceQuit(); } }; /** Selects all text in window. */ private final Action _selectAllAction = new AbstractAction("Select All") { public void actionPerformed(ActionEvent ae) { _selectAll(); } }; /** Shows the find/replace tab in the interactions pane. Only executes in the event thread. */ private void _showFindReplaceTab(boolean showDetachedWindow) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); final boolean wasDisplayed = isDisplayed(_findReplace); showTab(_findReplace, showDetachedWindow); if (!wasDisplayed) { _findReplace.beginListeningTo(_currentDefPane); } _findReplace.setVisible(true); _tabbedPane.setSelectedComponent(_findReplace); } /** Action that shows the find/replace tab. Only executes in the event thread. */ private final Action _findReplaceAction = new AbstractAction("Find/Replace") { public void actionPerformed(ActionEvent ae) { _showFindReplaceTab(true); _findReplace.requestFocusInWindow(); // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected EventQueue.invokeLater(new Runnable() { public void run() { _findReplace.requestFocusInWindow(); } }); } }; /** Find the next instance of the find word. */ private final Action _findNextAction = new AbstractAction("Find Next") { public void actionPerformed(ActionEvent ae) { _showFindReplaceTab(false); if (!DrJava.getConfig().getSetting(FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) { // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected EventQueue.invokeLater(new Runnable() { public void run() { _findReplace.requestFocusInWindow(); } }); } _findReplace.findNext(); _currentDefPane.requestFocusInWindow(); // atempt to fix intermittent bug where _currentDefPane listens but does not echo and won't undo! } }; /** Does the find next in the opposite direction. If the direction is backward it searches forward. */ private final Action _findPrevAction = new AbstractAction("Find Previous") { public void actionPerformed(ActionEvent ae) { _showFindReplaceTab(false); if (!DrJava.getConfig().getSetting(FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) { // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected EventQueue.invokeLater(new Runnable() { public void run() { _findReplace.requestFocusInWindow(); } }); } _findReplace.findPrevious(); _currentDefPane.requestFocusInWindow(); } }; /** Asks the user for a line number and goes there. */ private final Action _gotoLineAction = new AbstractAction("Go to Line...") { public void actionPerformed(ActionEvent ae) { int pos = _gotoLine(); _currentDefPane.requestFocusInWindow(); if (pos != -1) _currentDefPane.setCaretPosition(pos); // The preceding is a brute force attempt to fix intermittent failure to display caret } }; private static abstract class ClassNameAndPackageEntry implements Comparable<ClassNameAndPackageEntry> { /** Return the simple class name, e.g. "Integer". */ public abstract String getClassName(); /** Return the full package including the last period, e.g. "java.lang.". */ public abstract String getFullPackage(); public int compareTo(ClassNameAndPackageEntry other) { int res = getClassName().toLowerCase().compareTo(other.getClassName().toLowerCase()); if (res != 0) { return res; } return getFullPackage().toLowerCase().compareTo(other.getFullPackage().toLowerCase()); } // WARNING: this relation is finer grained that the equivalance relation induced by compareTo above public boolean equals(Object other) { if (other == null || ! (other instanceof ClassNameAndPackageEntry)) return false; // multiple subclasses defined ClassNameAndPackageEntry o = (ClassNameAndPackageEntry) other; return (getClassName().equals(o.getClassName()) && getFullPackage().equals(o.getFullPackage())); } public int hashCode() { return hash(getClassName(), getFullPackage()); } } /** Wrapper class for the "Go to File" and "Auto-Complete" dialog list entries. * Provides the ability to have the same OpenDefinitionsDocument in there multiple * times with different toString() results. */ public static class GoToFileListEntry extends ClassNameAndPackageEntry { public final OpenDefinitionsDocument doc; protected String fullPackage = null; protected final String str; public GoToFileListEntry(OpenDefinitionsDocument d, String s) { doc = d; str = s; } public String getFullPackage() { if (fullPackage != null) { return fullPackage; } fullPackage = ""; if (doc!=null) { try { fullPackage = doc.getPackageName(); if (fullPackage.length() > 0) { fullPackage += '.'; } } catch(Exception e) { fullPackage = ""; } } return fullPackage; } public String getClassName() { return str; } public String toString() { return str; } } /** Reset the position of the "Go to File" dialog. */ public void resetGotoFileDialogPosition() { initGotoFileDialog(); _gotoFileDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_GOTOFILE_STATE, "default"); } } /** Initialize dialog if necessary. */ void initGotoFileDialog() { if (_gotoFileDialog == null) { PredictiveInputFrame.InfoSupplier<GoToFileListEntry> info = new PredictiveInputFrame.InfoSupplier<GoToFileListEntry>() { public String value(GoToFileListEntry entry) { final StringBuilder sb = new StringBuilder(); if (entry.doc != null) { try { try { sb.append(FileOps.stringMakeRelativeTo(entry.doc.getRawFile(), entry.doc.getSourceRoot())); } catch(IOException e) { sb.append(entry.doc.getFile()); } } catch(edu.rice.cs.drjava.model.FileMovedException e) { sb.append(entry + " was moved"); } catch(java.lang.IllegalStateException e) { sb.append(entry); } catch(InvalidPackageException e) { sb.append(entry); } } else sb.append(entry); return sb.toString(); } }; PredictiveInputFrame.CloseAction<GoToFileListEntry> okAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() { public String getName() { return "OK"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<GoToFileListEntry> p) { if (p.getItem() != null) { final OpenDefinitionsDocument newDoc = p.getItem().doc; final boolean docChanged = ! newDoc.equals(_model.getActiveDocument()); final boolean docSwitch = _model.getActiveDocument() != newDoc; if (docSwitch) _model.setActiveDocument(newDoc); final int curLine = newDoc.getCurrentLine(); final String t = p.getText(); final int last = t.lastIndexOf(':'); if (last >= 0) { try { String end = t.substring(last + 1); int val = Integer.parseInt(end); final int lineNum = Math.max(1, val); Runnable command = new Runnable() { public void run() { try { _jumpToLine(lineNum); } // adds this region to browser history catch (RuntimeException e) { _jumpToLine(curLine); } } }; if (docSwitch) { // postpone running command until after document switch, which is pending in the event queue EventQueue.invokeLater(command); } else command.run(); } catch(RuntimeException e) { /* ignore */ } } else if (docChanged) { // defer executing this code until after active document switch (if any) is complete addToBrowserHistory(); } } hourglassOff(); return null; } }; PredictiveInputFrame.CloseAction<GoToFileListEntry> cancelAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() { public String getName() { return "Cancel"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<GoToFileListEntry> p) { hourglassOff(); return null; } }; java.util.ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>> strategies = new java.util.ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>>(); strategies.add(new PredictiveInputModel.FragmentLineNumStrategy<GoToFileListEntry>()); strategies.add(new PredictiveInputModel.PrefixLineNumStrategy<GoToFileListEntry>()); strategies.add(new PredictiveInputModel.RegExLineNumStrategy<GoToFileListEntry>()); List<PredictiveInputFrame.CloseAction<GoToFileListEntry>> actions = new ArrayList<PredictiveInputFrame.CloseAction<GoToFileListEntry>>(); actions.add(okAction); actions.add(cancelAction); _gotoFileDialog = new PredictiveInputFrame<GoToFileListEntry>(MainFrame.this, "Go to File", true, // force true, // ignore case info, strategies, actions, 1, // cancel is action 1 new GoToFileListEntry(null, "dummyGoto")) { public void setOwnerEnabled(boolean b) { if (b) { hourglassOff(); } else { hourglassOn(); } } }; // putting one dummy entry in the list; it will be changed later anyway if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) { _gotoFileDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STATE)); } } } /** The "Go to File" dialog instance. */ volatile PredictiveInputFrame<GoToFileListEntry> _gotoFileDialog = null; /** Action implementing "Go to file" command, which asks the user for a file name and goes there. */ private final Action _gotoFileAction = new AbstractAction("Go to File...") { public void actionPerformed(ActionEvent ae) { initGotoFileDialog(); List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments(); if (docs == null || docs.size() == 0) { return; // do nothing } GoToFileListEntry currentEntry = null; ArrayList<GoToFileListEntry> list; if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) { list = new ArrayList<GoToFileListEntry>(2 * docs.size()); } else { list = new ArrayList<GoToFileListEntry>(docs.size()); } for(OpenDefinitionsDocument d: docs) { GoToFileListEntry entry = new GoToFileListEntry(d, d.toString()); if (d.equals(_model.getActiveDocument())) currentEntry = entry; list.add(entry); if (DrJava.getConfig().getSetting(DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) { try { try { String relative = FileOps.stringMakeRelativeTo(d.getFile(), d.getSourceRoot()); if (!relative.equals(d.toString())) { list.add(new GoToFileListEntry(d, d.getPackageName() + "." + d.toString())); } } catch(IOException e) { /* ignore */ } catch(edu.rice.cs.drjava.model.definitions.InvalidPackageException e) { /* ignore */ } } catch(IllegalStateException e) { /* ignore */ } } } _gotoFileDialog.setItems(true, list); // ignore case if (currentEntry != null) _gotoFileDialog.setCurrentItem(currentEntry); hourglassOn(); // Where is the corresponding hourglassOff()? /* if (! Utilities.TEST_MODE) */ _gotoFileDialog.setVisible(true); } }; /** Goes to the file specified by the word the cursor is on. */ void _gotoFileUnderCursor() { // Utilities.show("Calling gotoFileUnderCursor()"); OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); String mask = ""; int loc = getCurrentDefPane().getCaretPosition(); String s = odd.getText(); // find start int start = loc; while(start>0) { if (! Character.isJavaIdentifierPart(s.charAt(start-1))) { break; } --start; } while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start<loc)) { ++start; } // find end int end = loc-1; while(end<s.length()-1) { if (! Character.isJavaIdentifierPart(s.charAt(end+1))) { break; } ++end; } if ((start>=0) && (end<s.length())) { mask = s.substring(start, end + 1); } gotoFileMatchingMask(mask); } /** Goes to the file matching the specified mask. * @param mask word specifying the file to go to*/ public void gotoFileMatchingMask(String mask) { List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments(); if ((docs == null) || (docs.size() == 0)) return; // do nothing GoToFileListEntry currentEntry = null; ArrayList<GoToFileListEntry> list; list = new ArrayList<GoToFileListEntry>(docs.size()); for(OpenDefinitionsDocument d: docs) { GoToFileListEntry entry = new GoToFileListEntry(d, d.toString()); if (d.equals(_model.getActiveDocument())) currentEntry = entry; list.add(entry); } PredictiveInputModel<GoToFileListEntry> pim = new PredictiveInputModel<GoToFileListEntry>(true, new PrefixStrategy<GoToFileListEntry>(), list); pim.setMask(mask); // Utilities.show("Matching items are: " + pim.getMatchingItems()); if (pim.getMatchingItems().size() == 1) { // exactly one match, go to file if (pim.getCurrentItem() != null) { boolean docChanged = !pim.getCurrentItem().doc.equals(_model.getActiveDocument()); // if (docChanged) { addToBrowserHistory(); } _model.setActiveDocument(pim.getCurrentItem().doc); if (docChanged) { // defer executing this code until after active document switch is complete addToBrowserHistory(); } } } else { // try appending ".java" and see if it's unique pim.extendMask(".java"); if (pim.getMatchingItems().size() == 1) { // exactly one match with ".java" appended, go to file if (pim.getCurrentItem() != null) { boolean docChanged = !pim.getCurrentItem().doc.equals(_model.getActiveDocument()); // if (docChanged) { addToBrowserHistory(); } _model.setActiveDocument(pim.getCurrentItem().doc); if (docChanged) { // defer executing this code until after active document switch is complete addToBrowserHistory(); } } } else { // not exactly one match pim.setMask(mask); if (pim.getMatchingItems().size() == 0) { // if there are no matches, shorten the mask until there is at least one mask = pim.getMask(); while (mask.length()>0) { mask = mask.substring(0, mask.length() - 1); pim.setMask(mask); if (pim.getMatchingItems().size()>0) { break; } } } initGotoFileDialog(); _gotoFileDialog.setModel(true, pim); // ignore case if (currentEntry != null) _gotoFileDialog.setCurrentItem(currentEntry); hourglassOn(); /* Following boolean flag suppresses display of the dialog during unit testing. If the unit test is revised * to confirm that the dialog is displayed, this test must be removed. */ if (MainFrame.this.isVisible()) _gotoFileDialog.setVisible(true); } } } /** Goes to the file specified by the word the cursor is on. */ final Action gotoFileUnderCursorAction = new AbstractAction("Go to File Under Cursor") { public void actionPerformed(ActionEvent ae) { _gotoFileUnderCursor(); } }; /** Wrapper class for the "Open Javadoc" and "Auto Import" dialog list entries. * Provides the ability to have the same class name in there multiple times in different packages. */ public static class JavaAPIListEntry extends ClassNameAndPackageEntry { private final String str, fullStr; private final URL url; public JavaAPIListEntry(String s, String full, URL u) { str = s; fullStr = full; url = u; } public String toString() { return str; } public String getFullString() { return fullStr; } public URL getURL() { return url; } public String getClassName() { return str; } public String getFullPackage() { int pos = fullStr.lastIndexOf('.'); if (pos>=0) { return fullStr.substring(0,pos+1); } return ""; } } /** Reset the position of the "Open Javadoc" dialog. */ public void resetOpenJavadocDialogPosition() { initOpenJavadocDialog(); _openJavadocDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_OPENJAVADOC_STATE, "default"); } } /** Initialize dialog if necessary. */ void initOpenJavadocDialog() { if (_openJavadocDialog == null) { PredictiveInputFrame.InfoSupplier<JavaAPIListEntry> info = new PredictiveInputFrame.InfoSupplier<JavaAPIListEntry>() { public String value(JavaAPIListEntry entry) { return entry.getFullString(); } }; PredictiveInputFrame.CloseAction<JavaAPIListEntry> okAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() { public String getName() { return "OK"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<JavaAPIListEntry> p) { if (p.getItem() != null) { PlatformFactory.ONLY.openURL(p.getItem().getURL()); } hourglassOff(); return null; } }; PredictiveInputFrame.CloseAction<JavaAPIListEntry> cancelAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() { public String getName() { return "Cancel"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<JavaAPIListEntry> p) { hourglassOff(); return null; } }; // Note: PredictiveInputModel.* is statically imported java.util.ArrayList<MatchingStrategy<JavaAPIListEntry>> strategies = new java.util.ArrayList<MatchingStrategy<JavaAPIListEntry>>(); strategies.add(new FragmentStrategy<JavaAPIListEntry>()); strategies.add(new PrefixStrategy<JavaAPIListEntry>()); strategies.add(new RegExStrategy<JavaAPIListEntry>()); List<PredictiveInputFrame.CloseAction<JavaAPIListEntry>> actions = new ArrayList<PredictiveInputFrame.CloseAction<JavaAPIListEntry>>(); actions.add(okAction); actions.add(cancelAction); _openJavadocDialog = new PredictiveInputFrame<JavaAPIListEntry>(MainFrame.this, "Open Java API Javadoc Webpage", true, // force true, // ignore case info, strategies, actions, 1, // cancel is action 1 new JavaAPIListEntry("dummyJavadoc", "dummyJavadoc", null)) { public void setOwnerEnabled(boolean b) { if (b) { hourglassOff(); } else { hourglassOn(); } } }; // putting one dummy entry in the list; it will be changed later anyway if (DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) { _openJavadocDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STATE)); } generateJavaAPIList(); } } /** Generate Java API class list. */ public static List<JavaAPIListEntry> _generateJavaAPIList(String base, String stripPrefix, String suffix) { // TODO: put this in an AsyncTask List<JavaAPIListEntry> l = new ArrayList<JavaAPIListEntry>(); try { URL url = MainFrame.class.getResource("/edu/rice/cs/drjava/docs/javaapi"+suffix); InputStream urls = url.openStream(); InputStreamReader is = null; BufferedReader br = null; try { is = new InputStreamReader(urls); br = new BufferedReader(is); String line = br.readLine(); while(line != null) { final String aText = "<a href=\""; int aPos = line.toLowerCase().indexOf(aText); int aEndPos = line.toLowerCase().indexOf(".html\" ",aPos); if ((aPos>=0) && (aEndPos>=0)) { String link = line.substring(aPos+aText.length(), aEndPos); String fullClassName = link.substring(stripPrefix.length()).replace('/', '.'); String simpleClassName = fullClassName; int lastDot = fullClassName.lastIndexOf('.'); if (lastDot>=0) { simpleClassName = fullClassName.substring(lastDot + 1); } try { URL pageURL = new URL(base + link + ".html"); l.add(new JavaAPIListEntry(simpleClassName, fullClassName, pageURL)); } catch(MalformedURLException mue) { /* ignore, we'll just not put this class in the list */ } } line = br.readLine(); } } finally { if (br!=null) { br.close(); } if (is!=null) { is.close(); } if (urls!=null) { urls.close(); } } } catch(IOException ioe) { /* ignore, we'll just have an incomplete list */ } return l; } /** Generate Java API class list. */ public void generateJavaAPIList() { if (_javaAPIList == null) { // generate list String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION); // the string that will be ADDED to the beginning of the link to form the full URL String base = ""; // the string that will be REMOVED from the beginning of the link to form the fully-qualified class name String stripPrefix = ""; // the HTML file name that contains all the links String suffix = ""; if (linkVersion.equals(JAVADOC_AUTO_TEXT)) { // use the compiler's version of the Java API Javadoc edu.rice.cs.plt.reflect.JavaVersion ver = _model.getCompilerModel().getActiveCompiler().version(); if (ver==edu.rice.cs.plt.reflect.JavaVersion.JAVA_1_4) { linkVersion = JAVADOC_1_4_TEXT; } else if (ver==edu.rice.cs.plt.reflect.JavaVersion.JAVA_5) { linkVersion = JAVADOC_1_5_TEXT; } else if (ver==edu.rice.cs.plt.reflect.JavaVersion.JAVA_6) { linkVersion = JAVADOC_1_6_TEXT; } else { linkVersion = JAVADOC_1_3_TEXT; } } if (linkVersion.equals(JAVADOC_1_3_TEXT)) { base = DrJava.getConfig().getSetting(JAVADOC_1_3_LINK) + "/"; stripPrefix = ""; // nothing needs to be stripped, links in 1.3 Javadoc are relative suffix = "/allclasses-1.3.html"; } else if (linkVersion.equals(JAVADOC_1_4_TEXT)) { base = DrJava.getConfig().getSetting(JAVADOC_1_4_LINK) + "/"; stripPrefix = ""; // nothing needs to be stripped, links in 1.4 Javadoc are relative suffix = "/allclasses-1.4.html"; } else if (linkVersion.equals(JAVADOC_1_5_TEXT)) { base = DrJava.getConfig().getSetting(JAVADOC_1_5_LINK) + "/"; stripPrefix = ""; // nothing needs to be stripped, links in 1.5 Javadoc are relative suffix = "/allclasses-1.5.html"; } else if (linkVersion.equals(JAVADOC_1_6_TEXT)) { base = ""; // links in 1.6 Javadoc are absolute, so nothing needs to be added to get an absolute URL // but we do need to strip the absolute part to get correct fully-qualified class names // and we take the default string here, not what the user entered, because the links in // our allclasses-1.6.html file go to the original Sun website. stripPrefix = JAVADOC_1_6_LINK.getDefaultString() + "/"; suffix = "/allclasses-1.6.html"; } else { // no valid Javadoc URL return; } _javaAPIList = _generateJavaAPIList(base, stripPrefix, suffix); if (_javaAPIList.size()==0) { _javaAPIList = null; } } } /** The "Open Javadoc" dialog instance. */ PredictiveInputFrame<JavaAPIListEntry> _openJavadocDialog = null; /** The list of Java API classes. */ List<JavaAPIListEntry> _javaAPIList = null; /** Action that asks the user for a file name and goes there. Only executes in the event thread. */ private Action _openJavadocAction = new AbstractAction("Open Java API Javadoc...") { public void actionPerformed(ActionEvent ae) { initOpenJavadocDialog(); _openJavadocDialog.setItems(true, _javaAPIList); // ignore case hourglassOn(); _openJavadocDialog.setVisible(true); } }; /** Opens the Javadoc specified by the word the cursor is on. Only executes in the event thread. */ private void _openJavadocUnderCursor() { generateJavaAPIList(); if (_javaAPIList == null) { // Utilities.show("Cannot load Java API class list. No network connectivity?"); return; } PredictiveInputModel<JavaAPIListEntry> pim = new PredictiveInputModel<JavaAPIListEntry>(true, new PrefixStrategy<JavaAPIListEntry>(), _javaAPIList); OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); String mask = ""; int loc = getCurrentDefPane().getCaretPosition(); String s = odd.getText(); // find start int start = loc; while(start>0) { if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; } --start; } while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start<loc)) { ++start; } // find end int end = loc-1; while(end<s.length()-1) { if (!Character.isJavaIdentifierPart(s.charAt(end+1))) { break; } ++end; } if ((start>=0) && (end<s.length())) { mask = s.substring(start, end + 1); pim.setMask(mask); } // Utilities.show("Matching items are: " + pim.getMatchingItems()); if (pim.getMatchingItems().size() == 1) { // exactly one match, go to file if (pim.getCurrentItem() != null) { PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL()); } } else { // try appending ".java" and see if it's unique pim.extendMask(".java"); if (pim.getMatchingItems().size() == 1) { // exactly one match with ".java" appended, go to file if (pim.getCurrentItem() != null) { PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL()); } } else { // not exactly one match pim.setMask(mask); JavaAPIListEntry foundItem = null; int found = 0; if (pim.getMatchingItems().size() == 0) { // if there are no matches, shorten the mask until there is at least one mask = pim.getMask(); while(mask.length()>0) { mask = mask.substring(0, mask.length() - 1); pim.setMask(mask); if (pim.getMatchingItems().size() > 0) { break; } } } else { // there are several matches, see if there is an exact match for(JavaAPIListEntry e: pim.getMatchingItems()) { if (e.toString().equalsIgnoreCase(mask)) { ++found; foundItem = e; } } } if (found==1) { // open unique item and return PlatformFactory.ONLY.openURL(pim.getCurrentItem().getURL()); } else { initOpenJavadocDialog(); _openJavadocDialog.setModel(true, pim); // ignore case hourglassOn(); _openJavadocDialog.setVisible(true); } } } } /** Open Javadoc page specified by the word the cursor is on. */ final Action _openJavadocUnderCursorAction = new AbstractAction("Open Java API Javadoc for Word Under Cursor...") { public void actionPerformed(ActionEvent ae) { _openJavadocUnderCursor(); } }; /** Reset the position of the "Complete Word" dialog. */ public void resetCompleteWordDialogPosition() { initCompleteWordDialog(); _completeWordDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_COMPLETE_WORD_STATE, "default"); } } /** Initialize dialog if necessary. */ void initCompleteWordDialog() { if (_completeWordDialog == null) { // checkbox whether Java API classes should be completed as well _completeJavaAPICheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String curMask = _completeWordDialog.getMask(); if (_completeJavaAPICheckbox.isSelected()) { DrJava.getConfig().setSetting(OptionConstants.DIALOG_COMPLETE_JAVAAPI, Boolean.TRUE); List<ClassNameAndPackageEntry> l = _completeWordDialog.getList(); addJavaAPIToList(l); _completeWordDialog.setItems(true,l); } else { // unselected, remove Java API classes from list List<ClassNameAndPackageEntry> l = _completeWordDialog.getList(); generateJavaAPIList(); if (_javaAPIList==null) { DrJava.getConfig().setSetting(OptionConstants.DIALOG_COMPLETE_JAVAAPI, Boolean.FALSE); _completeJavaAPICheckbox.setSelected(false); _completeJavaAPICheckbox.setEnabled(false); List<ClassNameAndPackageEntry> n = new ArrayList<ClassNameAndPackageEntry>(); for(ClassNameAndPackageEntry entry: l) { if (!(entry instanceof JavaAPIListEntry)) { n.add(entry); } } _completeWordDialog.setItems(true,n); } else { for(JavaAPIListEntry entry: _javaAPIList) { l.remove(entry); } _completeWordDialog.setItems(true,l); } } _completeWordDialog.setMask(curMask); _completeWordDialog.resetFocus(); } }); PlatformFactory.ONLY.setMnemonic(_completeJavaAPICheckbox,'j'); PredictiveInputFrame.InfoSupplier<ClassNameAndPackageEntry> info = new PredictiveInputFrame.InfoSupplier<ClassNameAndPackageEntry>() { public String value(ClassNameAndPackageEntry entry) { // show full class name as information StringBuilder sb = new StringBuilder(); sb.append(entry.getFullPackage()); sb.append(entry.getClassName()); return sb.toString(); } }; PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry> okAction = new PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry>() { public String getName() { return "OK"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); } public String getToolTipText() { return "Complete the identifier"; } public Object value(PredictiveInputFrame<ClassNameAndPackageEntry> p) { if (p.getItem() != null) { OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); try { String mask = ""; int loc = getCurrentDefPane().getCaretPosition(); String s = odd.getText(0, loc); // check that we're at the end of a word if ((loc<s.length()) && (!Character.isWhitespace(s.charAt(loc))) && ("()[]{}<>.,:;/*+-!~&|%".indexOf(s.charAt(loc)) == -1)) return null; // find start int start = loc; while(start>0) { if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; } --start; } while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start < loc)) { ++start; } if (!s.substring(start, loc).equals(p.getItem().toString())) { odd.remove(start, loc-start); odd.insertString(start, p.getItem().getClassName(), null); } } catch(BadLocationException ble) { /* ignore, just don't auto-complete */ } } hourglassOff(); return null; } }; PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry> fullAction = new PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry>() { public String getName() { return "Fully Qualified"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, OptionConstants.MASK); } public String getToolTipText() { return "Complete the word using the fully-qualified class name"; } public Object value(PredictiveInputFrame<ClassNameAndPackageEntry> p) { if (p.getItem() != null) { OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); try { String mask = ""; int loc = getCurrentDefPane().getCaretPosition(); String s = odd.getText(0, loc); // check that we're at the end of a word if ((loc<s.length()) && (!Character.isWhitespace(s.charAt(loc))) && ("()[]{}<>.,:;/*+-!~&|%".indexOf(s.charAt(loc)) == -1)) return null; // find start int start = loc; while(start>0) { if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; } --start; } while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start < loc)) { ++start; } if (!s.substring(start, loc).equals(p.getItem().toString())) { odd.remove(start, loc-start); StringBuilder sb = new StringBuilder(); sb.append(p.getItem().getFullPackage()); sb.append(p.getItem().getClassName()); odd.insertString(start, sb.toString(), null); } } catch(BadLocationException ble) { /* ignore, just don't auto-complete */ } } hourglassOff(); return null; } }; PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry> cancelAction = new PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry>() { public String getName() { return "Cancel"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<ClassNameAndPackageEntry> p) { hourglassOff(); return null; } }; // Note: PredictiveInputModel.* is statically imported java.util.ArrayList<MatchingStrategy<ClassNameAndPackageEntry>> strategies = new java.util.ArrayList<MatchingStrategy<ClassNameAndPackageEntry>>(); strategies.add(new FragmentStrategy<ClassNameAndPackageEntry>()); strategies.add(new PrefixStrategy<ClassNameAndPackageEntry>()); strategies.add(new RegExStrategy<ClassNameAndPackageEntry>()); List<PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry>> actions = new ArrayList<PredictiveInputFrame.CloseAction<ClassNameAndPackageEntry>>(); actions.add(okAction); actions.add(fullAction); actions.add(cancelAction); GoToFileListEntry entry = new GoToFileListEntry(new DummyOpenDefDoc() { public String getPackageNameFromDocument() { return ""; } }, "dummyComplete"); _completeWordDialog = new PredictiveInputFrame<ClassNameAndPackageEntry>(MainFrame.this, "Auto-Complete Word", true, // force true, // ignore case info, strategies, actions, 2, // cancel is action 23 entry) { public void setOwnerEnabled(boolean b) { if (b) { hourglassOff(); } else { hourglassOn(); } } protected JComponent[] makeOptions() { return new JComponent[] { _completeJavaAPICheckbox }; } }; // putting one dummy entry in the list; it will be changed later anyway if (DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) { _completeWordDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STATE)); } } } void addJavaAPIToList(List<ClassNameAndPackageEntry> list) { generateJavaAPIList(); if (_javaAPIList==null) { DrJava.getConfig().setSetting(OptionConstants.DIALOG_COMPLETE_JAVAAPI, Boolean.FALSE); _completeJavaAPICheckbox.setSelected(false); _completeJavaAPICheckbox.setEnabled(false); } else { for(JavaAPIListEntry entry: _javaAPIList) { list.add(entry); } } } /** The "Complete File" dialog instance. */ volatile PredictiveInputFrame<GoToFileListEntry> _completeFileDialog = null; /** The "Complete Word" dialog instance. */ volatile PredictiveInputFrame<ClassNameAndPackageEntry> _completeWordDialog = null; JCheckBox _completeJavaAPICheckbox = new JCheckBox("Java API"); /** Complete the word the cursor is on. Only executes in the event thread. */ private void _completeWordUnderCursor() { List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments(); if ((docs == null) || (docs.size() == 0)) return; // do nothing _completeJavaAPICheckbox.setSelected(DrJava.getConfig().getSetting(OptionConstants.DIALOG_COMPLETE_JAVAAPI)); _completeJavaAPICheckbox.setEnabled(true); ClassNameAndPackageEntry currentEntry = null; ArrayList<ClassNameAndPackageEntry> list; if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue()) && (_completeClassList.size()>0)) { list = new ArrayList<ClassNameAndPackageEntry>(_completeClassList.size()); list.addAll(_completeClassList); } else { list = new ArrayList<ClassNameAndPackageEntry>(docs.size()); for(OpenDefinitionsDocument d: docs) { if (d.isUntitled()) continue; String str = d.toString(); if (str.lastIndexOf('.')>=0) { str = str.substring(0, str.lastIndexOf('.')); } GoToFileListEntry entry = new GoToFileListEntry(d, str); if (d.equals(_model.getActiveDocument())) currentEntry = entry; list.add(entry); } } if (DrJava.getConfig().getSetting(OptionConstants.DIALOG_COMPLETE_JAVAAPI)) { addJavaAPIToList(list); } PredictiveInputModel<ClassNameAndPackageEntry> pim = new PredictiveInputModel<ClassNameAndPackageEntry>(true, new PrefixStrategy<ClassNameAndPackageEntry>(), list); OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); boolean uniqueMatch = true; try { String mask = ""; int loc = getCurrentDefPane().getCaretPosition(); String s = odd.getText(0, loc); // check that we're at the end of a word if ((loc<s.length()) && (!Character.isWhitespace(s.charAt(loc))) && ("()[]{}<>.,:;/*+-!~&|%".indexOf(s.charAt(loc)) == -1)) return; // find start int start = loc; while(start > 0) { if (!Character.isJavaIdentifierPart(s.charAt(start-1))) { break; } --start; } while((start<s.length()) && (!Character.isJavaIdentifierStart(s.charAt(start))) && (start < loc)) { ++start; } int end = loc-1; if ((start>=0) && (end < s.length())) { mask = s.substring(start, end + 1); pim.setMask(mask); } if (pim.getMatchingItems().size() == 1) { if (pim.getCurrentItem() != null) { // exactly one match, auto-complete if (! s.substring(start, loc).equals(pim.getCurrentItem().toString())) { odd.remove(start, loc - start); odd.insertString(start, pim.getCurrentItem().toString(), null); } return; } } else { // not exactly one match uniqueMatch = false; pim.setMask(mask); if (pim.getMatchingItems().size() == 0) { // if there are no matches, shorten the mask until there is at least one mask = pim.getMask(); while(mask.length() > 0) { mask = mask.substring(0, mask.length() - 1); pim.setMask(mask); if (pim.getMatchingItems().size() > 0) { break; } } } initCompleteWordDialog(); _completeWordDialog.setModel(true, pim); // ignore case _completeWordDialog.selectStrategy(); if (currentEntry != null) _completeWordDialog.setCurrentItem(currentEntry); hourglassOn(); _completeWordDialog.setVisible(true); } } catch(BadLocationException ble) { /* ignore, just don't auto-complete */ } } /** Auto-completes word the cursor is on. */ final Action completeWordUnderCursorAction = new AbstractAction("Auto-Complete Word Under Cursor") { public void actionPerformed(ActionEvent ae) { _completeWordUnderCursor(); } }; /** Indents the current selection. */ private final Action _indentLinesAction = new AbstractAction("Indent Line(s)") { public void actionPerformed(ActionEvent ae) { hourglassOn(); try { _currentDefPane.endCompoundEdit(); _currentDefPane.indent(); } finally { hourglassOff(); } } }; /** Action for commenting out a block of text using wing comments. */ private final Action _commentLinesAction = new AbstractAction("Comment Line(s)") { public void actionPerformed(ActionEvent ae) { hourglassOn(); try{ commentLines(); } finally{ hourglassOff(); } } }; /** Action for un-commenting a block of commented text. */ private final Action _uncommentLinesAction = new AbstractAction("Uncomment Line(s)") { public void actionPerformed(ActionEvent ae){ hourglassOn(); try{ uncommentLines(); } finally{ hourglassOff(); } } }; /** Clears DrJava's output console. */ private final Action _clearConsoleAction = new AbstractAction("Clear Console") { public void actionPerformed(ActionEvent ae) { _model.resetConsole(); } }; /** Shows the DebugConsole. */ private final Action _showDebugConsoleAction = new AbstractAction("Show DrJava Debug Console") { public void actionPerformed(ActionEvent e) { DrJavaRoot.showDrJavaDebugConsole(MainFrame.this); } }; /* Enables the reset interactions command. Not currently used, since this action is NEVER disabled. */ public void enableResetInteractions() { _resetInteractionsAction.setEnabled(true); } /** Resets the Interactions pane. */ private final Action _resetInteractionsAction = new AbstractAction("Reset Interactions") { public void actionPerformed(ActionEvent ae) { if (! DrJava.getConfig().getSetting(INTERACTIONS_RESET_PROMPT).booleanValue()) { _doResetInteractions(); return; } String title = "Confirm Reset Interactions"; String message = "Are you sure you want to reset the Interactions Pane?"; ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, title, message); int rc = dialog.show(); if (rc == JOptionPane.YES_OPTION) { _doResetInteractions(); if (dialog.getCheckBoxValue()) { DrJava.getConfig().setSetting(INTERACTIONS_RESET_PROMPT, Boolean.FALSE); } } } }; private void _doResetInteractions() { _tabbedPane.setSelectedIndex(INTERACTIONS_TAB); updateStatusField("Resetting Interactions"); _model.getInteractionsModel().enableRestart(); // Lots of work, so use another thread new Thread(new Runnable() { public void run() {_model.resetInteractions(_model.getWorkingDirectory(), true); } }).start(); } /** Defines actions that displays the interactions classpath. */ private final Action _viewInteractionsClassPathAction = new AbstractAction("View Interactions Classpath...") { public void actionPerformed(ActionEvent e) { viewInteractionsClassPath(); } }; /** Displays the interactions classpath. */ public void viewInteractionsClassPath() { String cp = IterUtil.multilineToString(_model.getInteractionsClassPath()); new DrJavaScrollableDialog(this, "Interactions Classpath", "Current Interpreter Classpath", cp).show(); } /** Action that shows what help documentation is available. Only executes in the event thread. */ private final Action _helpAction = new AbstractAction("Help") { public void actionPerformed(ActionEvent ae) { // Create frame if we haven't yet // if (_helpFrame == null) { // _helpFrame = new HelpFrame(); // } _helpFrame.setVisible(true); } }; /** Action that shows the quick start documentation. Only executes in the event thread. */ private final Action _quickStartAction = new AbstractAction("QuickStart") { public void actionPerformed(ActionEvent ae) { // Create frame if we haven't yet // if (_quickStartFrame == null) { // _quickStartFrame = new QuickStartFrame(); // } _quickStartFrame.setVisible(true); } }; /** Action that pops up an info dialog. Only runs in the event thread. */ private final Action _aboutAction = new AbstractAction("About") { public void actionPerformed(ActionEvent ae) { // Create dialog if we haven't yet // if (_aboutDialog == null) _aboutDialog = new AboutDialog(MainFrame.this); // Point p = MainFrame.this.getLocation(); _aboutDialog.setVisible(true); // _aboutDialog.setLocation(p.x+(MainFrame.this.getWidth() - _aboutDialog.getWidth())/2, // p.y+(MainFrame.this.getHeight()-_aboutDialog.getHeight())/2); } }; /** Action that pops up a dialog that checks for a new version. Only runs in the event thread. */ private final Action _checkNewVersionAction = new AbstractAction("Check for New Version") { public void actionPerformed(ActionEvent ae) { NewVersionPopup popup = new NewVersionPopup(MainFrame.this); popup.setVisible(true); } }; /** Asks whether DrJava may contact the DrJava developers and send system information. */ private final Action _drjavaSurveyAction = new AbstractAction("Send System Information") { public void actionPerformed(ActionEvent ae) { DrJavaSurveyPopup popup = new DrJavaSurveyPopup(MainFrame.this); popup.setVisible(true); } }; /** Action that pops up the DrJava errors dialog. Only runs in the event thread. */ private final Action _errorsAction = new AbstractAction("DrJava Errors") { public void actionPerformed(ActionEvent ae) { setPopupLoc(DrJavaErrorWindow.singleton()); DrJavaErrorWindow.singleton().setVisible(true); } }; /** Action that switches to next document. Only runs in the event thread. */ private final Action _switchToNextAction = new AbstractAction("Next Document") { public void actionPerformed(ActionEvent ae) { this.setEnabled(false); if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation()) _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue()); //disables switching documents while the next one is opening up, in order to prevent out of control switching _model.setActiveNextDocument(); _findReplace.updateFirstDocInSearch(); this.setEnabled(true); // defer executing this code until after active document switch (if any) is complete addToBrowserHistory(); } }; /** Switches to previous document. */ private final Action _switchToPrevAction = new AbstractAction("Previous Document") { public void actionPerformed(ActionEvent ae) { this.setEnabled(false); if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation()) _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue()); _model.setActivePreviousDocument(); _findReplace.updateFirstDocInSearch(); this.setEnabled(true); // defer executing this code until after active document switch (if any) is complete addToBrowserHistory(); } }; /** Switches focus to next pane. */ private final Action _switchToNextPaneAction = new AbstractAction("Next Pane") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); this.setEnabled(false); _switchPaneFocus(true); this.setEnabled(true); } }; /** Browse back in the browser history. */ private final Action _browseBackAction = new AbstractAction("Browse Back") { public void actionPerformed(ActionEvent ae) { updateStatusField("Browsing Back"); this.setEnabled(false); if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation()) _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue()); //disables switching documents while the next one is opening up, in order to prevent out of control switching BrowserHistoryManager rm = _model.getBrowserHistoryManager(); // // add current location to history // addToBrowserHistory(); // then move back BrowserDocumentRegion r = rm.prevCurrentRegion(_model.getNotifier()); if (r != null) scrollToDocumentAndOffset(r.getDocument(), r.getStartOffset(), false, false); _configureBrowsing(); // this.setEnabled(true); } }; /** Browse forward in the browser history. */ private final Action _browseForwardAction = new AbstractAction("Browse Forward") { public void actionPerformed(ActionEvent ae) { updateStatusField("Browsing Forward"); this.setEnabled(false); if (_docSplitPane.getDividerLocation() < _docSplitPane.getMinimumDividerLocation()) _docSplitPane.setDividerLocation(DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue()); //disables switching documents while the next one is opening up, in order to prevent out of control switching BrowserHistoryManager rm = _model.getBrowserHistoryManager(); // // add current location to history // addToBrowserHistory(); // then move forward BrowserDocumentRegion r = rm.nextCurrentRegion(_model.getNotifier()); if (r != null) scrollToDocumentAndOffset(r.getDocument(), r.getStartOffset(), false, false); _configureBrowsing(); // this.setEnabled(true); } }; /** Switches focus to previous pane. */ private final Action _switchToPreviousPaneAction = new AbstractAction("Previous Pane") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); this.setEnabled(false); _switchPaneFocus(false); this.setEnabled(true); } }; /** Go to the closing brace. */ private final Action _gotoClosingBraceAction = new AbstractAction("Go to Closing Brace") { public void actionPerformed(ActionEvent ae) { OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); try { int pos = odd._findNextEnclosingBrace(getCurrentDefPane().getCaretPosition(), '{', '}'); if (pos != -1) { getCurrentDefPane().setCaretPosition(pos); } } catch(BadLocationException ble) { /* just ignore and don't move */ } } }; /** Go to the opening brace. */ private final Action _gotoOpeningBraceAction = new AbstractAction("Go to Opening Brace") { public void actionPerformed(ActionEvent ae) { OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); try { int pos = odd._findPrevEnclosingBrace(getCurrentDefPane().getCaretPosition(), '{', '}'); if (pos != -1) { getCurrentDefPane().setCaretPosition(pos); } } catch(BadLocationException ble) { /* just ignore and don't move */ } } }; /** This takes a component and gives it focus, showing it if it's a tab. The interactionsPane and consolePane * are wrapped in scrollpanes, so we have to specifically check for those and unwrap them. * @param c the pane to switch focus to */ private void _switchToPane(Component c) { Component newC = c; // if (c == _interactionsContainer) newC = _interactionsPane; // if (c == _consoleScroll) newC = _consolePane; showTab(newC, true); } /** This method allows the user to cycle through the definitions pane and all of the open tabs. * @param next true if we want to go to the next pane, false if the previous. */ private void _switchPaneFocus(boolean next) { int numTabs = _tabbedPane.getTabCount(); /* If next, then we go to the next tab */ if (next) _switchToPane(_tabbedPane.getComponentAt((numTabs + _tabbedPane.getSelectedIndex() +1 ) % numTabs)); else _switchToPane(_tabbedPane.getComponentAt((numTabs + _tabbedPane.getSelectedIndex() - 1) % numTabs)); } /** Action that calls the ConfigFrame to edit preferences. Only runs in the event thread. */ private final Action _editPreferencesAction = new AbstractAction("Preferences ...") { public void actionPerformed(ActionEvent ae) { _configFrame.setUp(); setPopupLoc(_configFrame); _configFrame.setVisible(true); _configFrame.toFront(); } }; private volatile AbstractAction _projectPropertiesAction = new AbstractAction("Project Properties") { public void actionPerformed(ActionEvent ae) { _editProject(); } }; /** Action that enables the debugger. Only runs in the event thread. */ private final Action _toggleDebuggerAction = new AbstractAction("Debug Mode") { public void actionPerformed(ActionEvent ae) { this.setEnabled(false); debuggerToggle(); this.setEnabled(true); } }; /** Action that resumes debugging. Only runs in the event thread. */ private final Action _resumeDebugAction = new AbstractAction("Resume Debugger") { public void actionPerformed(ActionEvent ae) { try { debuggerResume(); } catch (DebugException de) { _showDebugError(de); } } }; /** Action that steps into the next method call. Only runs in the event thread. */ private final Action _stepIntoDebugAction = new AbstractAction("Step Into") { public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.StepType.STEP_INTO); } }; /** Action that executes the next line, without stepping into methods. Only runs in the event thread. */ private final Action _stepOverDebugAction = new AbstractAction("Step Over") { public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.StepType.STEP_OVER); } }; /** Action that steps out of the next method call. Only runs in the event thread. */ private final Action _stepOutDebugAction = new AbstractAction("Step Out") { public void actionPerformed(ActionEvent ae) { debuggerStep(Debugger.StepType.STEP_OUT); } }; /** Suspend debugging */ /*private Action _suspendDebugAction = new AbstractAction("Suspend Debugger") { public void actionPerformed(ActionEvent ae) { _debugSuspend(); } };*/ /** Toggles a breakpoint on the current line */ final Action _toggleBreakpointAction = new AbstractAction("Toggle Breakpoint on Current Line") { public void actionPerformed(ActionEvent ae) { debuggerToggleBreakpoint(); } }; /** Clears all breakpoints */ private final Action _clearAllBreakpointsAction = new AbstractAction("Clear All Breakpoints") { public void actionPerformed(ActionEvent ae) { debuggerClearAllBreakpoints(); } }; /** Action that shows the breakpoints tab. Only runs in the event thread. */ private final Action _breakpointsPanelAction = new AbstractAction("Breakpoints") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); showTab(_breakpointsPanel, true); _breakpointsPanel.setVisible(true); _tabbedPane.setSelectedComponent(_breakpointsPanel); // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _breakpointsPanel has been selected EventQueue.invokeLater(new Runnable() { public void run() { _breakpointsPanel.requestFocusInWindow(); } }); } }; /** Action that shows the bookmarks tab. Only runs in the event thread. */ private final Action _bookmarksPanelAction = new AbstractAction("Bookmarks") { public void actionPerformed(ActionEvent ae) { if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); showTab(_bookmarksPanel, true); _tabbedPane.setSelectedComponent(_bookmarksPanel); // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _bookmarksPanel has been selected EventQueue.invokeLater(new Runnable() { public void run() { _bookmarksPanel.requestFocusInWindow(); } }); } }; // /** Selects the next recent document. */ // private final Action _nextRecentDocumentAction = new Abstract Action("Select Next Recent Document") { // public void actionPerformed(ActionEvent ae) { nextRecentDoc(); } // }; // // /** Selects the previous recent document. */ // private final Action _prevRecentDocumentAction = new Abstract Action("Select Previous Recent Document") { // public void actionPerformed(ActionEvent ae) { prevRecentDoc(); } // }; /** Toggles a bookmark. */ private final Action _toggleBookmarkAction = new AbstractAction("Toggle Bookmark") { public void actionPerformed(ActionEvent ae) { toggleBookmark(); } }; /** Toggle a bookmark. */ public void toggleBookmark() { // Utilities.show("MainFrame.toggleBookmark called"); assert EventQueue.isDispatchThread(); addToBrowserHistory(); OpenDefinitionsDocument odd = getCurrentDefPane().getOpenDefDocument(); _model._toggleBookmark(_currentDefPane.getSelectionStart(), _currentDefPane.getSelectionEnd()); showTab(_bookmarksPanel, true); } /** Add the current location to the browser history. */ public void addToBrowserHistory() { EventQueue.invokeLater(new Runnable() { public void run() { _model.addToBrowserHistory(); } }); } /** Create a new find results tab. * @param rm the region manager that will contain the regions * @param title the title for the panel * @return new find results tab. * @param searchString string that was searched for * @param searchAll whether all files were searched * @param doc weak reference to document in which search occurred (or started, if all documents were searched) * @param findReplace the FindReplacePanel that created this FindResultsPanel */ public FindResultsPanel createFindResultsPanel(final RegionManager<MovingDocumentRegion> rm, String title, String searchString, boolean searchAll, boolean matchCase, boolean wholeWord, boolean noComments, boolean noTestCases, WeakReference<OpenDefinitionsDocument> doc, FindReplacePanel findReplace) { final FindResultsPanel panel = new FindResultsPanel(this, rm, title, searchString, searchAll, matchCase, wholeWord, noComments, noTestCases, doc, findReplace); final AbstractMap<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights = new IdentityHashMap<MovingDocumentRegion, HighlightManager.HighlightInfo>(); final Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair = new Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>>(panel, highlights); _findResults.add(pair); // hook highlighting listener to find results manager rm.addListener(new RegionManagerListener<MovingDocumentRegion>() { public void regionAdded(MovingDocumentRegion r) { panel.addRegion(r); DefinitionsPane pane = getDefPaneGivenODD(r.getDocument()); // if (pane == null) System.err.println("ODD " + r.getDocument() + " produced a null DefinitionsPane!"); highlights.put(r, pane.getHighlightManager(). addHighlight(r.getStartOffset(), r.getEndOffset(), panel.getSelectedPainter())); } public void regionChanged(MovingDocumentRegion r) { regionRemoved(r); regionAdded(r); } public void regionRemoved(MovingDocumentRegion r) { // System.err.println("MainFrame$highlightListener.regionRemoved(" + r + ") called"); panel.removeRegion(r); // Removes panel if it becomes empty // Utilities.show("Removing highlight for region " + r); HighlightManager.HighlightInfo highlight = highlights.get(r); // Utilities.show("The retrieved highlight is " + highlight); if (highlight != null) highlight.remove(); highlights.remove(r); // The following is done in FindResultsPanel.removeRegion // // close the panel and dispose of its MainFrame resources when all regions have been removed. // if (rm.getDocuments().isEmpty()) { // panel._close(); // _close removes the panel from _tabs and pair from _findResults // } } }); // attach a listener to the panel that removes pair from _findResults when the panel is closed panel.addCloseListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { _findResults.remove(pair); } }); _tabs.addLast(panel); panel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = panel; } }); return panel; } /** Disable "Find Again" on "Find All" tabs that use a document that was closed. */ void disableFindAgainOnClose(List<OpenDefinitionsDocument> projDocs) { for(TabbedPanel t: _tabs) { if (t instanceof FindResultsPanel) { FindResultsPanel p = (FindResultsPanel)t; if (projDocs.contains(p.getDocument())) { p.disableFindAgain(); } } } } /** Action that shows a find results tab. Only runs in event thread. */ public void showFindResultsPanel(final FindResultsPanel panel) { assert EventQueue.isDispatchThread(); if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); showTab(panel, true); // panel.setVisible(true); _tabbedPane.setSelectedComponent(panel); // Use EvenQueue.invokeLater to ensure that focus is set AFTER the findResultsPanel has been selected EventQueue.invokeLater(new Runnable() { public void run() { panel.requestFocusInWindow(); } }); }; /** Cuts from the caret to the end of the current line to the clipboard. */ protected final Action _cutLineAction = new AbstractAction("Cut Line") { public void actionPerformed(ActionEvent ae) { ActionMap actionMap = _currentDefPane.getActionMap(); int oldCol = _model.getActiveDocument().getCurrentCol(); actionMap.get(DefaultEditorKit.selectionEndLineAction).actionPerformed(ae); // if oldCol is equal to the current column, then selectionEndLine did // nothing, so we're at the end of the line and should remove the newline // character if (oldCol == _model.getActiveDocument().getCurrentCol()) { // Puts newline character on the clipboard also, not just content as before. actionMap.get(DefaultEditorKit.selectionForwardAction).actionPerformed(ae); cutAction.actionPerformed(ae); } else cutAction.actionPerformed(ae); } }; /** Deletes text from the caret to the end of the current line. */ protected final Action _clearLineAction = new AbstractAction("Clear Line") { public void actionPerformed(ActionEvent ae) { ActionMap actionMap = _currentDefPane.getActionMap(); actionMap.get(DefaultEditorKit.selectionEndLineAction).actionPerformed(ae); actionMap.get(DefaultEditorKit.deleteNextCharAction).actionPerformed(ae); } }; /** Moves the caret to the "intelligent" beginning of the line. * @see #_getBeginLinePos */ private final Action _beginLineAction = new AbstractAction("Begin Line") { public void actionPerformed(ActionEvent ae) { int beginLinePos = _getBeginLinePos(); _currentDefPane.setCaretPosition(beginLinePos); } }; /** Selects to the "intelligent" beginning of the line. * @see #_getBeginLinePos */ private final Action _selectionBeginLineAction = new AbstractAction("Select to Beginning of Line") { public void actionPerformed(ActionEvent ae) { int beginLinePos = _getBeginLinePos(); _currentDefPane.moveCaretPosition(beginLinePos); } }; /** Returns the "intelligent" beginning of line. If the caret is to fhe right of the first non-whitespace character, * the position of the first non-whitespace character is returned. If the caret is on or to the left of the first * non-whitespace character, the beginning of the line is returned. */ private int _getBeginLinePos() { try { int currPos = _currentDefPane.getCaretPosition(); OpenDefinitionsDocument openDoc = _model.getActiveDocument(); openDoc.setCurrentLocation(currPos); return openDoc.getIntelligentBeginLinePos(currPos); } catch (BadLocationException ble) { // Shouldn't happen: we're using a legal position throw new UnexpectedException(ble); } } private final FileOpenSelector _interactionsHistoryFileSelector = new FileOpenSelector() { public File[] getFiles() throws OperationCanceledException { return getOpenFiles(_interactionsHistoryChooser); } }; /** Interprets the commands in a file in the interactions window. */ private final Action _executeHistoryAction = new AbstractAction("Execute Interactions History...") { public void actionPerformed(ActionEvent ae) { // Show interactions tab _tabbedPane.setSelectedIndex(INTERACTIONS_TAB); _interactionsHistoryChooser.setDialogTitle("Execute Interactions History"); try { _model.loadHistory(_interactionsHistoryFileSelector); } catch (FileNotFoundException fnf) { _showFileNotFoundError(fnf); } catch (IOException ioe) { _showIOError(ioe); } _interactionsPane.requestFocusInWindow(); } }; /** Closes the currently executing interactions script, if there is one. */ private void _closeInteractionsScript() { if (_interactionsScriptController != null) { _interactionsContainer.remove(_interactionsScriptPane); _interactionsScriptController = null; _interactionsScriptPane = null; _tabbedPane.invalidate(); _tabbedPane.repaint(); } } /** Action to load an interactions history as a replayable script. */ private final Action _loadHistoryScriptAction = new AbstractAction("Load Interactions History as Script...") { public void actionPerformed(ActionEvent e) { try { _interactionsHistoryChooser.setDialogTitle("Load Interactions History"); InteractionsScriptModel ism = _model.loadHistoryAsScript(_interactionsHistoryFileSelector); _interactionsScriptController = new InteractionsScriptController(ism, new AbstractAction("Close") { public void actionPerformed(ActionEvent e) { _closeInteractionsScript(); _interactionsPane.requestFocusInWindow(); } }, _interactionsPane); _interactionsScriptPane = _interactionsScriptController.getPane(); _interactionsContainer.add(_interactionsScriptPane, BorderLayout.EAST); _tabbedPane.invalidate(); _tabbedPane.repaint(); } catch (FileNotFoundException fnf) { _showFileNotFoundError(fnf); } catch (IOException ioe) { _showIOError(ioe); } catch (OperationCanceledException oce) { } } }; /** Save the commands in the interactions window's history to a file */ private final Action _saveHistoryAction = new AbstractAction("Save Interactions History...") { public void actionPerformed(ActionEvent ae) { String[] options = {"Yes","No","Cancel"}; int resp = JOptionPane.showOptionDialog(MainFrame.this, "Edit interactions history before saving?", "Edit History?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,options, options[1]); // Cancel if (resp == 2 || resp == JOptionPane.CLOSED_OPTION) return; String history = _model.getHistoryAsStringWithSemicolons(); // Edit the history if (resp == 0) history = (new HistorySaveDialog(MainFrame.this)).editHistory(history); if (history == null) return; // save cancelled _interactionsHistoryChooser.setDialogTitle("Save Interactions History"); FileSaveSelector selector = new FileSaveSelector() { public File getFile() throws OperationCanceledException { // Don't try to set the fileName with getSaveFile; // just display the dialog and get file with getChosenFile, otherwise // the suggested file name will be whatever document is open. // ED (8.14.03): Had to add this next block of code from getSaveFile to // fix bug #788311 "NullPointer when saving history" File selection = _interactionsHistoryChooser.getSelectedFile();//_saveChooser.getSelectedFile(); if (selection != null) { _interactionsHistoryChooser.setSelectedFile(selection.getParentFile()); _interactionsHistoryChooser.setSelectedFile(selection); _interactionsHistoryChooser.setSelectedFile(null); } // return getSaveFile(_interactionsHistoryChooser); _interactionsHistoryChooser.setMultiSelectionEnabled(false); int rc = _interactionsHistoryChooser.showSaveDialog(MainFrame.this); File c = getChosenFile(_interactionsHistoryChooser, rc); //Moved from history itself to here to account for bug #989232, non-existant default //history file found if ((c!=null) && (c.getName().indexOf('.') == -1)) { c = new File(c.getAbsolutePath() + "." + InteractionsHistoryFilter.HIST_EXTENSION); } _interactionsHistoryChooser.setSelectedFile(c); return c; } public boolean warnFileOpen(File f) { return true; } public boolean verifyOverwrite() { return _verifyOverwrite(); } public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; } }; try { _model.saveHistory(selector, history);} catch (IOException ioe) { _showIOError(new IOException("An error occured writing the history to a file")); } _interactionsPane.requestFocusInWindow(); } }; /** Clears the commands in the interaction history. */ private final Action _clearHistoryAction = new AbstractAction("Clear Interactions History") { public void actionPerformed(ActionEvent ae) { _model.clearHistory(); _interactionsPane.requestFocusInWindow(); } }; /** How DrJava responds to window events. */ private final WindowListener _windowCloseListener = new WindowAdapter() { public void windowActivated(WindowEvent ev) { } public void windowClosed(WindowEvent ev) { } public void windowClosing(WindowEvent ev) { _quit(); } public void windowDeactivated(WindowEvent ev) { } public void windowDeiconified(WindowEvent ev) { try { _model.getActiveDocument().revertIfModifiedOnDisk(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException e) { _showIOError(e);} } public void windowIconified(WindowEvent ev) { } public void windowOpened(WindowEvent ev) { _currentDefPane.requestFocusInWindow(); } }; private final MouseListener _resetFindReplaceListener = new MouseListener() { public void mouseClicked (MouseEvent e) { } public void mousePressed (MouseEvent e) { } //as mouseReleased event so that it happens after the document has been set in the model and defPane public void mouseReleased (MouseEvent e) {_findReplace.updateFirstDocInSearch();} public void mouseEntered (MouseEvent e) { } public void mouseExited (MouseEvent e) { } }; // ------------- File Display Managers for File Icons ------------ private static final DJFileDisplayManager _djFileDisplayManager20; private static final DJFileDisplayManager _djFileDisplayManager30; private static final OddDisplayManager _oddDisplayManager20; private static final OddDisplayManager _oddDisplayManager30; private static final Icon _djProjectIcon; static { Icon java, dj0, dj1, dj2, other, star, jup, juf; java = MainFrame.getIcon("JavaIcon20.gif"); dj0 = MainFrame.getIcon("ElementaryIcon20.gif"); dj1 = MainFrame.getIcon("IntermediateIcon20.gif"); dj2 = MainFrame.getIcon("AdvancedIcon20.gif"); other = MainFrame.getIcon("OtherIcon20.gif"); _djFileDisplayManager20 = new DJFileDisplayManager(java,dj0,dj1,dj2,other); java = MainFrame.getIcon("JavaIcon30.gif"); dj0 = MainFrame.getIcon("ElementaryIcon30.gif"); dj1 = MainFrame.getIcon("IntermediateIcon30.gif"); dj2 = MainFrame.getIcon("AdvancedIcon30.gif"); other = MainFrame.getIcon("OtherIcon30.gif"); _djFileDisplayManager30 = new DJFileDisplayManager(java,dj0,dj1,dj2,other); star = MainFrame.getIcon("ModStar20.gif"); jup = MainFrame.getIcon("JUnitPass20.gif"); juf = MainFrame.getIcon("JUnitFail20.gif"); _oddDisplayManager20 = new OddDisplayManager(_djFileDisplayManager20,star,jup,juf); star = MainFrame.getIcon("ModStar30.gif"); jup = MainFrame.getIcon("JUnitPass30.gif"); juf = MainFrame.getIcon("JUnitFail30.gif"); _oddDisplayManager30 = new OddDisplayManager(_djFileDisplayManager30,star,jup,juf); _djProjectIcon = MainFrame.getIcon("ProjectIcon.gif"); } /** This manager is meant to retrieve the correct icons for the given filename. The only files recognized * are the files obviously listed below in the function (.java, .dj0, .dj1, .dj2). The icons that represent * each filetype are given into the managers constructor upon instantiation. This class is static since * it currently does not depend of the main frame for information. */ private static class DJFileDisplayManager extends DefaultFileDisplayManager { private final Icon _java; private final Icon _dj0; private final Icon _dj1; private final Icon _dj2; private final Icon _other; public DJFileDisplayManager(Icon java, Icon dj0, Icon dj1, Icon dj2, Icon other) { _java = java; _dj0 = dj0; _dj1 = dj1; _dj2 = dj2; _other = other; } /** This method chooses the custom icon only for the known filetypes. If these filetypes are not receiving * the correct icons, make sure the filenames are correct and that the icons are present in the ui/icons * directory. */ public Icon getIcon(File f) { if (f == null) return _other; Icon ret = null; if (! f.isDirectory()) { String name = f.getName().toLowerCase(); if (name.endsWith(".java")) ret = _java; if (name.endsWith(".dj0")) ret = _dj0; if (name.endsWith(".dj1")) ret = _dj1; if (name.endsWith(".dj2")) ret = _dj2; } if (ret == null) { ret = super.getIcon(f); if (ret.getIconHeight() < _java.getIconHeight()) { ret = new CenteredIcon(ret, _java.getIconWidth(), _java.getIconHeight()); } } return ret; } } /** This class wraps the file display managers by superimposing any notification icons on top of the base * file icon. Currently, only the modified star is allowed, but everything is set up to add notification * icons for whether a document has passed the junit test (for display in the tree). This class is static * for now. It may be necessary to make it dynamic when implementing the junit notifications. */ private static class OddDisplayManager implements DisplayManager<OpenDefinitionsDocument> { private final Icon _star; // private Icon _juPass; // private Icon _juFail; private final FileDisplayManager _default; /** Standard constructor. * @param star The star icon will be put flush to the left 1/4 the way down * @param junitPass indicator of junit success, placed at bottom right * @param junitFail indicator of junit failure, placed at bottom right */ public OddDisplayManager(FileDisplayManager fdm, Icon star, Icon junitPass, Icon junitFail) { _star = star; // _juPass = junitPass; // _juFail = junitFail; _default = fdm; } public Icon getIcon(OpenDefinitionsDocument odd) { File f = null; try { f = odd.getFile(); } catch(FileMovedException fme) { /* do nothing */ } if (odd.isModifiedSinceSave()) return makeLayeredIcon(_default.getIcon(f), _star); return _default.getIcon(f); } public String getName(OpenDefinitionsDocument doc) { return doc.getFileName(); } private LayeredIcon makeLayeredIcon(Icon base, Icon star) { return new LayeredIcon(new Icon[]{base, star}, new int[]{0, 0}, new int[]{0, (base.getIconHeight() / 4)}); } }; /** This is what is given to the JTreeSortNavigator. This simply resolves the INavItem to an OpenDefDoc * using the model and forwards it to the OddDisplayManager for size 20. */ private final DisplayManager<INavigatorItem> _navPaneDisplayManager = new DisplayManager<INavigatorItem>() { public Icon getIcon(INavigatorItem item) { OpenDefinitionsDocument odd = (OpenDefinitionsDocument) item; // FIX THIS! return _oddDisplayManager20.getIcon(odd); } public String getName(INavigatorItem name) { return name.getName(); } }; /** These listeners support the travel operations that cycle through recent documents. */ KeyListener _historyListener = new KeyListener() { public void keyPressed(KeyEvent e) { int backQuote = java.awt.event.KeyEvent.VK_BACK_QUOTE; if (e.getKeyCode() == backQuote && e.isControlDown() && ! e.isShiftDown()) nextRecentDoc(); if (e.getKeyCode() == backQuote && e.isControlDown() && e.isShiftDown()) prevRecentDoc(); // else if (e.getKeyCode()==java.awt.event.KeyEvent.VK_BACK_QUOTE) { // transferFocusUpCycle(); // } } public void keyReleased(KeyEvent e) { if (e.getKeyCode() == java.awt.event.KeyEvent.VK_CONTROL) hideRecentDocFrame(); } public void keyTyped(KeyEvent e) { /* noop */ } }; FocusListener _focusListenerForRecentDocs = new FocusListener() { public void focusLost(FocusEvent e) { hideRecentDocFrame(); } public void focusGained(FocusEvent e) { } }; public static DJFileDisplayManager getFileDisplayManager20() { return _djFileDisplayManager20; } public static DJFileDisplayManager getFileDisplayManager30() { return _djFileDisplayManager30; } public static OddDisplayManager getOddDisplayManager20() { return _oddDisplayManager20; } public static OddDisplayManager getOddDisplayManager30() { return _oddDisplayManager30; } public DisplayManager<INavigatorItem> getNavPaneDisplayManager() { return _navPaneDisplayManager; } /* ----------------------- Constructor is here! --------------------------- */ /** Creates the main window, and shows it. */ public MainFrame() { // Cache the config object, since we use it many, many times. final Configuration config = DrJava.getConfig(); // Utilities.show("MainFrame starting"); // create our model _model = new DefaultGlobalModel(); _showDebugger = _model.getDebugger().isAvailable(); _findReplace = new FindReplacePanel(this, _model); if (_showDebugger) { _debugPanel = new DebugPanel(this); _breakpointsPanel = new BreakpointsPanel(this, _model.getBreakpointManager()); } else { _debugPanel = null; _breakpointsPanel = null; } _compilerErrorPanel = new CompilerErrorPanel(_model, this); _consoleController = new ConsoleController(_model.getConsoleDocument(), _model.getSwingConsoleDocument()); _consolePane = _consoleController.getPane(); _consoleScroll = new BorderlessScrollPane(_consolePane) { public boolean requestFocusInWindow() { super.requestFocusInWindow(); return _consolePane.requestFocusInWindow(); } }; _interactionsController = new InteractionsController(_model.getInteractionsModel(), _model.getSwingInteractionsDocument()); _interactionsPane = _interactionsController.getPane(); // _interactionsController.setCachedCaretPos(0); // _interactionsController.setCachedPromptPos(_model.getConsoleDocument().getPromptPos()); _interactionsContainer = new JPanel(new BorderLayout()); /* { public boolean requestFocusInWindow() { super.requestFocusInWindow(); return _interactionsPane.requestFocusInWindow(); } };*/ _lastFocusOwner = _interactionsContainer; _junitErrorPanel = new JUnitPanel(_model, this); _javadocErrorPanel = new JavadocErrorPanel(_model, this); _bookmarksPanel = new BookmarksPanel(this, _model.getBookmarkManager()); // Initialize the status bar _setUpStatusBar(); // Preliminary layout /* Definitions Pane */ /* Ensure that DefinitionsPane uses the correct EditorKit! This has to be stored as a static field on * DefinitionsPane because the JEditorPane constructor uses it before we get a chance to assign it to an instance * field ... */ DefinitionsPane.setEditorKit(_model.getEditorKit()); _defScrollPanes = new HashMap<OpenDefinitionsDocument, JScrollPane>(); /* Set up tabbed pane and navigation pane. */ _tabbedPane = new JTabbedPane(); _tabbedPane.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { Component c = _tabbedPane.getSelectedComponent(); // System.err.println("focus gained in tabbed pane with tab " + c + " with paramString " + e.paramString()); if (c == _interactionsContainer) { _interactionsPane.requestFocusInWindow(); // System.err.println("Selected tab was interactions container"); } else if (c == _findReplace) _findReplace.getFindField().requestFocusInWindow(); } public void focusLost(FocusEvent e) { } }); _tabbedPane.addFocusListener(_focusListenerForRecentDocs); _tabbedPane.addKeyListener(_historyListener); // TODO: can this code be moved to the MainFrame keymap? if(Utilities.isPlasticLaf()) { _tabbedPane.putClientProperty(com.jgoodies.looks.Options.EMBEDDED_TABS_KEY, Boolean.TRUE); } JScrollPane defScroll = _createDefScrollPane(_model.getActiveDocument()); _docSplitPane = new BorderlessSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(_model.getDocumentNavigator().asContainer()), defScroll); _debugSplitPane = new BorderlessSplitPane(JSplitPane.VERTICAL_SPLIT, true); _mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, _docSplitPane, _tabbedPane); // Lightweight parsing has been disabled until we have something that is beneficial and works better in the background. // // The OptionListener for LIGHTWEIGHT_PARSING_ENABLED. // OptionListener<Boolean> parsingEnabledListener = new OptionListener<Boolean>() { // public void optionChanged(OptionEvent<Boolean> oce) { // if (oce.value) { // _model.getParsingControl().addListener(new LightWeightParsingListener() { // public void enclosingClassNameUpdated(OpenDefinitionsDocument doc, String old, String updated) { // if (doc==_model.getActiveDocument()) { updateStatusField(); } // } // }); // } // _model.getParsingControl().reset(); // _model.getParsingControl().setAutomaticUpdates(oce.value); // updateStatusField(); // } // }; // DrJava.getConfig().addOptionListener(LIGHTWEIGHT_PARSING_ENABLED, parsingEnabledListener); // parsingEnabledListener. // optionChanged(new OptionEvent<Boolean>(LIGHTWEIGHT_PARSING_ENABLED, // DrJava.getConfig(). // getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue())); // // Utilities.show("Global Model started"); _tabbedPanesFrame = new DetachedFrame("Tabbed Panes", MainFrame.this, new Runnable1<DetachedFrame>() { public void run(DetachedFrame frame) { frame.getContentPane().add(_tabbedPane); } }, new Runnable1<DetachedFrame>() { public void run(DetachedFrame frame) { _mainSplit.setBottomComponent(_tabbedPane); } }); _tabbedPanesFrame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { _detachTabbedPanesMenuItem.setSelected(false); DrJava.getConfig().setSetting(DETACH_TABBEDPANES, false); } }); _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener); _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs); /* Listens for clicks in the document navigator to reset the first document in an all-documents search for wrapping * purposes. */ _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener); if (_showDebugger) _model.getDebugger().addListener(new UIDebugListener()); // add listener to debug manager // Timer to display a message if a debugging step takes a long time _debugStepTimer = new Timer(DEBUG_STEP_TIMER_VALUE, new ActionListener() { public void actionPerformed(ActionEvent e) { _model.printDebugMessage("Stepping..."); } }); _debugStepTimer.setRepeats(false); // Working directory is default place to start (bug #895998). File workDir = _model.getMasterWorkingDirectory(); // Overrides JFileChooser to display the full path of the directory _openChooser = new JFileChooser() { public void setCurrentDirectory(File dir) { //next two lines are order dependent! super.setCurrentDirectory(dir); setDialogTitle("Open: " + getCurrentDirectory()); } }; _openChooser.setPreferredSize(new Dimension(650, 410)); _openChooser.setCurrentDirectory(workDir); _openChooser.setFileFilter(_javaSourceFilter); _openChooser.setMultiSelectionEnabled(true); _openRecursiveCheckBox = new JCheckBox("Open folders recursively"); _openRecursiveCheckBox.setSelected(config.getSetting(OptionConstants.OPEN_FOLDER_RECURSIVE).booleanValue()); _folderChooser = makeFolderChooser(workDir); //Get most recently opened project for filechooser Vector<File> recentProjects = config.getSetting(RECENT_PROJECTS); _openProjectChooser = new JFileChooser(); _openProjectChooser.setPreferredSize(new Dimension(650, 410)); if (recentProjects.size() > 0 && recentProjects.elementAt(0).getParentFile() != null) _openProjectChooser.setCurrentDirectory(recentProjects.elementAt(0).getParentFile()); else _openProjectChooser.setCurrentDirectory(workDir); _openProjectChooser.setFileFilter(_projectFilter); _openProjectChooser.setMultiSelectionEnabled(false); _saveChooser = new JFileChooser() { public void setCurrentDirectory(File dir) { //next two lines are order dependent! super.setCurrentDirectory(dir); setDialogTitle("Save: " + getCurrentDirectory()); } }; _saveChooser.setPreferredSize(new Dimension(650, 410)); _saveChooser.setCurrentDirectory(workDir); _saveChooser.setFileFilter(_javaSourceFilter); _interactionsHistoryChooser = new JFileChooser(); _interactionsHistoryChooser.setPreferredSize(new Dimension(650, 410)); _interactionsHistoryChooser.setCurrentDirectory(workDir); _interactionsHistoryChooser.setFileFilter(new InteractionsHistoryFilter()); _interactionsHistoryChooser.setMultiSelectionEnabled(true); //set up the hourglass cursor setGlassPane(new GlassPane()); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); // Set up listeners addWindowListener(_windowCloseListener); // Create the main model listener and attach it to the global model _mainListener = new ModelListener(); _model.addListener(_mainListener); // Initialize tabs before DefPane _setUpTabs(); // DefinitionsPane _recentDocFrame = new RecentDocFrame(this); OpenDefinitionsDocument activeDoc = _model.getActiveDocument(); _recentDocFrame.pokeDocument(activeDoc); _currentDefDoc = activeDoc.getDocument(); _currentDefPane = (DefinitionsPane) defScroll.getViewport().getView(); _currentDefPane.notifyActive(); // Get proper cross-platform mask. int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); // set up key-bindings KeyBindingManager.ONLY.setMainFrame(this); KeyBindingManager.ONLY.setActionMap(_currentDefPane.getActionMap()); _setUpKeyBindingMaps(); _posListener.updateLocation(); // Need to set undo/redo actions to point to the initial def pane // on switching documents later these pointers will also switch _undoAction.setDelegatee(_currentDefPane.getUndoAction()); _redoAction.setDelegatee(_currentDefPane.getRedoAction()); _compilerErrorPanel.reset(); _junitErrorPanel.reset(); _javadocErrorPanel.reset(); // Create menubar and menus _menuBar = new MenuBar(); _fileMenu = _setUpFileMenu(mask); _editMenu = _setUpEditMenu(mask); _toolsMenu = _setUpToolsMenu(mask); _projectMenu = _setUpProjectMenu(mask); _debugMenu = null; if (_showDebugger) _debugMenu = _setUpDebugMenu(mask); _languageLevelMenu = _setUpLanguageLevelMenu(mask); _helpMenu = _setUpHelpMenu(mask); // initialize menu bar and actions _setUpActions(); _setUpMenuBar(); // _setUpDocumentSelector(); _setUpContextMenus(); // Create toolbar and buttons _toolBar = new JToolBar(); _undoButton = _createManualToolbarButton(_undoAction); _redoButton = _createManualToolbarButton(_redoAction); // initialize _toolBar _setUpToolBar(); // Create detachable debug frame if (_debugPanel!=null) { // using debugger _debugFrame = new DetachedFrame("Debugger", MainFrame.this, new Runnable1<DetachedFrame>() { public void run(DetachedFrame frame) { frame.getContentPane().add(_debugPanel); } }, new Runnable1<DetachedFrame>() { public void run(DetachedFrame frame) { _debugSplitPane.setTopComponent(_docSplitPane); _debugSplitPane.setBottomComponent(_debugPanel); _mainSplit.setTopComponent(_debugSplitPane); } }); _debugFrame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { if (_debugFrame==null) return; // debugger not used _detachDebugFrameMenuItem.setSelected(false); DrJava.getConfig().setSetting(DETACH_DEBUGGER, false); } }); } else { // not using debugger _debugFrame = null; } // add recent file and project manager RecentFileAction fileAct = new RecentFileManager.RecentFileAction() { public void actionPerformed(FileOpenSelector selector) { open(selector); } }; _recentFileManager = new RecentFileManager(_fileMenu.getItemCount() - 2, _fileMenu, fileAct, OptionConstants.RECENT_FILES); RecentFileAction projAct = new RecentFileManager.RecentFileAction() { public void actionPerformed(FileOpenSelector selector) { openProject(selector); } }; _recentProjectManager = new RecentFileManager(_projectMenu.getItemCount() - 2, _projectMenu, projAct, OptionConstants.RECENT_PROJECTS); // Set frame icon setIconImage(getIcon("drjava64.png").getImage()); // Size and position int x = config.getSetting(WINDOW_X).intValue(); int y = config.getSetting(WINDOW_Y).intValue(); int width = config.getSetting(WINDOW_WIDTH).intValue(); int height = config.getSetting(WINDOW_HEIGHT).intValue(); int state = config.getSetting(WINDOW_STATE).intValue(); // Bounds checking. // suggested from zaq@nosi.com, to keep the frame on the screen! Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); final int menubarHeight = 24; if (height > screenSize.height - menubarHeight) height = screenSize.height - menubarHeight; // Too tall, so resize if (width > screenSize.width) width = screenSize.width; // Too wide, so resize // I assume that we want to be contained on the default screen. // TODO: support spanning screens in multi-screen setups. Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(). getDefaultConfiguration().getBounds(); if (x == Integer.MAX_VALUE) x = (bounds.width - width + bounds.x) / 2; // magic value for "not set" - center. if (y == Integer.MAX_VALUE) y = (bounds.height - height + bounds.y) / 2; // magic value for "not set" - center. if (x < bounds.x) x = bounds.x; // Too far left, move to left edge. if (y < bounds.y) y = bounds.y; // Too far up, move to top edge. if ((x + width) > (bounds.x + bounds.width)) x = bounds.width - width + bounds.x; // Too far right, move to right edge. if ((y + height) > (bounds.y + bounds.height)) y = bounds.height - height + bounds.y; // Too far down, move to bottom edge. //ensure that we don't set window state to minimized state &= ~Frame.ICONIFIED; if (!Toolkit.getDefaultToolkit().isFrameStateSupported(state)) { //we have a bad state, so reset to default state = WINDOW_STATE.getDefault(); } // Set to the new correct size and location setBounds(x, y, width, height); //Work-aroung for Java bug #6365898? //setExtendedState does not work until the window in shown on Linux. final int stateCopy = state; addWindowListener(new WindowAdapter() { public void windowOpened(WindowEvent e) { setExtendedState(stateCopy); //this is a one-off listener removeWindowListener(this); } }); _setUpPanes(); updateStatusField(); _promptBeforeQuit = config.getSetting(QUIT_PROMPT).booleanValue(); // Set the fonts _setMainFont(); Font doclistFont = config.getSetting(FONT_DOCLIST); _model.getDocCollectionWidget().setFont(doclistFont); // Set the colors _updateNormalColor(); _updateBackgroundColor(); // Add OptionListeners for the colors. config.addOptionListener(DEFINITIONS_NORMAL_COLOR, new NormalColorOptionListener()); config.addOptionListener(DEFINITIONS_BACKGROUND_COLOR, new BackgroundColorOptionListener()); /* Add option listeners for changes to config options. NOTE: We should only add listeners to view-related (or view- * dependent) config options here. Model options should go in DefaultGlobalModel._registerOptionListeners(). */ config.addOptionListener(FONT_MAIN, new MainFontOptionListener()); config.addOptionListener(FONT_LINE_NUMBERS, new LineNumbersFontOptionListener()); config.addOptionListener(FONT_DOCLIST, new DoclistFontOptionListener()); config.addOptionListener(FONT_TOOLBAR, new ToolbarFontOptionListener()); config.addOptionListener(TOOLBAR_ICONS_ENABLED, new ToolbarOptionListener()); config.addOptionListener(TOOLBAR_TEXT_ENABLED, new ToolbarOptionListener()); config.addOptionListener(TOOLBAR_ENABLED, new ToolbarOptionListener()); config.addOptionListener(LINEENUM_ENABLED, new LineEnumOptionListener()); config.addOptionListener(QUIT_PROMPT, new QuitPromptOptionListener()); config.addOptionListener(RECENT_FILES_MAX_SIZE, new RecentFilesOptionListener()); config.addOptionListener(ALLOW_PRIVATE_ACCESS, new OptionListener<Boolean>() { public void optionChanged(OptionEvent<Boolean> oce) { _model.getInteractionsModel().setPrivateAccessible(oce.value.booleanValue()); } }); config.addOptionListener(FORCE_TEST_SUFFIX, new OptionListener<Boolean>() { public void optionChanged(OptionEvent<Boolean> oce) { _model.getJUnitModel().setForceTestSuffix(oce.value.booleanValue()); } }); // The OptionListener for JAVADOC_API_REF_VERSION. OptionListener<String> choiceOptionListener = new OptionListener<String>() { public void optionChanged(OptionEvent<String> oce) { _javaAPIList = null; } }; DrJava.getConfig().addOptionListener(JAVADOC_API_REF_VERSION, choiceOptionListener); // The OptionListener for JAVADOC_XXX_LINK. OptionListener<String> link13OptionListener = new OptionListener<String>() { public void optionChanged(OptionEvent<String> oce) { String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION); if (linkVersion.equals(JAVADOC_1_3_TEXT)) { _javaAPIList = null; } } }; DrJava.getConfig().addOptionListener(JAVADOC_1_3_LINK, link13OptionListener); OptionListener<String> link14OptionListener = new OptionListener<String>() { public void optionChanged(OptionEvent<String> oce) { String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION); if (linkVersion.equals(JAVADOC_1_4_TEXT)) { _javaAPIList = null; } } }; DrJava.getConfig().addOptionListener(JAVADOC_1_4_LINK, link14OptionListener); OptionListener<String> link15OptionListener = new OptionListener<String>() { public void optionChanged(OptionEvent<String> oce) { String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION); if (linkVersion.equals(JAVADOC_1_5_TEXT)) { _javaAPIList = null; } } }; DrJava.getConfig().addOptionListener(JAVADOC_1_5_LINK, link15OptionListener); OptionListener<String> link16OptionListener = new OptionListener<String>() { public void optionChanged(OptionEvent<String> oce) { String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION); if (linkVersion.equals(JAVADOC_1_6_TEXT)) { _javaAPIList = null; } } }; DrJava.getConfig().addOptionListener(JAVADOC_1_6_LINK, link16OptionListener); // Initialize DocumentRegion highlights hashtables, for easy removal of highlights _documentBreakpointHighlights = new IdentityHashMap<Breakpoint, HighlightManager.HighlightInfo>(); _documentBookmarkHighlights = new IdentityHashMap<OrderedDocumentRegion, HighlightManager.HighlightInfo>(); // Initialize cached frames and dialogs _configFrame = new ConfigFrame(this); _helpFrame = new HelpFrame(); _aboutDialog = new AboutDialog(MainFrame.this); _quickStartFrame = new QuickStartFrame(); _interactionsScriptController = null; _executeExternalDialog = new ExecuteExternalDialog(MainFrame.this); _editExternalDialog = new EditExternalDialog(MainFrame.this); _jarOptionsDialog = new JarOptionsDialog(MainFrame.this); initTabbedPanesFrame(); initDebugFrame(); initJarOptionsDialog(); initExecuteExternalProcessDialog(); // _projectPropertiesFrame = null; config.addOptionListener(LOOK_AND_FEEL, new ConfigOptionListeners.LookAndFeelListener(_configFrame)); config.addOptionListener(PLASTIC_THEMES, new ConfigOptionListeners.PlasticThemeListener(_configFrame)); OptionListener<String> slaveJVMArgsListener = new ConfigOptionListeners.SlaveJVMArgsListener(_configFrame); config.addOptionListener(SLAVE_JVM_ARGS, slaveJVMArgsListener); _slaveJvmXmxListener = new ConfigOptionListeners.SlaveJVMXMXListener(_configFrame); config.addOptionListener(SLAVE_JVM_XMX, _slaveJvmXmxListener); OptionListener<String> masterJVMArgsListener = new ConfigOptionListeners.MasterJVMArgsListener(_configFrame); config.addOptionListener(MASTER_JVM_ARGS, masterJVMArgsListener); _masterJvmXmxListener = new ConfigOptionListeners.MasterJVMXMXListener(_configFrame); config.addOptionListener(MASTER_JVM_XMX, _masterJvmXmxListener); config.addOptionListener(JAVADOC_CUSTOM_PARAMS, new ConfigOptionListeners.JavadocCustomParamsListener(_configFrame)); ConfigOptionListeners.sanitizeSlaveJVMArgs(this, config.getSetting(SLAVE_JVM_ARGS), slaveJVMArgsListener); ConfigOptionListeners.sanitizeSlaveJVMXMX(this, config.getSetting(SLAVE_JVM_XMX)); ConfigOptionListeners.sanitizeMasterJVMArgs(this, config.getSetting(MASTER_JVM_ARGS), masterJVMArgsListener); ConfigOptionListeners.sanitizeMasterJVMXMX(this, config.getSetting(MASTER_JVM_XMX)); ConfigOptionListeners.sanitizeJavadocCustomParams(this, config.getSetting(JAVADOC_CUSTOM_PARAMS)); // If any errors occurred while parsing config file, show them _showConfigException(); KeyBindingManager.ONLY.setShouldCheckConflict(false); // Platform-specific UI setup. PlatformFactory.ONLY.afterUISetup(_aboutAction, _editPreferencesAction, _quitAction); setUpKeys(); // discard ` character if it was used for the next/prev recent doc feature KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() { public boolean dispatchKeyEvent(KeyEvent e) { boolean discardEvent = false; if ((e.getID() == KeyEvent.KEY_TYPED) && (e.getKeyChar()=='`') && (((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) || ((e.getModifiersEx() & (InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK)) == (InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK))) && (e.getComponent().getClass().equals(DefinitionsPane.class))) { // System.out.println("discarding `, modifiers = "+e.getModifiersEx()+": "+e.getComponent()); discardEvent = true; } return discardEvent; } }); if (DrJava.getConfig().getSetting(edu.rice.cs.drjava.config.OptionConstants.REMOTE_CONTROL_ENABLED)) { // start remote control server if no server is running try { if (! RemoteControlClient.isServerRunning()) { edu.rice.cs.drjava.RemoteControlServer rcServer = new edu.rice.cs.drjava.RemoteControlServer(this); } } catch(IOException ioe) { try { RemoteControlClient.openFile(null); } catch(IOException ignored) { // ignore } if (!Utilities.TEST_MODE && !System.getProperty("user.name").equals(RemoteControlClient.getServerUser())) { Object[] options = {"Disable","Ignore"}; String msg = "<html>Could not start DrJava's remote control server"; if (RemoteControlClient.getServerUser()!=null) { msg += "<br>because user "+RemoteControlClient.getServerUser()+" is already using the same port"; } msg += ".<br>Please select an unused port in the Preferences dialog.<br>"+ "In the meantime, do you want to disable the remote control feature?"; int n = JOptionPane.showOptionDialog(MainFrame.this, msg, "Could Not Start Remote Control Server", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (n==JOptionPane.YES_OPTION) { DrJava.getConfig().setSetting(edu.rice.cs.drjava.config.OptionConstants.REMOTE_CONTROL_ENABLED, false); } } } } setUpDrJavaProperties(); DrJavaErrorHandler.setButton(_errorsButton); // check for new version if desired by user boolean askedForNewVersion = false; if (! DrJava.getConfig().getSetting(OptionConstants.NEW_VERSION_NOTIFICATION) .equals(OptionConstants.NEW_VERSION_NOTIFICATION_CHOICES.get(3)) && !edu.rice.cs.util.swing.Utilities.TEST_MODE) { int days = DrJava.getConfig().getSetting(NEW_VERSION_NOTIFICATION_DAYS); java.util.Date nextCheck = new java.util.Date(DrJava.getConfig().getSetting(OptionConstants.LAST_NEW_VERSION_NOTIFICATION) + days * 24L * 60 * 60 * 1000); // x days after last check; 24L ensures long accumulation if (new java.util.Date().after(nextCheck)) { askedForNewVersion = true; EventQueue.invokeLater(new Runnable() { public void run() { NewVersionPopup popup = new NewVersionPopup(MainFrame.this); if (popup.checkNewVersion()) { popup.setVisible(true); } } }); } } if (!askedForNewVersion) { // check for new version if desired by user // but only if we haven't just asked if the user wants to download a new version // two dialogs on program start is too much clutter if (DrJava.getConfig().getSetting(DIALOG_DRJAVA_SURVEY_ENABLED) && !edu.rice.cs.util.swing.Utilities.TEST_MODE) { if (DrJavaSurveyPopup.maySubmitSurvey()) { // either enough days have passed, or the configuration has changed EventQueue.invokeLater(new Runnable() { public void run() { DrJavaSurveyPopup popup = new DrJavaSurveyPopup(MainFrame.this); popup.setVisible(true); } }); } } } initDone(); // call mandated by SwingFrame contract EventQueue.invokeLater(new Runnable() { public void run() { _tabbedPanesFrame.setDisplayInFrame(DrJava.getConfig().getSetting(DETACH_TABBEDPANES)); } }); } // End of MainFrame constructor public void setVisible(boolean b) { _updateToolBarVisible(); super.setVisible(b); } /** This method sets up all the DrJava properties that can be used as variables * in external process command lines. */ public void setUpDrJavaProperties() { final String DEF_DIR = "${drjava.working.dir}"; DrJavaPropertySetup.setup(); // Files PropertyMaps.TEMPLATE. setProperty("DrJava", new FileProperty("drjava.current.file", new Thunk<File>() { public File value() { return _model.getActiveDocument().getRawFile(); } }, "Returns the current document in DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which the output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE.setProperty("DrJava", new DrJavaProperty("drjava.current.line", "Returns the current line in the Definitions Pane.") { public void update(PropertyMaps pm) { _value = String.valueOf(_posListener.lastLine()); } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("DrJava", new DrJavaProperty("drjava.current.col", "Returns the current column in the Definitions Pane.") { public void update(PropertyMaps pm) { // int line = _currentDefPane.getCurrentLine(); // int lineOffset = _currentDefPane.getLineStartOffset(line); // int caretPos = _currentDefPane.getCaretPosition(); _value = String.valueOf(_posListener.lastCol()); } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("DrJava", new FileProperty("drjava.working.dir", new Thunk<File>() { public File value() { return _model.getInteractionsModel().getWorkingDirectory(); } }, "Returns the current working directory of DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("DrJava", new FileProperty("drjava.master.working.dir", new Thunk<File>() { public File value() { return _model.getMasterWorkingDirectory(); } }, "Returns the working directory of the DrJava master JVM.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); // Files PropertyMaps.TEMPLATE. setProperty("DrJava", new FileListProperty("drjava.all.files", File.pathSeparator, DEF_DIR, "Returns a list of all files open in DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which output should be relative\"\n"+ "\tsep=\"<separator between files>\"") { protected List<File> getList(PropertyMaps pm) { ArrayList<File> l = new ArrayList<File>(); for(OpenDefinitionsDocument odd: _model.getOpenDefinitionsDocuments()) { l.add(odd.getRawFile()); } return l; } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("DrJava", new FileListProperty("drjava.project.files", File.pathSeparator, DEF_DIR, "Returns a list of all files open in DrJava that belong " + "to a project and are underneath the project root.\n" + "Optional attributes:\n" + "\trel=\"<dir to which output should be relative\"\n" + "\tsep=\"<separator between files>\"") { protected List<File> getList(PropertyMaps pm) { ArrayList<File> l = new ArrayList<File>(); for(OpenDefinitionsDocument odd: _model.getProjectDocuments()) { l.add(odd.getRawFile()); } return l; } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }).listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files")); PropertyMaps.TEMPLATE. setProperty("DrJava", new FileListProperty("drjava.included.files", File.pathSeparator, DEF_DIR, "Returns a list of all files open in DrJava that are " + "not underneath the project root but are included in " + "the project.\n" + "Optional attributes:\n" + "\trel=\"<dir to which output should be relative\"\n" + "\tsep=\"<separator between files>\"") { protected List<File> getList(PropertyMaps pm) { ArrayList<File> l = new ArrayList<File>(); for(OpenDefinitionsDocument odd: _model.getAuxiliaryDocuments()) { l.add(odd.getRawFile()); } return l; } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }).listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files")); PropertyMaps.TEMPLATE. setProperty("DrJava", new FileListProperty("drjava.external.files", File.pathSeparator, DEF_DIR, "Returns a list of all files open in DrJava that are "+ "not underneath the project root and are not included in "+ "the project.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which output should be relative\"\n"+ "\tsep=\"<separator between files>\"") { protected List<File> getList(PropertyMaps pm) { ArrayList<File> l = new ArrayList<File>(); for(OpenDefinitionsDocument odd: _model.getNonProjectDocuments()) { l.add(odd.getRawFile()); } return l; } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }).listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files")); PropertyMaps.TEMPLATE. setProperty("Misc", new DrJavaProperty("input", "(User Input...)", "Get an input string from the user.\n"+ "Optional attributes:\n"+ "\tprompt=\"<prompt to display>\"\n"+ "\tdefault=\"<suggestion to the user>\"") { public String toString() { return "(User Input...)"; } public void update(PropertyMaps pm) { String msg = _attributes.get("prompt"); if (msg == null) msg = "Please enter text for the external process."; String input = _attributes.get("default"); if (input == null) input = ""; input = JOptionPane.showInputDialog(MainFrame.this, msg, input); if (input == null) input = _attributes.get("default"); if (input == null) input = ""; _value = input; } public String getCurrent(PropertyMaps pm) { invalidate(); return super.getCurrent(pm); } public void resetAttributes() { _attributes.clear(); _attributes.put("prompt", null); _attributes.put("default", null); } }); // Project PropertyMaps.TEMPLATE. setProperty("Project", new DrJavaProperty("project.mode", "Evaluates to true if a project is loaded.") { public void update(PropertyMaps pm) { Boolean b = _model.isProjectActive(); String f = _attributes.get("fmt").toLowerCase(); if (f.equals("int")) _value = b ? "1" : "0"; else if (f.equals("yes")) _value = b ? "yes" : "no"; else _value = b.toString(); } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } public void resetAttributes() { _attributes.clear(); _attributes.put("fmt", "boolean"); } }); PropertyMaps.TEMPLATE. setProperty("Project", new DrJavaProperty("project.changed", "Evaluates to true if the project has been "+ "changed since the last save.") { //TODO: factor out repeated code! public void update(PropertyMaps pm) { // long millis = System.currentTimeMillis(); String f = _attributes.get("fmt").toLowerCase(); Boolean b = _model.isProjectChanged(); if (f.equals("int")) _value = b ? "1" : "0"; else if (f.equals("yes")) _value = b ? "yes" : "no"; else _value = b.toString(); } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } public void resetAttributes() { _attributes.clear(); _attributes.put("fmt", "boolean"); } }); PropertyMaps.TEMPLATE. setProperty("Project", new FileProperty("project.file", new Thunk<File>() { public File value() { return _model.getProjectFile(); } }, "Returns the current project file in DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which the output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("Project", new FileProperty("project.main.class", new Thunk<File>() { public File value() { return _model.getMainClass(); } }, "Returns the current project file in DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which the output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("Project", new FileProperty("project.root", new Thunk<File>() { public File value() { return _model.getProjectRoot(); } }, "Returns the current project root in DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which the output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("Project", new FileProperty("project.build.dir", new Thunk<File>() { public File value() { return _model.getBuildDirectory(); } }, "Returns the current build directory in DrJava.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which the output should be relative\"") { public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); RecursiveFileListProperty classFilesProperty = new RecursiveFileListProperty("project.class.files", File.pathSeparator, DEF_DIR, _model.getBuildDirectory().getAbsolutePath(), "Returns the class files currently in the build directory.") { /** Reset the attributes. */ public void resetAttributes() { _attributes.clear(); _attributes.put("sep", _sep); _attributes.put("rel", _dir); _attributes.put("dir", _model.getBuildDirectory().getAbsolutePath()); _attributes.put("filter", "*.class"); _attributes.put("dirfilter", "*"); } }; PropertyMaps.TEMPLATE.setProperty("Project", classFilesProperty); PropertyMaps.TEMPLATE. setProperty("Project", new DrJavaProperty("project.auto.refresh", "Evaluates to true if project auto-refresh is enabled.") { public void update(PropertyMaps pm) { Boolean b = _model.getAutoRefreshStatus(); String f = _attributes.get("fmt").toLowerCase(); if (f.equals("int")) _value = b ? "1" : "0"; else if (f.equals("yes")) _value = b ? "yes" : "no"; else _value = b.toString(); } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } public void resetAttributes() { _attributes.clear(); _attributes.put("fmt", "boolean"); } }); PropertyMaps.TEMPLATE. setProperty("Project", new FileListProperty("project.excluded.files", File.pathSeparator, DEF_DIR, "Returns a list of files that are excluded from DrJava's "+ "project auto-refresh.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which output should be relative\"\n"+ "\tsep=\"<separator between files>\"") { protected List<File> getList(PropertyMaps pm) { ArrayList<File> l = new ArrayList<File>(); for(File f: _model.getExclFiles()) { l.add(f); } return l; } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); PropertyMaps.TEMPLATE. setProperty("Project", new FileListProperty("project.extra.class.path", File.pathSeparator, DEF_DIR, "Returns a list of files in the project's extra "+ "class path.\n"+ "Optional attributes:\n"+ "\trel=\"<dir to which output should be relative\"\n"+ "\tsep=\"<separator between files>\"") { protected List<File> getList(PropertyMaps pm) { ArrayList<File> l = new ArrayList<File>(); for(File f: _model.getExtraClassPath()) { l.add(f); } return l; } public String getLazy(PropertyMaps pm) { return getCurrent(pm); } }); // Actions PropertyMaps.TEMPLATE.setProperty("Action", new DrJavaActionProperty("action.save.all", "(Save All...)", "Execute a \"Save All\" action.") { public void update(PropertyMaps pm) { _saveAll(); } }); PropertyMaps.TEMPLATE. setProperty("Action", new DrJavaActionProperty("action.compile.all", "(Compile All...)", "Execute a \"Compile All\" action.") { public void update(PropertyMaps pm) { _compileAll(); } }); PropertyMaps.TEMPLATE. setProperty("Action", new DrJavaActionProperty("action.clean", "(Clean Build Directory...)", "Execute a \"Clean Build Directory\" action.") { public void update(PropertyMaps pm) { // could not use _clean(), since ProjectFileGroupingState.cleanBuildDirectory() // is implemented as an asynchronous task, and DrJava would not wait for its completion edu.rice.cs.plt.io.IOUtil.deleteRecursively(_model.getBuildDirectory()); } }); PropertyMaps.TEMPLATE.setProperty("Action", new DrJavaActionProperty("action.open.file", "(Open File...)", "Execute an \"Open File\" action.\n"+ "Required attributes:\n"+ "\tfile=\"<file to open>\"\n"+ "Optional attributes:\n"+ "\tline=\"<line number to display>") { public void update(PropertyMaps pm) { if (_attributes.get("file") != null) { final String dir = StringOps. unescapeFileName(StringOps.replaceVariables(DEF_DIR, pm, PropertyMaps.GET_CURRENT)); final String fil = StringOps. unescapeFileName(StringOps.replaceVariables(_attributes.get("file"), pm, PropertyMaps.GET_CURRENT)); FileOpenSelector fs = new FileOpenSelector() { public File[] getFiles() { if (fil.startsWith("/")) { return new File[] { new File(fil) }; } else { return new File[] { new File(dir, fil) }; } } }; open(fs); int lineNo = -1; if (_attributes.get("line")!=null) { try { lineNo = Integer.valueOf(_attributes.get("line")); } catch(NumberFormatException nfe) { lineNo = -1; } } if (lineNo >= 0) { final int l = lineNo; Utilities.invokeLater(new Runnable() { public void run() { _jumpToLine(l); } }); } } } /** Reset the attributes. */ public void resetAttributes() { _attributes.clear(); _attributes.put("file", null); _attributes.put("line", null); } }); PropertyMaps.TEMPLATE. setProperty("Action", new DrJavaActionProperty("action.auto.refresh", "(Auto-Refresh...)", "Execute an \"Auto-Refresh Project\" action.") { public void update(PropertyMaps pm) { _model.autoRefreshProject(); } }); } /** Set a new painters for existing breakpoint highlights. */ void refreshBreakpointHighlightPainter() { for(java.util.Map.Entry<Breakpoint,HighlightManager.HighlightInfo> pair: _documentBreakpointHighlights.entrySet()) { if (pair.getKey().isEnabled()) pair.getValue().refresh(DefinitionsPane.BREAKPOINT_PAINTER); else pair.getValue().refresh(DefinitionsPane.DISABLED_BREAKPOINT_PAINTER); } } /** Set new painter for existing bookmark highlights. */ void refreshBookmarkHighlightPainter() { for(HighlightManager.HighlightInfo hi: _documentBookmarkHighlights.values()) { hi.refresh(DefinitionsPane.BOOKMARK_PAINTER); } } /** Set new painter for existing find results highlights. */ void refreshFindResultsHighlightPainter(FindResultsPanel panel, LayeredHighlighter.LayerPainter painter) { for(Pair<FindResultsPanel, Map<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair: _findResults) { if (pair.first() == panel) { Map<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights = pair.second(); for(HighlightManager.HighlightInfo hi: highlights.values()) { hi.refresh(painter); } } } } /** Creates the folder chooser during MainFrame initialization which does not run in event thread. */ private DirectoryChooser makeFolderChooser(final File workDir) { assert duringInit() || EventQueue.isDispatchThread(); final DirectoryChooser dc = new DirectoryChooser(this); /* The following code fragement was moved to the event thread because setSelectedFile occasionally generates an * ArrayOutOfBoundsException otherwise. */ dc.setSelectedFile(workDir); dc.setApproveButtonText("Select"); dc.setDialogTitle("Open Folder"); dc.setAccessory(_openRecursiveCheckBox); return dc; } // // private JFileChooser makeFolderChooser(File workDir) { // _folderChooser = new JFileChooser(); // _folderChooser.setMultiSelectionEnabled(false); // _folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // _folderChooser.setCurrentDirectory(workDir); // _folderChooser.setApproveButtonText("Select"); // _folderChooser.setFileFilter(new DirectoryFilter()); // _folderChooser.setDialogTitle("Open Folder"); // // // Container button_row = (Container)findButtonContainer(_folderChooser, _folderChooser.getApproveButtonText()); // Container buttons = (Container) button_row.getParent(); // //// Component c2 = ((BorderLayout)_folderChooser.getLayout()).getLayoutComponent(BorderLayout.SOUTH); // //// System.out.println("c1: " + c1); //// System.out.println("c2: " + c2); // // //// JPanel buttons = (JPanel)c2; //// JPanel button_row = (JPanel)buttons.getComponent(3); // JPanel bottom_row = new JPanel(); // bottom_row.setLayout(new BorderLayout()); // bottom_row.add(new JCheckBox("Recursive Open"), BorderLayout.CENTER); // bottom_row.add(button_row, BorderLayout.EAST); // buttons.add(bottom_row); // // return _folderChooser; // } // private Container findButtonContainer(Container container, String buttonText) { // Container answer = null; // Component[] cs = container.getComponents(); // for(Component c: cs) { // if (c instanceof JButton && ((JButton)c).getText().equals(buttonText)) { // return container; // }else if (c instanceof Container) { // answer = findButtonContainer((Container)c, buttonText); // } // // if (answer != null) break; // } // return answer; // } /** Sets up the ctrl-tab listener. */ private void setUpKeys() { setFocusTraversalKeysEnabled(false); } /** Relying on inherited dispose() method. */ /** @return The model providing the logic for this view. */ public SingleDisplayModel getModel() { return _model; } /** Returns the frame's interactions pane. (Package private accessor) */ InteractionsPane getInteractionsPane() { return _interactionsPane; } /** Returns the frame's interactions controller. (Package private accessor) */ InteractionsController getInteractionsController() { return _interactionsController; } /** @return The frame's close button (Package private accessor). */ JButton getCloseButton() { return _closeButton; } /** For testing purposes. * @return The frame's compileAll button (Package private accessor) */ JButton getCompileAllButton() { return _compileButton; } private volatile int _hourglassNestLevel = 0; /** Make the cursor an hourglass. Only runs in the event thread. */ public void hourglassOn() { assert EventQueue.isDispatchThread(); _hourglassNestLevel++; if (_hourglassNestLevel == 1) { getGlassPane().setVisible(true); _currentDefPane.setEditable(false); setAllowKeyEvents(false); } } /** Return the cursor to normal. Only runs in the event thread. */ public void hourglassOff() { assert EventQueue.isDispatchThread(); _hourglassNestLevel--; if (_hourglassNestLevel == 0) { getGlassPane().setVisible(false); _currentDefPane.setEditable(true); setAllowKeyEvents(true); } } private volatile boolean _allowKeyEvents = true; public void setAllowKeyEvents(boolean a) { _allowKeyEvents = a; } public boolean getAllowKeyEvents() { return _allowKeyEvents; } /** Toggles whether the debugger is enabled or disabled, and updates the display accordingly. Only runs in the * event thread. */ public void debuggerToggle() { assert EventQueue.isDispatchThread(); // Make sure the debugger is available Debugger debugger = _model.getDebugger(); if (! debugger.isAvailable()) return; updateStatusField("Toggling Debugger Mode"); try { if (isDebuggerReady()) debugger.shutdown(); else { // Turn on debugger hourglassOn(); try { debugger.startUp(); // may kick active document (if unmodified) out of memory! // System.err.println("Trying to start debugger"); _model.refreshActiveDocument(); _updateDebugStatus(); } finally { hourglassOff(); } } } catch (DebugException de) { _showError(de, "Debugger Error", "Could not start the debugger."); } catch (NoClassDefFoundError err) { _showError(err, "Debugger Error", "Unable to find the JPDA package for the debugger.\n" + "Please make sure either tools.jar or jpda.jar is\n" + "in your classpath when you start DrJava."); _setDebugMenuItemsEnabled(false); } } /** Display the debugger tab and update the Debug menu accordingly. */ public void showDebugger() { assert EventQueue.isDispatchThread(); _setDebugMenuItemsEnabled(true); _showDebuggerPanel(); } /** Hide the debugger tab and update the Debug menu accordingly. */ public void hideDebugger() { _setDebugMenuItemsEnabled(false); _hideDebuggerPanel(); } private void _showDebuggerPanel() { if (_detachDebugFrameMenuItem.isSelected()) { _debugFrame.setDisplayInFrame(true); } else { _debugSplitPane.setTopComponent(_docSplitPane); _mainSplit.setTopComponent(_debugSplitPane); } _debugPanel.updateData(); _lastFocusOwner.requestFocusInWindow(); } private void _hideDebuggerPanel() { if (_detachDebugFrameMenuItem.isSelected()) { _debugFrame.setVisible(false); } else { _mainSplit.setTopComponent(_docSplitPane); } _lastFocusOwner.requestFocusInWindow(); } /** ONLY executes in event thread. */ public void updateStatusField(String text) { assert EventQueue.isDispatchThread(); _statusField.setText(text); _statusField.paint(getGraphics()); // force an immediate repaint } /** Updates the status field with the current status of the Definitions Pane. */ public void updateStatusField() { OpenDefinitionsDocument doc = _model.getActiveDocument(); String fileName = doc.getCompletePath(); if (! fileName.equals(_fileTitle)) { _fileTitle = fileName; setTitle(fileName); _model.getDocCollectionWidget().repaint(); } String path = doc.getCompletePath(); String text = "Editing " + path; // Lightweight parsing has been disabled until we have something that is beneficial and works better in the background. // if (DrJava.getConfig().getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()) { // String temp = _model.getParsingControl().getEnclosingClassName(doc); // if ((temp != null) && (temp.length() > 0)) { text = text + " - " + temp; } // _statusField.setToolTipText("Full path for file: " + path); if (! _statusField.getText().equals(text)) { _statusField.setText(text); _statusField.paint(getGraphics()); // force immediate painting of the _statusField } } /** Prompt the user to select a place to open files from, then load them. Ask the user if they'd like to save * previous changes (if the current document has been modified) before opening. * @param jfc the open dialog from which to extract information * @return an array of the files that were chosen */ public File[] getOpenFiles(JFileChooser jfc) throws OperationCanceledException { int rc = jfc.showOpenDialog(this); return getChosenFiles(jfc, rc); } /** Prompt the user to select a place to save the current document. */ public File getSaveFile(JFileChooser jfc) throws OperationCanceledException { // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X! // File selection = jfc.getSelectedFile();//_saveChooser.getSelectedFile(); // if (selection != null) { // jfc.setSelectedFile(selection.getParentFile()); // jfc.setSelectedFile(selection); // jfc.setSelectedFile(null); // } OpenDefinitionsDocument active = _model.getActiveDocument(); // Fill in class name //if (active.isUntitled()) { try { String className = active.getFirstTopLevelClassName(); if (!className.equals("")) { jfc.setSelectedFile(new File(jfc.getCurrentDirectory(), className)); } } catch (ClassNameNotFoundException e) { // Don't set selected file } // TODO: Why are we working with _saveChooser first, then call jfc.showSaveDialog(this)? (mgricken) _saveChooser.removeChoosableFileFilter(_projectFilter); _saveChooser.removeChoosableFileFilter(_javaSourceFilter); _saveChooser.setFileFilter(_javaSourceFilter); jfc.setMultiSelectionEnabled(false); int rc = jfc.showSaveDialog(this); return getChosenFile(jfc, rc); } /** Returns the current DefinitionsPane. */ public DefinitionsPane getCurrentDefPane() { return _currentDefPane; } /** Returns the currently shown error panel if there is one. Otherwise returns null. */ public ErrorPanel getSelectedErrorPanel() { Component c = _tabbedPane.getSelectedComponent(); if (c instanceof ErrorPanel) return (ErrorPanel) c; return null; } /** Returns whether the compiler output tab is currently showing. */ public boolean isCompilerTabSelected() { return _tabbedPane.getSelectedComponent() == _compilerErrorPanel; } /** Returns whether the test output tab is currently showing. */ public boolean isTestTabSelected() { return _tabbedPane.getSelectedComponent() == _junitErrorPanel; } /** Returns whether the JavaDoc output tab is currently showing. */ public boolean isJavadocTabSelected() { return _tabbedPane.getSelectedComponent() == _javadocErrorPanel; } /** Makes sure save and compile buttons and menu items are enabled and disabled appropriately after document * modifications. */ private void _installNewDocumentListener(final OpenDefinitionsDocument d) { d.addDocumentListener(new DocumentUIListener() { public void changedUpdate(DocumentEvent e) { } public void insertUpdate(DocumentEvent e) { _saveAction.setEnabled(true); if (isDebuggerEnabled() && _debugPanel.getStatusText().equals("")) _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC); } public void removeUpdate(DocumentEvent e) { _saveAction.setEnabled(true); if (isDebuggerEnabled() && _debugPanel.getStatusText().equals("")) _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC); } }); } /** Changes the message text toward the right of the status bar * @param msg The message to place in the status bar */ public void setStatusMessage(String msg) { _statusReport.setText(msg); } /** Sets the message text in the status bar to the null string. */ public void clearStatusMessage() { _statusReport.setText(""); } /** Sets the font of the status bar message * @param f The new font of the status bar message */ public void setStatusMessageFont(Font f) { _statusReport.setFont(f); } /** Sets the color of the text in the status bar message * @param c The color of the text */ public void setStatusMessageColor(Color c) { _statusReport.setForeground(c); } /** Performs op on each document in docs and invalidates the various project file collection properties. */ private void _processDocs(Collection<OpenDefinitionsDocument> docs, Runnable1<OpenDefinitionsDocument> op) { for (OpenDefinitionsDocument doc: docs) { if (doc != null && ! doc.isUntitled()) { op.run(doc); try { String path = _model.fixPathForNavigator(doc.getFile().getCanonicalPath()); _model.getDocumentNavigator().refreshDocument(doc, path); } catch(IOException e) { /* do nothing */ } } } PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.project.files").invalidate(); PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.included.files").invalidate(); PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.external.files").invalidate(); } /* Converts the selected files to auxiliary files. Access is ackage protected rather than private to support access * by ProjectMenuTest.testSaveProject. */ void _moveToAuxiliary() { Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() { public void run(OpenDefinitionsDocument d) { _model.addAuxiliaryFile(d); } }; _processDocs(_model.getDocumentNavigator().getSelectedDocuments(), op); } /** Removes selected auxiliary files. */ private void _removeAuxiliary() { Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() { public void run(OpenDefinitionsDocument d) { _model.removeAuxiliaryFile(d); } }; _processDocs(_model.getDocumentNavigator().getSelectedDocuments(), op); } /** Converts all external files to auxiliary files. */ void _moveAllToAuxiliary() { assert EventQueue.isDispatchThread(); Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() { public void run(OpenDefinitionsDocument d) { _model.addAuxiliaryFile(d); } }; _processDocs(_model.getDocumentNavigator().getDocumentsInBin(_model.getExternalBinTitle()), op); } /** Converts all auxiliary files to external files. */ private void _removeAllAuxiliary() { assert EventQueue.isDispatchThread(); Runnable1<OpenDefinitionsDocument> op = new Runnable1<OpenDefinitionsDocument>() { public void run(OpenDefinitionsDocument d) { _model.removeAuxiliaryFile(d); } }; _processDocs(_model.getDocumentNavigator().getDocumentsInBin(_model.getAuxiliaryBinTitle()), op); } private void _new() { updateStatusField("Creating a new Untitled Document"); _model.newFile(); } private void _open() { updateStatusField("Opening File"); open(_openSelector); } private void _openFolder() { openFolder(_folderChooser); } private void _openFileOrProject() { try { final File[] fileList = _openFileOrProjectSelector.getFiles(); FileOpenSelector fos = new FileOpenSelector() { public File[] getFiles() { return fileList; } }; if (_openChooser.getFileFilter().equals(_projectFilter)) openProject(fos); else open(fos); } catch(OperationCanceledException oce) { /* do nothing */ } } /** Puts the given text into the current definitions pane at the current caret position. */ private void _putTextIntoDefinitions(String text) { int caretPos = _currentDefPane.getCaretPosition(); try { _model.getActiveDocument().insertString(caretPos, text, null); } catch (BadLocationException ble) { throw new UnexpectedException(ble); } } /** Sets the left navigator pane to the correct component as dictated by the model. */ private void _resetNavigatorPane() { if (_model.getDocumentNavigator() instanceof JTreeSortNavigator) { JTreeSortNavigator<?> nav = (JTreeSortNavigator<?>)_model.getDocumentNavigator(); nav.setDisplayManager(getNavPaneDisplayManager()); nav.setRootIcon(_djProjectIcon); } _docSplitPane.remove(_docSplitPane.getLeftComponent()); _docSplitPane.setLeftComponent(new JScrollPane(_model.getDocumentNavigator().asContainer())); Font doclistFont = DrJava.getConfig().getSetting(FONT_DOCLIST); _model.getDocCollectionWidget().setFont(doclistFont); _updateNormalColor(); _updateBackgroundColor(); } /** Asks the user to select the project file to open and starts the process of opening the project. */ private void _openProject() { openProject(_openProjectSelector); } public void openProject(FileOpenSelector projectSelector) { try { final File[] files = projectSelector.getFiles(); if (files.length < 1) throw new IllegalStateException("Open project file selection not canceled but no project file was selected."); final File file = files[0]; updateStatusField("Opening project " + file); try { hourglassOn(); // make sure there are no open projects if (! _model.isProjectActive() || (_model.isProjectActive() && _closeProject())) _openProjectHelper(file); } catch(Exception e) { e.printStackTrace(System.out); } finally { hourglassOff(); } } catch(OperationCanceledException oce) { /* do nothing, we just won't open anything */ } } /** Oversees the opening of the project by delegating to the model to parse and initialize the project * while resetting the navigator pane and opening up the files itself. * @param projectFile the file of the project to open */ private void _openProjectHelper(File projectFile) { _currentProjFile = projectFile; try { _mainListener.resetFNFCount(); _model.openProject(projectFile); _setUpProjectButtons(projectFile); _openProjectUpdate(); if (_mainListener.someFilesNotFound()) _model.setProjectChanged(true); _completeClassList = new ArrayList<GoToFileListEntry>(); // reset auto-completion list addToBrowserHistory(); } catch(MalformedProjectFileException e) { _showProjectFileParseError(e); // add to an error adapter return; } catch(FileNotFoundException e) { _showFileNotFoundError(e); // add to an error adapter return; } catch(IOException e) { _showIOError(e); // add to an error adapter return; } } private void _setUpProjectButtons(File projectFile) { _compileButton = _updateToolbarButton(_compileButton, _compileProjectAction); _junitButton = _updateToolbarButton(_junitButton, _junitProjectAction); _recentProjectManager.updateOpenFiles(projectFile); } private void _openProjectUpdate() { if (_model.isProjectActive()) { _closeProjectAction.setEnabled(true); _saveProjectAction.setEnabled(true); _saveProjectAsAction.setEnabled(true); _exportProjectInOldFormatAction.setEnabled(true); _projectPropertiesAction.setEnabled(true); // _junitProjectAction.setEnabled(true); _junitProjectAction.setEnabled(true); // _compileOpenProjectAction.setEnabled(true); _compileProjectAction.setEnabled(true); _jarProjectAction.setEnabled(true); if (_model.getBuildDirectory() != null) _cleanAction.setEnabled(true); _autoRefreshAction.setEnabled(true); _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener); _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs); _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener); _resetNavigatorPane(); _model.refreshActiveDocument(); // _compileButton.setToolTipText("<html>Compile all documents in the project.source tree<br>" + // "Auxiliary and external files are excluded.</html>"); } } boolean _closeProject() { return _closeProject(false); } /** Closes project when DrJava is not in the process of quitting. * @return true if the project is closed, false if cancelled. */ boolean closeProject() { updateStatusField("Closing current project"); return _closeProject(); } /** Saves the project file; closes all open project files; and calls _model.closeProject(quitting) the * clean up the state of the global model. It also restores the list view navigator * @ param quitting whether the project is being closed as part of quitting DrJava * @return true if the project is closed, false if cancelled */ boolean _closeProject(boolean quitting) { _completeClassList = new ArrayList<GoToFileListEntry>(); // reset auto-completion list _autoImportClassList = new ArrayList<JavaAPIListEntry>(); // reset auto-import list if (_checkProjectClose()) { List<OpenDefinitionsDocument> projDocs = _model.getProjectDocuments(); // System.err.println("projDocs = " + projDocs); _cleanUpDebugger(); boolean couldClose = _model.closeFiles(projDocs); if (! couldClose) return false; disableFindAgainOnClose(projDocs); // disable "Find Again" for documents that are closed // project file has been saved and all files closed if (quitting) return true; _model.closeProject(quitting); Component renderer = _model.getDocumentNavigator().getRenderer(); new ForegroundColorListener(renderer); new BackgroundColorListener(renderer); _resetNavigatorPane(); if (_model.getDocumentCount() == 1) _model.setActiveFirstDocument(); _closeProjectAction.setEnabled(false); _saveProjectAction.setEnabled(false); _saveProjectAsAction.setEnabled(false); _exportProjectInOldFormatAction.setEnabled(false); _projectPropertiesAction.setEnabled(false); _jarProjectAction.setEnabled(false); _junitProjectAction.setEnabled(false); // _compileOpenProjectAction.setEnabled(false); _compileProjectAction.setEnabled(false); _setUpContextMenus(); _currentProjFile = FileOps.NULL_FILE; // _compileButton.setToolTipText("Compile all open documents"); return true; } else return false; // Project closing cancelled in _checkProjectClose dialog } private void _configureBrowsing() { BrowserHistoryManager bm = _model.getBrowserHistoryManager(); if (bm.getRegions().isEmpty()) { _browseForwardAction.setEnabled(false); _browseBackAction.setEnabled(false); return; } _browseForwardAction.setEnabled(true); _browseBackAction.setEnabled(true); if (bm.isCurrentRegionFirst()) _browseBackAction.setEnabled(false); if (bm.isCurrentRegionLast()) _browseForwardAction.setEnabled(false); } private boolean _checkProjectClose() { if (_model.isProjectChanged()) { String fname = _model.getProjectFile().getName(); String text = fname + " has been modified. Would you like to save it?"; int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "Save " + fname + "?", JOptionPane.YES_NO_CANCEL_OPTION); switch (rc) { case JOptionPane.YES_OPTION: _saveProject(); return true; case JOptionPane.NO_OPTION: return true; case JOptionPane.CLOSED_OPTION: case JOptionPane.CANCEL_OPTION: return false; default: throw new RuntimeException("Invalid rc: " + rc); } } return true; } public File getCurrentProject() { return _currentProjFile; } /** Opens all the files returned by the FileOpenSelector prompting the user to handle the cases where files are * already open, files are missing, or the action was canceled by the user * @param openSelector the selector that returns the files to open */ public void open(FileOpenSelector openSelector) { try { hourglassOn(); _model.openFiles(openSelector); } catch (AlreadyOpenException aoe) { OpenDefinitionsDocument[] openDocs = aoe.getOpenDocuments(); for(OpenDefinitionsDocument openDoc : openDocs) { String fileName; try { fileName = openDoc.getFile().getName(); } catch (IllegalStateException ise) { // Can't happen: this open document must have a file throw new UnexpectedException(ise); } catch (FileMovedException fme) { // File was deleted, but use the same name anyway fileName = fme.getFile().getName(); } try { File f = openDoc.getFile(); if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f); } catch (IllegalStateException ise) { // Impossible: saved => has a file throw new UnexpectedException(ise); } catch (FileMovedException fme) { File f = fme.getFile(); // Recover, show it in the list anyway if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f); } } } catch (OperationCanceledException oce) { /* do not open file */ } catch (FileNotFoundException fnf) { _showFileNotFoundError(fnf); } catch (IOException ioe) { _showIOError(ioe); } finally { hourglassOff(); } } /** Opens all the files in the directory returned by the FolderSelector. * @param chooser the selector that returns the files to open * TODO: change the dialog title to give the current path rather than "..." */ public void openFolder(DirectoryChooser chooser) { String type = "'." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[DrJava.getConfig().getSetting(LANGUAGE_LEVEL)] + "' "; chooser.setDialogTitle("Open All " + type + "Files in ..."); File openDir = FileOps.NULL_FILE; try { File activeFile = _model.getActiveDocument().getFile(); if (activeFile != null) openDir = activeFile.getParentFile(); else openDir = _model.getProjectRoot(); } catch(FileMovedException e) { /* do nothing */ } int result = chooser.showDialog(openDir); if (result != DirectoryChooser.APPROVE_OPTION) return; // canceled or error File dir = chooser.getSelectedDirectory(); boolean rec = _openRecursiveCheckBox.isSelected(); DrJava.getConfig().setSetting(OptionConstants.OPEN_FOLDER_RECURSIVE, Boolean.valueOf(rec)); updateStatusField("Opening folder " + dir); _openFolder(dir, rec); } /** Opens all the files in the specified directory; it opens all files in nested folders if rec is true. * @param dir the specified directory * @param rec true if files in nested folders should be opened */ private void _openFolder(File dir, boolean rec) { hourglassOn(); try { _model.openFolder(dir, rec); } catch(AlreadyOpenException e) { /* do nothing */ } catch(IOException e) { _showIOError(e); } catch(OperationCanceledException oce) { /* do nothing */ } finally { hourglassOff(); } } /** Delegates directly to the model to close the active document */ private void _close() { // LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>(); // l.add(_model.getActiveDocument()); // _model.closeFiles(l); // this works with multiple selected files now java.util.List<OpenDefinitionsDocument> l = _model.getDocumentNavigator().getSelectedDocuments(); boolean queryNecessary = false; // is a query necessary because the files are project or auxiliary files? for (OpenDefinitionsDocument doc: l) { if ((_model.isProjectActive() && doc.inProjectPath()) || doc.isAuxiliaryFile()) { queryNecessary = true; break; } } if (queryNecessary) { int rc; String fileName = null; Object[] options = {"Yes", "No"}; if (l.size()==1) { OpenDefinitionsDocument doc = l.get(0); try { if (doc.isUntitled()) fileName = "File"; else fileName = _model.getActiveDocument().getFile().getName(); } catch(FileMovedException e) { fileName = e.getFile().getName(); } String text = "Closing this file will permanently remove it from the current project." + "\nAre you sure that you want to close this file?"; rc = JOptionPane.showOptionDialog(MainFrame.this, text,"Close " + fileName + "?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); } else { fileName = l.size()+" files"; String text = "Closing these "+fileName+" will permanently remove them from the current project." + "\nAre you sure that you want to close these files?"; rc = JOptionPane.showOptionDialog(MainFrame.this, text, "Close "+l.size()+" files?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); } if (rc != JOptionPane.YES_OPTION) return; updateStatusField("Closing " + fileName); _model.setProjectChanged(true); } disableFindAgainOnClose(l); // disable "Find Again" for documents that are closed // Either this is an external file or user actually wants to close it for(OpenDefinitionsDocument doc: l) { _model.closeFile(doc); } } private void _closeFolder() { OpenDefinitionsDocument d; ArrayList<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments(); final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>(); if (_model.getDocumentNavigator().isGroupSelected()) { for (OpenDefinitionsDocument doc: docs) { if (_model.getDocumentNavigator().isSelectedInGroup(doc)) { l.add(doc); } } disableFindAgainOnClose(l); // disable "Find Again" for documents that are closed _model.closeFiles(l); if (! l.isEmpty()) _model.setProjectChanged(true); } } private void _printDefDoc() { try { _model.getActiveDocument().print(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (PrinterException e) { _showError(e, "Print Error", "An error occured while printing."); } catch (BadLocationException e) { _showError(e, "Print Error", "An error occured while printing."); } } private void _printConsole() { try { _model.getConsoleDocument().print(); } catch (PrinterException e) { _showError(e, "Print Error", "An error occured while printing."); } } private void _printInteractions() { try { _model.getInteractionsDocument().print(); } catch (PrinterException e) { _showError(e, "Print Error", "An error occured while printing."); } } /** Opens a new PrintPreview frame. */ private void _printDefDocPreview() { try { _model.getActiveDocument().preparePrintJob(); new PreviewDefDocFrame(_model, this); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (BadLocationException e) { _showError(e, "Print Error", "An error occured while preparing the print preview."); } catch (IllegalStateException e) { _showError(e, "Print Error", "An error occured while preparing the print preview."); } } private void _printConsolePreview() { try { _model.getConsoleDocument().preparePrintJob(); new PreviewConsoleFrame(_model, this, false); } catch (IllegalStateException e) { _showError(e, "Print Error", "An error occured while preparing the print preview."); } } private void _printInteractionsPreview() { try { _model.getInteractionsDocument().preparePrintJob(); new PreviewConsoleFrame(_model, this, true); } catch (IllegalStateException e) { _showError(e, "Print Error", "An error occured while preparing the print preview."); } } private void _pageSetup() { PrinterJob job = PrinterJob.getPrinterJob(); _model.setPageFormat(job.pageDialog(_model.getPageFormat())); } //Called by testCases void closeAll() { _closeAll(); } private void _closeAll() { updateStatusField("Closing All Files"); if (!_model.isProjectActive() || _model.isProjectActive() && _closeProject()) _model.closeAllFiles(); } private boolean _save() { updateStatusField("Saving File"); try { // now works with multiple files List<OpenDefinitionsDocument> l = _model.getDocumentNavigator().getSelectedDocuments(); boolean success = false; for(OpenDefinitionsDocument doc: l) { if (doc.saveFile(_saveSelector)) { getDefPaneGivenODD(doc).hasWarnedAboutModified(false); success = true; } } // _model.refreshActiveDocument() is not sufficient here; it does not re-select // the same document in flat-file mode _model.setActiveDocument(_model.getActiveDocument()); return success; // if (_model.getActiveDocument().saveFile(_saveSelector)) { // _currentDefPane.hasWarnedAboutModified(false); // // /**This highlights the document in the navigator */ // _model.setActiveDocument(_model.getActiveDocument()); // // return true; // } // else return false; } catch (IOException ioe) { _showIOError(ioe); return false; } } private boolean _saveAs() { updateStatusField("Saving File Under New Name"); try { boolean toReturn = _model.getActiveDocument().saveFileAs(_saveAsSelector); _model.setActiveDocument(_model.getActiveDocument()); // highlights the document in the navigator return toReturn; } catch (IOException ioe) { _showIOError(ioe); return false; } } private boolean _rename() { try { if (!_model.getActiveDocument().fileExists()) return _saveAs(); else { File fileToDelete; try { fileToDelete = _model.getActiveDocument().getFile(); } catch (FileMovedException fme) { return _saveAs(); } boolean toReturn = _model.getActiveDocument().saveFileAs(_saveAsSelector); /** Delete the old file if save was successful. */ // TODO: what if delete() fails? (mgricken) if (toReturn && ! _model.getActiveDocument().getFile().equals(fileToDelete)) fileToDelete.delete(); /** this highlights the document in the navigator */ _model.setActiveDocument(_model.getActiveDocument()); return toReturn; } } catch (IOException ioe) { _showIOError(ioe); return false; } } /* Package private to allow use in MainFrameTest. */ void _saveAll() { hourglassOn(); try { if (_model.isProjectActive()) _saveProject(); _model.saveAllFiles(_saveSelector); } catch (IOException ioe) { _showIOError(ioe); } finally { hourglassOff(); } } void _saveAllOld() { hourglassOn(); File file = _currentProjFile; try { if (_model.isProjectActive()) { if (file.getName().indexOf(".") == -1) file = new File (file.getAbsolutePath() + OLD_PROJECT_FILE_EXTENSION); _model.exportOldProject(file, gatherProjectDocInfo()); } _model.saveAllFiles(_saveSelector); } catch (IOException ioe) { _showIOError(ioe); } finally { hourglassOff(); } } // Called by the ProjectPropertiesFrame void saveProject() { _saveProject(); } private void _saveProject() { //File file = _model.getProjectFile(); _saveProjectHelper(_currentProjFile); } /** Edits project frame. Only runs in the event thread. */ private void _editProject() { ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(this); ppf.setVisible(true); ppf.reset(); ppf.toFront(); // ppf actions save state of ppf in global model } /** Closes all files and makes a new project. */ private void _newProject() { _closeProject(true); // suppress resetting interactions; it will be done in _model.newProject() below _saveChooser.setFileFilter(_projectFilter); _saveChooser.setMultiSelectionEnabled(false); int rc = _saveChooser.showSaveDialog(this); if (rc == JFileChooser.APPROVE_OPTION) { File projectFile = _saveChooser.getSelectedFile(); if (projectFile == null || (projectFile.exists() && ! _verifyOverwrite())) { return; } String fileName = projectFile.getName(); // ensure that saved file has extesion ".xml" if (! fileName.endsWith(".xml")) { int lastIndex = fileName.lastIndexOf("."); if (lastIndex == -1) projectFile = new File (projectFile.getAbsolutePath() + ".xml"); else projectFile = new File(fileName.substring(0, lastIndex) + ".xml"); } _model.createNewProject(projectFile); // sets model to a new FileGroupingState for project file pf // ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(MainFrame.this, file); // ppf.saveSettings(); // Saves new project profile in global model _editProject(); // edits the properties of the new FileGroupingState try { _model.configNewProject(); } // configures the new project in the model catch(IOException e) { throw new UnexpectedException(e); } _setUpProjectButtons(projectFile); _currentProjFile = projectFile; } } /** Pops up the _saveChooser dialog, asks the user for a new project file name, and sets the project file to the * specified file. Nothing is written in the file system; this action is performed by a subsequent _saveAll(). * @return false if the user canceled the action */ private boolean _saveProjectAs() { // // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X! _saveChooser.removeChoosableFileFilter(_projectFilter); _saveChooser.removeChoosableFileFilter(_javaSourceFilter); _saveChooser.setFileFilter(_projectFilter); // File selection = _saveChooser.getSelectedFile(); // if (selection != null) { // what is this block of commands for? // _saveChooser.setSelectedFile(selection.getParentFile()); // _saveChooser.setSelectedFile(selection); // _saveChooser.setSelectedFile(null); // } if (_currentProjFile != FileOps.NULL_FILE) _saveChooser.setSelectedFile(_currentProjFile); _saveChooser.setMultiSelectionEnabled(false); int rc = _saveChooser.showSaveDialog(this); if (rc == JFileChooser.APPROVE_OPTION) { File file = _saveChooser.getSelectedFile(); if ((file!=null) && (! file.exists() || _verifyOverwrite())) { _model.setProjectFile(file); _currentProjFile = file; } } return (rc == JFileChooser.APPROVE_OPTION); } void _saveProjectHelper(File file) { try { if (file.getName().indexOf(".") == -1) file = new File (file.getAbsolutePath() + PROJECT_FILE_EXTENSION); String fileName = file.getCanonicalPath(); if (fileName.endsWith(OLD_PROJECT_FILE_EXTENSION)) { String text = "The project will be saved in XML format." + "\nDo you want to change the project file's extension to \""+PROJECT_FILE_EXTENSION+"\"?"; Object[] options = {"Change to \""+PROJECT_FILE_EXTENSION+"\"", "Keep \"" + fileName.substring(fileName.lastIndexOf('.'))+"\""}; int rc = 1; if (!Utilities.TEST_MODE) { rc = JOptionPane.showOptionDialog(MainFrame.this, text, "Change Extension?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); } if (rc == 0) { fileName = fileName.substring(0,fileName.length() - OLD_PROJECT_FILE_EXTENSION.length()) + PROJECT_FILE_EXTENSION; file = new File(fileName); if (! file.exists() || _verifyOverwrite()) { _model.setProjectFile(file); _currentProjFile = file; } } } _model.saveProject(file, gatherProjectDocInfo()); // if (!(_model.getDocumentNavigator() instanceof JTreeSortNavigator)) { // _openProjectHelper(file); // } } catch(IOException ioe) { _showIOError(ioe); } _recentProjectManager.updateOpenFiles(file); _model.setProjectChanged(false); } public HashMap<OpenDefinitionsDocument,DocumentInfoGetter> gatherProjectDocInfo() { HashMap<OpenDefinitionsDocument,DocumentInfoGetter> map = new HashMap<OpenDefinitionsDocument,DocumentInfoGetter>(); List<OpenDefinitionsDocument> docs = _model.getProjectDocuments(); for(OpenDefinitionsDocument doc: docs) { map.put(doc, _makeInfoGetter(doc)); } return map; } /** Gets the information to be saved for a project document. * Implementation may change if the scroll/selection information is later stored in a place other than the * definitions pane. Hopefully this info will eventually be backed up in the OpenDefinitionsDocument in which * case all this code should be refactored into the model's _saveProject method */ private DocumentInfoGetter _makeInfoGetter(final OpenDefinitionsDocument doc) { JScrollPane s = _defScrollPanes.get(doc); if (s == null) s = _createDefScrollPane(doc); final JScrollPane scroller = s; final DefinitionsPane pane = _currentDefPane; // rhs was (DefinitionsPane)scroller.getViewport().getView(); return new DocumentInfoGetter() { public Pair<Integer,Integer> getSelection() { Integer selStart = Integer.valueOf(pane.getSelectionStart()); Integer selEnd = Integer.valueOf(pane.getSelectionEnd()); if ( selStart == 0 && selEnd == 0) return new Pair<Integer,Integer>(pane.getCaretPosition(),pane.getCaretPosition()); if (pane.getCaretPosition() == selStart) return new Pair<Integer,Integer>(selEnd,selStart); return new Pair<Integer,Integer>(selStart,selEnd); } public Pair<Integer,Integer> getScroll() { Integer scrollv = Integer.valueOf(pane.getVerticalScroll()); Integer scrollh = Integer.valueOf(pane.getHorizontalScroll()); return new Pair<Integer,Integer>(scrollv,scrollh); } public File getFile() { return doc.getRawFile(); } public String getPackage() { return doc.getPackageName(); } public boolean isActive() { return _model.getActiveDocument() == doc; } public boolean isUntitled() { return doc.isUntitled(); } }; } private void _revert() { // this works with multiple selected files now java.util.List<OpenDefinitionsDocument> l = _model.getDocumentNavigator().getSelectedDocuments(); for(OpenDefinitionsDocument d: l) { _revert(d); } } private void _revert(OpenDefinitionsDocument doc) { try { doc.revertFile(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } } /** private void _revertAll() { try { _model.revertAllFiles(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } } */ private void _quit() { // AbstractGlobalModel._log.log("MainFrame.quit() called"); if (_promptBeforeQuit) { String title = "Quit DrJava?"; String message = "Are you sure you want to quit DrJava?"; ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, title, message); int rc = dialog.show(); if (rc != JOptionPane.YES_OPTION) return; else { // Only remember the checkbox if they say yes if (dialog.getCheckBoxValue() == true) { DrJava.getConfig().setSetting(QUIT_PROMPT, Boolean.FALSE); } } } _executeExternalDialog.setVisible(false); // tried passing false here. seemed to help with bug // [ 1478796 ] DrJava Does Not Shut Down With Project Open // on HP tc1100 and Toshiba Portege tablet PCs, but did not help in all cases if (! _closeProject(true)) { return; /* if user pressed cancel, do not quit */ } _recentFileManager.saveRecentFiles(); _recentProjectManager.saveRecentFiles(); if (! _model.closeAllFilesOnQuit()) { return; /* if user pressed cancel, do not quit */ } _storePositionInfo(); // Save recent files, but only if there wasn't a problem at startUp // (Don't want to overwrite a custom config file with a simple typo.) if (! DrJava.getConfig().hadStartupException()) { try { DrJava.getConfig().saveConfiguration(); } catch (IOException ioe) { _showIOError(ioe); } } //DrJava.consoleOut().println("Quitting DrJava..."); dispose(); // Free GUI elements of this frame _model.quit(); } private void _forceQuit() { _model.forceQuit(); } /** Stores the current position and size info for window and panes to the config framework. Only runs in the event * thread. */ private void _storePositionInfo() { Configuration config = DrJava.getConfig(); // Window bounds. if (config.getSetting(WINDOW_STORE_POSITION).booleanValue()) { Rectangle bounds = getBounds(); config.setSetting(WINDOW_HEIGHT, Integer.valueOf(bounds.height)); config.setSetting(WINDOW_WIDTH, Integer.valueOf(bounds.width)); config.setSetting(WINDOW_X, Integer.valueOf(bounds.x)); config.setSetting(WINDOW_Y, Integer.valueOf(bounds.y)); config.setSetting(WINDOW_STATE, Integer.valueOf(getExtendedState())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(WINDOW_HEIGHT, WINDOW_HEIGHT.getDefault()); config.setSetting(WINDOW_WIDTH, WINDOW_WIDTH.getDefault()); config.setSetting(WINDOW_X, WINDOW_X.getDefault()); config.setSetting(WINDOW_Y, WINDOW_Y.getDefault()); config.setSetting(WINDOW_STATE, WINDOW_STATE.getDefault()); } // "Go to File" dialog position and size. if ((DrJava.getConfig().getSetting(DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) && (_gotoFileDialog != null) && (_gotoFileDialog.getFrameState() != null)) { config.setSetting(DIALOG_GOTOFILE_STATE, (_gotoFileDialog.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(DIALOG_GOTOFILE_STATE, DIALOG_GOTOFILE_STATE.getDefault()); } // "Open Javadoc" dialog position and size. if ((DrJava.getConfig().getSetting(DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) && (_openJavadocDialog != null) && (_openJavadocDialog.getFrameState() != null)) { config.setSetting(DIALOG_OPENJAVADOC_STATE, (_openJavadocDialog.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(DIALOG_OPENJAVADOC_STATE, DIALOG_OPENJAVADOC_STATE.getDefault()); } // "Complete Word" dialog position and size. if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) && (_completeWordDialog != null) && (_completeWordDialog.getFrameState() != null)) { config.setSetting(DIALOG_COMPLETE_WORD_STATE, (_completeWordDialog.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(DIALOG_COMPLETE_WORD_STATE, DIALOG_COMPLETE_WORD_STATE.getDefault()); } // "Create Jar from Project" dialog position and size. if ((DrJava.getConfig().getSetting(DIALOG_JAROPTIONS_STORE_POSITION).booleanValue()) && (_jarOptionsDialog != null) && (_jarOptionsDialog.getFrameState() != null)) { config.setSetting(DIALOG_JAROPTIONS_STATE, (_jarOptionsDialog.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(DIALOG_JAROPTIONS_STATE, DIALOG_JAROPTIONS_STATE.getDefault()); } // "Tabbed Panes" frame position and size. if ((DrJava.getConfig().getSetting(DIALOG_TABBEDPANES_STORE_POSITION).booleanValue()) && (_tabbedPanesFrame != null) && (_tabbedPanesFrame.getFrameState() != null)) { config.setSetting(DIALOG_TABBEDPANES_STATE, (_tabbedPanesFrame.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(DIALOG_TABBEDPANES_STATE, DIALOG_TABBEDPANES_STATE.getDefault()); } // "Debugger" frame position and size. if ((DrJava.getConfig().getSetting(DIALOG_DEBUGFRAME_STORE_POSITION).booleanValue()) && (_debugFrame != null) && (_debugFrame.getFrameState() != null)) { config.setSetting(DIALOG_DEBUGFRAME_STATE, (_debugFrame.getFrameState().toString())); } else { // Reset to defaults to restore pristine behavior. config.setSetting(DIALOG_DEBUGFRAME_STATE, DIALOG_DEBUGFRAME_STATE.getDefault()); } // Panel heights. if (_showDebugger) config.setSetting(DEBUG_PANEL_HEIGHT, Integer.valueOf(_debugPanel.getHeight())); // Doc list width. config.setSetting(DOC_LIST_WIDTH, Integer.valueOf(_docSplitPane.getDividerLocation())); } private void _cleanUpDebugger() { if (isDebuggerReady()) _model.getDebugger().shutdown(); } private void _compile() { // now works with multiple files _cleanUpDebugger(); hourglassOn(); try { // final OpenDefinitionsDocument doc = _model.getActiveDocument(); try { _model.getCompilerModel().compile(_model.getDocumentNavigator().getSelectedDocuments()); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } } finally { hourglassOff();} // update(getGraphics()); } private void _compileFolder() { _cleanUpDebugger(); hourglassOn(); try { OpenDefinitionsDocument d; ArrayList<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments(); final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>(); if (_model.getDocumentNavigator().isGroupSelected()) { for (OpenDefinitionsDocument doc: docs) { if (_model.getDocumentNavigator().isSelectedInGroup(doc)) l.add(doc); } // new Thread("Compile Folder") { // public void run() { try { _model.getCompilerModel().compile(l); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } // } // }.start(); } } finally { hourglassOff(); } // update(getGraphics()); } private void _compileProject() { _cleanUpDebugger(); // new Thread("Compile All") { // public void run() { hourglassOn(); try { _model.getCompilerModel().compileProject(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } finally { hourglassOff(); } // } // }.start(); // update(getGraphics()); } private void _compileAll() { _cleanUpDebugger(); hourglassOn(); try { _model.getCompilerModel().compileAll(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } finally{ hourglassOff(); } } private boolean showCleanWarning() { if (DrJava.getConfig().getSetting(PROMPT_BEFORE_CLEAN).booleanValue()) { String buildDirTxt = ""; try { buildDirTxt = _model.getBuildDirectory().getCanonicalPath(); } catch (Exception e) { buildDirTxt = _model.getBuildDirectory().getPath(); } ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, "Clean Build Directory?", "Cleaning your build directory will delete all\n" + "class files and empty folders within that directory.\n" + "Are you sure you want to clean\n" + buildDirTxt + "?", "Do not show this message again"); int rc = dialog.show(); switch (rc) { case JOptionPane.YES_OPTION: _saveAll(); // Only remember checkbox if they say yes if (dialog.getCheckBoxValue()) DrJava.getConfig().setSetting(PROMPT_BEFORE_CLEAN, Boolean.FALSE); return true; case JOptionPane.NO_OPTION: return false; case JOptionPane.CANCEL_OPTION: return false; case JOptionPane.CLOSED_OPTION: return false; default: throw new RuntimeException("Invalid rc from showConfirmDialog: " + rc); } } return true; } private void _clean() { _model.cleanBuildDirectory(); } // The model performs this as an AsyncTask /** List with entries for the complete dialog. */ ArrayList<GoToFileListEntry> _completeClassList = new ArrayList<GoToFileListEntry>(); /** List with entries for the auto-import dialog. */ ArrayList<JavaAPIListEntry> _autoImportClassList = new ArrayList<JavaAPIListEntry>(); /** Scan the build directory for class files and update the auto-completion list. */ private void _scanClassFiles() { Thread t = new Thread(new Runnable() { public void run() { File buildDir = _model.getBuildDirectory(); HashSet<GoToFileListEntry> hs = new HashSet<GoToFileListEntry>(); HashSet<JavaAPIListEntry> hs2 = new HashSet<JavaAPIListEntry>(); if (buildDir!=null) { List<File> classFiles = _model.getClassFiles(); DummyOpenDefDoc dummyDoc = new DummyOpenDefDoc(); for(File f: classFiles) { String s = f.toString(); if (s.lastIndexOf(java.io.File.separatorChar) >= 0) { s = s.substring(s.lastIndexOf(java.io.File.separatorChar)+1); } s = s.substring(0, s.lastIndexOf(".class")); s = s.replace('$', '.'); int pos = 0; boolean ok = true; while ((pos=s.indexOf('.', pos)) >= 0) { if (s.length() <= pos + 1 || Character.isDigit(s.charAt(pos + 1))) { ok = false; break; } ++pos; } if (ok) { if (s.lastIndexOf('.') >= 0) { s = s.substring(s.lastIndexOf('.') + 1); } GoToFileListEntry entry = new GoToFileListEntry(dummyDoc, s); hs.add(entry); try { String rel = FileOps.stringMakeRelativeTo(f, buildDir); String full = rel.replace(java.io.File.separatorChar, '.'); full = full.substring(0, full.lastIndexOf(".class")); if (full.indexOf('$')<0) { // no $ in the name means not an inner class // we do not support inner classes, because that would mean // having to determine public static scope hs2.add(new JavaAPIListEntry(s, full, null)); } } catch(IOException ioe) { /* ignore, just don't add this one */ } catch(SecurityException se) { /* ignore, just don't add this one */ } } } } _completeClassList = new ArrayList<GoToFileListEntry>(hs); _autoImportClassList = new ArrayList<JavaAPIListEntry>(hs2); } }); t.setPriority(Thread.MIN_PRIORITY); t.start(); } private void _runProject() { if (_model.isProjectActive()) { try { final File f = _model.getMainClass(); if (f != null) { updateStatusField("Running Open Project"); OpenDefinitionsDocument doc = _model.getDocumentForFile(f); doc.runMain(); } } catch (ClassNameNotFoundException e) { // Display a warning message if a class name can't be found. String msg = "DrJava could not find the top level class name in the\n" + "current document, so it could not run the class. Please\n" + "make sure that the class is properly defined first."; JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } } else _runMain(); } /** Internal helper method to run the main method of the current document in the interactions pane. */ private void _runMain() { updateStatusField("Running main Method of Current Document"); try { _model.getActiveDocument().runMain(); } catch (ClassNameNotFoundException e) { // Display a warning message if a class name can't be found. String msg = "DrJava could not find the top level class name in the\n" + "current document, so it could not run the class. Please\n" + "make sure that the class is properly defined first."; JOptionPane.showMessageDialog(MainFrame.this, msg, "No Class Found", JOptionPane.ERROR_MESSAGE); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException ioe) { _showIOError(ioe); } } private void _junit() { hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted new Thread("Run JUnit on Current Document") { public void run() { _disableJUnitActions(); // now also works with multiple documents // hourglassOn(); // moved into the prelude before this thread start try { _model.getJUnitModel().junitDocs(_model.getDocumentNavigator().getSelectedDocuments()); } catch(UnexpectedException e) { _junitInterrupted(e); } catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); } } }.start(); } private void _junitFolder() { updateStatusField("Running Unit Tests in Current Folder"); hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted new Thread("Run JUnit on specified folder") { public void run() { INavigatorItem n; _disableJUnitActions(); // hourglassOn(); // turned off when JUnitStarted event is fired if (_model.getDocumentNavigator().isGroupSelected()) { ArrayList<OpenDefinitionsDocument> docs = _model.getDocumentNavigator().getDocuments(); final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>(); for (OpenDefinitionsDocument doc: docs) { if (_model.getDocumentNavigator().isSelectedInGroup(doc)) l.add(doc); } try { _model.getJUnitModel().junitDocs(l); } // hourglassOn executed by junitStarted() catch(UnexpectedException e) { _junitInterrupted(e); } catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); } } } }.start(); } /** Tests the documents in the project source tree. Assumes that DrJava is in project mode. */ private void _junitProject() { updateStatusField("Running JUnit Tests in Project"); hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted _disableJUnitActions(); try { _model.getJUnitModel().junitProject(); } catch(UnexpectedException e) { _junitInterrupted(e); } catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); } } /** Tests all open documents. */ private void _junitAll() { updateStatusField("Running All Open Unit Tests"); hourglassOn(); // turned off in junitStarted/nonTestCase/_junitInterrupted _disableJUnitActions(); try { _model.getJUnitModel().junitAll(); } catch(UnexpectedException e) { _junitInterrupted(e); } catch(Exception e) { _junitInterrupted(new UnexpectedException(e)); } } /* These are used to save the state of the enabled property of the actions disabled during junit testing. */ private volatile DecoratedAction _junit_compileProjectDecoratedAction; private volatile DecoratedAction _junit_compileAllDecoratedAction; private volatile DecoratedAction _junit_compileFolderDecoratedAction; private volatile DecoratedAction _junit_junitFolderDecoratedAction; private volatile DecoratedAction _junit_junitAllDecoratedAction; private volatile DecoratedAction _junit_junitDecoratedAction; private volatile DecoratedAction _junit_junitOpenProjectFilesDecoratedAction; private volatile DecoratedAction _junit_cleanDecoratedAction; private volatile DecoratedAction _junit_autoRefreshDecoratedAction; private volatile DecoratedAction _junit_projectPropertiesDecoratedAction; private volatile DecoratedAction _junit_runProjectDecoratedAction; private volatile DecoratedAction _junit_runDecoratedAction; /** An AbstractAction that prevents changes to the decoree's enabled flag. */ private static class DecoratedAction extends AbstractAction { /** The AbstractAction that is being decorated. */ AbstractAction _decoree; /** The "shallow" enabled flag. */ boolean _shallowEnabled; /** Create an action decorating the specified action, then sets the decoree's enabled flag to b. */ public DecoratedAction(AbstractAction a, boolean b) { super((String)a.getValue("Name")); _decoree = a; _shallowEnabled = _decoree.isEnabled(); _decoree.setEnabled(b); } public void actionPerformed(ActionEvent ae) { _decoree.actionPerformed(ae); } /** Do not change the decoree's enabled flag, but cache this value in the shallow enabled flag. */ public void setEnabled(boolean b) { _shallowEnabled = b; } /** Write the shallow enabled flag to the decoree, then return the decoree */ public AbstractAction getUpdatedDecoree() { _decoree.setEnabled(_shallowEnabled); return _decoree; } } /** Sets the enabled status to false of all actions that could conflict with JUnit while its is running a test. * This method saves aside the previous enable state of each action so that when the test is finished, any action * disabled before the test will remain disabled afterward. */ private void _disableJUnitActions() { // _compileProjectActionEnabled = _compileProjectAction.isEnabled(); // _compileAllActionEnabled = _compileAllAction.isEnabled(); //_compileFolderActionEnabled = _compileFolderAction.isEnabled(); //_junitFolderActionEnabled = _junitFolderAction.isEnabled(); //_junitAllActionEnabled = _junitAllAction.isEnabled(); //_junitActionEnabled = _junitAction.isEnabled(); //_junitProjectActionEnabled = _junitProjectAction.isEnabled(); //_cleanActionEnabled = _cleanAction.isEnabled(); //_projectPropertiesActionEnabled = _projectPropertiesAction.isEnabled(); //_runProjectActionEnabled = _runProjectAction.isEnabled(); // _compileProjectAction.setEnabled(false); //_compileAllAction.setEnabled(false); //_compileFolderAction.setEnabled(false); //_junitFolderAction.setEnabled(false); //_junitAllAction.setEnabled(false); //_junitAction.setEnabled(false); //_junitProjectAction.setEnabled(false); //_cleanAction.setEnabled(false); //_projectPropertiesAction.setEnabled(false); //_runProjectAction.setEnabled(false); _compileProjectAction = _junit_compileProjectDecoratedAction = new DecoratedAction(_compileProjectAction, false); _compileAllAction = _junit_compileAllDecoratedAction = new DecoratedAction(_compileAllAction, false); _compileFolderAction = _junit_compileFolderDecoratedAction = new DecoratedAction(_compileFolderAction, false); _junitFolderAction = _junit_junitFolderDecoratedAction = new DecoratedAction(_junitFolderAction, false); _junitAllAction = _junit_junitAllDecoratedAction = new DecoratedAction(_junitAllAction, false); _junitAction = _junit_junitDecoratedAction = new DecoratedAction(_junitAction, false); _junitProjectAction = _junit_junitOpenProjectFilesDecoratedAction = new DecoratedAction(_junitProjectAction, false); _cleanAction = _junit_cleanDecoratedAction = new DecoratedAction(_cleanAction, false); _autoRefreshAction = _junit_autoRefreshDecoratedAction = new DecoratedAction(_autoRefreshAction, false); _projectPropertiesAction = _junit_projectPropertiesDecoratedAction = new DecoratedAction(_projectPropertiesAction, false); _runProjectAction = _junit_runProjectDecoratedAction = new DecoratedAction(_runProjectAction, false); _runAction = _junit_runDecoratedAction = new DecoratedAction(_runAction, false); } private void _restoreJUnitActionsEnabled() { // _compileProjectAction.setEnabled(_compileProjectActionEnabled); // _compileAllAction.setEnabled(_compileAllActionEnabled); // //_compileOpenProjectAction.setEnabled(_compileOpenProjectActionEnabled); // _compileFolderAction.setEnabled(_compileFolderActionEnabled); // _junitFolderAction.setEnabled(_junitFolderActionEnabled); // _junitAllAction.setEnabled(_junitAllActionEnabled); // _junitAction.setEnabled(_junitActionEnabled); // _junitProjectAction.setEnabled(_junitProjectActionEnabled); // //_junitProjectAction.setEnabled(_junitProjectActionEnabled); // _cleanAction.setEnabled(_cleanActionEnabled); // _projectPropertiesAction.setEnabled(_projectPropertiesActionEnabled); // _runProjectAction.setEnabled(_runProjectActionEnabled); _compileProjectAction = _junit_compileProjectDecoratedAction.getUpdatedDecoree(); _compileAllAction = _junit_compileAllDecoratedAction.getUpdatedDecoree(); _compileFolderAction = _junit_compileFolderDecoratedAction.getUpdatedDecoree(); _junitFolderAction = _junit_junitFolderDecoratedAction.getUpdatedDecoree(); _junitAllAction = _junit_junitAllDecoratedAction.getUpdatedDecoree(); _junitAction = _junit_junitDecoratedAction.getUpdatedDecoree(); _junitProjectAction = _junit_junitOpenProjectFilesDecoratedAction.getUpdatedDecoree(); _cleanAction = _junit_cleanDecoratedAction.getUpdatedDecoree(); _autoRefreshAction = _junit_autoRefreshDecoratedAction.getUpdatedDecoree(); _projectPropertiesAction = _junit_projectPropertiesDecoratedAction.getUpdatedDecoree(); _runProjectAction = _junit_runProjectDecoratedAction.getUpdatedDecoree(); _runAction = _junit_runDecoratedAction.getUpdatedDecoree(); } // /** // * Suspends the current execution of the debugger // */ // private void debuggerSuspend() throws DebugException { // if (isDebuggerReady()) // _model.getDebugger().suspend(); // } /** Resumes the debugger's current execution. */ void debuggerResume() throws DebugException { if (isDebuggerReady()) { _model.getDebugger().resume(); removeCurrentLocationHighlight(); } } /** Steps in the debugger. */ void debuggerStep(Debugger.StepType type) { if (isDebuggerReady()) { try { _model.getDebugger().step(type); } catch (IllegalStateException ise) { // This may happen if the user if stepping very frequently, // and is even more likely if they are using both hotkeys // and UI buttons. Ignore it in this case. // Hopefully, there are no other situations where // the user can be trying to step while there are no // suspended threads. } catch (DebugException de) { _showError(de, "Debugger Error", "Could not create a step request."); } } } /** Toggles a breakpoint on the current line. */ void debuggerToggleBreakpoint() { addToBrowserHistory(); OpenDefinitionsDocument doc = _model.getActiveDocument(); boolean isUntitled = doc.isUntitled(); if (isUntitled) { JOptionPane.showMessageDialog(this, "You must save and compile this document before you can\n" + "set a breakpoint in it.", "Must Save and Compile", JOptionPane.ERROR_MESSAGE); return; } boolean isModified = doc.isModifiedSinceSave(); if (isDebuggerReady() && isModified && !_currentDefPane.hasWarnedAboutModified() && DrJava.getConfig().getSetting(WARN_BREAKPOINT_OUT_OF_SYNC).booleanValue()) { String message = "This document has been modified and may be out of sync\n" + "with the debugger. It is recommended that you first\n" + "save and recompile before continuing to use the debugger,\n" + "to avoid any unexpected errors. Would you still like to\n" + "toggle the breakpoint on the specified line?"; String title = "Toggle breakpoint on modified file?"; ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(this, title, message); int rc = dialog.show(); switch (rc) { case JOptionPane.YES_OPTION: _currentDefPane.hasWarnedAboutModified(true); if (dialog.getCheckBoxValue()) { DrJava.getConfig().setSetting(WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE); } break; case JOptionPane.NO_OPTION: if (dialog.getCheckBoxValue()) DrJava.getConfig().setSetting(WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE); return; case JOptionPane.CANCEL_OPTION: case JOptionPane.CLOSED_OPTION: // do nothing return; default: throw new RuntimeException("Invalid rc from showConfirmDialog: " + rc); } } try { Debugger debugger = _model.getDebugger(); debugger.toggleBreakpoint(doc, _currentDefPane.getCaretPosition(), _currentDefPane.getCurrentLine(), true); } catch (DebugException de) { _showError(de, "Debugger Error", "Could not set a breakpoint at the current line."); } } // private void _getText(String name) { _field = name; } // /** Adds a watch to a given variable or field. */ // void debuggerAddWatch() { // if (isDebuggerReady()) { // //final String field; // OpenDefinitionsDocument doc = _model.getActiveDocument(); // final JDialog getFieldDialog = new JDialog(this, "Choose Field to be Watched", true); // //getFieldDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); // final JTextField fieldName = new JTextField(); // getFieldDialog.setSize(new Dimension(150, 60)); // getFieldDialog.getContentPane().add(fieldName); // fieldName.addActionListener(new ActionListener() { // public void actionPerformed(ActionEvent ae) { // _getText(fieldName.getText()); // getFieldDialog.dispose(); // } // }); // getFieldDialog.setLocation(300,300); // getFieldDialog.show(); // Debugger debugger = _model.getDebugger(); // debugger.addWatch(_field); // } // } // /** Displays all breakpoints currently set in the debugger. */ // void _printBreakpoints() { _model.getDebugger().printBreakpoints(); } /** Clears all breakpoints from the debugger. */ void debuggerClearAllBreakpoints() { _model.getBreakpointManager().clearRegions(); } void _showFileMovedError(FileMovedException fme) { try { File f = fme.getFile(); OpenDefinitionsDocument doc = _model.getDocumentForFile(f); if (doc != null && _saveSelector.shouldSaveAfterFileMoved(doc, f)) _saveAs(); } catch (IOException ioe) { /* Couldn't find the document, so ignore the FME */ } } void _showProjectFileParseError(MalformedProjectFileException mpfe) { _showError(mpfe, "Invalid Project File", "DrJava could not read the given project file."); } void _showFileNotFoundError(FileNotFoundException fnf) { _showError(fnf, "File Not Found", "The specified file was not found on disk."); } void _showIOError(IOException ioe) { _showError(ioe, "Input/output error", "An I/O exception occurred during the last operation."); } void _showClassNotFoundError(ClassNotFoundException cnfe) { _showError(cnfe, "Class Not Found", "A ClassNotFound exception occurred during the last operation.\n" + "Please check that your classpath includes all relevant directories.\n\n"); } void _showNoClassDefError(NoClassDefFoundError ncde) { _showError(ncde, "No Class Def", "A NoClassDefFoundError occurred during the last operation.\n" + "Please check that your classpath includes all relevant paths.\n\n"); } void _showDebugError(DebugException de) { _showError(de, "Debug Error", "A Debugger error occurred in the last operation.\n\n"); } void _showJUnitInterrupted(UnexpectedException e) { _showWarning(e.getCause(), "JUnit Testing Interrupted", "The slave JVM has thrown a RemoteException probably indicating that it has been reset.\n\n"); } private void _showError(Throwable e, String title, String message) { JOptionPane.showMessageDialog(this, message + "\n" + e, title, JOptionPane.ERROR_MESSAGE); } private void _showWarning(Throwable e, String title, String message) { JOptionPane.showMessageDialog(this, message + "\n" + e, title, JOptionPane.WARNING_MESSAGE); } /** Check if any errors occurred while parsing the config file, and display a message if necessary. */ private void _showConfigException() { if (DrJava.getConfig().hadStartupException()) { Exception e = DrJava.getConfig().getStartupException(); _showError(e, "Error in Config File", "Could not read the '.drjava' configuration file\n" + "in your home directory. Starting with default\n" + "values instead.\n\n" + "The problem was:\n"); } } /** Returns the File selected by the JFileChooser. * @param fc File chooser presented to the user * @param choice return value from fc * @return Selected File * @throws OperationCanceledException if file choice canceled * @throws RuntimeException if fc returns a bad file or choice */ private File getChosenFile(JFileChooser fc, int choice) throws OperationCanceledException { switch (choice) { case JFileChooser.CANCEL_OPTION: case JFileChooser.ERROR_OPTION: throw new OperationCanceledException(); case JFileChooser.APPROVE_OPTION: File chosen = fc.getSelectedFile(); if (chosen != null) { //append the appropriate language level extension if not written by user if (fc.getFileFilter() instanceof JavaSourceFilter) { if (chosen.getName().indexOf(".") == -1) return new File(chosen.getAbsolutePath() + "." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[DrJava.getConfig().getSetting(LANGUAGE_LEVEL)]); } return chosen; } else throw new RuntimeException("Filechooser returned null file"); default: // impossible since rc must be one of these throw new RuntimeException("Filechooser returned bad rc " + choice); } } /** Returns the Files selected by the JFileChooser. * @param fc File chooser presented to the user * @param choice return value from fc * @return Selected Files - this array will be size 1 for single-selection dialogs. * @throws OperationCanceledException if file choice canceled * @throws RuntimeException if fc returns a bad file or choice */ private File[] getChosenFiles(JFileChooser fc, int choice) throws OperationCanceledException { switch (choice) { case JFileChooser.CANCEL_OPTION: case JFileChooser.ERROR_OPTION: throw new OperationCanceledException(); case JFileChooser.APPROVE_OPTION: File[] chosen = fc.getSelectedFiles(); if (chosen == null) throw new UnexpectedException(new OperationCanceledException(), "filechooser returned null file"); // Following code reviewed for bug 70902-- JVF // If this is a single-selection dialog, getSelectedFiles() will always // return a zero-size array -- handle it differently. if (chosen.length == 0) { if (!fc.isMultiSelectionEnabled()) { return new File[] { fc.getSelectedFile() }; } else { /* This is the workaround for bug 70902: sometimes Mac OS X will return * APPROVE_OPTION when the user clicks the close (x) control button * on the dialog window, even though nothing is selected. */ throw new OperationCanceledException(); } } else { return chosen; } default: // impossible since rc must be one of these throw new UnexpectedException(new OperationCanceledException(), "filechooser returned bad rc " + choice); } } private void _selectAll() { _currentDefPane.selectAll(); } /** Jump to the specified line and return the offset. Only runs in event thread. * @return offset */ public int _jumpToLine(int lineNum) { int pos = _model.getActiveDocument().gotoLine(lineNum); addToBrowserHistory(); _currentDefPane.setCaretPosition(pos); _currentDefPane.centerViewOnOffset(pos); return pos; } /** Ask the user what line they'd like to jump to, then go there. */ private int _gotoLine() { final String msg = "What line would you like to go to?"; final String title = "Go to Line"; String lineStr = JOptionPane.showInputDialog(this, msg, title, JOptionPane.QUESTION_MESSAGE); try { if (lineStr != null) { int lineNum = Integer.parseInt(lineStr); return _jumpToLine(lineNum); } } catch (NumberFormatException nfe) { // invalid input for line number Toolkit.getDefaultToolkit().beep(); // Do nothing. } //catch (BadLocationException ble) { } return -1; } /** Removes the ErrorCaretListener corresponding to the given document, after that document has been closed. * (Allows pane and listener to be garbage collected...) */ private void _removeErrorListener(OpenDefinitionsDocument doc) { JScrollPane scroll = _defScrollPanes.get(doc); if (scroll != null) { DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView(); pane.removeCaretListener(pane.getErrorCaretListener()); } } /** Initializes all action objects. Adds icons and descriptions to several of the actions. Note: this * initialization will later be done in the constructor of each action, which will subclass AbstractAction. */ private void _setUpActions() { _setUpAction(_newAction, "New", "Create a new document"); _setUpAction(_newJUnitTestAction, "New", "Create a new JUnit test case class"); _setUpAction(_newProjectAction, "New", "Make a new project"); _setUpAction(_openAction, "Open", "Open an existing file"); _setUpAction(_openFolderAction, "Open Folder", "OpenAll", "Open all files within a directory"); _setUpAction(_openFileOrProjectAction, "Open", "Open an existing file or project"); _setUpAction(_openProjectAction, "Open", "Open an existing project"); _setUpAction(_saveAction, "Save", "Save the current document"); _setUpAction(_saveAsAction, "Save As", "SaveAs", "Save the current document with a new name"); _setUpAction(_renameAction, "Rename", "Rename", "Rename the current document"); _setUpAction(_saveProjectAction, "Save", "Save", "Save the current project"); _saveProjectAction.setEnabled(false); _setUpAction(_saveProjectAsAction, "Save As", "SaveAs", "Save current project to new project file"); _saveProjectAsAction.setEnabled(false); _setUpAction(_exportProjectInOldFormatAction, "Export Project In Old \"" + OLD_PROJECT_FILE_EXTENSION + "\" Format", "SaveAs", "Export Project In Old \"" + OLD_PROJECT_FILE_EXTENSION + "\" Format"); _exportProjectInOldFormatAction.setEnabled(false); _setUpAction(_revertAction, "Revert", "Revert the current document to the saved version"); // No longer used // _setUpAction(_revertAllAction, "Revert All", "RevertAll", // "Revert all open documents to the saved versions"); _setUpAction(_closeAction, "Close", "Close the current document"); _setUpAction(_closeAllAction, "Close All", "CloseAll", "Close all documents"); _setUpAction(_closeProjectAction, "Close", "CloseAll", "Close the current project"); _closeProjectAction.setEnabled(false); _setUpAction(_projectPropertiesAction, "Project Properties", "Preferences", "Edit Project Properties"); _projectPropertiesAction.setEnabled(false); // _setUpAction(_junitProjectAction, "Test", "Test", "Test the current project"); // _junitProjectAction.setEnabled(false); _setUpAction(_junitProjectAction, "Test Project", "Test the documents in the project source tree"); _junitProjectAction.setEnabled(false); // _setUpAction(_compileOpenProjectAction, "Compile", "Compile", "Compile the open project documents"); _setUpAction(_compileProjectAction, "Compile Project", "Compile the documents in the project source tree"); // _compileOpenProjectAction.setEnabled(false); _compileProjectAction.setEnabled(false); _setUpAction(_runProjectAction, "Run Project", "Run the project's main method"); _runProjectAction.setEnabled(false); _setUpAction(_jarProjectAction, "Jar", "Create a jar archive from this project"); _jarProjectAction.setEnabled(false); _setUpAction(_saveAllAction, "Save All", "SaveAll", "Save all open documents"); _setUpAction(_cleanAction, "Clean", "Clean Build directory"); _cleanAction.setEnabled(false); _setUpAction(_autoRefreshAction, "Auto-Refresh", "Auto-refresh project"); _autoRefreshAction.setEnabled(false); _setUpAction(_compileAction, "Compile Current Document", "Compile the current document"); _setUpAction(_compileAllAction, "Compile", "Compile all open documents"); _setUpAction(_printDefDocAction, "Print", "Print the current main document"); _setUpAction(_printConsoleAction, "Print", "Print the Console pane"); _setUpAction(_printInteractionsAction, "Print", "Print the Interactions pane"); _setUpAction(_pageSetupAction, "Page Setup", "PageSetup", "Change the printer settings"); _setUpAction(_printDefDocPreviewAction, "Print Preview", "PrintPreview", "Preview how the document will be printed"); _setUpAction(_printConsolePreviewAction, "Print Preview", "PrintPreview", "Preview how the console document will be printed"); _setUpAction(_printInteractionsPreviewAction, "Print Preview", "PrintPreview", "Preview how the interactions document will be printed"); _setUpAction(_quitAction, "Quit", "Quit", "Quit DrJava"); _setUpAction(_undoAction, "Undo", "Undo previous command"); _setUpAction(_redoAction, "Redo", "Redo last undo"); _undoAction.putValue(Action.NAME, "Undo Previous Command"); _redoAction.putValue(Action.NAME, "Redo Last Undo"); _setUpAction(cutAction, "Cut", "Cut selected text to the clipboard"); _setUpAction(copyAction, "Copy", "Copy selected text to the clipboard"); _setUpAction(pasteAction, "Paste", "Paste text from the clipboard"); _setUpAction(_pasteHistoryAction, "Paste from History", "Paste text from the clipboard history"); _setUpAction(_selectAllAction, "Select All", "Select all text"); cutAction.putValue(Action.NAME, "Cut"); copyAction.putValue(Action.NAME, "Copy"); pasteAction.putValue(Action.NAME, "Paste"); _pasteHistoryAction.putValue(Action.NAME, "Paste from History"); _setUpAction(_indentLinesAction, "Indent Lines", "Indent all selected lines"); _setUpAction(_commentLinesAction, "Comment Lines", "Comment out all selected lines"); _setUpAction(_uncommentLinesAction, "Uncomment Lines", "Uncomment all selected lines"); _setUpAction(completeWordUnderCursorAction, "Auto-Complete Word Under Cursor", "Auto-complete the word the cursor is currently located on"); _setUpAction(_bookmarksPanelAction, "Bookmarks", "Display the bookmarks panel"); _setUpAction(_toggleBookmarkAction, "Toggle Bookmark", "Toggle the bookmark at the current cursor location"); _setUpAction(_followFileAction, "Follow File", "Follow a file's updates"); _setUpAction(_executeExternalProcessAction, "Execute External", "Execute external process"); _setUpAction(_editExternalProcessesAction, "Preferences", "Edit saved external processes"); _setUpAction(_findReplaceAction, "Find", "Find or replace text in the document"); _setUpAction(_findNextAction, "Find Next", "Repeats the last find"); _setUpAction(_findPrevAction, "Find Previous", "Repeats the last find in the opposite direction"); _setUpAction(_gotoLineAction, "Go to line", "Play", "Go to a line number in the document"); _setUpAction(_gotoFileAction, "Go to File", "Go to a file specified by its name"); _setUpAction(gotoFileUnderCursorAction, "Go to File Under Cursor", "Go to the file specified by the word the cursor is located on"); _setUpAction(_switchToPrevAction, "Previous Document", "Up", "Switch to the previous document"); _setUpAction(_switchToNextAction, "Next Document", "Down", "Switch to the next document"); _setUpAction(_browseBackAction, "Back", "Back", "Move back in the browser history"); _setUpAction(_browseForwardAction, "Forward", "Forward", "Move forward in the browser history"); _setUpAction(_switchToPreviousPaneAction, "Previous Pane", "Switch focus to the previous pane"); _setUpAction(_switchToNextPaneAction, "Next Pane", "Switch focus to the next pane"); _setUpAction(_gotoOpeningBraceAction, "Go to Opening Brace", "Go th the opening brace of the block enclosing the cursor"); _setUpAction(_gotoClosingBraceAction, "Go to Closing Brace", "Go th the closing brace of the block enclosing the cursor"); _setUpAction(_editPreferencesAction, "Preferences", "Edit configurable settings in DrJava"); _setUpAction(_junitAction, "Test Current", "Run JUnit over the current document"); _setUpAction(_junitAllAction, "Test", "Run JUnit over all open JUnit tests"); _setUpAction(_javadocAllAction, "Javadoc", "Create and save Javadoc for the packages of all open documents"); _setUpAction(_javadocCurrentAction, "Preview Javadoc Current", "Preview the Javadoc for the current document"); _setUpAction(_runAction, "Run", "Run the main method of the current document"); _setUpAction(_openJavadocAction, "Open Java API Javadoc...", "Open the Java API Javadoc Web page for a class"); _setUpAction(_openJavadocUnderCursorAction, "Open Java API Javadoc for Word Under Cursor...", "Open the Java API " + "Javadoc Web page for the word under the cursor"); _setUpAction(_executeHistoryAction, "Execute History", "Load and execute a history of interactions from a file"); _setUpAction(_loadHistoryScriptAction, "Load History as Script", "Load a history from a file as a series of interactions"); _setUpAction(_saveHistoryAction, "Save History", "Save the history of interactions to a file"); _setUpAction(_clearHistoryAction, "Clear History", "Clear the current history of interactions"); //_setUpAction(_abortInteractionAction, "Break", "Abort the current interaction"); _setUpAction(_resetInteractionsAction, "Reset", "Reset the Interactions Pane"); _resetInteractionsAction.setEnabled(true); _setUpAction(_viewInteractionsClassPathAction, "View Interactions Classpath", "Display the classpath in use by the Interactions Pane"); _setUpAction(_copyInteractionToDefinitionsAction, "Lift Current Interaction", "Copy the current interaction into the Definitions Pane"); _setUpAction(_clearConsoleAction, "Clear Console", "Clear all text in the Console Pane"); _setUpAction(_showDebugConsoleAction, "Show DrJava Debug Console", "<html>Show a console for debugging DrJava<br>" + "(with \"mainFrame\", \"model\", and \"config\" variables defined)</html>"); if (_model.getDebugger().isAvailable()) { _setUpAction(_toggleDebuggerAction, "Debug Mode", "Enable or disable DrJava's debugger"); _setUpAction(_toggleBreakpointAction, "Toggle Breakpoint", "Set or clear a breakpoint on the current line"); _setUpAction(_clearAllBreakpointsAction, "Clear Breakpoints", "Clear all breakpoints in all classes"); _setUpAction(_resumeDebugAction, "Resume", "Resume the current suspended thread"); _setUpAction(_stepIntoDebugAction, "Step Into", "Step into the current line or method call"); _setUpAction(_stepOverDebugAction, "Step Over", "Step over the current line or method call"); _setUpAction(_stepOutDebugAction, "Step Out", "Step out of the current method"); _setUpAction(_breakpointsPanelAction, "Breakpoints", "Display the breakpoints panel"); } _setUpAction(_helpAction, "Help", "Show documentation on how to use DrJava"); _setUpAction(_quickStartAction, "Help", "View Quick Start Guide for DrJava"); _setUpAction(_aboutAction, "About", "About DrJava"); _setUpAction(_checkNewVersionAction, "Check for New Version", "Find", "Check for New Version"); _setUpAction(_drjavaSurveyAction, "Send System Information", "About", "Send anonymous system information to DrJava developers"); _setUpAction(_errorsAction, "DrJava Errors", "drjavaerror", "Show a window with internal DrJava errors"); _setUpAction(_forceQuitAction, "Force Quit", "Stop", "Force DrJava to quit without cleaning up"); } private void _setUpAction(Action a, String name, String icon, String shortDesc) { a.putValue(Action.SMALL_ICON, _getIcon(icon + "16.gif")); a.putValue(Action.DEFAULT, name); a.putValue(Action.SHORT_DESCRIPTION, shortDesc); } private void _setUpAction(Action a, String icon, String shortDesc) { _setUpAction(a, icon, icon, shortDesc); } /** Returns the icon with the given name. All icons are assumed to reside in the /edu/rice/cs/drjava/ui/icons * directory. * @param name Name of icon image file * @return ImageIcon object constructed from the file */ private ImageIcon _getIcon(String name) { return getIcon(name); } public static ImageIcon getIcon(String name) { URL url = MainFrame.class.getResource(ICON_PATH + name); if (url != null) return new ImageIcon(url); return null; } /** This allows us to intercept key events when compiling testing and turn them off when the glass pane is up. */ private class MenuBar extends JMenuBar { public boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { if (MainFrame.this.getAllowKeyEvents()) return super.processKeyBinding(ks, e, condition, pressed); return false; } } /** Sets up the components of the menu bar and links them to the private fields within MainFrame. This method * serves to make the code more legible on the higher calling level, i.e., the constructor. * @param frame frame for which the menu bar should be set * @param menuBar menu bar to which the individual menus should be added * @param menus menus to add */ private void _setUpMenuBar() { _menuBar.add(_fileMenu); _menuBar.add(_editMenu); _menuBar.add(_toolsMenu); _menuBar.add(_projectMenu); if (_showDebugger) _menuBar.add(_debugMenu); _menuBar.add(_languageLevelMenu); _menuBar.add(_helpMenu); // Plastic-specific style hints if(Utilities.isPlasticLaf()) { _menuBar.putClientProperty(com.jgoodies.looks.Options.HEADER_STYLE_KEY, com.jgoodies.looks.HeaderStyle.BOTH); } setJMenuBar(_menuBar); } /** Adds an Action as a menu item to the given menu, using the specified configurable keystroke. * @param menu Menu to add item to * @param a Action for the menu item * @param opt Configurable keystroke for the menu item */ private void _addMenuItem(JMenu menu, Action a, Option<KeyStroke> opt) { JMenuItem item; item = menu.add(a); _setMenuShortcut(item, a, opt); } /** Sets the given menu item to have the specified configurable keystroke. * @param item Menu item containing the action * @param a Action for the menu item * @param opt Configurable keystroke for the menu item */ private void _setMenuShortcut(JMenuItem item, Action a, Option<KeyStroke> opt) { KeyStroke ks = DrJava.getConfig().getSetting(opt); // Checks that "a" is the action associated with the keystroke. // Need to check in case two actions were assigned to the same // key in the config file. // Also check that the keystroke isn't the NULL_KEYSTROKE, which // can strangely be triggered by certain keys in Windows. KeyBindingManager.ONLY.put(opt, a, item, item.getText()); if (ks != KeyStrokeOption.NULL_KEYSTROKE && KeyBindingManager.ONLY.get(ks) == a) { item.setAccelerator(ks); //KeyBindingManager.Singleton.addListener(opt, item); } } /** Creates and returns a file menu. Side effects: sets values for _saveMenuItem. */ private JMenu _setUpFileMenu(int mask) { JMenu fileMenu = new JMenu("File"); PlatformFactory.ONLY.setMnemonic(fileMenu,KeyEvent.VK_F); // New, open _addMenuItem(fileMenu, _newAction, KEY_NEW_FILE); _addMenuItem(fileMenu, _newJUnitTestAction, KEY_NEW_TEST); _addMenuItem(fileMenu, _openAction, KEY_OPEN_FILE); _addMenuItem(fileMenu, _openFolderAction, KEY_OPEN_FOLDER); //_addMenuItem(fileMenu, _openProjectAction, KEY_OPEN_PROJECT); fileMenu.addSeparator(); _addMenuItem(fileMenu, _saveAction, KEY_SAVE_FILE); _saveAction.setEnabled(true); _addMenuItem(fileMenu, _saveAsAction, KEY_SAVE_FILE_AS); _addMenuItem(fileMenu, _saveAllAction, KEY_SAVE_ALL_FILES); _addMenuItem(fileMenu, _renameAction, KEY_RENAME_FILE); _renameAction.setEnabled(false); // fileMenu.add(_saveProjectAsAction); _addMenuItem(fileMenu, _revertAction, KEY_REVERT_FILE); _revertAction.setEnabled(false); //tmpItem = fileMenu.add(_revertAllAction); // Close, Close all fileMenu.addSeparator(); _addMenuItem(fileMenu, _closeAction, KEY_CLOSE_FILE); _addMenuItem(fileMenu, _closeAllAction, KEY_CLOSE_ALL_FILES); //_addMenuItem(fileMenu, _closeProjectAction, KEY_CLOSE_PROJECT); // Page setup, print preview, print fileMenu.addSeparator(); _addMenuItem(fileMenu, _pageSetupAction, KEY_PAGE_SETUP); _addMenuItem(fileMenu, _printDefDocPreviewAction, KEY_PRINT_PREVIEW); _addMenuItem(fileMenu, _printDefDocAction, KEY_PRINT); // Quit fileMenu.addSeparator(); _addMenuItem(fileMenu, _quitAction, KEY_QUIT); return fileMenu; } /** Creates and returns a edit menu. */ private JMenu _setUpEditMenu(int mask) { JMenu editMenu = new JMenu("Edit"); PlatformFactory.ONLY.setMnemonic(editMenu,KeyEvent.VK_E); // Undo, redo _addMenuItem(editMenu, _undoAction, KEY_UNDO); _addMenuItem(editMenu, _redoAction, KEY_REDO); // Cut, copy, paste, select all editMenu.addSeparator(); _addMenuItem(editMenu, cutAction, KEY_CUT); _addMenuItem(editMenu, copyAction, KEY_COPY); _addMenuItem(editMenu, pasteAction, KEY_PASTE); _addMenuItem(editMenu, _pasteHistoryAction, KEY_PASTE_FROM_HISTORY); _addMenuItem(editMenu, _selectAllAction, KEY_SELECT_ALL); // Indent lines, comment lines editMenu.addSeparator(); //_addMenuItem(editMenu, _indentLinesAction, KEY_INDENT); JMenuItem editItem = editMenu.add(_indentLinesAction); editItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); _addMenuItem(editMenu, _commentLinesAction, KEY_COMMENT_LINES); _addMenuItem(editMenu, _uncommentLinesAction, KEY_UNCOMMENT_LINES); _addMenuItem(editMenu, completeWordUnderCursorAction, KEY_COMPLETE_FILE); // Find/replace, goto editMenu.addSeparator(); _addMenuItem(editMenu, _findReplaceAction, KEY_FIND_REPLACE); _addMenuItem(editMenu, _findNextAction, KEY_FIND_NEXT); _addMenuItem(editMenu, _findPrevAction, KEY_FIND_PREV); _addMenuItem(editMenu, _gotoLineAction, KEY_GOTO_LINE); _addMenuItem(editMenu, _gotoFileAction, KEY_GOTO_FILE); _addMenuItem(editMenu, gotoFileUnderCursorAction, KEY_GOTO_FILE_UNDER_CURSOR); // Next, prev doc editMenu.addSeparator(); _addMenuItem(editMenu, _switchToPrevAction, KEY_PREVIOUS_DOCUMENT); _addMenuItem(editMenu, _switchToNextAction, KEY_NEXT_DOCUMENT); _addMenuItem(editMenu, _browseBackAction, KEY_BROWSE_BACK); _addMenuItem(editMenu, _browseForwardAction, KEY_BROWSE_FORWARD); _addMenuItem(editMenu, _gotoOpeningBraceAction, KEY_OPENING_BRACE); _addMenuItem(editMenu, _gotoClosingBraceAction, KEY_CLOSING_BRACE); editMenu.addSeparator(); _addMenuItem(editMenu, _switchToPreviousPaneAction, KEY_PREVIOUS_PANE); _addMenuItem(editMenu, _switchToNextPaneAction, KEY_NEXT_PANE); _detachTabbedPanesMenuItem = _newCheckBoxMenuItem(_detachTabbedPanesAction); _detachTabbedPanesMenuItem.setSelected(DrJava.getConfig().getSetting(DETACH_TABBEDPANES)); _setMenuShortcut(_detachTabbedPanesMenuItem, _detachTabbedPanesAction, KEY_DETACH_TABBEDPANES); editMenu.add(_detachTabbedPanesMenuItem); // access to configurations GUI editMenu.addSeparator(); _addMenuItem(editMenu, _editPreferencesAction, KEY_PREFERENCES); // Add the menus to the menu bar return editMenu; } /** Creates and returns a tools menu. */ private JMenu _setUpToolsMenu(int mask) { JMenu toolsMenu = new JMenu("Tools"); PlatformFactory.ONLY.setMnemonic(toolsMenu,KeyEvent.VK_T); // Compile, Test, Javadoc _addMenuItem(toolsMenu, _compileAllAction, KEY_COMPILE_ALL); _addMenuItem(toolsMenu, _compileAction, KEY_COMPILE); _addMenuItem(toolsMenu, _junitAllAction, KEY_TEST_ALL); _addMenuItem(toolsMenu, _junitAction, KEY_TEST); toolsMenu.addSeparator(); // Run _addMenuItem(toolsMenu, _runAction, KEY_RUN); _addMenuItem(toolsMenu, _resetInteractionsAction, KEY_RESET_INTERACTIONS); toolsMenu.addSeparator(); // Javadoc final JMenu javadocMenu = new JMenu("Javadoc"); _addMenuItem(javadocMenu, _javadocAllAction, KEY_JAVADOC_ALL); _addMenuItem(javadocMenu, _javadocCurrentAction, KEY_JAVADOC_CURRENT); javadocMenu.addSeparator(); _addMenuItem(javadocMenu, _openJavadocAction, KEY_OPEN_JAVADOC); _addMenuItem(javadocMenu, _openJavadocUnderCursorAction, KEY_OPEN_JAVADOC_UNDER_CURSOR); toolsMenu.add(javadocMenu); final JMenu historyMenu = new JMenu("History"); _addMenuItem(historyMenu, _executeHistoryAction, KEY_EXECUTE_HISTORY); _addMenuItem(historyMenu, _loadHistoryScriptAction, KEY_LOAD_HISTORY_SCRIPT); _addMenuItem(historyMenu, _saveHistoryAction, KEY_SAVE_HISTORY); _addMenuItem(historyMenu, _clearHistoryAction, KEY_CLEAR_HISTORY); toolsMenu.add(historyMenu); // Abort/reset interactions, clear console /* _abortInteractionAction.setEnabled(false); _addMenuItem(toolsMenu, _abortInteractionAction, KEY_ABORT_INTERACTION); */ final JMenu interMenu = new JMenu("Interactions & Console"); _addMenuItem(interMenu, _viewInteractionsClassPathAction, KEY_VIEW_INTERACTIONS_CLASSPATH); _addMenuItem(interMenu, _copyInteractionToDefinitionsAction, KEY_LIFT_CURRENT_INTERACTION); _addMenuItem(interMenu, _printInteractionsAction, KEY_PRINT_INTERACTIONS); interMenu.addSeparator(); _addMenuItem(interMenu, _clearConsoleAction, KEY_CLEAR_CONSOLE); _addMenuItem(interMenu, _printConsoleAction, KEY_PRINT_CONSOLE); if (DrJava.getConfig().getSetting(SHOW_DEBUG_CONSOLE).booleanValue()) { toolsMenu.add(_showDebugConsoleAction); } toolsMenu.add(interMenu); final JMenu extMenu = new JMenu("External Processes"); _addMenuItem(extMenu, _executeExternalProcessAction, KEY_EXEC_PROCESS); final JMenuItem execItem = extMenu.getItem(0); extMenu.addSeparator(); extMenu.add(_editExternalProcessesAction); toolsMenu.add(extMenu); final int savedCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_COUNT); final int namesCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_NAMES).size(); final int cmdlinesCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_CMDLINES).size(); final int workdirsCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_WORKDIRS).size(); final int enclosingFileCount = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_ENCLOSING_DJAPP_FILES).size(); if ((savedCount!=namesCount) || (savedCount!=cmdlinesCount) || (savedCount!=workdirsCount) || (savedCount!=enclosingFileCount)) { DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_COUNT, 0); DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_NAMES, new Vector<String>()); DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_CMDLINES, new Vector<String>()); DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_WORKDIRS, new Vector<String>()); DrJava.getConfig().setSetting(OptionConstants.EXTERNAL_SAVED_ENCLOSING_DJAPP_FILES, new Vector<String>()); } OptionListener<Integer> externalSavedCountListener = new OptionListener<Integer>() { public void optionChanged(final OptionEvent<Integer> oce) { extMenu.removeAll(); extMenu.add(execItem); extMenu.addSeparator(); for (int count=0; count<oce.value; ++count) { final int i = count; final Vector<String> names = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_NAMES); final Vector<String> cmdlines = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_CMDLINES); final Vector<String> workdirs = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_WORKDIRS); final Vector<String> enclosingfiles = DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_ENCLOSING_DJAPP_FILES); extMenu.insert(new AbstractAction(names.get(i)) { public void actionPerformed(ActionEvent ae) { try { PropertyMaps pm = PropertyMaps.TEMPLATE.clone(); String s = enclosingfiles.get(i).trim(); ((MutableFileProperty) pm.getProperty("enclosing.djapp.file")). setFile(s.length() > 0 ? new File(s) : null); _executeExternalDialog. runCommand(names.get(i),cmdlines.get(i),workdirs.get(i),enclosingfiles.get(i),pm); } catch(CloneNotSupportedException e) { throw new edu.rice.cs.util.UnexpectedException(e); } } },i+2); } if (oce.value>0) { extMenu.addSeparator(); } extMenu.add(_editExternalProcessesAction); _editExternalProcessesAction.setEnabled(true); // always keep enabled, because it allows import } }; DrJava.getConfig().addOptionListener(OptionConstants.EXTERNAL_SAVED_COUNT, externalSavedCountListener); externalSavedCountListener. optionChanged(new OptionEvent<Integer>(OptionConstants.EXTERNAL_SAVED_COUNT, DrJava.getConfig().getSetting(OptionConstants.EXTERNAL_SAVED_COUNT))); toolsMenu.addSeparator(); _addMenuItem(toolsMenu, _bookmarksPanelAction, KEY_BOOKMARKS_PANEL); _addMenuItem(toolsMenu, _toggleBookmarkAction, KEY_BOOKMARKS_TOGGLE); toolsMenu.addSeparator(); _addMenuItem(toolsMenu, _followFileAction, KEY_FOLLOW_FILE); // Add the menus to the menu bar return toolsMenu; } /** Creates and returns a project menu. */ private JMenu _setUpProjectMenu(int mask) { JMenu projectMenu = new JMenu("Project"); PlatformFactory.ONLY.setMnemonic(projectMenu,KeyEvent.VK_P); // New, open projectMenu.add(_newProjectAction); _addMenuItem(projectMenu, _openProjectAction, KEY_OPEN_PROJECT); //Save projectMenu.add(_saveProjectAction); //SaveAs projectMenu.add(_saveProjectAsAction); // Close _addMenuItem(projectMenu, _closeProjectAction, KEY_CLOSE_PROJECT); projectMenu.addSeparator(); // run project // projectMenu.add(_compileOpenProjectAction); projectMenu.add(_compileProjectAction); projectMenu.add(_junitProjectAction); projectMenu.add(_runProjectAction); // projectMenu.add(_junitProjectAction); projectMenu.add(_cleanAction); projectMenu.add(_autoRefreshAction); projectMenu.add(_jarProjectAction); projectMenu.addSeparator(); // eventually add project options projectMenu.add(_projectPropertiesAction); return projectMenu; } /** Creates and returns a debug menu. */ private JMenu _setUpDebugMenu(int mask) { JMenu debugMenu = new JMenu("Debugger"); PlatformFactory.ONLY.setMnemonic(debugMenu,KeyEvent.VK_D); // Enable debugging item _debuggerEnabledMenuItem = _newCheckBoxMenuItem(_toggleDebuggerAction); _debuggerEnabledMenuItem.setSelected(false); _setMenuShortcut(_debuggerEnabledMenuItem, _toggleDebuggerAction, KEY_DEBUG_MODE_TOGGLE); debugMenu.add(_debuggerEnabledMenuItem); debugMenu.addSeparator(); _addMenuItem(debugMenu, _toggleBreakpointAction, KEY_DEBUG_BREAKPOINT_TOGGLE); //_printBreakpointsMenuItem = debugMenu.add(_printBreakpointsAction); //_clearAllBreakpointsMenuItem = _addMenuItem(debugMenu, _clearAllBreakpointsAction, KEY_DEBUG_CLEAR_ALL_BREAKPOINTS); _addMenuItem(debugMenu, _breakpointsPanelAction, KEY_DEBUG_BREAKPOINT_PANEL); debugMenu.addSeparator(); //_addMenuItem(debugMenu, _suspendDebugAction, KEY_DEBUG_SUSPEND); _addMenuItem(debugMenu, _resumeDebugAction, KEY_DEBUG_RESUME); _addMenuItem(debugMenu, _stepIntoDebugAction, KEY_DEBUG_STEP_INTO); _addMenuItem(debugMenu, _stepOverDebugAction, KEY_DEBUG_STEP_OVER); _addMenuItem(debugMenu, _stepOutDebugAction, KEY_DEBUG_STEP_OUT); debugMenu.addSeparator(); _detachDebugFrameMenuItem = _newCheckBoxMenuItem(_detachDebugFrameAction); _detachDebugFrameMenuItem.setSelected(DrJava.getConfig().getSetting(DETACH_DEBUGGER)); _setMenuShortcut(_detachDebugFrameMenuItem, _detachDebugFrameAction, KEY_DETACH_DEBUGGER); debugMenu.add(_detachDebugFrameMenuItem); // Start off disabled _setDebugMenuItemsEnabled(false); // Add the menu to the menu bar return debugMenu; } /** Called every time the debug mode checkbox is toggled. The resume and step * functions should always be disabled. */ private void _setDebugMenuItemsEnabled(boolean isEnabled) { _debuggerEnabledMenuItem.setSelected(isEnabled); //_suspendDebugAction.setEnabled(false); _resumeDebugAction.setEnabled(false); _stepIntoDebugAction.setEnabled(false); _stepOverDebugAction.setEnabled(false); _stepOutDebugAction.setEnabled(false); _detachDebugFrameAction.setEnabled(isEnabled); if (_showDebugger) _debugPanel.disableButtons(); } /** Enables and disables the appropriate menu items in the debug menu depending upon the state of the current thread. * @param isSuspended is true when the current thread has just been suspended * false if the current thread has just been resumed */ private void _setThreadDependentDebugMenuItems(boolean isSuspended) { //_suspendDebugAction.setEnabled(!isSuspended); _resumeDebugAction.setEnabled(isSuspended); _stepIntoDebugAction.setEnabled(isSuspended); _stepOverDebugAction.setEnabled(isSuspended); _stepOutDebugAction.setEnabled(isSuspended); _debugPanel.setThreadDependentButtons(isSuspended); } /** Creates and returns the language levels menu. */ private JMenu _setUpLanguageLevelMenu(int mask) { JMenu languageLevelMenu = new JMenu("Language Level"); PlatformFactory.ONLY.setMnemonic(languageLevelMenu,KeyEvent.VK_L); ButtonGroup group = new ButtonGroup(); final Configuration config = DrJava.getConfig(); int currentLanguageLevel = config.getSetting(LANGUAGE_LEVEL); JRadioButtonMenuItem rbMenuItem; rbMenuItem = new JRadioButtonMenuItem("Full Java"); rbMenuItem.setToolTipText("Use full Java syntax"); if (currentLanguageLevel == DrJavaRoot.FULL_JAVA) { rbMenuItem.setSelected(true); } rbMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.FULL_JAVA); }}); group.add(rbMenuItem); languageLevelMenu.add(rbMenuItem); languageLevelMenu.addSeparator(); rbMenuItem = new JRadioButtonMenuItem("Elementary"); rbMenuItem.setToolTipText("Use Elementary language-level features"); if (currentLanguageLevel == DrJavaRoot.ELEMENTARY_LEVEL) { rbMenuItem.setSelected(true); } rbMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.ELEMENTARY_LEVEL); }}); group.add(rbMenuItem); languageLevelMenu.add(rbMenuItem); rbMenuItem = new JRadioButtonMenuItem("Intermediate"); rbMenuItem.setToolTipText("Use Intermediate language-level features"); if (currentLanguageLevel == DrJavaRoot.INTERMEDIATE_LEVEL) { rbMenuItem.setSelected(true); } rbMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.INTERMEDIATE_LEVEL); }}); group.add(rbMenuItem); languageLevelMenu.add(rbMenuItem); rbMenuItem = new JRadioButtonMenuItem("Advanced"); rbMenuItem.setToolTipText("Use Advanced language-level features"); if (currentLanguageLevel == DrJavaRoot.ADVANCED_LEVEL) { rbMenuItem.setSelected(true); } rbMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.ADVANCED_LEVEL); }}); group.add(rbMenuItem); languageLevelMenu.add(rbMenuItem); return languageLevelMenu; } /** Creates and returns a help menu. */ private JMenu _setUpHelpMenu(int mask) { JMenu helpMenu = new JMenu("Help"); PlatformFactory.ONLY.setMnemonic(helpMenu,KeyEvent.VK_H); _addMenuItem(helpMenu, _helpAction, KEY_HELP); _addMenuItem(helpMenu, _quickStartAction, KEY_QUICKSTART); helpMenu.addSeparator(); _addMenuItem(helpMenu, _aboutAction, KEY_ABOUT); _addMenuItem(helpMenu, _drjavaSurveyAction, KEY_DRJAVA_SURVEY); _addMenuItem(helpMenu, _checkNewVersionAction, KEY_CHECK_NEW_VERSION); _addMenuItem(helpMenu, _errorsAction, KEY_DRJAVA_ERRORS); helpMenu.addSeparator(); _addMenuItem(helpMenu, _forceQuitAction, KEY_FORCE_QUIT); _addMenuItem(helpMenu, _exportProjectInOldFormatAction, KEY_EXPORT_OLD); return helpMenu; } /** Creates a toolbar button for undo and redo, which behave differently. */ JButton _createManualToolbarButton(Action a) { final JButton ret; Font buttonFont = DrJava.getConfig().getSetting(FONT_TOOLBAR); // Check whether icons should be shown boolean useIcon = DrJava.getConfig().getSetting(TOOLBAR_ICONS_ENABLED).booleanValue(); boolean useText = DrJava.getConfig().getSetting(TOOLBAR_TEXT_ENABLED).booleanValue(); final Icon icon = (useIcon) ? (Icon) a.getValue(Action.SMALL_ICON) : null; if (icon == null) { ret = new UnfocusableButton((String) a.getValue(Action.DEFAULT)); } else { ret = new UnfocusableButton(icon); if (useText) ret.setText((String) a.getValue(Action.DEFAULT)); } ret.setEnabled(false); ret.addActionListener(a); ret.setToolTipText( (String) a.getValue(Action.SHORT_DESCRIPTION)); ret.setFont(buttonFont); // Boolean test = a instanceof DelegatingAction; a.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("enabled".equals(evt.getPropertyName())) { Boolean val = (Boolean) evt.getNewValue(); ret.setEnabled(val.booleanValue()); } } }); return ret; } /** Sets up all buttons for the toolbar except for undo and redo, which use _createManualToolbarButton. */ public JButton _createToolbarButton(Action a) { boolean useText = DrJava.getConfig().getSetting(TOOLBAR_TEXT_ENABLED).booleanValue(); boolean useIcons = DrJava.getConfig().getSetting(TOOLBAR_ICONS_ENABLED).booleanValue(); Font buttonFont = DrJava.getConfig().getSetting(FONT_TOOLBAR); final JButton result = new UnfocusableButton(a); result.setText((String) a.getValue(Action.DEFAULT)); result.setFont(buttonFont); if (! useIcons) result.setIcon(null); if (! useText && (result.getIcon() != null)) result.setText(""); return result; } /** Removes the button b from the toolbar and creates new button in its place. Only runs in the event thread. */ public JButton _updateToolbarButton(JButton b, Action a) { final JButton result = _createToolbarButton(a); int index = _toolBar.getComponentIndex(b); _toolBar.remove(b); _toolBar.add(result, index); _fixToolbarHeights(); return result; } /** Sets up the toolbar with several useful buttons. Most buttons are always enabled, but those that are not are * maintained in fields to allow enabling and disabling. */ private void _setUpToolBar() { _toolBar.setFloatable(false); // _toolBar.addSeparator(); // New, open, save, close _toolBar.add(_createToolbarButton(_newAction)); _toolBar.add(_createToolbarButton(_openFileOrProjectAction)); _toolBar.add(_createToolbarButton(_saveAction)); _closeButton = _createToolbarButton(_closeAction); _toolBar.add(_closeButton); // Cut, copy, paste _toolBar.addSeparator(); _toolBar.add(_createToolbarButton(cutAction)); _toolBar.add(_createToolbarButton(copyAction)); _toolBar.add(_createToolbarButton(pasteAction)); // Undo, redo // Simple workaround, for now, for bug # 520742: // Undo/Redo button text in JDK 1.3 // We just manually create the JButtons, and we *don't* set up // PropertyChangeListeners on the action's name. //_toolBar.addSeparator(); _toolBar.add(_undoButton); _toolBar.add(_redoButton); // Find _toolBar.addSeparator(); _toolBar.add(_createToolbarButton(_findReplaceAction)); // Compile, reset, abort _toolBar.addSeparator(); _toolBar.add(_compileButton = _createToolbarButton(_compileAllAction)); _toolBar.add(_createToolbarButton(_resetInteractionsAction)); //_toolBar.add(_createToolbarButton(_abortInteractionAction)); // Run, Junit, and JavaDoc _toolBar.addSeparator(); _toolBar.add(_runButton = _createToolbarButton(_runAction)); _toolBar.add(_junitButton = _createToolbarButton(_junitAllAction)); _toolBar.add(_createToolbarButton(_javadocAllAction)); // DrJava Errors _toolBar.addSeparator(); _errorsButton = _createToolbarButton(_errorsAction); _errorsButton.setVisible(false); _errorsButton.setBackground(DrJava.getConfig().getSetting(DRJAVA_ERRORS_BUTTON_COLOR)); _toolBar.add(_errorsButton); /** The OptionListener for DRJAVA_ERRORS_BUTTON_COLOR. */ OptionListener<Color> errBtnColorOptionListener = new OptionListener<Color>() { public void optionChanged(OptionEvent<Color> oce) { _errorsButton.setBackground(oce.value); } }; DrJava.getConfig().addOptionListener(DRJAVA_ERRORS_BUTTON_COLOR, errBtnColorOptionListener); // Correct the vertical height of the buttons. _fixToolbarHeights(); // Plastic-specific style hints if(Utilities.isPlasticLaf()) { _toolBar.putClientProperty("JToolBar.isRollover", Boolean.FALSE); _toolBar.putClientProperty(com.jgoodies.looks.Options.HEADER_STYLE_KEY, com.jgoodies.looks.HeaderStyle.BOTH); } getContentPane().add(_toolBar, BorderLayout.NORTH); // _updateToolBarVisible(); // created a visible GUI component during initialization! } /** Sets the toolbar as either visible or invisible based on the config option. Only runs in the event thread. */ private void _updateToolBarVisible() { _toolBar.setVisible(DrJava.getConfig().getSetting(TOOLBAR_ENABLED)); } /** Update the toolbar's buttons, following any change to TOOLBAR_ICONS_ENABLED, TOOLBAR_TEXT_ENABLED, or * FONT_TOOLBAR (name, style, text) */ private void _updateToolbarButtons() { _updateToolBarVisible(); Component[] buttons = _toolBar.getComponents(); Font toolbarFont = DrJava.getConfig().getSetting(FONT_TOOLBAR); boolean iconsEnabled = DrJava.getConfig().getSetting(TOOLBAR_ICONS_ENABLED).booleanValue(); boolean textEnabled = DrJava.getConfig().getSetting(TOOLBAR_TEXT_ENABLED).booleanValue(); for (int i = 0; i< buttons.length; i++) { if (buttons[i] instanceof JButton) { JButton b = (JButton) buttons[i]; Action a = b.getAction(); // Work-around for strange configuration of undo/redo buttons /* if (a == null) { ActionListener[] al = b.getActionListeners(); // 1.4 only for (int j=0; j<al.length; j++) { if (al[j] instanceof Action) { a = (Action) al[j]; break; } } } */ b.setFont(toolbarFont); if (a == null) { if (b == _undoButton) a = _undoAction; else if (b == _redoButton) a = _redoAction; else continue; } if (b.getIcon() == null) { if (iconsEnabled) b.setIcon( (Icon) a.getValue(Action.SMALL_ICON)); } else if (!iconsEnabled && b.getText().equals("")) b.setIcon(null); if (b.getText().equals("")) { if (textEnabled) b.setText( (String) a.getValue(Action.DEFAULT)); } else if (!textEnabled && b.getIcon() != null) b.setText(""); } } // Correct the vertical height of the buttons. _fixToolbarHeights(); } /** Ensures that all toolbar buttons have the same height. */ private void _fixToolbarHeights() { Component[] buttons = _toolBar.getComponents(); // First, find the maximum height of all the buttons. int max = 0; for (int i = 0; i< buttons.length; i++) { // We only care about the JButtons. if (buttons[i] instanceof JButton) { JButton b = (JButton) buttons[i]; // reset any preferred size we have set b.setPreferredSize(null); // get the preferred height, since that's what we want to use Dimension d = b.getPreferredSize(); int cur = (int) d.getHeight(); if (cur > max) { max = cur; } } } // Now set all button heights to the max. for (int i = 0; i< buttons.length; i++) { // We only care about the JButtons. if (buttons[i] instanceof JButton) { JButton b = (JButton) buttons[i]; Dimension d = new Dimension((int) b.getPreferredSize().getWidth(), max); // JToolBar inexplicably uses the max size // also set preferred size for consistency b.setPreferredSize(d); b.setMaximumSize(d); } } // _toolbar.revalidate(); } /** Sets up the status bar with the filename field. Only called from MainFrame constructor. */ private void _setUpStatusBar() { // Initialize the 3 labels: _statusField.setFont(_statusField.getFont().deriveFont(Font.PLAIN)); _statusReport.setHorizontalAlignment(SwingConstants.RIGHT); JPanel fileNameAndMessagePanel = new JPanel(new BorderLayout()); fileNameAndMessagePanel.add(_statusField, BorderLayout.CENTER); fileNameAndMessagePanel.add(_statusReport, BorderLayout.EAST); _currLocationField.setFont(_currLocationField.getFont().deriveFont(Font.PLAIN)); _currLocationField.setHorizontalAlignment(SwingConstants.RIGHT); _currLocationField.setPreferredSize(new Dimension(165,12)); // _currLocationField.setVisible(true); // Initialize the status bar panel // SpringLayout layout = new SpringLayout(); _statusBar.add( fileNameAndMessagePanel, BorderLayout.CENTER ); // _statusBar.add( sbMessagePanel, BorderLayout.CENTER ); _statusBar.add( _currLocationField, BorderLayout.EAST ); _statusBar. setBorder(new CompoundBorder(new EmptyBorder(2,2,2,2), new CompoundBorder(new BevelBorder(BevelBorder.LOWERED), new EmptyBorder(2,2,2,2)))); getContentPane().add(_statusBar, BorderLayout.SOUTH); // //Adjust constraints for the fileName label so it's next to the left edge. // layout.getConstraints(_statusField).setX(Spring.constant(0)); // // //Adjust constraints for the message label so it's spaced a bit from the right. // //and doesn't interfere with the left-most label // layout.putConstraint(SpringLayout.EAST, _statusReport, -65, // SpringLayout.EAST, _statusBar); // // //Adjust constraints for the location label so it's next to the right edge. // layout.putConstraint(SpringLayout.EAST, _currLocationField, 0, // SpringLayout.EAST, _statusBar); // // //Adjust constraints for the panel to set its size // layout.putConstraint(SpringLayout.SOUTH, _statusBar, 0, // SpringLayout.SOUTH, _currLocationField); } /** Inner class to handle updating the current position in a document. Registered with the DefinitionsPane. **/ private class PositionListener implements CaretListener { /* Cached caret coordinates */ private int _offset; private int _line; private int _col; // The following method only runs in the event thread because it is called from DefinitionsPane public void caretUpdate(final CaretEvent ce) { // DefinitionsDocument doc = _model.getActiveDocument().getDocument(); int offset = ce.getDot(); try { if (offset == _offset + 1 && _currentDefDoc.getText(_offset, 1).charAt(0) != '\n') { _col += 1; _offset += 1; } else { Element root = _currentDefDoc.getDefaultRootElement(); int line = root.getElementIndex(offset); _line = line + 1; // line numbers are 1-based _col = offset - root.getElement(line).getStartOffset(); } } catch(BadLocationException e) { /* do nothing; should never happen */ } finally { _offset = offset; updateLocation(_line, _col); } } // This method appears safe outside the event thread public void updateLocation() { // OpenDefinitionsDocument doc = _model.getActiveDocument(); _line = _currentDefDoc.getCurrentLine(); _col = _currentDefDoc.getCurrentCol(); updateLocation(_line, _col); } private void updateLocation(int line, int col) { // Can run outside the event thread because setText is thread safe. _currLocationField.setText(line + ":" + col +" \t"); // Space before "\t" required on Mac to avoid obscuring // Lightweight parsing has been disabled until we have something that is beneficial and works better in the background. // _model.getParsingControl().delay(); } public int lastLine() { return _line; } public int lastCol() { return _col; } } /* Only called from MainFrame constructor. */ private void _setUpTabs() { // Interactions _interactionsController.setPrevPaneAction(_switchToPreviousPaneAction); _interactionsController.setNextPaneAction(_switchToNextPaneAction); JScrollPane interactionsScroll = new BorderlessScrollPane(_interactionsPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); _interactionsContainer.add(interactionsScroll, BorderLayout.CENTER); if (_showDebugger) { // hook highlighting listener to breakpoint manager _model.getBreakpointManager().addListener(new RegionManagerListener<Breakpoint>() { /* Called when a breakpoint is added. Only runs in event thread. */ public void regionAdded(final Breakpoint bp) { DefinitionsPane bpPane = getDefPaneGivenODD(bp.getDocument()); _documentBreakpointHighlights. put(bp, bpPane.getHighlightManager(). addHighlight(bp.getStartOffset(), bp.getEndOffset(), bp.isEnabled() ? DefinitionsPane.BREAKPOINT_PAINTER : DefinitionsPane.DISABLED_BREAKPOINT_PAINTER)); _updateDebugStatus(); } /** Called when a breakpoint is changed. Only runs in event thread. */ public void regionChanged(Breakpoint bp) { regionRemoved(bp); regionAdded(bp); } /** Called when a breakpoint is removed. Only runs in event thread. */ public void regionRemoved(final Breakpoint bp) { HighlightManager.HighlightInfo highlight = _documentBreakpointHighlights.get(bp); if (highlight != null) highlight.remove(); _documentBreakpointHighlights.remove(bp); } }); } // hook highlighting listener to bookmark manager _model.getBookmarkManager().addListener(new RegionManagerListener<OrderedDocumentRegion>() { // listener methods only run in the event thread public void regionAdded(OrderedDocumentRegion r) { DefinitionsPane bpPane = getDefPaneGivenODD(r.getDocument()); _documentBookmarkHighlights. put(r, bpPane.getHighlightManager(). addHighlight(r.getStartOffset(), r.getEndOffset(), DefinitionsPane.BOOKMARK_PAINTER)); } public void regionChanged(OrderedDocumentRegion r) { regionRemoved(r); regionAdded(r); } public void regionRemoved(OrderedDocumentRegion r) { HighlightManager.HighlightInfo highlight = _documentBookmarkHighlights.get(r); if (highlight != null) highlight.remove(); _documentBookmarkHighlights.remove(r); } }); _tabbedPane.addChangeListener(new ChangeListener () { /* Only runs in the event thread. */ public void stateChanged(ChangeEvent e) { // System.err.println("_tabbedPane.stateChanged called with event " + e); clearStatusMessage(); if (_tabbedPane.getSelectedIndex() == INTERACTIONS_TAB) { // Use EventQueue because this action must execute AFTER all pending events in the event queue // System.err.println("Interactions Container Selected"); _interactionsContainer.setVisible(true); // kluge to overcome subtle focus bug EventQueue.invokeLater(new Runnable() { public void run() { _interactionsContainer.requestFocusInWindow(); } }); } else if (_tabbedPane.getSelectedIndex() == CONSOLE_TAB) { // Use EventQueue because this action must execute AFTER all pending events in the event queue // System.err.println("Console Scroll Selected"); EventQueue.invokeLater(new Runnable() { public void run() { _consoleScroll.requestFocusInWindow(); } }); } // Update error highlights? if (_currentDefPane != null) { int pos = _currentDefPane.getCaretPosition(); _currentDefPane.removeErrorHighlight(); // removes highlighting whenever the current tabbed pane is switched _currentDefPane.getErrorCaretListener().updateHighlight(pos); } } }); _tabbedPane.add("Interactions", _interactionsContainer); _tabbedPane.add("Console", _consoleScroll); _interactionsPane.addKeyListener(_historyListener); _interactionsPane.addFocusListener(_focusListenerForRecentDocs); _consoleScroll.addKeyListener(_historyListener); _consoleScroll.addFocusListener(_focusListenerForRecentDocs); _tabs.addLast(_compilerErrorPanel); _tabs.addLast(_junitErrorPanel); _tabs.addLast(_javadocErrorPanel); _tabs.addLast(_findReplace); if (_showDebugger) { _tabs.addLast(_breakpointsPanel); } _tabs.addLast(_bookmarksPanel); _interactionsContainer.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { EventQueue.invokeLater(new Runnable() { public void run() { // System.err.println("Requesting focus in interactions pane"); _interactionsPane.requestFocusInWindow(); } }); } }); _interactionsPane.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _interactionsContainer; } }); _consolePane.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _consoleScroll; } }); _compilerErrorPanel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _compilerErrorPanel; } }); _junitErrorPanel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _junitErrorPanel; } }); _javadocErrorPanel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _javadocErrorPanel; } }); _findReplace.getFindField().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _findReplace; } }); if (_showDebugger) { _breakpointsPanel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _breakpointsPanel; } }); } _bookmarksPanel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = _bookmarksPanel; } }); } /** Realizes this MainFrame by setting it visibile and configures the tabbed Pane. Only runs in the event thread. */ public void start() { // Make the MainFrame visible and show the compiler tab EventQueue.invokeLater(new Runnable() { public void run() { setVisible(true); _compilerErrorPanel.setVisible(true); showTab(_compilerErrorPanel, true); /* The following two step sequence was laboriously developed by trial and error; without it the _tabbedPane * does not display properly. */ _tabbedPane.invalidate(); _tabbedPane.repaint(); } }); } /** Sets up the context menu to show in the document pane. */ private void _setUpContextMenus() { // pop-up menu for a folder in tree view // _navPaneFolderPopupMenu = new JPopupMenu(); /* * Phil Repicky -smallproj * 2/14/2005 * Make these do something: * _navPaneFolderPopupMenu.add("Open a File in this Folder Action"); * _navPaneFolderPopupMenu.add("Make a New File in this Folder Action"); */ // _navPaneFolderPopupMenu.add(_newFileFolderAction); // _navPaneFolderPopupMenu.add(_openOneFolderAction); // _navPaneFolderPopupMenu.add(_openAllFolderAction); // _navPaneFolderPopupMenu.add(_closeFolderAction); // _navPaneFolderPopupMenu.add(_compileFolderAction); // _navPaneFolderPopupMenu.add(_junitFolderAction); // _navPanePopupMenuForRoot = new JPopupMenu(); // _navPanePopupMenuForRoot.add(_saveProjectAction); // _navPanePopupMenuForRoot.add(_closeProjectAction); // _navPanePopupMenuForRoot.addSeparator(); // _navPanePopupMenuForRoot.add(_compileProjectAction); // _navPanePopupMenuForRoot.add(_runProjectAction); // _navPanePopupMenuForRoot.add(_junitProjectAction); // _navPanePopupMenuForRoot.addSeparator(); // _navPanePopupMenuForRoot.add(_projectPropertiesAction); // _navPanePopupMenuForExternal = new JPopupMenu(); // _navPanePopupMenuForExternal.add(_saveAction); // _navPanePopupMenuForExternal.add(_saveAsAction); // _navPanePopupMenuForExternal.add(_renameAction); // _navPanePopupMenuForExternal.add(_revertAction); // _navPanePopupMenuForExternal.addSeparator(); // _navPanePopupMenuForExternal.add(_closeAction); // _navPanePopupMenuForExternal.addSeparator(); // _navPanePopupMenuForExternal.add(_printDefDocAction); // _navPanePopupMenuForExternal.add(_printDefDocPreviewAction); // _navPanePopupMenuForExternal.addSeparator(); // _navPanePopupMenuForExternal.add(_compileAction); // _navPanePopupMenuForExternal.add(_junitAction); // _navPanePopupMenuForExternal.add(_javadocCurrentAction); // _navPanePopupMenuForExternal.add(_runAction); // _navPanePopupMenuForExternal.addSeparator(); // _navPanePopupMenuForExternal.add(_moveToAuxiliaryAction); // _navPanePopupMenuForAuxiliary = new JPopupMenu(); // _navPanePopupMenuForAuxiliary.add(_saveAction); // _navPanePopupMenuForAuxiliary.add(_saveAsAction); // _navPanePopupMenuForAuxiliary.add(_renameAction); // _navPanePopupMenuForAuxiliary.add(_revertAction); // _navPanePopupMenuForAuxiliary.addSeparator(); // _navPanePopupMenuForAuxiliary.add(_closeAction); // _navPanePopupMenuForAuxiliary.addSeparator(); // _navPanePopupMenuForAuxiliary.add(_printDefDocAction); // _navPanePopupMenuForAuxiliary.add(_printDefDocPreviewAction); // _navPanePopupMenuForAuxiliary.addSeparator(); // _navPanePopupMenuForAuxiliary.add(_compileAction); // _navPanePopupMenuForAuxiliary.add(_junitAction); // _navPanePopupMenuForAuxiliary.add(_javadocCurrentAction); // _navPanePopupMenuForAuxiliary.add(_runAction); // _navPanePopupMenuForAuxiliary.addSeparator(); // _navPanePopupMenuForAuxiliary.add(_removeAuxiliaryAction); // NavPane menu // _navPanePopupMenu = new JPopupMenu(); // _navPanePopupMenu.add(_saveAction); // _navPanePopupMenu.add(_saveAsAction); // _navPanePopupMenu.add(_renameAction); // _navPanePopupMenu.add(_revertAction); // _navPanePopupMenu.addSeparator(); // _navPanePopupMenu.add(_closeAction); // _navPanePopupMenu.addSeparator(); // _navPanePopupMenu.add(_printDefDocAction); // _navPanePopupMenu.add(_printDefDocPreviewAction); // _navPanePopupMenu.addSeparator(); // _navPanePopupMenu.add(_compileAction); // _navPanePopupMenu.add(_junitAction); // _navPanePopupMenu.add(_javadocCurrentAction); // _navPanePopupMenu.add(_runAction); _model.getDocCollectionWidget().addMouseListener(new RightClickMouseAdapter() { protected void _popupAction(MouseEvent e) { boolean showContextMenu = true; if (!_model.getDocumentNavigator().isSelectedAt(e.getX(), e.getY())) { // click on a item that wasn't selected, change selection showContextMenu = _model.getDocumentNavigator().selectDocumentAt(e.getX(), e.getY()); } if (showContextMenu) { boolean rootSelected = _model.getDocumentNavigator().isRootSelected(); boolean folderSelected = false; boolean docSelected = false; boolean externalSelected = false; boolean auxiliarySelected = false; boolean externalBinSelected = false; boolean auxiliaryBinSelected = false; final int docSelectedCount = _model.getDocumentNavigator().getDocumentSelectedCount(); final int groupSelectedCount = _model.getDocumentNavigator().getGroupSelectedCount(); try { java.util.Set<String> groupNames = _model.getDocumentNavigator().getNamesOfSelectedTopLevelGroup(); if (docSelectedCount>0) { // when documents are selected, ignore all other options and only deal with documents rootSelected = false; if (groupNames.contains(_model.getSourceBinTitle())) { // a document in the "[ Source Files ]" bin is selected docSelected = true; } if (groupNames.contains(_model.getExternalBinTitle())) { // a document in the "[ External Files ]" bin is selected externalSelected = true; } if (groupNames.contains(_model.getAuxiliaryBinTitle())) { // a document in the "[ Included External Files ]" bin is selected auxiliarySelected = true; } } else { // no document selected, check other options if (groupSelectedCount>0) { // at least one folder is selected if (!_model.getDocumentNavigator().isTopLevelGroupSelected()) { // it is really a folder and not a top level bin, e.g. "[ Source Files ]" folderSelected = true; } else { // it is a top level bin, e.g. "[ Source Files ]" if (groupNames.contains(_model.getSourceBinTitle())) { // the "[ Source Files ]" bin is selected, treat as normal folder folderSelected = true; } if (groupNames.contains(_model.getExternalBinTitle())) { // the "[ External Files ]" bin is selected externalBinSelected = true; } if (groupNames.contains(_model.getAuxiliaryBinTitle())) { // the "[ Included External Files ]" bin is selected auxiliaryBinSelected = true; } } } } } catch(GroupNotSelectedException ex) { // we're looking at the root of the tree, or we're in list view... if (_model.isProjectActive()) { // project view, so the root has been selected rootSelected = true; } else { // list view, so treat it as simple documents docSelected = true; rootSelected = false; folderSelected = false; externalSelected = false; auxiliarySelected = false; externalBinSelected = false; auxiliaryBinSelected = false; } } if (!rootSelected && !folderSelected && !docSelected && !externalSelected && !auxiliarySelected && !externalBinSelected && !auxiliaryBinSelected) { // nothing selected, don't display anything return; } final JPopupMenu m = new JPopupMenu(); if (docSelectedCount==0) { docSelected = externalSelected = auxiliarySelected = false; } if (groupSelectedCount==0) { folderSelected = false; } if (rootSelected) { // root selected m.add(Utilities.createDelegateAction("Save Project", _saveProjectAction)); m.add(Utilities.createDelegateAction("Close Project", _closeProjectAction)); m.add(_compileProjectAction); m.add(_runProjectAction); m.add(_junitProjectAction); m.add(_projectPropertiesAction); } if (folderSelected) { // folder selected if (m.getComponentCount()>0) { m.addSeparator(); } if (groupSelectedCount==1) { // "New File in Folder" and "Open File in Folder" only work if exactly // one folder is selected m.add(_newFileFolderAction); m.add(_openOneFolderAction); // get singular/plural right m.add(Utilities.createDelegateAction("Open All Files in Folder", _openAllFolderAction)); m.add(_closeFolderAction); m.add(_compileFolderAction); m.add(_junitFolderAction); } else if (groupSelectedCount>1) { if (!externalBinSelected && !auxiliaryBinSelected) { // open only makes sense if it's real folders, and not // the external or auxiliary bins m.add(Utilities.createDelegateAction("Open All Files in All Folders (" + groupSelectedCount + ")", _openAllFolderAction)); } m.add(Utilities. createDelegateAction("Close All Folders ("+groupSelectedCount+")", _closeFolderAction)); m.add(Utilities. createDelegateAction("Compile All Folders ("+groupSelectedCount+")", _compileFolderAction)); m.add(Utilities. createDelegateAction("Test All Folders ("+groupSelectedCount+")", _junitFolderAction)); } } if (docSelected || externalSelected || auxiliarySelected) { // some kind of document selected if (m.getComponentCount()>0) { m.addSeparator(); } if (docSelectedCount==1) { m.add(Utilities.createDelegateAction("Save File", _saveAction)); m.add(Utilities.createDelegateAction("Save File As...", _saveAsAction)); m.add(Utilities.createDelegateAction("Rename File", _renameAction)); m.add(Utilities.createDelegateAction("Revert File to Saved", _revertAction)); m.add(Utilities.createDelegateAction("Close File", _closeAction)); m.add(Utilities.createDelegateAction("Print File...", _printDefDocAction)); m.add(Utilities.createDelegateAction("Print File Preview...", _printDefDocPreviewAction)); m.add(Utilities.createDelegateAction("Compile File", _compileAction)); m.add(Utilities.createDelegateAction("Test File", _junitAction)); m.add(Utilities.createDelegateAction("Preview Javadoc for File", _javadocCurrentAction)); m.add(Utilities.createDelegateAction("Run File's Main Method", _runAction)); } else if (docSelectedCount>1) { m.add(Utilities.createDelegateAction("Save All Files ("+docSelectedCount+")", _saveAction)); m.add(Utilities.createDelegateAction("Revert All Files to Saved ("+docSelectedCount+")", _revertAction)); m.add(Utilities.createDelegateAction("Close All Files ("+docSelectedCount+")", _closeAction)); m.add(Utilities.createDelegateAction("Compile All Files ("+docSelectedCount+")", _compileAction)); m.add(Utilities.createDelegateAction("Test All Files ("+docSelectedCount+")", _junitAction)); } } if (externalSelected && !docSelected && !auxiliarySelected) { // external document selected, but no regular or auxiliary documents if (m.getComponentCount()>0) { m.addSeparator(); } if (docSelectedCount==1) { m.add(Utilities.createDelegateAction("Include File With Project", _moveToAuxiliaryAction)); } else if (docSelectedCount>1) { m.add(Utilities.createDelegateAction("Include All Files With Project ("+docSelectedCount+")", _moveToAuxiliaryAction)); } } if (auxiliarySelected && !docSelected && !externalSelected) { // auxiliary document selected, but no regular or external documents if (m.getComponentCount()>0) { m.addSeparator(); } if (docSelectedCount==1) { m.add(Utilities.createDelegateAction("Do Not Include File With Project", _removeAuxiliaryAction)); } else if (docSelectedCount>1) { m.add(Utilities.createDelegateAction("Do Not Include Any Files With Project ("+docSelectedCount+")", _removeAuxiliaryAction)); } } if (!folderSelected && (externalBinSelected || auxiliaryBinSelected)) { // external or auxiliary bin selected, but no regular folder if (m.getComponentCount()>0) { m.addSeparator(); } m.add(Utilities.createDelegateAction("Close All Files", _closeFolderAction)); m.add(Utilities.createDelegateAction("Compile All Files", _compileFolderAction)); m.add(Utilities.createDelegateAction("Test All Files", _junitFolderAction)); } if (externalBinSelected && !auxiliaryBinSelected) { // external bin selected m.add(Utilities.createDelegateAction("Include All Files With Project", _moveAllToAuxiliaryAction)); } if (auxiliaryBinSelected && !externalBinSelected) { // auxiliary bin selected m.add(Utilities.createDelegateAction("Do Not Include Any Files With Project", _removeAllAuxiliaryAction)); } m.show(e.getComponent(), e.getX(), e.getY()); } } }); // _model.getDocCollectionWidget().addMouseListener(new RightClickMouseAdapter() { // protected void _popupAction(MouseEvent e) { // if (_model.getDocumentNavigator().selectDocumentAt(e.getX(), e.getY())) { // if (_model.getDocumentNavigator().isGroupSelected()) // _navPaneFolderPopupMenu.show(e.getComponent(), e.getX(), e.getY()); // // else { // try { // String groupName = _model.getDocumentNavigator().getNameOfSelectedTopLevelGroup(); // if (groupName.equals(_model.getSourceBinTitle())) // _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); // else if (groupName.equals(_model.getExternalBinTitle())) { // INavigatorItem n = _model.getDocumentNavigator().getCurrent(); // if (n != null) { // OpenDefinitionsDocument d = (OpenDefinitionsDocument) n; // if (d.isUntitled()) { _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); } // else _navPanePopupMenuForExternal.show(e.getComponent(), e.getX(), e.getY()); // } // } // else if (groupName.equals(_model.getAuxiliaryBinTitle())) // _navPanePopupMenuForAuxiliary.show(e.getComponent(), e.getX(), e.getY()); // } // catch(GroupNotSelectedException ex) { // // we're looking at the root of the tree, or we're in list view... // if (_model.isProjectActive()) // _navPanePopupMenuForRoot.show(e.getComponent(), e.getX(), e.getY()); // else _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); // } // } // } // } // }); // Interactions pane menu _interactionsPanePopupMenu = new JPopupMenu(); _interactionsPanePopupMenu.add(cutAction); _interactionsPanePopupMenu.add(copyAction); _interactionsPanePopupMenu.add(pasteAction); _interactionsPanePopupMenu.addSeparator(); _interactionsPanePopupMenu.add(_printInteractionsAction); _interactionsPanePopupMenu.add(_printInteractionsPreviewAction); _interactionsPanePopupMenu.addSeparator(); _interactionsPanePopupMenu.add(_executeHistoryAction); _interactionsPanePopupMenu.add(_loadHistoryScriptAction); _interactionsPanePopupMenu.add(_saveHistoryAction); _interactionsPanePopupMenu.add(_clearHistoryAction); _interactionsPanePopupMenu.addSeparator(); _interactionsPanePopupMenu.add(_resetInteractionsAction); _interactionsPanePopupMenu.add(_viewInteractionsClassPathAction); _interactionsPanePopupMenu.add(_copyInteractionToDefinitionsAction); _interactionsPane.addMouseListener(new RightClickMouseAdapter() { protected void _popupAction(MouseEvent e) { _interactionsPane.requestFocusInWindow(); _interactionsPanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); } }); // // This listener updates the _cachedCaretPosition in the _interactionsController when the cursor is manually set. // _interactionsPane.addMouseListener(new MouseInputAdapter() { // public void mouseClicked(MouseEvent e) { // _interactionsController.setCachedCaretPos(_interactionsPane.viewToModel(e.getPoint())); // } // }); _consolePanePopupMenu = new JPopupMenu(); _consolePanePopupMenu.add(_clearConsoleAction); _consolePanePopupMenu.addSeparator(); _consolePanePopupMenu.add(_printConsoleAction); _consolePanePopupMenu.add(_printConsolePreviewAction); _consolePane.addMouseListener(new RightClickMouseAdapter() { protected void _popupAction(MouseEvent e) { _consolePane.requestFocusInWindow(); _consolePanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); } }); } private void nextRecentDoc() { // Utilities.show("BACK_QUOTE typed"); if (_recentDocFrame.isVisible()) _recentDocFrame.next(); else _recentDocFrame.setVisible(true); } private void prevRecentDoc() { // Utilities.show("BACK_QUOTE typed"); if (_recentDocFrame.isVisible()) _recentDocFrame.prev(); else _recentDocFrame.setVisible(true); } private void hideRecentDocFrame() { if (_recentDocFrame.isVisible()) { _recentDocFrame.setVisible(false); OpenDefinitionsDocument doc = _recentDocFrame.getDocument(); if (doc != null) { // addToBrowserHistory(); _model.setActiveDocument(doc); // addToBrowserHistory(); } } } private volatile Object _updateLock = new Object(); private Component _lastUpdatedComponent = null; private boolean _tabUpdatePending = false; public static long UPDATE_DELAY = 3000L; // update delay threshold in milliseconds /** Updates the tabbed panel in a granular fashion to avoid swamping the event thread. The update is always performed * if the selected component has changed since the last call or _tabUpdatePending is false. */ public void updateTabbedPane() { final JComponent c = (JComponent) _tabbedPane.getSelectedComponent(); synchronized(_updateLock) { if (c == null || (_tabUpdatePending && c == _lastUpdatedComponent)) return; } _tabUpdatePending = true; Thread updater = new Thread(new Runnable() { public void run() { synchronized(_updateLock) { try { _updateLock.wait(UPDATE_DELAY); } catch(InterruptedException e) { /* fall through */ } } EventQueue.invokeLater(new Runnable() { public void run() { synchronized(_updateLock) { _tabUpdatePending = false; _lastUpdatedComponent = c; } // System.err.println("Repainting " + c); c.revalidate(); c.repaint(); } }); } }); updater.start(); } private static boolean isDisplayed(TabbedPanel p) { return p != null && p.isDisplayed(); } /** Create new DefinitionsPane and JScrollPane for an open definitions document. Package private for testing purposes. * @param doc The open definitions document to wrap * @return JScrollPane containing a DefinitionsPane for the given document. */ JScrollPane _createDefScrollPane(OpenDefinitionsDocument doc) { DefinitionsPane pane = new DefinitionsPane(this, doc); pane.addKeyListener(_historyListener); pane.addFocusListener(_focusListenerForRecentDocs); // Add listeners _installNewDocumentListener(doc); ErrorCaretListener caretListener = new ErrorCaretListener(doc, pane, this); pane.addErrorCaretListener(caretListener); // Limiting line numbers to just lines existing in the document. doc.addDocumentListener(new DocumentUIListener() { private void updateUI() { if (isDisplayed(_breakpointsPanel)) { _breakpointsPanel.repaint(); } if (isDisplayed(_bookmarksPanel)) { _bookmarksPanel.repaint(); } updateTabbedPane(); _lastChangeTime = System.currentTimeMillis(); // TODO: what about changes to file names? } public void changedUpdate(DocumentEvent e) { /* updateUI(); */ } // signifcant changes are inserts and removes public void insertUpdate(DocumentEvent e) { updateUI(); } public void removeUpdate(DocumentEvent e) { updateUI(); } }); // add a listener to update line and column. pane.addCaretListener(_posListener); // add a focus listener to this definitions pane. pane.addFocusListener(new LastFocusListener()); // Add to a scroll pane final JScrollPane scroll = new BorderlessScrollPane(pane, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); pane.setScrollPane(scroll); //scroll.setBorder(null); // removes all default borders (MacOS X installs default borders) if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) { scroll.setRowHeaderView(new LineEnumRule(pane)); } _defScrollPanes.put(doc, scroll); return scroll; } private void _setUpPanes() { // DefinitionsPane // JScrollPane defScroll = _defScrollPanes.get(_model.getActiveDocument()); // Try to create debug panel (see if JSwat is around) if (_showDebugger) { try { // Set the panel's size. int debugHeight = DrJava.getConfig().getSetting(DEBUG_PANEL_HEIGHT).intValue(); Dimension debugMinSize = _debugPanel.getMinimumSize(); // TODO: check bounds compared to entire window. if ((debugHeight > debugMinSize.height)) debugMinSize.height = debugHeight; _debugPanel.setPreferredSize(debugMinSize); } catch(NoClassDefFoundError e) { // Don't use the debugger _showDebugger = false; } } _debugSplitPane.setBottomComponent(_debugPanel); _mainSplit.setResizeWeight(1.0); _debugSplitPane.setResizeWeight(1.0); getContentPane().add(_mainSplit, BorderLayout.CENTER); // This is annoyingly order-dependent. Since split contains _docSplitPane, // we need to get split's divider set up first to give _docSplitPane an // overall size. Then we can set _docSplitPane's divider. Ahh, Swing. // Also, according to the Swing docs, we need to set these dividers AFTER // we have shown the window. How annoying. // int tabHeight = DrJava.getConfig().getSetting(TABS_HEIGHT).intValue(); // 2*getHeight()/3 _mainSplit.setDividerLocation(_mainSplit.getHeight() - 132); // _mainSplit.setDividerLocation(_mainSplit.getHeight() - tabHeight); _mainSplit.setOneTouchExpandable(true); _debugSplitPane.setOneTouchExpandable(true); int docListWidth = DrJava.getConfig().getSetting(DOC_LIST_WIDTH).intValue(); // TODO: Check bounds. _docSplitPane.setDividerLocation(docListWidth); _docSplitPane.setOneTouchExpandable(true); } /** Switch to the JScrollPane containing the DefinitionsPane for the active document. Must run in event thread.*/ void _switchDefScrollPane() { // demoted to package private protection to test the disabling editing while compiling functionality. // and to support brute force fix to DefinitionsPane bug on return from compile with errors // Added 2004-May-27 // Notify the definitions pane that is being replaced (becoming inactive) _currentDefPane.notifyInactive(); // Utilities.showDebug("_switchDefScrollPane called"); // Utilities.showDebug("Right before getting the scrollPane"); OpenDefinitionsDocument activeDoc = _model.getActiveDocument(); _currentDefDoc = activeDoc.getDocument(); JScrollPane scroll = _defScrollPanes.get(activeDoc); if (scroll == null) scroll = _createDefScrollPane(activeDoc); // Fix OS X scrollbar bug before switching _reenableScrollBar(); int oldLocation = _docSplitPane.getDividerLocation(); _docSplitPane.setRightComponent(scroll); //crazy line _docSplitPane.setDividerLocation(oldLocation); // if the current def pane is uneditable, that means we arrived here from a compile with errors. We're // guaranteed to make it editable again when we return from the compilation, so we take the state // with us. We guarantee only one definitions pane is un-editable at any time. if (_currentDefPane.isEditable()) { _currentDefPane = (DefinitionsPane) scroll.getViewport().getView(); _currentDefPane.notifyActive(); } else { try { _currentDefPane.setEditable(true); } catch(NoSuchDocumentException e) { /* It's OK */ } _currentDefPane = (DefinitionsPane) scroll.getViewport().getView(); _currentDefPane.notifyActive(); _currentDefPane.setEditable(false); } // reset the undo/redo menu items resetUndo(); _updateDebugStatus(); } /** Refresh the JScrollPane containing the DefinitionsPane for the active document. Must run in event thread.*/ private void _refreshDefScrollPane() { // Added 2004-May-27 // Notify the definitions pane that is being replaced (becoming inactive) _currentDefPane.notifyInactive(); // Utilities.showDebug("_switchDefScrollPane called"); // Utilities.showDebug("Right before getting the scrollPane"); OpenDefinitionsDocument doc = _model.getActiveDocument(); JScrollPane scroll = _defScrollPanes.get(doc); // if (scroll == null) scroll = _createDefScrollPane(doc); // Fix OS X scrollbar bug before switching _reenableScrollBar(); int oldLocation = _docSplitPane.getDividerLocation(); _docSplitPane.setRightComponent(scroll); //crazy line _docSplitPane.setDividerLocation(oldLocation); // // if the current def pane is uneditable, that means we arrived here from a compile with errors. We're // // guaranteed to make it editable again when we return from the compilation, so we take the state // // with us. We guarantee only one definitions pane is un-editable at any time. // if (_currentDefPane.isEditable()) { // _currentDefPane = (DefinitionsPane) scroll.getViewport().getView(); _currentDefPane.notifyActive(); // } // else { // try { _currentDefPane.setEditable(true); } // catch(NoSuchDocumentException e) { /* It's OK */ } // // _currentDefPane = (DefinitionsPane) scroll.getViewport().getView(); // _currentDefPane.notifyActive(); // _currentDefPane.setEditable(false); // } // // reset the undo/redo menu items resetUndo(); _updateDebugStatus(); } /** Resets the undo/redo menu items */ public void resetUndo() { _undoAction.setDelegatee(_currentDefPane.getUndoAction()); _redoAction.setDelegatee(_currentDefPane.getRedoAction()); } public DefinitionsPane getDefPaneGivenODD(OpenDefinitionsDocument doc) { JScrollPane scroll = _defScrollPanes.get(doc); if (scroll == null) { if (_model.getOpenDefinitionsDocuments().contains(doc)) scroll = _createDefScrollPane(doc); else throw new UnexpectedException(new Exception("Attempted to get DefinitionsPane for a closed document")); } DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView(); return pane; } /** Addresses Mac OS X bug where the scrollbars are disabled in one document after opening another. */ private void _reenableScrollBar() { JScrollPane scroll = _defScrollPanes.get(_model.getActiveDocument()); if (scroll == null) throw new UnexpectedException(new Exception("Current definitions scroll pane not found.")); JScrollBar oldbar = scroll.getVerticalScrollBar(); JScrollBar newbar = scroll.createVerticalScrollBar(); newbar.setMinimum(oldbar.getMinimum()); newbar.setMaximum(oldbar.getMaximum()); newbar.setValue(oldbar.getValue()); newbar.setVisibleAmount(oldbar.getVisibleAmount()); newbar.setEnabled(true); newbar.revalidate(); scroll.setVerticalScrollBar(newbar); // This needs to be repeated for the horizontal scrollbar oldbar = scroll.getHorizontalScrollBar(); newbar = scroll.createHorizontalScrollBar(); newbar.setMinimum(oldbar.getMinimum()); newbar.setMaximum(oldbar.getMaximum()); newbar.setValue(oldbar.getValue()); newbar.setVisibleAmount(oldbar.getVisibleAmount()); newbar.setEnabled(true); newbar.revalidate(); scroll.setHorizontalScrollBar(newbar); scroll.revalidate(); } /** Returns a JRadioButtonMenuItem that looks like a JCheckBoxMenuItem. This is a workaround for a known * bug on OS X's version of Java. (See http://developer.apple.com/qa/qa2001/qa1154.html) * @param action Action for the menu item * @return JRadioButtonMenuItem with a checkbox icon */ private JMenuItem _newCheckBoxMenuItem(Action action) { String RADIO_ICON_KEY = "RadioButtonMenuItem.checkIcon"; String CHECK_ICON_KEY = "CheckBoxMenuItem.checkIcon"; // Store the default radio button icon to put back later Object radioIcon = UIManager.get(RADIO_ICON_KEY); // Replace radio button's checkIcon with that of JCheckBoxMenuItem // so that our menu item looks like a checkbox UIManager.put(RADIO_ICON_KEY, UIManager.get(CHECK_ICON_KEY)); JRadioButtonMenuItem pseudoCheckBox = new JRadioButtonMenuItem(action); // Put original radio button checkIcon back. UIManager.put(RADIO_ICON_KEY, radioIcon); return pseudoCheckBox; } /** Gets the absolute file, or if necessary, the canonical file. * @param f the file for which to get the full path * @return the file representing the full path to the given file */ private File _getFullFile(File f) throws IOException { if (PlatformFactory.ONLY.isWindowsPlatform() && ((f.getAbsolutePath().indexOf("..") != -1) || (f.getAbsolutePath().indexOf("./") != -1) || (f.getAbsolutePath().indexOf(".\\") != -1))) { return f.getCanonicalFile(); } return f.getAbsoluteFile(); } /** Sets the current directory to be that of the given file. */ private void _setCurrentDirectory(File file) { /* We want to use absolute paths whenever possible, since canonical paths resolve symbolic links and can be quite * long and unintuitive. However, Windows blows up if you set the current directory of a JFileChooser to an * absolute path with ".." in it. In that case, we'll use the canonical path for the file chooser. (Fix for * bug 707734) Extended this to fix "./" and ".\" also (bug 774896) */ try { file = _getFullFile(file); _openChooser.setCurrentDirectory(file); _saveChooser.setCurrentDirectory(file); DrJava.getConfig().setSetting(LAST_DIRECTORY, file); } catch (IOException ioe) { // If getCanonicalFile throws an IOException, we can't set the directory of the file chooser. Oh well. } } /** Sets the current directory to be that of document's file. */ private void _setCurrentDirectory(OpenDefinitionsDocument doc) { try { File file = doc.getFile(); if (file != null) _setCurrentDirectory(file); // if no file, leave in current directory } catch (FileMovedException fme) { // file was deleted, but try to go the directory _setCurrentDirectory(fme.getFile()); } } /** Sets the font of all panes and panels to the main font. */ private void _setMainFont() { Font f = DrJava.getConfig().getSetting(FONT_MAIN); for (JScrollPane scroll: _defScrollPanes.values()) { if (scroll != null) { DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView(); pane.setFont(f); // Update the font of the line enumeration rule if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) { scroll.setRowHeaderView( new LineEnumRule(pane) ); } } } // Update Interactions Pane _interactionsPane.setFont(f); _interactionsController.setDefaultFont(f); // Update Console Pane _consolePane.setFont(f); _consoleController.setDefaultFont(f); _findReplace.setFieldFont(f); _compilerErrorPanel.setListFont(f); _junitErrorPanel.setListFont(f); _javadocErrorPanel.setListFont(f); } /** Updates the text color for the doc list. */ private void _updateNormalColor() { // Get the new value. Color norm = DrJava.getConfig().getSetting(DEFINITIONS_NORMAL_COLOR); // Change the text (foreground) color for the doc list. _model.getDocCollectionWidget().setForeground(norm); // We also need to immediately repaint the foremost scroll pane. _repaintLineNums(); } /** Updates the background color for the doc list. */ private void _updateBackgroundColor() { // Get the new value. Color back = DrJava.getConfig().getSetting(DEFINITIONS_BACKGROUND_COLOR); // Change the background color for the doc list. _model.getDocCollectionWidget().setBackground(back); // We also need to immediately repaint the foremost scroll pane. _repaintLineNums(); } /** Updates the font and colors of the line number display. */ private void _updateLineNums() { if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) { // Update the font for all line number displays for (JScrollPane spane: _defScrollPanes.values()) { LineEnumRule ler = (LineEnumRule) spane.getRowHeader().getView(); ler.updateFont(); ler.revalidate(); } // We also need to immediately repaint the foremost scroll pane. _repaintLineNums(); } } /** Repaints the line numbers on the active scroll pane. */ private void _repaintLineNums() { JScrollPane front = _defScrollPanes.get(_model.getActiveDocument()); if (front != null) { JViewport rhvport = front.getRowHeader(); if (rhvport != null) { Component view = rhvport.getView(); if (view != null) view.repaint(); } } } // /** Revalidate the line numers, i.e. also redraw the ones not currently visible. */ // public void revalidateLineNums() { // if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) { // JScrollPane sp = _defScrollPanes.get(_model.getActiveDocument()); // if (sp!=null) { // LineEnumRule ler = (LineEnumRule)sp.getRowHeader().getView(); // ler.revalidate(); // _repaintLineNums(); // } // } // } /** Update the row header (line number enumeration) for the definitions scroll pane. */ private void _updateDefScrollRowHeader() { boolean ruleEnabled = DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue(); for (JScrollPane scroll: _defScrollPanes.values()) { if (scroll != null) { DefinitionsPane pane = (DefinitionsPane) scroll.getViewport().getView(); if (scroll.getRowHeader() == null || scroll.getRowHeader().getView() == null) { if (ruleEnabled) scroll.setRowHeaderView(new LineEnumRule(pane)); } else if (! ruleEnabled) scroll.setRowHeaderView(null); } } } /** Removes the current highlight. */ public void removeCurrentLocationHighlight() { if (_currentLocationHighlight != null) { _currentLocationHighlight.remove(); _currentLocationHighlight = null; } } /** Disable any step timer. */ private void _disableStepTimer() { synchronized(_debugStepTimer) { if (_debugStepTimer.isRunning()) _debugStepTimer.stop(); } } /** Checks if debugPanel's status bar displays the DEBUGGER_OUT_OF_SYNC message but the current document is * in sync. Clears the debugPanel's status bar in this case. Does not assume that frame is in debug mode. * Must be executed in event thread. */ private void _updateDebugStatus() { if (! isDebuggerReady()) return; // if the document is untitled, don't show that it is out of sync since it can't be debugged anyway if (_model.getActiveDocument().isUntitled() || _model.getActiveDocument().getClassFileInSync()) { // Hide message if (_debugPanel.getStatusText().equals(DEBUGGER_OUT_OF_SYNC)) _debugPanel.setStatusText(""); } else { // Show message if (_debugPanel.getStatusText().equals("")) { _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC); } } _debugPanel.repaint(); // display the updated panel } /** Ensures that the interactions pane is not editable during an interaction. */ protected void _disableInteractionsPane() { assert EventQueue.isDispatchThread(); _interactionsPane.setEditable(false); _interactionsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); if (_interactionsScriptController != null) _interactionsScriptController.setActionsDisabled(); } /** Ensures that the interactions pane is editable after an interaction completes. */ protected void _enableInteractionsPane() { _interactionsPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); _interactionsPane.setEditable(true); _interactionsController.moveToEnd(); if (_interactionsPane.hasFocus()) _interactionsPane.getCaret().setVisible(true); if (_interactionsScriptController != null) _interactionsScriptController.setActionsEnabled(); } /** Comment current selection using wing commenting. public for testing purposes only. Runs in event thread. */ public void commentLines() { // Delegate everything to the DefinitionsDocument. OpenDefinitionsDocument openDoc = _model.getActiveDocument(); int caretPos = _currentDefPane.getCaretPosition(); openDoc.setCurrentLocation(caretPos); int start = _currentDefPane.getSelectionStart(); int end = _currentDefPane.getSelectionEnd(); // _currentDefPane.endCompoundEdit(); // _currentDefPane.notifyInactive(); int newEnd = openDoc.commentLines(start, end); // _currentDefPane.notifyActive(); _currentDefPane.setCaretPosition(start+2); if (start != end) _currentDefPane.moveCaretPosition(newEnd); } /** Uncomment current selection using wing commenting. Public for testing purposes only. Runs in event thread. */ public void uncommentLines() { // Delegate everything to the DefinitionsDocument. OpenDefinitionsDocument openDoc = _model.getActiveDocument(); int caretPos = _currentDefPane.getCaretPosition(); openDoc.setCurrentLocation(caretPos); int start = _currentDefPane.getSelectionStart(); int end = _currentDefPane.getSelectionEnd(); _currentDefPane.endCompoundEdit(); //notify inactive to prevent refreshing of the DefPane every time an insertion is made // _currentDefPane.notifyInactive(); openDoc.setCurrentLocation(start); Position startPos; try { startPos = openDoc.createUnwrappedPosition(start); } catch (BadLocationException e) { throw new UnexpectedException(e); } int startOffset = startPos.getOffset(); final int newEnd = openDoc.uncommentLines(start, end); // _currentDefPane.notifyActive(); if (startOffset != startPos.getOffset()) start -= 2; final int f_start = start; final boolean moveSelection = start != end; // Utilities.invokeAndWait(new Runnable() { // public void run() { _currentDefPane.setCaretPosition(f_start); if (moveSelection) _currentDefPane.moveCaretPosition(newEnd); // } // }); } /** Blocks access to DrJava while the hourglass cursor is on. */ private static class GlassPane extends JComponent { /** Creates a new GlassPane over the DrJava window. */ public GlassPane() { addKeyListener(new KeyAdapter() { }); addMouseListener(new MouseAdapter() { }); super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } } /** Called when a specific document and offset should be displayed. Must be executed only in the event thread. * @param doc Document to display * @param offset Offset to display * @param shouldHighlight true iff the line should be highlighted. */ public void scrollToDocumentAndOffset(final OpenDefinitionsDocument doc, final int offset, final boolean shouldHighlight) { scrollToDocumentAndOffset(doc, offset, shouldHighlight, true); } public void goToRegionAndHighlight(final IDocumentRegion r) { addToBrowserHistory(); OpenDefinitionsDocument doc = r.getDocument(); boolean toSameDoc = doc == _model.getActiveDocument(); Runnable command = new Runnable() { public void run() { int startOffset = r.getStartOffset(); int endOffset = r.getEndOffset(); _currentLocationHighlight = _currentDefPane.getHighlightManager(). addHighlight(startOffset, endOffset, DefinitionsPane.THREAD_PAINTER); _currentDefPane.centerViewOnOffset(startOffset); _currentDefPane.select(startOffset, endOffset); _currentDefPane.requestFocusInWindow(); } }; if (! toSameDoc) { _model.setActiveDocument(doc); // queues event actions _findReplace.updateFirstDocInSearch(); EventQueue.invokeLater(command); // postpone running command until queued event actions complete. } else { _model.refreshActiveDocument(); command.run(); } } /** Called when a specific document and offset should be displayed. Must be executed only in the event thread. * @param doc Document to display * @param offset Offset to display * @param shouldHighlight true iff the line should be highlighted. * @param shouldAddToHistory true if the location before and after the switch should be added to the browser history */ public void scrollToDocumentAndOffset(final OpenDefinitionsDocument doc, final int offset, final boolean shouldHighlight, final boolean shouldAddToHistory) { assert duringInit() || EventQueue.isDispatchThread(); if (shouldAddToHistory) addToBrowserHistory(); final boolean toSameDoc = _model.getActiveDocument().equals(doc); Runnable command = new Runnable() { public void run() { // get the line number after the switch of documents was made int lineNumber = doc.getLineOfOffset(offset) + 1; // this block occurs if the documents is already open and as such has a positive size if (_currentDefPane.getSize().getWidth() > 0 && _currentDefPane.getSize().getHeight() > 0) { EventQueue.invokeLater(new Runnable() { public void run() { if (! toSameDoc) Utilities.clearEventQueue(); // pause to let async aspects of active document switch complete _currentDefPane.centerViewOnOffset(offset); _currentDefPane.requestFocusInWindow(); } }); } if (shouldHighlight) { removeCurrentLocationHighlight(); int startOffset = doc._getOffset(lineNumber); // Much faster to directly search back from offset! if (startOffset > -1) { int endOffset = doc._getLineEndPos(startOffset); if (endOffset > -1) { _currentLocationHighlight = _currentDefPane.getHighlightManager(). addHighlight(startOffset, endOffset, DefinitionsPane.THREAD_PAINTER); } } } if (_showDebugger) { // Give the interactions pane focus so we can debug _interactionsPane.requestFocusInWindow(); // System.err.println("Showing Interactions Tab" ); // showTab(_interactionsContainer); // Note: disabled to avoid switching to interactions when browsing findall results _updateDebugStatus(); } } }; if (! toSameDoc) { _model.setActiveDocument(doc); // queues event actions _findReplace.updateFirstDocInSearch(); EventQueue.invokeLater(command); // postpone running command until queued event actions complete. } else { _model.refreshActiveDocument(); command.run(); } } /** Listens to events from the debugger. */ private class UIDebugListener implements DebugListener { /* Must be executed in evevt thread.*/ public void debuggerStarted() { showDebugger(); } /* Must be executed in evevt thread.*/ public void debuggerShutdown() { _disableStepTimer(); hideDebugger(); removeCurrentLocationHighlight(); } /** Called when a step is requested on the current thread. Must be executed in event thread. */ public void stepRequested() { // Print a message if step takes a long time synchronized(_debugStepTimer) { if (! _debugStepTimer.isRunning()) _debugStepTimer.start(); } } public void currThreadSuspended() { assert EventQueue.isDispatchThread(); _disableStepTimer(); _setThreadDependentDebugMenuItems(true); } /* Must be executed in the event thread. */ public void currThreadResumed() { _setThreadDependentDebugMenuItems(false); removeCurrentLocationHighlight(); } /** Called when the given line is reached by the current thread in the debugger, to request that the line be * displayed. Must be executed only in the event thread. * @param doc Document to display * @param lineNumber Line to display or highlight * @param shouldHighlight true iff the line should be highlighted. */ public void threadLocationUpdated(OpenDefinitionsDocument doc, int lineNumber, boolean shouldHighlight) { scrollToDocumentAndOffset(doc, doc._getOffset(lineNumber), shouldHighlight); } /* Must be executed in event thread. */ public void currThreadDied() { assert EventQueue.isDispatchThread(); _disableStepTimer(); if (isDebuggerReady()) { try { if (!_model.getDebugger().hasSuspendedThreads()) { // no more suspended threads, resume default debugger state // all thread dependent debug menu items are disabled _setThreadDependentDebugMenuItems(false); removeCurrentLocationHighlight(); // Make sure we're at the prompt // (This should really be fixed in InteractionsController, not here.) _interactionsController.moveToPrompt(); // there are no suspended threads, bring back prompt } } catch (DebugException de) { _showError(de, "Debugger Error", "Error with a thread in the debugger."); } } } public void currThreadSet(DebugThreadData dtd) { } public void regionAdded(final Breakpoint bp) { } public void breakpointReached(Breakpoint bp) { showTab(_interactionsContainer, true); } public void regionChanged(Breakpoint bp) { } public void regionRemoved(final Breakpoint bp) { } public void watchSet(final DebugWatchData w) { } public void watchRemoved(final DebugWatchData w) { } public void threadStarted() { } public void nonCurrThreadDied() { } } /** @author jlugo */ private class DJAsyncTaskLauncher extends AsyncTaskLauncher { protected boolean shouldSetEnabled() { return true; } protected void setParentContainerEnabled(boolean enabled) { if (enabled) hourglassOff(); else hourglassOn(); } protected IAsyncProgress createProgressMonitor(final String description, final int min, final int max) { return new IAsyncProgress() { private ProgressMonitor _monitor = new ProgressMonitor(MainFrame.this, description, "", min, max); public void close() { _monitor.close(); } public int getMaximum() { return _monitor.getMaximum() ; } public int getMillisToDecideToPopup() { return _monitor.getMillisToDecideToPopup(); } public int getMillisToPopup() { return _monitor.getMillisToPopup(); } public int getMinimum() { return _monitor.getMinimum(); } public String getNote() { return _monitor.getNote(); } public boolean isCanceled() { return _monitor.isCanceled(); } public void setMaximum(int m) { _monitor.setMaximum(m); } public void setMinimum(int m) { _monitor.setMinimum(m); } public void setNote(String note) { _monitor.setNote(note); } public void setProgress(int nv) { _monitor.setProgress(nv); } }; } } /** Ask the user to increase the slave's max heap setting. */ void askToIncreaseSlaveMaxHeap() { String value = "set to "+DrJava.getConfig().getSetting(SLAVE_JVM_XMX)+" MB"; if ((!("".equals(DrJava.getConfig().getSetting(SLAVE_JVM_XMX)))) && ((OptionConstants.heapSizeChoices.get(0).equals(DrJava.getConfig().getSetting(SLAVE_JVM_XMX))))) { value = "not set, implying the system's default"; } String res = (String)JOptionPane. showInputDialog(MainFrame.this, "Your program ran out of memory. You may try to enter a larger\n" + "maximum heap size for the Interactions JVM. The maximum heap size is\n" + "currently "+value+".\n"+ "A restart is required after changing this setting.", "Increase Maximum Heap Size?", JOptionPane.QUESTION_MESSAGE, null, OptionConstants.heapSizeChoices.toArray(), DrJava.getConfig().getSetting(SLAVE_JVM_XMX)); if (res != null) { // temporarily make MainFrame the parent of the dialog that pops up DrJava.getConfig().removeOptionListener(SLAVE_JVM_XMX, _slaveJvmXmxListener); final ConfigOptionListeners.SlaveJVMXMXListener l = new ConfigOptionListeners.SlaveJVMXMXListener(MainFrame.this); DrJava.getConfig().addOptionListener(SLAVE_JVM_XMX, l); // change the setting DrJava.getConfig().setSetting(SLAVE_JVM_XMX,res.trim()); EventQueue.invokeLater(new Runnable() { public void run() { // reinstall ConfigFrame as parent DrJava.getConfig().removeOptionListener(SLAVE_JVM_XMX, l); DrJava.getConfig().addOptionListener(SLAVE_JVM_XMX, _slaveJvmXmxListener); } }); } _model.getInteractionsModel().resetLastErrors(); } /** Ask the user to increase the master's max heap setting. */ void askToIncreaseMasterMaxHeap() { String value = "set to "+DrJava.getConfig().getSetting(MASTER_JVM_XMX)+" MB"; if ((!("".equals(DrJava.getConfig().getSetting(MASTER_JVM_XMX)))) && ((OptionConstants.heapSizeChoices.get(0).equals(DrJava.getConfig().getSetting(MASTER_JVM_XMX))))) { value = "not set, implying the system's default"; } String res = (String)JOptionPane.showInputDialog(MainFrame.this, "DrJava ran out of memory. You may try to enter a larger\n"+ "maximum heap size for the main JVM. The maximum heap size is\n"+ "currently "+value+".\n"+ "A restart is required after changing this setting.", "Increase Maximum Heap Size?", JOptionPane.QUESTION_MESSAGE, null, OptionConstants.heapSizeChoices.toArray(), DrJava.getConfig().getSetting(MASTER_JVM_XMX)); if (res!=null) { // temporarily make MainFrame the parent of the dialog that pops up DrJava.getConfig().removeOptionListener(MASTER_JVM_XMX, _masterJvmXmxListener); final ConfigOptionListeners.MasterJVMXMXListener l = new ConfigOptionListeners.MasterJVMXMXListener(MainFrame.this); DrJava.getConfig().addOptionListener(MASTER_JVM_XMX, l); // change the setting DrJava.getConfig().setSetting(MASTER_JVM_XMX,res.trim()); EventQueue.invokeLater(new Runnable() { public void run() { // reinstall ConfigFrame as parent DrJava.getConfig().removeOptionListener(MASTER_JVM_XMX, l); DrJava.getConfig().addOptionListener(MASTER_JVM_XMX, _masterJvmXmxListener); } }); } _model.getInteractionsModel().resetLastErrors(); } /** Inner class to listen to all events in the model. */ private class ModelListener implements GlobalModelListener { public <P,R> void executeAsyncTask(AsyncTask<P,R> task, P param, boolean showProgress, boolean lockUI) { new DJAsyncTaskLauncher().executeTask(task, param, showProgress, lockUI); } public void handleAlreadyOpenDocument(OpenDefinitionsDocument doc) { // boolean docChanged = !doc.equals(_model.getActiveDocument()); // if (docChanged) { addToBrowserHistory(); } // Always switch to doc _model.setActiveDocument(doc); // // defer executing this code until after active document switch (if any) is complete // EventQueue.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } }); // Prompt to revert if modified if (doc.isModifiedSinceSave()) { String title = "Revert to Saved?"; String message = doc.getFileName() + " is already open and modified.\n" + "Would you like to revert to the version on disk?\n"; int choice = JOptionPane.showConfirmDialog(MainFrame.this, message, title, JOptionPane.YES_NO_OPTION); if (choice == JOptionPane.YES_OPTION) { _revert(doc); } } } public void newFileCreated(final OpenDefinitionsDocument doc) { _createDefScrollPane(doc); PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); } private volatile int _fnfCount = 0; private boolean resetFNFCount() { return _fnfCount == 0; } private boolean someFilesNotFound() { PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); return _fnfCount > 0; } public void filesNotFound(File... files) { if (files.length == 0) return; _fnfCount += files.length; if (files.length == 1) { JOptionPane.showMessageDialog(MainFrame.this, "The following file could not be found and has been removed from the project.\n" + files[0].getPath(), "File Not Found", JOptionPane.ERROR_MESSAGE); } else { final java.util.List<String> filePaths = new ArrayList<String>(); for (File f : files) { filePaths.add(f.getPath()); } ScrollableListDialog<String> dialog = new ScrollableListDialog.Builder<String>() .setOwner(MainFrame.this) .setTitle("Files Not Found") .setText("The following files could not be found and have been removed from the project.") .setItems(filePaths) .setMessageType(JOptionPane.ERROR_MESSAGE) .build(); setPopupLoc(dialog); dialog.showDialog(); PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); } } public File[] filesReadOnly(File... files) { if (files.length == 0) return new File[0]; _fnfCount += files.length; final ArrayList<String> choices = new java.util.ArrayList<String>(); choices.add("Yes"); choices.add("No"); final java.util.List<String> filePaths = new ArrayList<String>(); for (File f : files) { filePaths.add(f.getPath()); } ScrollableListDialog<String> dialog = new ScrollableListDialog.Builder<String>() .setOwner(MainFrame.this) .setTitle("Files are Read-Only") .setText("The following files could not be saved because they are read-only.\n"+ "Do you want to overwrite them anyway?") .setItems(filePaths) .setSelectedItems(filePaths) .setMessageType(JOptionPane.QUESTION_MESSAGE) .clearButtons() .addButton(new JButton("Yes")) .addButton(new JButton("No")) .setSelectable(true) .build(); boolean overwrite = false; if (files.length == 1) { int res = JOptionPane.showConfirmDialog(MainFrame.this, "The following file could not be saved because it is read-only.\n" + "Do you want to overwrite it anyway?\n" + files[0].getPath(), "File is Read-Only", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); overwrite = (res == 0); } else { setPopupLoc(dialog); dialog.showDialog(); overwrite = (dialog.getButtonPressed() == 0); } if (overwrite) { if (files.length == 1) return files; else { File[] overwriteFiles = new File[dialog.getSelectedItems().size()]; int i = 0; for(String s: dialog.getSelectedItems()) { overwriteFiles[i++] = new File(s); } return overwriteFiles; } } else return new File[0]; } public void fileSaved(final OpenDefinitionsDocument doc) { doc.documentSaved(); // used to update the document cache _saveAction.setEnabled(false); _renameAction.setEnabled(true); _revertAction.setEnabled(true); updateStatusField(); _currentDefPane.requestFocusInWindow(); PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); try { File f = doc.getFile(); if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f); } catch (FileMovedException fme) { File f = fme.getFile(); // Recover, show it in the list anyway if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f); } // Check class file sync status, in case file was renamed _updateDebugStatus(); } public void fileOpened(final OpenDefinitionsDocument doc) { _fileOpened(doc); PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); } private void _fileOpened(final OpenDefinitionsDocument doc) { try { File f = doc.getFile(); if (! _model.inProject(f)) { _recentFileManager.updateOpenFiles(f); PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); } } catch (FileMovedException fme) { File f = fme.getFile(); // Recover, show it in the list anyway if (! _model.inProject(f)) _recentFileManager.updateOpenFiles(f); } } public void fileClosed(final OpenDefinitionsDocument doc) { _fileClosed(doc); } /** Does the work of closing a file */ private void _fileClosed(OpenDefinitionsDocument doc) { // assert EventQueue.isDispatchThread(); _recentDocFrame.closeDocument(doc); _removeErrorListener(doc); JScrollPane jsp = _defScrollPanes.get(doc); if (jsp != null) { ((DefinitionsPane)jsp.getViewport().getView()).close(); _defScrollPanes.remove(doc); } PropertyMaps.TEMPLATE.getProperty("DrJava", "drjava.all.files").invalidate(); } public void fileReverted(OpenDefinitionsDocument doc) { updateStatusField(); _saveAction.setEnabled(false); _currentDefPane.resetUndo(); _currentDefPane.hasWarnedAboutModified(false); _currentDefPane.setPositionAndScroll(0); _updateDebugStatus(); } public void undoableEditHappened() { assert EventQueue.isDispatchThread(); _currentDefPane.getUndoAction().updateUndoState(); _currentDefPane.getRedoAction().updateRedoState(); } public void activeDocumentRefreshed(final OpenDefinitionsDocument active) { assert EventQueue.isDispatchThread(); // System.err.println("activeDocumentRefreshed"); _recentDocFrame.pokeDocument(active); _refreshDefScrollPane(); // Update error highlights int pos = _currentDefPane.getCaretPosition(); _currentDefPane.getErrorCaretListener().updateHighlight(pos); focusOnLastFocusOwner(); } public void activeDocumentChanged(final OpenDefinitionsDocument active) { assert EventQueue.isDispatchThread(); // Utilities.show("MainFrame Listener: ActiveDocument changed to " + active); // code that accesses the GUI must run in the event-dispatching thread. _recentDocFrame.pokeDocument(active); _switchDefScrollPane(); // Updates _currentDefPane boolean isModified = active.isModifiedSinceSave(); boolean canCompile = (! isModified && ! active.isUntitled()); boolean hasName = ! active.isUntitled(); _saveAction.setEnabled(! canCompile); _renameAction.setEnabled(hasName); _revertAction.setEnabled(hasName); // Update error highlights int pos = _currentDefPane.getCaretPosition(); _currentDefPane.getErrorCaretListener().updateHighlight(pos); // Update FileChoosers' directory _setCurrentDirectory(active); // Update title and position updateStatusField(); _posListener.updateLocation(); // update display (adding "*") in navigatgorPane if (isModified) _model.getDocumentNavigator().repaint(); try { active.revertIfModifiedOnDisk(); } catch (FileMovedException fme) { _showFileMovedError(fme); } catch (IOException e) { _showIOError(e); } // Change Find/Replace to the new defpane if (isDisplayed(_findReplace)) { _findReplace.stopListening(); _findReplace.beginListeningTo(_currentDefPane); //uninstallFindReplaceDialog(_findReplace); //installFindReplaceDialog(_findReplace); } // _lastFocusOwner = _currentDefPane; EventQueue.invokeLater(new Runnable() { public void run() { _lastFocusOwner = _currentDefPane; // System.err.println("Requesting focus on new active document"); _currentDefPane.requestFocusInWindow(); PropertyMaps.TEMPLATE.getProperty("DrJava","drjava.current.file").invalidate(); } }); } public void focusOnLastFocusOwner() { // System.err.println("focusOnLastFocusOwner() called; _lastFocusOwner = " + _lastFocusOwner); _lastFocusOwner.requestFocusInWindow(); } /** Moves focus in MainFrame to the definitions pane. */ public void focusOnDefinitionsPane() { _currentDefPane.requestFocusInWindow(); } public void interactionStarted() { _disableInteractionsPane(); _runAction.setEnabled(false); _runProjectAction.setEnabled(false); } public void interactionEnded() { assert EventQueue.isDispatchThread(); // overkill; this method is a listener invocation wrapped in invokeLater final InteractionsModel im = _model.getInteractionsModel(); final String lastError = im.getLastError(); final edu.rice.cs.drjava.config.FileConfiguration config = DrJava.getConfig(); if (config != null && config.getSetting(edu.rice.cs.drjava.config.OptionConstants.DIALOG_AUTOIMPORT_ENABLED)) { if (lastError != null) { // the interaction ended and there was an error // check that this error is different than the last one (second to last may be null): final String secondToLastError = im.getSecondToLastError(); if (secondToLastError != null || ! lastError.equals(secondToLastError)) { // this aborts the auto-importing if the same class comes up twice in a row if (lastError.startsWith("Static Error: Undefined class '") && lastError.endsWith("'")) { // it was an "undefined class" exception // show auto-import dialog String undefinedClassName = lastError.substring(lastError.indexOf('\'') + 1, lastError.lastIndexOf('\'')); _showAutoImportDialog(undefinedClassName); } else if (lastError.startsWith("java.lang.OutOfMemoryError")) { askToIncreaseSlaveMaxHeap(); } } } } else im.resetLastErrors(); // reset the last errors, so the dialog works again if it is re-enabled _enableInteractionsPane(); _runAction.setEnabled(true); _runProjectAction.setEnabled(_model.isProjectActive()); } public void interactionErrorOccurred(final int offset, final int length) { _interactionsPane.highlightError(offset, length); } /** Called when the active interpreter is changed. * @param inProgress Whether the new interpreter is currently in progress with an interaction (i.e., whether an * interactionEnded event will be fired) */ public void interpreterChanged(final boolean inProgress) { _runAction.setEnabled(! inProgress); _runProjectAction.setEnabled(! inProgress); if (inProgress) _disableInteractionsPane(); else _enableInteractionsPane(); } public void compileStarted() { assert EventQueue.isDispatchThread(); showTab(_compilerErrorPanel, true); _compilerErrorPanel.setCompilationInProgress(); _saveAction.setEnabled(false); } public void compileEnded(File workDir, final List<? extends File> excludedFiles) { assert EventQueue.isDispatchThread(); _compilerErrorPanel.reset(excludedFiles.toArray(new File[0])); if (isDebuggerReady()) { // _model.getActiveDocument().checkIfClassFileInSync(); _updateDebugStatus(); } if ((DrJava.getConfig().getSetting(DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue()) && (_model.getBuildDirectory() != null)) { _scanClassFiles(); } _model.refreshActiveDocument(); } /** Called if a compilation is aborted. */ public void compileAborted(Exception e) { /* Should probably display a simple popup */ } /** Called after the active compiler has been changed. */ public void activeCompilerChanged() { String linkVersion = DrJava.getConfig().getSetting(JAVADOC_API_REF_VERSION); if (linkVersion.equals(JAVADOC_AUTO_TEXT)) { // The Java API Javadoc version must match the compiler. Since compiler was changed, we rebuild the API list _javaAPIList = null; generateJavaAPIList(); } } public void prepareForRun(final OpenDefinitionsDocument doc) { // Only change GUI from event-dispatching AbstractDJDocument assert EventQueue.isDispatchThread(); // Switch to the interactions pane to show results. showTab(_interactionsContainer, true); _lastFocusOwner = _interactionsContainer; } /** Only runs in event thread. */ public void junitStarted() { assert EventQueue.isDispatchThread(); /* Note: hourglassOn() is done by various junit commands (other than junitClasses); hourglass must be off * for actual testing; the balancing simpleHourglassOff() is located here and in nonTestCase */ try { showTab(_junitErrorPanel, true); _junitErrorPanel.setJUnitInProgress(); // _junitAction.setEnabled(false); // _junitAllAction.setEnabled(false); } finally { // Utilities.show("Turning hourglassOff"); hourglassOff(); } } /** We are junit'ing a specific list of classes given their source files. */ public void junitClassesStarted() { assert EventQueue.isDispatchThread(); // Only change GUI from event-dispatching thread // new ScrollableDialog(null, "junitClassesStarted called in MainFrame", "", "").show(); showTab(_junitErrorPanel, true); _junitErrorPanel.setJUnitInProgress(); // _junitAction.setEnabled(false); // _junitAllAction.setEnabled(false); } //public void junitRunning() { } public void junitSuiteStarted(final int numTests) { assert EventQueue.isDispatchThread(); _junitErrorPanel.progressReset(numTests); } public void junitTestStarted(final String name) { assert EventQueue.isDispatchThread(); _junitErrorPanel.getErrorListPane().testStarted(name); /* this does nothing! */ } public void junitTestEnded(final String name, final boolean succeeded, final boolean causedError) { assert EventQueue.isDispatchThread(); // new ScrollableDialog(null, "junitTestEnded(" + name + ", " + succeeded + ", " + causedError + ")", "", ""). // show(); _junitErrorPanel.getErrorListPane().testEnded(name, succeeded, causedError); // this does nothing! _junitErrorPanel.progressStep(succeeded); _model.refreshActiveDocument(); } public void junitEnded() { assert EventQueue.isDispatchThread(); // new ScrollableDialog(null, "MainFrame.junitEnded() called", "", "").show(); _restoreJUnitActionsEnabled(); _junitErrorPanel.reset(); _model.refreshActiveDocument(); } /** Fire just before javadoc asynchronous thread is started. Only runs in the event thread. */ public void javadocStarted() { assert EventQueue.isDispatchThread(); hourglassOn(); showTab(_javadocErrorPanel, true); _javadocErrorPanel.setJavadocInProgress(); _javadocAllAction.setEnabled(false); _javadocCurrentAction.setEnabled(false); } public void javadocEnded(final boolean success, final File destDir, final boolean allDocs) { // Only change GUI from event-dispatching thread assert EventQueue.isDispatchThread(); try { showTab(_javadocErrorPanel, true); _javadocAllAction.setEnabled(true); _javadocCurrentAction.setEnabled(true); _javadocErrorPanel.reset(); _model.refreshActiveDocument(); } finally { hourglassOff(); } // Display the results. if (success) { String className; try { className = _model.getActiveDocument().getQualifiedClassName(); className = className.replace('.', File.separatorChar); } catch (ClassNameNotFoundException cnf) { // If there is no class name, pass the empty string as a flag. We don't want to blow up here. className = ""; } try { String fileName = (allDocs || className.equals("")) ? "index.html" : (className + ".html"); File index = new File(destDir, fileName); URL address = FileOps.toURL(index.getAbsoluteFile()); if (! PlatformFactory.ONLY.openURL(address)) { JavadocFrame _javadocFrame = new JavadocFrame(destDir, className, allDocs); _javadocFrame.setVisible(true); } } catch (MalformedURLException me) { throw new UnexpectedException(me); } catch (IllegalStateException ise) { // JavadocFrame couldn't find any output files! // Display a message. String msg = "Javadoc completed successfully, but did not produce any HTML files.\n" + "Please ensure that your access level in Preferences is appropriate."; JOptionPane.showMessageDialog(MainFrame.this, msg, "No output to display.", JOptionPane.INFORMATION_MESSAGE); } } } public void interpreterExited(final int status) { // Only show prompt if option is set and not in TEST_MODE if (DrJava.getConfig().getSetting(INTERACTIONS_EXIT_PROMPT).booleanValue() && ! Utilities.TEST_MODE && MainFrame.this.isVisible()) { // Synchronously pop up a dialog box concerning restarting the JVM. String msg = "The interactions window was terminated by a call " + "to System.exit(" + status + ").\n" + "The interactions window will now be restarted."; String title = "Interactions terminated by System.exit(" + status + ")"; ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, title, msg, "Do not show this message again", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION); if (dialog.show() == JOptionPane.OK_OPTION && dialog.getCheckBoxValue()) { DrJava.getConfig().setSetting(INTERACTIONS_EXIT_PROMPT, Boolean.FALSE); } } } public void interpreterResetFailed(Throwable t) { interpreterReady(FileOps.NULL_FILE); } public void interpreterResetting() { assert duringInit() || EventQueue.isDispatchThread(); _junitAction.setEnabled(false); _junitAllAction.setEnabled(false); _junitProjectAction.setEnabled(false); _runAction.setEnabled(false); _runProjectAction.setEnabled(false); _closeInteractionsScript(); _interactionsPane.setEditable(false); _interactionsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); if (_showDebugger) _toggleDebuggerAction.setEnabled(false); } public void interpreterReady(File wd) { assert duringInit() || EventQueue.isDispatchThread(); interactionEnded(); _runAction.setEnabled(true); _runProjectAction.setEnabled(_model.isProjectActive()); _junitAction.setEnabled(true); _junitAllAction.setEnabled(true); _junitProjectAction.setEnabled(_model.isProjectActive()); // This action should not be enabled until the slave JVM is used // _resetInteractionsAction.setEnabled(true); if (_showDebugger) _toggleDebuggerAction.setEnabled(true); /* This line was moved here from interpreterResetting because it was possible to get an InputBox in * InteractionsController between interpreterResetting and interpreterReady. Fixes bug #917054 * "Interactions Reset Bug". */ _interactionsController.interruptConsoleInput(); } public void slaveJVMUsed() { /* _resetInteractionsAction.setEnabled(true); */ } public void consoleReset() { } public void saveBeforeCompile() { assert EventQueue.isDispatchThread(); // The following event thread switch supports legacy test code that calls compile methods outside of the // event thread. The wait is necessary because compilation process cannot proceed until saving is complete. _saveAllBeforeProceeding ("To compile, you must first save ALL modified files.\n" + "Would you like to save and then compile?", ALWAYS_SAVE_BEFORE_COMPILE, "Always save before compiling"); } /** Compile all open source files if this option is configured or running as a unit test. Otherwise, pop up a * dialog to ask if all open source files should be compiled in order to test the program. */ public void compileBeforeJUnit(final CompilerListener testAfterCompile) { // System.err.println("in compileBeforeJUnit, TEST_MODE = " + Utilities.TEST_MODE); if (DrJava.getConfig().getSetting(ALWAYS_COMPILE_BEFORE_JUNIT).booleanValue() || Utilities.TEST_MODE) { // Compile all open source files _model.getCompilerModel().addListener(testAfterCompile); // listener removes itself _compileAll(); } else { // pop up a window to ask if all open files should be compiled before testing String title = "Must Compile All Source Files to Run Unit Tests"; String msg = "To unit test all documents, you must first compile all out of sync source files.\n" + "Would you like to compile all files and run the specified test?"; int rc = JOptionPane.showConfirmDialog(MainFrame.this, msg, title, JOptionPane.YES_NO_OPTION); switch (rc) { case JOptionPane.YES_OPTION: // compile all open source files and test _model.getCompilerModel().addListener(testAfterCompile); // listener removes itself _compileAll(); break; case JOptionPane.CLOSED_OPTION: case JOptionPane.NO_OPTION: // abort unit testing // _model.getJUnitModel().nonTestCase(true); // cleans up _junitInterrupted(new UnexpectedException("Unit testing cancelled by user")); break; default: throw new UnexpectedException("Invalid returnCode from showConfirmDialog: " + rc); } } } public void saveBeforeJavadoc() { _saveAllBeforeProceeding ("To run Javadoc, you must first save ALL modified files.\n" + "Would you like to save and then run Javadoc?", ALWAYS_SAVE_BEFORE_JAVADOC, "Always save before running Javadoc"); } /** Helper method shared by all "saveBeforeX" methods. In JUnit tests, YES option is automatically selected * @param message a prompt message to be displayed to the user * @param option the BooleanOption for the prompt dialog checkbox * @param checkMsg the description of the checkbox ("Always save before X") */ private void _saveAllBeforeProceeding(String message, BooleanOption option, String checkMsg) { // new ScrollableDialog(null, "saveBeforeProceeding called in MainFrame", "", "").show(); if (_model.hasModifiedDocuments()) { if (! DrJava.getConfig().getSetting(option).booleanValue() && ! Utilities.TEST_MODE) { ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, "Must Save All Files to Continue", message, checkMsg); int rc = dialog.show(); switch (rc) { case JOptionPane.YES_OPTION: _saveAll(); // Only remember checkbox if they say yes if (dialog.getCheckBoxValue()) DrJava.getConfig().setSetting(option, Boolean.TRUE); break; case JOptionPane.NO_OPTION: case JOptionPane.CANCEL_OPTION: case JOptionPane.CLOSED_OPTION: // do nothing break; default: throw new RuntimeException("Invalid rc from showConfirmDialog: " + rc); } } else _saveAll(); } } /** Saves the active document which is untitled. */ public void saveUntitled() { _saveAs(); } public void filePathContainsPound() { if (DrJava.getConfig().getSetting(WARN_PATH_CONTAINS_POUND).booleanValue()) { String msg = "Files whose paths contain the '#' symbol cannot be used in the\n" + "Interactions Pane due to a bug in Java's file to URL conversion.\n" + "It is suggested that you change the name of the directory\n" + "containing the '#' symbol."; String title = "Path Contains Pound Sign"; ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(MainFrame.this, title, msg, "Do not show this message again", JOptionPane.WARNING_MESSAGE, JOptionPane.DEFAULT_OPTION); if (dialog.show() == JOptionPane.OK_OPTION && dialog.getCheckBoxValue()) { DrJava.getConfig().setSetting(WARN_PATH_CONTAINS_POUND, Boolean.FALSE); } } } /** Event that is fired with there is nothing to test. JUnit is never started. */ public void nonTestCase(boolean isTestAll) { assert EventQueue.isDispatchThread(); // Utilities.showStackTrace(new UnexpectedException("We should not have called nonTestCase")); final String message = isTestAll ? "There are no compiled JUnit TestCases available for execution.\n" + "Perhaps you have not yet compiled your test files." : "The current document is not a valid JUnit test case.\n" + "Please make sure that:\n" + "- it has been compiled and\n" + "- it is a subclass of junit.framework.TestCase.\n"; JOptionPane.showMessageDialog(MainFrame.this, message, "Test Only Executes JUnit test cases", JOptionPane.ERROR_MESSAGE); DrJavaErrorHandler.record(new UnexpectedException("NonTestCase should not be called!")); // clean up as in JUnitEnded try { showTab(_junitErrorPanel, true); _resetJUnit(); } finally { hourglassOff(); _restoreJUnitActionsEnabled(); } } /** Event that is fired when testing encounters an illegal class file. JUnit is never started. */ public void classFileError(ClassFileError e) { assert EventQueue.isDispatchThread(); final String message = "The class file for class " + e.getClassName() + " in source file " + e.getCanonicalPath() + " cannot be loaded.\n " + "When DrJava tries to load it, the following error is generated:\n" + e.getError(); JOptionPane.showMessageDialog(MainFrame.this, message, "Testing works only on valid class files", JOptionPane.ERROR_MESSAGE); // clean up as junitEnded except hourglassOff (should factored into a private method) showTab(_junitErrorPanel, true); _junitAction.setEnabled(true); _junitAllAction.setEnabled(true); _junitProjectAction.setEnabled(_model.isProjectActive()); _junitErrorPanel.reset(); } /** Only callable from within the event-handling thread */ public void currentDirectoryChanged(final File dir) { _setCurrentDirectory(dir); } /** Check if the specified document has been modified. If it has, ask the user if he would like to save it * and save the document if yes. Also give the user a "cancel" option to cancel doing the operation * that got us here in the first place. * * @return A boolean indicating whether the user cancelled the save process. False means cancel. */ public boolean canAbandonFile(OpenDefinitionsDocument doc) { return _fileSaveHelper(doc, JOptionPane.YES_NO_CANCEL_OPTION); } private boolean _fileSaveHelper(OpenDefinitionsDocument doc, int paneOption) { String text,fname; OpenDefinitionsDocument lastActive = _model.getActiveDocument(); if (lastActive != doc) _model.setActiveDocument(doc); boolean notFound = false; try { File file = doc.getFile(); if (file == null) { fname = "Untitled file"; text = "Untitled file has been modified. Would you like to save it?"; } else { fname = file.getName(); text = fname + " has been modified. Would you like to save it?"; } } catch (FileMovedException fme) { // File was deleted, but use the same name anyway fname = fme.getFile().getName(); text = fname + " not found on disk. Would you like to save to another file?"; notFound = true; } int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "Save " + fname + "?", paneOption); switch (rc) { case JOptionPane.YES_OPTION: boolean saved = false; if (notFound) saved = _saveAs(); else saved = _save(); if (doc != lastActive) { _model.setActiveDocument(lastActive); // breaks when "if" clause omitted } return saved; case JOptionPane.NO_OPTION: if (doc != lastActive) { _model.setActiveDocument(lastActive); // breaks when "if" clause omitted } return true; case JOptionPane.CLOSED_OPTION: case JOptionPane.CANCEL_OPTION: return false; default: // never executed throw new RuntimeException("Invalid option: " + rc); } } /** Check if the current document has been modified. If it has, ask the user if he would like to save it * and save the document if yes. * @return true if quitting should continue, false if the user cancelled */ public boolean quitFile(OpenDefinitionsDocument doc) { return _fileSaveHelper(doc, JOptionPane.YES_NO_CANCEL_OPTION); } /** Called to ask the listener if it is OK to revert the current document to a newer version saved on file. */ public boolean shouldRevertFile(OpenDefinitionsDocument doc) { String fname; if (! _model.getActiveDocument().equals(doc)) { _model.setActiveDocument(doc); } try { File file = doc.getFile(); if (file == null) fname = "Untitled file"; else fname = file.getName(); } catch (FileMovedException fme) { fname = fme.getFile().getName(); } // File was deleted, but use same name anyway String text = fname + " has changed on disk. Would you like to reload it?\n" + "This will discard any changes you have made."; int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, fname + " Modified on Disk", JOptionPane.YES_NO_OPTION); switch (rc) { case JOptionPane.YES_OPTION: return true; case JOptionPane.NO_OPTION: return false; case JOptionPane.CLOSED_OPTION: case JOptionPane.CANCEL_OPTION: return false; default: throw new RuntimeException("Invalid rc: " + rc); } } public void interactionIncomplete() { } /* Changes to the state */ public void projectBuildDirChanged() { if (_model.getBuildDirectory() != null) { _cleanAction.setEnabled(true); } else _cleanAction.setEnabled(false); } public void projectWorkDirChanged() { } public void projectModified() { // _saveProjectAction.setEnabled(_model.isProjectChanged()); } public void projectClosed() { _model.getDocumentNavigator().asContainer().addKeyListener(_historyListener); _model.getDocumentNavigator().asContainer().addFocusListener(_focusListenerForRecentDocs); _model.getDocumentNavigator().asContainer().addMouseListener(_resetFindReplaceListener); // new ScrollableDialog(null, "Closing JUnit Error Panel in MainFrame", "", "").show(); removeTab(_junitErrorPanel); _runButton = _updateToolbarButton(_runButton, _runAction); _compileButton = _updateToolbarButton(_compileButton, _compileAllAction); _junitButton = _updateToolbarButton(_junitButton, _junitAllAction); projectRunnableChanged(); } /* Opens project from command line. */ public void openProject(File projectFile, FileOpenSelector files) { _setUpContextMenus(); projectRunnableChanged(); _setUpProjectButtons(projectFile); open(files); _openProjectUpdate(); } public void projectRunnableChanged() { if (_model.getMainClass() != null && _model.getMainClass().exists()) { _runProjectAction.setEnabled(_model.isProjectActive()); _runButton = _updateToolbarButton(_runButton, _runProjectAction); } else { _runProjectAction.setEnabled(false); _runButton = _updateToolbarButton(_runButton, _runAction); } } public void documentNotFound(OpenDefinitionsDocument d, File f) { _model.setProjectChanged(true); String text = "File " + f.getAbsolutePath() + "\ncould not be found on disk! It was probably moved\n" + "or deleted. Would you like to try to find it?"; int rc = JOptionPane.showConfirmDialog(MainFrame.this, text, "File Moved or Deleted", JOptionPane.YES_NO_OPTION); if (rc == JOptionPane.NO_OPTION) return; if (rc == JOptionPane.YES_OPTION) { try { File[] opened = _openSelector.getFiles(); d.setFile(opened[0]); } catch(OperationCanceledException oce) { // Interpret cancelled as "NO" } } // The following line was commented out because it breaks when a user want to close but not save a deleted file // else throw new DocumentClosedException(d,"Document in " + f + "closed unexpectedly"); // misnamed exception } public void browserChanged() { _configureBrowsing(); } } // End of ModelListener class public JViewport getDefViewport() { OpenDefinitionsDocument doc = _model.getActiveDocument(); // new ScrollableDialog(null, "Active Document is " + doc, "", "").show(); JScrollPane defScroll = _defScrollPanes.get(doc); return defScroll.getViewport(); } public void removeTab(final Component c) { if (_tabbedPane.getTabCount() > 1) { // if (_tabbedPane.getSelectedIndex() == _tabbedPane.getTabCount() - 1) // _tabbedPane.setSelectedIndex(_tabbedPane.getSelectedIndex() - 1); _tabbedPane.remove(c); ((TabbedPanel)c).setDisplayed(false); } _currentDefPane.requestFocusInWindow(); } /** Shows the bookmark panel in the tabbed pane. */ public void createBookmarks() { _createTab(_bookmarksPanel); } private void _createTab(TabbedPanel panel) { int numVisible = 0; for (TabbedPanel t: _tabs) { if (t == panel) { Icon icon = (panel instanceof FindResultsPanel) ? FIND_ICON : null; _tabbedPane.insertTab(panel.getName(), icon, panel, null, numVisible + 2); // interactions, console always shown panel.setVisible(true); panel.setDisplayed(true); panel.repaint(); break; } else if (isDisplayed(t)) numVisible++; } } public static final Icon FIND_ICON = getIcon("Find16.gif"); /** Shows the components passed in the appropriate place in the tabbedPane depending on the position of * the component in the _tabs list. Only runs in the event thread. * @param c the component to show in the tabbedPane * @param showDetachedWindow true if the "Detached Panes" window should be shown */ public void showTab(final Component c, boolean showDetachedWindow) { // TODO: put all of the _tabbedPane components in _tabs. eliminating special cases for interactions, console (which // are always displayed) assert EventQueue.isDispatchThread(); try { if (c instanceof TabbedPanel) _createTab((TabbedPanel) c); _tabbedPane.setSelectedComponent(c); c.requestFocusInWindow(); if (_mainSplit.getDividerLocation() > _mainSplit.getMaximumDividerLocation()) _mainSplit.resetToPreferredSizes(); } finally { if (showDetachedWindow && (_tabbedPanesFrame != null) && (_tabbedPanesFrame.isVisible())) { _tabbedPanesFrame.toFront(); } } } /** Warns the user that the current file is open and query them if they wish to save over the currently open file. */ private boolean _warnFileOpen(File f) { OpenDefinitionsDocument d = null; try { d = _model.getDocumentForFile(f); } catch(IOException ioe) { /* do nothing */ } Object[] options = {"Yes","No"}; if (d == null) return false; boolean dMod = d.isModifiedSinceSave(); String msg = "This file is already open in DrJava" + (dMod ? " and has been modified" : "") + ". Do you wish to overwrite it?"; int choice = JOptionPane.showOptionDialog(MainFrame.this, msg, "File Open Warning", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (choice == JOptionPane.YES_OPTION) return _model.closeFileWithoutPrompt(d); return false; } /** Confirms with the user that the file should be overwritten. * @return <code>true</code> iff the user accepts overwriting. */ private boolean _verifyOverwrite() { Object[] options = {"Yes","No"}; int n = JOptionPane.showOptionDialog(MainFrame.this, "This file already exists. Do you wish to overwrite the file?", "Confirm Overwrite", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); return (n == JOptionPane.YES_OPTION); } /* Resets the JUnit functions in main frame. */ private void _resetJUnit() { _junitAction.setEnabled(true); _junitAllAction.setEnabled(true); _junitProjectAction.setEnabled(_model.isProjectActive()); _junitErrorPanel.reset(); } /* Pops up a message and cleans up after unit testing has been interrupted. */ private void _junitInterrupted(final UnexpectedException e) { try { _showJUnitInterrupted(e); removeTab(_junitErrorPanel); _resetJUnit(); _model.refreshActiveDocument(); } finally { hourglassOff(); } } boolean isDebuggerReady() { return _showDebugger && _model.getDebugger().isReady(); } boolean isDebuggerEnabled() { return _showDebugger; } /** Return the find replace dialog. Package protected for use in tests. */ FindReplacePanel getFindReplaceDialog() { return _findReplace; } /** Builds the Hashtables in KeyBindingManager that record key-bindings and support live updating, conflict * resolution, and intelligent error messages (the ActionToNameMap). IMPORTANT: Don't use this mechanism to put * an action into the KeyBindingManager if the action is a menu item because menu actions are already included. * Putting in again will cause bug #803304 "Uncomment lines wont rebind". */ private void _setUpKeyBindingMaps() { final ActionMap actionMap = _currentDefPane.getActionMap(); final KeyBindingManager kbm = KeyBindingManager.ONLY; kbm.put(KEY_BACKWARD, actionMap.get(DefaultEditorKit.backwardAction), null, "Backward"); kbm.addShiftAction(KEY_BACKWARD, DefaultEditorKit.selectionBackwardAction); kbm.put(KEY_BEGIN_DOCUMENT, actionMap.get(DefaultEditorKit.beginAction), null, "Begin Document"); kbm.addShiftAction(KEY_BEGIN_DOCUMENT, DefaultEditorKit.selectionBeginAction); // kbm.put(KEY_BEGIN_LINE, actionMap.get(DefaultEditorKit.beginLineAction), null, "Begin Line"); kbm.put(KEY_BEGIN_LINE, _beginLineAction, null, "Begin Line"); // kbm.addShiftAction(KEY_BEGIN_LINE, DefaultEditorKit.selectionBeginLineAction); kbm.addShiftAction(KEY_BEGIN_LINE, _selectionBeginLineAction); kbm.put(KEY_PREVIOUS_WORD, actionMap.get(DefaultEditorKit.previousWordAction), null, "Previous Word"); kbm.addShiftAction(KEY_PREVIOUS_WORD, DefaultEditorKit.selectionPreviousWordAction); kbm.put(KEY_DOWN, actionMap.get(DefaultEditorKit.downAction), null, "Down"); kbm.addShiftAction(KEY_DOWN, DefaultEditorKit.selectionDownAction); kbm.put(KEY_END_DOCUMENT, actionMap.get(DefaultEditorKit.endAction), null, "End Document"); kbm.addShiftAction(KEY_END_DOCUMENT, DefaultEditorKit.selectionEndAction); kbm.put(KEY_END_LINE, actionMap.get(DefaultEditorKit.endLineAction), null, "End Line"); kbm.addShiftAction(KEY_END_LINE, DefaultEditorKit.selectionEndLineAction); kbm.put(KEY_NEXT_WORD, actionMap.get(DefaultEditorKit.nextWordAction), null, "Next Word"); kbm.addShiftAction(KEY_NEXT_WORD, DefaultEditorKit.selectionNextWordAction); kbm.put(KEY_FORWARD, actionMap.get(DefaultEditorKit.forwardAction), null, "Forward"); kbm.addShiftAction(KEY_FORWARD, DefaultEditorKit.selectionForwardAction); kbm.put(KEY_UP, actionMap.get(DefaultEditorKit.upAction), null, "Up"); kbm.addShiftAction(KEY_UP, DefaultEditorKit.selectionUpAction); // kbm.put(KEY_NEXT_RECENT_DOCUMENT, _nextRecentDocAction, null, "Next Recent Document"); // kbm.put(KEY_PREV_RECENT_DOCUMENT, _prevRecentDocAction, null, "Previous Recent Document"); // These last methods have no default selection methods kbm.put(KEY_PAGE_DOWN, actionMap.get(DefaultEditorKit.pageDownAction), null, "Page Down"); kbm.put(KEY_PAGE_UP, actionMap.get(DefaultEditorKit.pageUpAction), null, "Page Up"); kbm.put(KEY_CUT_LINE, _cutLineAction, null, "Cut Line"); kbm.put(KEY_CLEAR_LINE, _clearLineAction, null, "Clear Line"); kbm.put(KEY_SHIFT_DELETE_PREVIOUS, actionMap.get(DefaultEditorKit.deletePrevCharAction), null, "Delete Previous"); kbm.put(KEY_SHIFT_DELETE_NEXT, actionMap.get(DefaultEditorKit.deleteNextCharAction), null, "Delete Next"); } /** @param listener The ComponentListener to add to the open documents list * This method allows for testing of the dancing UI (See MainFrameTest.testDancingUI()). */ public void addComponentListenerToOpenDocumentsList(ComponentListener listener) { _docSplitPane.getLeftComponent().addComponentListener(listener); } /**For test purposes only. Returns the text in the status bar. Is used to test brace matching*/ public String getFileNameField() { return _statusField.getText(); } /**For test purposes only. Returns the edit menu*/ public JMenu getEditMenu() { return _editMenu; } /** The OptionListener for FONT_MAIN */ private class MainFontOptionListener implements OptionListener<Font> { public void optionChanged(OptionEvent<Font> oce) { _setMainFont(); } } /** The OptionListener for FONT_LINE_NUMBERS */ private class LineNumbersFontOptionListener implements OptionListener<Font> { public void optionChanged(OptionEvent<Font> oce) { _updateLineNums(); } } /** The OptionListener for FONT_DOCLIST */ private class DoclistFontOptionListener implements OptionListener<Font> { public void optionChanged(OptionEvent<Font> oce) { Font doclistFont = DrJava.getConfig().getSetting(FONT_DOCLIST); _model.getDocCollectionWidget().setFont(doclistFont); } } /** The OptionListener for FONT_TOOLBAR */ private class ToolbarFontOptionListener implements OptionListener<Font> { public void optionChanged(OptionEvent<Font> oce) { _updateToolbarButtons(); } } /** The OptionListener for DEFINITIONS_NORMAL_COLOR */ private class NormalColorOptionListener implements OptionListener<Color> { public void optionChanged(OptionEvent<Color> oce) { _updateNormalColor(); } } /** The OptionListener for DEFINITIONS_BACKGROUND_COLOR */ private class BackgroundColorOptionListener implements OptionListener<Color> { public void optionChanged(OptionEvent<Color> oce) { _updateBackgroundColor(); } } /** The OptionListener for TOOLBAR options */ private class ToolbarOptionListener implements OptionListener<Boolean> { public void optionChanged(OptionEvent<Boolean> oce) { _updateToolbarButtons(); } } /** The OptionListener for LINEENUM_ENABLED. */ private class LineEnumOptionListener implements OptionListener<Boolean> { public void optionChanged(OptionEvent<Boolean> oce) { _updateDefScrollRowHeader(); } } /** The OptionListener for QUIT_PROMPT. */ private class QuitPromptOptionListener implements OptionListener<Boolean> { public void optionChanged(OptionEvent<Boolean> oce) { _promptBeforeQuit = oce.value.booleanValue(); } } /** The OptionListener for RECENT_FILES_MAX_SIZE. */ private class RecentFilesOptionListener implements OptionListener<Integer> { public void optionChanged(OptionEvent<Integer> oce) { _recentFileManager.updateMax(oce.value.intValue()); _recentFileManager.numberItems(); _recentProjectManager.updateMax(oce.value.intValue()); _recentProjectManager.numberItems(); } } private class LastFocusListener extends FocusAdapter { public void focusGained(FocusEvent e) { _lastFocusOwner = e.getComponent(); // System.err.println("_lastFocusOwner = " + _lastFocusOwner); } }; /** Wrapper for setPopupLoc(Window, Component) that uses the window's owner as the owner to center the popup on. * @param popup the Popup window */ public void setPopupLoc(Window popup) { MainFrame.setPopupLoc(popup, (popup.getOwner() != null) ? popup.getOwner() : this); } /** Determines the location of the popup using a simple, uniform protocol. If the popup has an owner, the popup is * centered over the owner. If the popup has no owner(owner == null), the popup is centered over the first monitor. * In either case, the popup is moved and scaled if any part of it is not on the screen. This method should be * called for all popups to maintain uniformity in the DrJava UI. * @param popup the popup window * @param owner the parent component for the popup */ public static void setPopupLoc(Window popup, Component owner) { Rectangle frameRect = popup.getBounds(); Point ownerLoc = null; Dimension ownerSize = null; if (owner != null && owner.isVisible()) { ownerLoc = owner.getLocation(); ownerSize = owner.getSize(); } else { //for multi-monitor support //Question: do we want it to popup on the first monitor always? GraphicsDevice[] dev = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); Rectangle rec = dev[0].getDefaultConfiguration().getBounds(); ownerLoc = rec.getLocation(); ownerSize = rec.getSize(); } // center it on owner Point loc = new Point(ownerLoc.x + (ownerSize.width - frameRect.width) / 2, ownerLoc.y + (ownerSize.height - frameRect.height) / 2); frameRect.setLocation(loc); // now find the GraphicsConfiguration the popup is on GraphicsConfiguration gcBest = null; int gcBestArea = -1; GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gs = ge.getScreenDevices(); for (GraphicsDevice gd: gs) { GraphicsConfiguration gc = gd.getDefaultConfiguration(); Rectangle isect = frameRect.intersection(gc.getBounds()); int gcArea = isect.width*isect.height; if (gcArea > gcBestArea) { gcBest = gc; gcBestArea = gcArea; } } // make it fit on the screen Rectangle screenRect = gcBest.getBounds(); Dimension screenSize = screenRect.getSize(); Dimension frameSize = popup.getSize(); if (frameSize.height > screenSize.height) frameSize.height = screenSize.height; if (frameSize.width > screenSize.width) frameSize.width = screenSize.width; frameRect.setSize(frameSize); // center it on owner again loc = new Point(ownerLoc.x + (ownerSize.width - frameRect.width) / 2, ownerLoc.y + (ownerSize.height - frameRect.height) / 2); frameRect.setLocation(loc); // now fit it on the screen if (frameRect.x < screenRect.x) frameRect.x = screenRect.x; if (frameRect.x + frameRect.width > screenRect.x + screenRect.width) frameRect.x = screenRect.x + screenRect.width - frameRect.width; if (frameRect.y < screenRect.y) frameRect.y = screenRect.y; if (frameRect.y + frameRect.height > screenRect.y + screenRect.height) frameRect.y = screenRect.y + screenRect.height - frameRect.height; popup.setSize(frameRect.getSize()); popup.setLocation(frameRect.getLocation()); } /** Drag and drop target. */ DropTarget dropTarget = new DropTarget(this, this); /** Linux URI drag-and-drop data flavor. */ private static DataFlavor uriListFlavor; static { try { uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String"); } catch(ClassNotFoundException cnfe) { uriListFlavor = null; } } /** User dragged something into the component. */ public void dragEnter(DropTargetDragEvent dropTargetDragEvent) { dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); } public void dragExit(DropTargetEvent dropTargetEvent) {} public void dragOver(DropTargetDragEvent dropTargetDragEvent) {} public void dropActionChanged(DropTargetDragEvent dropTargetDragEvent){} /** User dropped something on the component. */ public /* synchronized */ void drop(DropTargetDropEvent dropTargetDropEvent) { assert EventQueue.isDispatchThread(); try { Transferable tr = dropTargetDropEvent.getTransferable(); if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor) || ((uriListFlavor!=null) && (tr.isDataFlavorSupported(uriListFlavor)))) { dropTargetDropEvent.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); java.util.List<File> fileList; if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { @SuppressWarnings("unchecked") java.util.List<File> data = (java.util.List<File>)tr.getTransferData(DataFlavor.javaFileListFlavor); fileList = data; } else { // work-around for Linux drag-and-drop; see Java bug 4899516 @SuppressWarnings("unchecked") String data = (String)tr.getTransferData(uriListFlavor); fileList = textURIListToFileList(data); } java.util.Iterator<File> iterator = fileList.iterator(); java.util.List<File> filteredFileList = new java.util.ArrayList<File>(); while (iterator.hasNext()) { File file = iterator.next(); if (file.isFile() && (file.getName().endsWith(".java") || file.getName().endsWith(".dj0") || file.getName().endsWith(".dj1") || file.getName().endsWith(".dj2") || file.getName().endsWith(".dj0") || file.getName().endsWith(".txt"))) { filteredFileList.add(file); } else if (file.isFile() && file.getName().endsWith(OptionConstants.EXTPROCESS_FILE_EXTENSION)) { openExtProcessFile(file); } } final File[] fileArray = filteredFileList.toArray(new File[filteredFileList.size()]); FileOpenSelector fs = new FileOpenSelector() { public File[] getFiles() { return fileArray; } }; open(fs); dropTargetDropEvent.getDropTargetContext().dropComplete(true); } else { dropTargetDropEvent.rejectDrop(); } } catch(IOException ioe) { ioe.printStackTrace(); dropTargetDropEvent.rejectDrop(); } catch (UnsupportedFlavorException ufe) { ufe.printStackTrace(); dropTargetDropEvent.rejectDrop(); } } /** Open stand-alone external process file. */ public static void openExtProcessFile(File file) { try { XMLConfig xc = new XMLConfig(file); ExecuteExternalDialog.addToMenu(xc.get("drjava/extprocess/name"), xc.get("drjava/extprocess/cmdline"), xc.get("drjava/extprocess/workdir"), ""); // We override the drjava/extprocess/enclosingfile and set it to the empty string "" // because this external process did not come from a *.djapp file that was a JAR file. } catch(XMLConfigException xce) { // this wasn't an XML file, try to treat it as a jar file openExtProcessJarFile(file); } } /** Open external process file in a jar file. */ public static void openExtProcessJarFile(File file) { try { JarFile jf = new JarFile(file); JarEntry je = jf.getJarEntry(EXTPROCESS_FILE_NAME_INSIDE_JAR); InputStream is = jf.getInputStream(je); XMLConfig xc = new XMLConfig(is); ExecuteExternalDialog.addToMenu(xc.get("drjava/extprocess/name"), xc.get("drjava/extprocess/cmdline"), xc.get("drjava/extprocess/workdir"), file.getAbsolutePath()); // We override the drjava/extprocess/enclosingfile and set it to the file specified // because this external process came from a *.djapp file that was a JAR file. is.close(); jf.close(); } catch(IOException ioe) { /* ignore drop */ } catch(XMLConfigException xce) { /* ignore drop */ } } /** Convert a string with URIs to a list of files. * @param data string with URIs * @return list of files */ private static java.util.List<File> textURIListToFileList(String data) { java.util.List<File> list = new java.util.ArrayList<File>(); java.util.StringTokenizer st = new java.util.StringTokenizer(data, "\r\n"); while(st.hasMoreTokens()) { String s = st.nextToken(); if (s.startsWith("#")) continue; // the line is a comment (as per the RFC 2483) try { java.net.URI uri = new java.net.URI(s); java.io.File file = new java.io.File(uri); list.add(file); } catch (java.net.URISyntaxException e) { /* malformed URI*/ } catch (IllegalArgumentException e) { /* the URI is not a valid 'file:' URI */ } } return list; } /** Reset the position of the "Open Javadoc" dialog. */ public void resetAutoImportDialogPosition() { initAutoImportDialog(); _autoImportDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_AUTOIMPORT_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_AUTOIMPORT_STATE, "default"); } } /** Initialize dialog if necessary. */ void initAutoImportDialog() { if (_autoImportDialog == null) { _autoImportPackageCheckbox = new JCheckBox("Import Package"); _autoImportPackageCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { _autoImportDialog.resetFocus(); } }); PlatformFactory.ONLY.setMnemonic(_autoImportPackageCheckbox,'p'); PredictiveInputFrame.InfoSupplier<JavaAPIListEntry> info = new PredictiveInputFrame.InfoSupplier<JavaAPIListEntry>() { public String value(JavaAPIListEntry entry) { // show full class name as information return entry.getFullString(); } }; PredictiveInputFrame.CloseAction<JavaAPIListEntry> okAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() { public String getName() { return "OK"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<JavaAPIListEntry> p) { String text; if (p.getItem() != null) { // if a class was selected... text = p.getItem().getFullString(); } else { // use the text that was entered text = p.getText(); } if (_autoImportPackageCheckbox.isSelected()) { int lastDot = text.lastIndexOf('.'); if (lastDot > 0) text = text.substring(0, lastDot + 1) + "*"; } final InteractionsModel im = _model.getInteractionsModel(); // Get the last line (the one that caused the error) and remove it from the history String lastLine = im.removeLastFromHistory(); // Import the selected class... String importLine = "import " + text + "; // auto-import"; // ... and try to do the last line again final String code = importLine + ((lastLine != null) ? ("\n" + lastLine) : ""); EventQueue.invokeLater(new Runnable() { public void run() { // interpret with the added import try { im.append(code, InteractionsDocument.DEFAULT_STYLE); im.interpretCurrentInteraction(); } finally { hourglassOff(); } } }); return null; } }; PredictiveInputFrame.CloseAction<JavaAPIListEntry> cancelAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() { public String getName() { return "Cancel"; } public KeyStroke getKeyStroke() { return KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); } public String getToolTipText() { return null; } public Object value(PredictiveInputFrame<JavaAPIListEntry> p) { // if no class was selected, just reset the error information so the dialog box works next time _model.getInteractionsModel().resetLastErrors(); hourglassOff(); return null; } }; java.util.ArrayList<MatchingStrategy<JavaAPIListEntry>> strategies = new java.util.ArrayList<MatchingStrategy<JavaAPIListEntry>>(); strategies.add(new FragmentStrategy<JavaAPIListEntry>()); strategies.add(new PrefixStrategy<JavaAPIListEntry>()); strategies.add(new RegExStrategy<JavaAPIListEntry>()); List<PredictiveInputFrame.CloseAction<JavaAPIListEntry>> actions = new ArrayList<PredictiveInputFrame.CloseAction<JavaAPIListEntry>>(); actions.add(okAction); actions.add(cancelAction); _autoImportDialog = new PredictiveInputFrame<JavaAPIListEntry>(MainFrame.this, "Auto Import Class", false, true, info, strategies, actions, 1, new JavaAPIListEntry("dummyImport", "dummyImport", null)) { public void setOwnerEnabled(boolean b) { if (b) hourglassOff(); else hourglassOn(); } protected JComponent[] makeOptions() { return new JComponent[] { _autoImportPackageCheckbox }; } }; // Put one dummy entry in the list; it will be changed later anyway if (DrJava.getConfig().getSetting(DIALOG_AUTOIMPORT_STORE_POSITION).booleanValue()) { _autoImportDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_AUTOIMPORT_STATE)); } generateJavaAPIList(); } } /** The "Auto Import" dialog instance. */ PredictiveInputFrame<JavaAPIListEntry> _autoImportDialog = null; JCheckBox _autoImportPackageCheckbox; /** Imports a class. */ void _showAutoImportDialog(String s) { generateJavaAPIList(); if (_javaAPIList == null) return; List<JavaAPIListEntry> autoImportList = new ArrayList<JavaAPIListEntry>(_javaAPIList); if (DrJava.getConfig().getSetting(DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue() && _autoImportClassList.size() > 0) { autoImportList.addAll(_autoImportClassList); } else { File projectRoot = _model.getProjectRoot(); List<OpenDefinitionsDocument> docs = _model.getOpenDefinitionsDocuments(); if (docs != null) { for (OpenDefinitionsDocument d: docs) { if (d.isUntitled()) continue; try { String rel = FileOps.stringMakeRelativeTo(d.getRawFile(), projectRoot); String full = rel.replace(java.io.File.separatorChar, '.'); for (String ext: edu.rice.cs.drjava.model.compiler.CompilerModel.EXTENSIONS) { if (full.endsWith(ext)) { full = full.substring(0, full.lastIndexOf(ext)); break; } } String simple = full; if (simple.lastIndexOf('.') >= 0) simple = simple.substring(simple.lastIndexOf('.') + 1); JavaAPIListEntry entry = new JavaAPIListEntry(simple, full, null); if (! autoImportList.contains(entry)) { autoImportList.add(entry); } } catch(IOException ioe) { /* ignore, just don't add this one */ } catch(SecurityException se) { /* ignore, just don't add this one */ } } } } PredictiveInputModel<JavaAPIListEntry> pim = new PredictiveInputModel<JavaAPIListEntry>(true, new PrefixStrategy<JavaAPIListEntry>(), autoImportList); pim.setMask(s); initAutoImportDialog(); _autoImportDialog.setModel(true, pim); // ignore case hourglassOn(); _autoImportPackageCheckbox.setSelected(false); _autoImportDialog.setVisible(true); } /** Follow a file. */ private final Action _followFileAction = new AbstractAction("Follow File...") { public void actionPerformed(ActionEvent ae) { _followFile(); } }; /** Open a file for following (like using "less" and F). Only runs in the event thread. */ private void _followFile() { updateStatusField("Opening File for Following"); try { final File[] files = _openAnyFileSelector.getFiles(); if (files == null) { return; } for (final File f: files) { if (f == null) continue; String end = f.getName(); int lastIndex = end.lastIndexOf(File.separatorChar); if (lastIndex >= 0) end = end.substring(lastIndex+1); final LessPanel panel = new LessPanel(this, "Follow: "+end, f); _tabs.addLast(panel); panel.getMainPanel().addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { _lastFocusOwner = panel; } }); panel.setVisible(true); showTab(panel, true); _tabbedPane.setSelectedComponent(panel); // Use EventQueue.invokeLater to ensure that focus is set AFTER the findResultsPanel has been selected EventQueue.invokeLater(new Runnable() { public void run() { panel.requestFocusInWindow(); } }); } } catch(OperationCanceledException oce) { /* ignore */ } } /** Execute an external process. */ private final Action _executeExternalProcessAction = new AbstractAction("New External Process...") { public void actionPerformed(ActionEvent ae) { _executeExternalProcess(); } }; /** Execute an external process and monitor its output. */ private void _executeExternalProcess() { _executeExternalDialog.setVisible(true); } /** The execute external dialog. */ private final ExecuteExternalDialog _executeExternalDialog; /** Initializes the "Execute External Process" dialog. */ private void initExecuteExternalProcessDialog() { if (DrJava.getConfig().getSetting(DIALOG_EXTERNALPROCESS_STORE_POSITION).booleanValue()) { _executeExternalDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_EXTERNALPROCESS_STATE)); } } /** Reset the position of the "Execute External Process" dialog. */ public void resetExecuteExternalProcessPosition() { _executeExternalDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_EXTERNALPROCESS_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_EXTERNALPROCESS_STATE, "default"); } } /** The edit external dialog. */ private final EditExternalDialog _editExternalDialog; /** Initializes the "Edit External Process" dialog. */ private void initEditExternalProcessDialog() { if (DrJava.getConfig().getSetting(DIALOG_EDITEXTERNALPROCESS_STORE_POSITION).booleanValue()) { _editExternalDialog.setFrameState(DrJava.getConfig().getSetting(DIALOG_EDITEXTERNALPROCESS_STATE)); } } /** Reset the position of the "Edit External Process" dialog. */ public void resetEditExternalProcessPosition() { _editExternalDialog.setFrameState("default"); if (DrJava.getConfig().getSetting(DIALOG_EDITEXTERNALPROCESS_STORE_POSITION).booleanValue()) { DrJava.getConfig().setSetting(DIALOG_EDITEXTERNALPROCESS_STATE, "default"); } } /** Action that edits saved processes. Only runs in the event thread. */ private final Action _editExternalProcessesAction = new AbstractAction("Edit...") { public void actionPerformed(ActionEvent ae) { _editExternalDialog.setVisible(true); } }; /** Return the modal window listener if available, otherwise returns a non-modal dummy listener. * Note that the WindowEvent passed to the toFrontAction runnable may not be the WindowEvent that * caused the window w to be pushed off the front, it may also be the WindowEvent that restores * w as front window after a modal dialog that trumped w was closed. * @param w window trying to get the modal window listener * @param toFrontAction action to be performed after the window has been moved to the front again * @param closeAction action to be performed when the window is closing * @return window listener */ public void installModalWindowAdapter(final Window w, final Runnable1<? super WindowEvent> toFrontAction, final Runnable1<? super WindowEvent> closeAction) { assert EventQueue.isDispatchThread(); if (_modalWindowAdapters.containsKey(w)) { // already installed return; } WindowAdapter wa; if (_modalWindowAdapterOwner == null) { // modal listener is available, claim it _modalWindowAdapterOwner = w; // create a window adapter performs the specified actions after delegating to the modal window adapter wa = new WindowAdapter() { final HashSet<Window> trumpedBy = new HashSet<Window>(); // set of windows that trumped this window in getting to the front final WindowAdapter regainFront = new WindowAdapter() { public void windowClosed(WindowEvent we) { // the window that trumped w was closed, so we're moving w back to the front w.toFront(); w.requestFocus(); toFrontAction.run(we); // then we remove the window that trumped w from the set of trump windows Window o = we.getOppositeWindow(); trumpedBy.remove(o); // and we remove this listener o.removeWindowListener(this); } }; public void toFront(WindowEvent we) { Window opposite = we.getOppositeWindow(); if (opposite instanceof Dialog) { Dialog d = (Dialog)opposite; if (d.isModal()) { // the other window is a real modal dialog, we'll leave it on top -- the window trumped this window if (!trumpedBy.contains(d)) { // add a listener to move this window back to the front when the opposite window has been closed d.addWindowListener(regainFront); // add trump window to set of windows that have trumped this window trumpedBy.add(d); } return; } } we.getWindow().toFront(); we.getWindow().requestFocus(); toFrontAction.run(we); } public void windowDeactivated(WindowEvent we) { toFront(we); } public void windowIconified(WindowEvent we) { toFront(we); } public void windowLostFocus(WindowEvent we) { toFront(we); } public void windowClosing(WindowEvent we) { closeAction.run(we); } }; } else { /* The modal listener is already owned by another window. The code block creates a window adapter that performs * closeActions but not toFrontActions because the latter could generate an endless loop with this window * competing with the modal listener window to stay on top. */ wa = new WindowAdapter() { public void windowDeactivated(WindowEvent we) { } public void windowIconified(WindowEvent we) { } public void windowLostFocus(WindowEvent we) { } public void windowClosing(WindowEvent we) { closeAction.run(we); } }; } // install it _modalWindowAdapters.put(w, wa); w.addWindowListener(wa); w.addWindowFocusListener(wa); } /** Removes the modal window adapter. * @param w window releasing the modal window adapter */ public /* synchronized */ void removeModalWindowAdapter(Window w) { assert EventQueue.isDispatchThread(); if (! _modalWindowAdapters.containsKey(w)) { // the specified window does not have a modal windowadapter return; } w.removeWindowListener(_modalWindowAdapters.get(w)); w.removeWindowFocusListener(_modalWindowAdapters.get(w)); _modalWindowAdapterOwner = null; _modalWindowAdapters.remove(w); } }

The table below shows all metrics for MainFrame.java.

MetricValueDescription
BLOCKS1553.00Number of blocks
BLOCK_COMMENT124.00Number of block comment lines
COMMENTS1784.00Comment lines
COMMENT_DENSITY 0.30Comment density
COMPARISONS723.00Number of comparison operators
CYCLOMATIC1677.00Cyclomatic complexity
DECL_COMMENTS549.00Comments in declarations
DOC_COMMENT650.00Number of javadoc comment lines
ELOC5866.00Effective lines of code
EXEC_COMMENTS795.00Comments in executable code
EXITS1144.00Procedure exits
FUNCTIONS777.00Number of function declarations
HALSTEAD_DIFFICULTY143.13Halstead difficulty
HALSTEAD_EFFORT 0.00Halstead effort
INTERFACE_COMPLEXITY1461.00Interface complexity
JAVA0001 0.00JAVA0001 Package name does not contain only lower case letters
JAVA0002 0.00JAVA0002 Package name does not begin with a top level domain name or country code
JAVA0003 0.00JAVA0003 Minimize use of on-demand (.*) imports
JAVA0004 0.00JAVA0004 Unnecessary import from java.lang
JAVA0005 1.00JAVA0005 Imports not in specified order
JAVA0006 1.00JAVA0006 Empty finally block
JAVA0007 2.00JAVA0007 Should not declare public field
JAVA0008 0.00JAVA0008 Empty catch block
JAVA0009 0.00JAVA0009 Protected member in final class
JAVA0010 0.00JAVA0010 Non-instantiable class does not contain a non-private static member
JAVA0011 0.00JAVA0011 Abstract class does not contain an abstract method
JAVA0012 0.00JAVA0012 Non-constructor method with same name as declaring class
JAVA0013 0.00JAVA0013 Non-blank final field is not static
JAVA0014 0.00JAVA0014 Class with only static members has non-private constructor
JAVA0015 0.00JAVA0015 Package class contains public nested type
JAVA0016 0.00JAVA0016 Abstract class contains public constructor
JAVA0017 0.00JAVA0017 Class name does not have required form
JAVA0018150.00JAVA0018 Method name does not have required form
JAVA0019 0.00JAVA0019 Interface name does not have required form
JAVA002077.00JAVA0020 Field name does not have required form
JAVA0021 0.00JAVA0021 Interface method name does not have required form
JAVA0022 5.00JAVA0022 Static final field name does not have required form
JAVA0023 0.00JAVA0023 Empty finalize method
JAVA0024 0.00JAVA0024 Empty class
JAVA0025 7.00JAVA0025 Method override is empty
JAVA0026 0.00JAVA0026 Finalize method with parameters
JAVA0029 2.00JAVA0029 Private method not used
JAVA0030 0.00JAVA0030 Private field not used
JAVA0031 2.00JAVA0031 Case statement not properly closed
JAVA0032 0.00JAVA0032 Switch statement missing default
JAVA0033 0.00JAVA0033 default: not last case in switch statement
JAVA0034229.00JAVA0034 Missing braces in if statement
JAVA0035 0.00JAVA0035 Missing braces in for statement
JAVA0036 0.00JAVA0036 Missing braces in while statement
JAVA0038 0.00JAVA0038 Non-case label in switch statement
JAVA0039 0.00JAVA0039 Break statement with label
JAVA0040 0.00JAVA0040 Switch statement contains N cases (maximum: M)
JAVA0041 0.00JAVA0041 Nested synchronized block
JAVA0042 0.00JAVA0042 Empty synchronized statement
JAVA0043 0.00JAVA0043 Inner class does not use outer class
JAVA0044 0.00JAVA0044 Serializable class with no instance variables
JAVA0045 0.00JAVA0045 Serializable class with only transient fields
JAVA0046 0.00JAVA0046 Name of class not derived from Exception ends with 'Exception'
JAVA0047 0.00JAVA0047 Serializable class derives from invalid base class
JAVA0048 0.00JAVA0048 Name of class derived from Exception does not end with 'Exception'
JAVA004933.00JAVA0049 Nested block at depth N (maximum: M)
JAVA0050 0.00JAVA0050 Class derives from java.lang.Error
JAVA0051 0.00JAVA0051 Class derives from java.lang.RuntimeException
JAVA0052 0.00JAVA0052 Class derives from java.lang.Throwable
JAVA0053 0.00JAVA0053 Unused label
JAVA0054 0.00JAVA0054 Inheritance depth N exceeds maximum M
JAVA0055 0.00JAVA0055 Class should be interface
JAVA0056 0.00JAVA0056 Unnecessary abstract modifier for interface or annotation
JAVA0057 0.00JAVA0057 Unnecessary default constructor
JAVA0058 0.00JAVA0058 Constructor calls super()
JAVA0059 0.00JAVA0059 Method override only calls super()
JAVA0061 3.00JAVA0061 Inaccessible member in anonymous class
JAVA0062 0.00JAVA0062 Public class missing public member or protected constructor
JAVA0063 0.00JAVA0063 Identifier name should not contain '$'
JAVA0064 0.00JAVA0064 N variations of identifier name (maximum: M)
JAVA0065 0.00JAVA0065 Unnecessary final modifier for method in final class
JAVA0066 0.00JAVA0066 Unnecessary modifier for interface nested type
JAVA0067 0.00JAVA0067 Array descriptor on identifier name
JAVA0068 3.00JAVA0068 Modifiers not declared in recommended order
JAVA0071 0.00JAVA0071 Strings compared with ==
JAVA0073 0.00JAVA0073 Integer division in floating-point context
JAVA0074 0.00JAVA0074 Use of Object.notify()
JAVA0075 0.00JAVA0075 Method parameter hides field
JAVA007610.00JAVA0076 Use of magic number
JAVA007710.00JAVA0077 Private field not used in declaring class
JAVA0078 0.00JAVA0078 Floating point values compared with ==
JAVA0079 0.00JAVA0079 Use of instance to reference static member
JAVA0080 7.00JAVA0080 Import declaration not used
JAVA0081 1.00JAVA0081 Boolean literal in comparison
JAVA0082 0.00JAVA0082 Unnecessary widening cast
JAVA0083 0.00JAVA0083 Unnecessary instanceof test
JAVA0084 0.00JAVA0084 Should use compound assignment operator
JAVA0085 0.00JAVA0085 Use of sun.* class
JAVA0087 0.00JAVA0087 Use of Thread.sleep()
JAVA0089 0.00JAVA0089 Use of restricted package
JAVA0092 0.00JAVA0092 Use of restricted type
JAVA0093 0.00JAVA0093 Redundant assignment
JAVA0094 0.00JAVA0094 Field hides a superclass field
JAVA0095 0.00JAVA0095 Uninitialized private field
JAVA0096 0.00JAVA0096 Field in nested class hides outer field
JAVA0098 1.00JAVA0098 Minimize use of implicit field initializers
JAVA0100 1.00JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0101 0.00JAVA0101 Unnecessary modifier for field in interface
JAVA0102 0.00JAVA0102 Last statement in finalize() not super.finalize()
JAVA0103 0.00JAVA0103 Explicit call to finalize()
JAVA0104 0.00JAVA0104 finalize() only calls super.finalize()
JAVA0105 0.00JAVA0105 Duplicate import declaration
JAVA0106 2.00JAVA0106 Unnecessary import from current package
JAVA010846.00JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
JAVA0109 3.00JAVA0109 Incorrect javadoc: no parameter 'parameter'
JAVA011034.00JAVA0110 Incorrect javadoc: no @return tag
JAVA0111 1.00JAVA0111 Incorrect javadoc: @return tag for void method
JAVA0112 0.00JAVA0112 Incorrect javadoc: no exception 'exception' in throws
JAVA0113 1.00JAVA0113 Incorrect javadoc: no @author tag
JAVA0114 1.00JAVA0114 Incorrect javadoc: no @version tag
JAVA0115 4.00JAVA0115 Incorrect javadoc: no @throws or @exception tag for 'exception'
JAVA0116 6.00JAVA0116 Missing javadoc: field 'field'
JAVA011725.00JAVA0117 Missing javadoc: method 'method'
JAVA0118 0.00JAVA0118 Missing javadoc: type 'type'
JAVA0119 0.00JAVA0119 Control variable changed within body of for loop
JAVA0123 0.00JAVA0123 Use all three components of for loop
JAVA0125 0.00JAVA0125 Continue statement with label
JAVA0126 0.00JAVA0126 Method declares unchecked exception in throws
JAVA0128 4.00JAVA0128 Public constructor in non-public class
JAVA0130 9.00JAVA0130 Non-static method does not use instance fields
JAVA0131 0.00JAVA0131 Compatible method does not override base
JAVA0132 0.00JAVA0132 Method overload with compatible signature
JAVA0133 0.00JAVA0133 Non-synchronized method overrides synchronized method
JAVA0135 0.00JAVA0135 Only one of Object.equals and Object.hashCode defined: missing 'method'
JAVA0136 2.00JAVA0136 N methods defined in class (maximum: M)
JAVA0137 1.00JAVA0137 Non-abstract class missing constructor
JAVA0138 1.00JAVA0138 N parameters defined for method (maximum: M)
JAVA0139 0.00JAVA0139 Definition of main other than public static void main(java.lang.String[])
JAVA0141 0.00JAVA0141 Unnecessary modifier for method in interface
JAVA0143 0.00JAVA0143 Synchronized method
JAVA0144 0.00JAVA0144 Line exceeds maximum M characters
JAVA0145 0.00JAVA0145 Tab character used in source file
JAVA0150 0.00JAVA0150 java.lang.Error (or subclass) thrown
JAVA0153 0.00JAVA0153 Inefficient conversion of integer to string
JAVA0159 0.00JAVA0159 Inefficient conversion of string to integer
JAVA0160 0.00JAVA0160 Method does not throw specified exception
JAVA0161 0.00JAVA0161 Conditional wait() not in loop
JAVA0163 0.00JAVA0163 Empty statement
JAVA0165 0.00JAVA0165 Conflicting return statement in finally block
JAVA016610.00JAVA0166 Generic exception caught
JAVA0167 0.00JAVA0167 ThreadDeath not rethrown
JAVA0169 0.00JAVA0169 Unnecessary catch block: exception 'exception'
JAVA0170 2.00JAVA0170 Caught exception not derived from java.lang.Exception
JAVA0171 9.00JAVA0171 Unused local variable
JAVA0173 9.00JAVA0173 Unused method parameter
JAVA0174 2.00JAVA0174 Assigned local variable never used
JAVA0175 2.00JAVA0175 Successive assignment to variable
JAVA0176 1.00JAVA0176 Local variable name does not have required form
JAVA017731.00JAVA0177 Variable declaration missing initializer
JAVA0179 0.00JAVA0179 Local variable hides visible field
JAVA0233 0.00JAVA0233 Definition of serialVersionUID other than 'private static final long serialVersionUID'
JAVA0234 4.00JAVA0234 Class is Serializable but does not define serialVersionUID
JAVA0235 0.00JAVA0235 Class defines serialVersionUID but does not implement Serializable
JAVA0236 0.00JAVA0236 Attempt to clone an object which does not implement Cloneable
JAVA0237 1.00JAVA0237 Class implements Cloneable but does not have public clone method
JAVA0238 0.00JAVA0238 Clone method does not call super.clone()
JAVA0239 0.00JAVA0239 Class declares 'readObject' or 'writeObject' but does not implement Serializable
JAVA0240 0.00JAVA0240 Serializable class which declares readObject or writeObject but not both
JAVA0241 0.00JAVA0241 'readObject' or 'writeObject' should be declared private in Serializable class
JAVA0242 0.00JAVA0242 Transient field in non-Serializable class
JAVA0243 0.00JAVA0243 'readResolve' or 'writeReplace' should be declared private or protected
JAVA0244 0.00JAVA0244 Field or method name in subclass differs only by case from inherited field or method
JAVA0245 0.00JAVA0245 JUnit TestCase with non-trivial constructor
JAVA0246 0.00JAVA0246 JUnit assertXXX statement missing message parameter
JAVA0247 0.00JAVA0247 JUnit 'setUp()' and 'tearDown()' should call super method
JAVA0248 0.00JAVA0248 JUnit method 'setUp' or 'tearDown' with incorrect signature
JAVA0249 0.00JAVA0249 JUnit TestCase 'suite()' should be declared static
JAVA0250 0.00JAVA0250 JUnit TestCase declares testXXX method with incorrect signature
JAVA0251 0.00JAVA0251 Use '%n' for line breaks in printf/format for platform independence
JAVA0252 0.00JAVA0252 'enum' is a Java 1.5 reserved word
JAVA0253 0.00JAVA0253 Not all enum constants consumed in switch statement
JAVA0254 1.00JAVA0254 Use enhanced for loop construct instead of Iterator
JAVA0255 0.00JAVA0255 Result of method invocation not used
JAVA0256 0.00JAVA0256 Assignment of external collection/array to field
JAVA0257 0.00JAVA0257 Use of 'Constant Interface' anti-pattern
JAVA0258 0.00JAVA0258 Implement Iterable for foreach compatibility
JAVA0259 0.00JAVA0259 Return of collection/array field
JAVA0260 0.00JAVA0260 Use 'enum' instead of Enumerated Type pattern
JAVA0261 0.00JAVA0261 Use specialized Enum collection types
JAVA0262 0.00JAVA0262 Use of char in integer context
JAVA0263 0.00JAVA0263 Long literal ends with 'l' instead of 'L'
JAVA0264 0.00JAVA0264 Integer math in long context - check for overflow
JAVA0265 3.00JAVA0265 Use of Throwable.printStackTrace()
JAVA0266 1.00JAVA0266 Use of System.out
JAVA0267 0.00JAVA0267 Use of System.err
JAVA0269 0.00JAVA0269 Contents of StringBuffer never used
JAVA0270 3.00JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
JAVA0271 1.00JAVA0271 Minimize use of on-demand (.*) static imports
JAVA0272 0.00JAVA0272 Thread.run() called
JAVA0273 0.00JAVA0273 Non-final derivative of Thread calls start() in constructor
JAVA0274 0.00JAVA0274 Serializable class has a synchronized readObject()
JAVA0275 0.00JAVA0275 Serializable class has a synchronized writeObject() and no other synchronized methods
JAVA0276 0.00JAVA0276 Unnecessary use of String constructor
JAVA0277 0.00JAVA0277 Iterator.next() implementation does not throw NoSuchElementException
JAVA0278 0.00JAVA0278 Unnecessary use of Boolean constructor
JAVA0279 0.00JAVA0279 Serialization method readObject or readObjectNoData calls an overridable method
JAVA0280 0.00JAVA0280 IllegalMonitorStateException caught
JAVA0281 0.00JAVA0281 Iterator.next() not called in loop
JAVA0282 0.00JAVA0282 Call to Iterator.next() in loop which does not test Iterator.hasNext()
JAVA0283 0.00JAVA0283 Control variable not updated in loop body
JAVA0284 0.00JAVA0284 Explicit garbage collection
JAVA0285 1.00JAVA0285 Dereference of potentially null variable
JAVA0286 0.00JAVA0286 Dereference of null variable
JAVA0287 2.00JAVA0287 Unnecessary null check
JAVA0288 0.00JAVA0288 Inconsistent null check
LINES9857.00Number of lines in the source file
LINE_COMMENT1010.00Number of line comments
LOC6966.00Lines of code
LOGICAL_LINES3922.00Number of statements
LOOPS24.00Number of loops
NEST_DEPTH 8.00Maximum nesting depth
OPERANDS17932.00Number of operands
OPERATORS35212.00Number of operators
PARAMS522.00Number of formal parameter declarations
PROGRAM_LENGTH53144.00Halstead program length
PROGRAM_VOCAB4964.00Halstead program vocabulary
PROGRAM_VOLUME 0.00Halstead program volume
RETURNS939.00Number of return points from functions
SIZE434952.00Size of the file in bytes
UNIQUE_OPERANDS4886.00Number of unique operands
UNIQUE_OPERATORS78.00Number of unique operators
WHITESPACE1107.00Number of whitespace lines