00001: /*BEGIN_COPYRIGHT_BLOCK
00002: *
00003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
00004: * All rights reserved.
00005: *
00006: * Redistribution and use in source and binary forms, with or without
00007: * modification, are permitted provided that the following conditions are met:
00008: * * Redistributions of source code must retain the above copyright
00009: * notice, this list of conditions and the following disclaimer.
00010: * * Redistributions in binary form must reproduce the above copyright
00011: * notice, this list of conditions and the following disclaimer in the
00012: * documentation and/or other materials provided with the distribution.
00013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
00014: * names of its contributors may be used to endorse or promote products
00015: * derived from this software without specific prior written permission.
00016: *
00017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028: *
00029: * This software is Open Source Initiative approved Open Source Software.
00030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
00031: *
00032: * This file is part of DrJava. Download the current version of this project
00033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
00034: *
00035: * END_COPYRIGHT_BLOCK*/
00036:
00037: package edu.rice.cs.drjava.ui;
00038:
00039: import javax.swing.*;
00040: import javax.swing.text.*;
00041: import javax.swing.event.*;
00042: import javax.swing.border.*;
00043: import java.awt.event.*;
00044: import java.awt.*;
00045: import java.awt.print.*;
00046: import java.awt.dnd.*;
00047: import java.beans.*;
00048:
00049: import java.io.*;
00050: import java.util.Collection;
00051: import java.util.Hashtable;
00052: import java.util.HashSet;
00053: import java.util.List;
00054: import java.util.LinkedList;
00055: import java.util.ArrayList;
00056: import java.util.Vector;
00057: import java.util.Enumeration;
00058: import java.net.URL;
00059: import java.net.MalformedURLException;
00060: import java.awt.datatransfer.*;
00061:
00062: import edu.rice.cs.drjava.DrJava;
00063: import edu.rice.cs.drjava.DrJavaRoot;
00064: import edu.rice.cs.drjava.platform.*;
00065: import edu.rice.cs.drjava.config.*;
00066: import edu.rice.cs.drjava.model.*;
00067: import edu.rice.cs.drjava.model.compiler.CompilerListener;
00068: import edu.rice.cs.drjava.model.definitions.NoSuchDocumentException;
00069: import edu.rice.cs.drjava.model.definitions.DocumentUIListener;
00070: import edu.rice.cs.drjava.model.definitions.CompoundUndoManager;
00071: import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException;
00072: import edu.rice.cs.drjava.model.definitions.InvalidPackageException;
00073: import edu.rice.cs.drjava.model.definitions.reducedmodel.*;
00074: import edu.rice.cs.drjava.model.debug.*;
00075: import edu.rice.cs.drjava.model.repl.*;
00076: import edu.rice.cs.drjava.model.javadoc.JavadocModel;
00077: import edu.rice.cs.drjava.ui.config.ConfigFrame;
00078: import edu.rice.cs.drjava.ui.predictive.PredictiveInputFrame;
00079: import edu.rice.cs.drjava.ui.predictive.PredictiveInputModel;
00080: import edu.rice.cs.drjava.ui.ClipboardHistoryFrame;
00081: import edu.rice.cs.drjava.model.ClipboardHistoryModel;
00082: import edu.rice.cs.drjava.model.FileSaveSelector;
00083: import edu.rice.cs.drjava.project.*;
00084:
00085: import edu.rice.cs.plt.tuple.Pair;
00086: import edu.rice.cs.plt.iter.IterUtil;
00087: import edu.rice.cs.plt.io.IOUtil;
00088: import edu.rice.cs.util.FileOpenSelector;
00089: import edu.rice.cs.util.FileOps;
00090: import edu.rice.cs.util.UnexpectedException;
00091: import edu.rice.cs.util.OperationCanceledException;
00092: import edu.rice.cs.util.classloader.ClassFileError;
00093: import edu.rice.cs.util.docnavigation.*;
00094: import edu.rice.cs.util.swing.AsyncTask;
00095: import edu.rice.cs.util.swing.AsyncTaskLauncher;
00096: import edu.rice.cs.util.swing.BorderlessScrollPane;
00097: import edu.rice.cs.util.swing.BorderlessSplitPane;
00098: import edu.rice.cs.util.swing.ConfirmCheckBoxDialog;
00099: import edu.rice.cs.util.swing.DelegatingAction;
00100: import edu.rice.cs.util.swing.DirectoryChooser;
00101: import edu.rice.cs.util.swing.FileDisplayManager;
00102: import edu.rice.cs.util.swing.HighlightManager;
00103: import edu.rice.cs.util.swing.RightClickMouseAdapter;
00104: import edu.rice.cs.util.swing.SwingWorker;
00105: import edu.rice.cs.util.swing.Utilities;
00106: import edu.rice.cs.util.swing.*;
00107: import edu.rice.cs.util.text.AbstractDocumentInterface;
00108:
00109: import static edu.rice.cs.drjava.config.OptionConstants.*;
00110: import edu.rice.cs.drjava.RemoteControlClient;
00111:
00112: /** DrJava's main window. */
00113: public class MainFrame extends JFrame implements ClipboardOwner,
00114: DropTargetListener {
00115:
00116: private static final int INTERACTIONS_TAB = 0;
00117: private static final int CONSOLE_TAB = 1;
00118: private static final String ICON_PATH = "/edu/rice/cs/drjava/ui/icons/";
00119: private static final String DEBUGGER_OUT_OF_SYNC = " Current document is out of sync with the debugger and should be recompiled!";
00120:
00121: /** Number of milliseconds to wait before displaying "Stepping..." message after a step is requested in
00122: * the debugger.
00123: */
00124: private static final int DEBUG_STEP_TIMER_VALUE = 2000;
00125:
00126: /** The model which controls all logic in DrJava. */
00127: private final SingleDisplayModel _model;
00128:
00129: /** The main model listener attached by the main frame to the global model */
00130: private final ModelListener _mainListener;
00131:
00132: /** Maps an OpenDefDoc to its JScrollPane. */
00133: private final Hashtable<OpenDefinitionsDocument, JScrollPane> _defScrollPanes;
00134:
00135: /** The currently displayed DefinitionsPane. */
00136: private volatile DefinitionsPane _currentDefPane;
00137:
00138: /** The filename currently being displayed. */
00139: private volatile String _fileTitle = "";
00140:
00141: // Tabbed panel fields
00142: public final LinkedList<TabbedPanel> _tabs = new LinkedList<TabbedPanel>();
00143:
00144: private final JTabbedPane _tabbedPane;
00145: private final CompilerErrorPanel _compilerErrorPanel;
00146: private final InteractionsPane _consolePane;
00147: private final JScrollPane _consoleScroll; // redirects focus to embedded _consolePane
00148: private final ConsoleController _consoleController; // move to controller
00149: private final InteractionsPane _interactionsPane;
00150: private final JPanel _interactionsContainer; // redirects focus to embedded _interactionsPane
00151: private final InteractionsController _interactionsController; // move to controller
00152: private final JUnitPanel _junitErrorPanel;
00153: private final JavadocErrorPanel _javadocErrorPanel;
00154: private final FindReplacePanel _findReplace;
00155: private final BreakpointsPanel _breakpointsPanel;
00156: private final BookmarksPanel _bookmarksPanel;
00157: private final LinkedList<Pair<FindResultsPanel, Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>>> _findResults = new LinkedList<Pair<FindResultsPanel, Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>>>();
00158:
00159: private volatile boolean _showDebugger; // whether the supporting context is debugger capable
00160:
00161: private volatile InteractionsScriptController _interactionsScriptController;
00162: private volatile InteractionsScriptPane _interactionsScriptPane;
00163: private volatile DebugPanel _debugPanel;
00164: private volatile Component _lastFocusOwner;
00165:
00166: /** Panel to hold both InteractionsPane and its sync message. */
00167:
00168: // Status bar fields
00169: private final JPanel _statusBar = new JPanel(new BorderLayout()); //( layout );
00170: private final JLabel _statusField = new JLabel();
00171: private final JLabel _statusReport = new JLabel(); //("This is the text for the center message");
00172: private final JLabel _currLocationField = new JLabel();
00173: private final PositionListener _posListener = new PositionListener();
00174:
00175: // Split panes for layout
00176: private final JSplitPane _docSplitPane;
00177: private final JSplitPane _debugSplitPane;
00178: private final JSplitPane _mainSplit;
00179:
00180: // private Container _docCollectionWidget;
00181: private volatile JButton _compileButton;
00182: private volatile JButton _closeButton;
00183: private volatile JButton _undoButton;
00184: private volatile JButton _redoButton;
00185: private volatile JButton _runButton;
00186: private volatile JButton _junitButton;
00187:
00188: private final JToolBar _toolBar;
00189: private final JFileChooser _interactionsHistoryChooser;
00190:
00191: // Menu fields
00192: private final JMenuBar _menuBar;
00193: private final JMenu _fileMenu;
00194: private final JMenu _editMenu;
00195: private final JMenu _toolsMenu;
00196: private final JMenu _projectMenu;
00197: private final JMenu _languageLevelMenu;
00198: private final JMenu _helpMenu;
00199:
00200: private volatile JMenu _debugMenu;
00201: private volatile JMenuItem _debuggerEnabledMenuItem;
00202:
00203: // Popup menus
00204: private JPopupMenu _interactionsPanePopupMenu;
00205: private JPopupMenu _consolePanePopupMenu;
00206:
00207: // Cached frames and dialogs
00208: private final ConfigFrame _configFrame;
00209: private final HelpFrame _helpFrame;
00210: private final QuickStartFrame _quickStartFrame;
00211: private final AboutDialog _aboutDialog;
00212: private final RecentDocFrame _recentDocFrame;
00213: /** Holds/shows the history of documents for ctrl-tab. */
00214:
00215: // private ProjectPropertiesFrame _projectPropertiesFrame;
00216: /** Keeps track of the recent files list in the File menu. */
00217: private final RecentFileManager _recentFileManager;
00218:
00219: /** Keeps track of the recent projects list in the Project menu */
00220: private final RecentFileManager _recentProjectManager;
00221:
00222: private volatile File _currentProjFile;
00223:
00224: /** Timer to display "Stepping..." message if a step takes longer than a certain amount of time. All accesses
00225: * must be synchronized on it.
00226: */
00227: private final Timer _debugStepTimer;
00228:
00229: /** The current highlight displaying the location of the debugger's thread,
00230: * if there is one. If there is none, this is null.
00231: */
00232: private volatile HighlightManager.HighlightInfo _currentThreadLocationHighlight = null;
00233:
00234: /** Table to map breakpoints to their corresponding highlight objects. */
00235: private final Hashtable<Breakpoint, HighlightManager.HighlightInfo> _documentBreakpointHighlights;
00236:
00237: /** Table to map bookmarks to their corresponding highlight objects. */
00238: private final Hashtable<DocumentRegion, HighlightManager.HighlightInfo> _documentBookmarkHighlights;
00239:
00240: /** Whether to display a prompt message before quitting. */
00241: private volatile boolean _promptBeforeQuit;
00242:
00243: /** For opening files. We have a persistent dialog to keep track of the last directory from which we opened. */
00244: private final JFileChooser _openChooser;
00245:
00246: /** For opening project files. */
00247: private final JFileChooser _openProjectChooser;
00248:
00249: /** For saving files. We have a persistent dialog to keep track of the last directory from which we saved. */
00250: private final JFileChooser _saveChooser;
00251:
00252: /** Filter for regular java files (.java and .j). */
00253: private final javax.swing.filechooser.FileFilter _javaSourceFilter = new JavaSourceFilter();
00254:
00255: /** Filter for drjava project files (.pjt) */
00256: private final javax.swing.filechooser.FileFilter _projectFilter = new javax.swing.filechooser.FileFilter() {
00257: public boolean accept(File f) {
00258: return f.isDirectory()
00259: || f.getPath().endsWith(PROJECT_FILE_EXTENSION);
00260: }
00261:
00262: public String getDescription() {
00263: return "DrJava Project Files (*.pjt)";
00264: }
00265: };
00266:
00267: /** Returns the files to open to the model (command pattern). */
00268: private final FileOpenSelector _openSelector = new FileOpenSelector() {
00269: public File[] getFiles() throws OperationCanceledException {
00270: //_openChooser.removeChoosableFileFilter(_projectFilter);
00271: _openChooser.resetChoosableFileFilters();
00272:
00273: _openChooser.setFileFilter(_javaSourceFilter);
00274: return getOpenFiles(_openChooser);
00275: }
00276: };
00277:
00278: /** Returns the files to open to the model (command pattern). */
00279: private final FileOpenSelector _openFileOrProjectSelector = new FileOpenSelector() {
00280: public File[] getFiles() throws OperationCanceledException {
00281: //_openChooser.removeChoosableFileFilter(_projectFilter);
00282: _openChooser.resetChoosableFileFilters();
00283:
00284: _openChooser.addChoosableFileFilter(_projectFilter);
00285: _openChooser.setFileFilter(_javaSourceFilter);
00286: return getOpenFiles(_openChooser);
00287: }
00288: };
00289:
00290: /** Returns the project file to open. */
00291: private final FileOpenSelector _openProjectSelector = new FileOpenSelector() {
00292: public File[] getFiles() throws OperationCanceledException {
00293: File[] retFiles = getOpenFiles(_openProjectChooser);
00294: return retFiles;
00295: }
00296: };
00297:
00298: /** Returns the file to save to the model (command pattern). */
00299: private final FileSaveSelector _saveSelector = new FileSaveSelector() {
00300: public File getFile() throws OperationCanceledException {
00301: return getSaveFile(_saveChooser);
00302: }
00303:
00304: public boolean warnFileOpen(File f) {
00305: return _warnFileOpen(f);
00306: }
00307:
00308: public boolean verifyOverwrite() {
00309: return _verifyOverwrite();
00310: }
00311:
00312: public boolean shouldSaveAfterFileMoved(
00313: OpenDefinitionsDocument doc, File oldFile) {
00314: _model.setActiveDocument(doc);
00315: String text = "File "
00316: + oldFile.getAbsolutePath()
00317: + "\ncould not be found on disk! It was probably moved\n"
00318: + "or deleted. Would you like to save it in a new file?";
00319: int rc = JOptionPane.showConfirmDialog(MainFrame.this ,
00320: text, "File Moved or Deleted",
00321: JOptionPane.YES_NO_OPTION);
00322: return (rc == JOptionPane.YES_OPTION);
00323: }
00324: };
00325:
00326: /** Returns the file to save to the model (command pattern). */
00327: private final FileSaveSelector _saveAsSelector = new FileSaveSelector() {
00328: public File getFile() throws OperationCanceledException {
00329: return getSaveFile(_saveChooser);
00330: }
00331:
00332: public boolean warnFileOpen(File f) {
00333: return _warnFileOpen(f);
00334: }
00335:
00336: public boolean verifyOverwrite() {
00337: return _verifyOverwrite();
00338: }
00339:
00340: public boolean shouldSaveAfterFileMoved(
00341: OpenDefinitionsDocument doc, File oldFile) {
00342: return true;
00343: }
00344: };
00345:
00346: /** Returns the file to save to the model (command pattern).
00347: private final FileSaveSelector _renameSelector = new FileSaveSelector() {
00348: public File getFile() throws OperationCanceledException { return getSaveFile(_saveChooser); }
00349: public boolean warnFileOpen(File f) { return _warnFileOpen(f); }
00350: public boolean verifyOverwrite() { return _verifyOverwrite(); }
00351: public boolean shouldSaveAfterFileMoved(OpenDefinitionsDocument doc, File oldFile) { return true; }
00352: }; */
00353:
00354: /** Provides the view's contribution to the Javadoc interaction. */
00355: private final JavadocDialog _javadocSelector = new JavadocDialog(
00356: this );
00357:
00358: /** Provides a chooser to open a directory */
00359: private final DirectoryChooser _folderChooser;
00360: private final JCheckBox _openRecursiveCheckBox;
00361:
00362: private final Action _moveToAuxiliaryAction = new AbstractAction(
00363: "Include With Project") {
00364: { /* initalization block */
00365: String msg = "<html>Open this document each time this project is opened.<br>"
00366: + "This file would then be compiled and tested with the<br>"
00367: + "rest of the project.</html>";
00368: putValue(Action.SHORT_DESCRIPTION, msg);
00369: }
00370:
00371: public void actionPerformed(ActionEvent ae) {
00372: _moveToAuxiliary();
00373: }
00374: };
00375: private final Action _removeAuxiliaryAction = new AbstractAction(
00376: "Do Not Include With Project") {
00377: {
00378: putValue(Action.SHORT_DESCRIPTION,
00379: "Do not open this document next time this project is opened.");
00380: }
00381:
00382: public void actionPerformed(ActionEvent ae) {
00383: _removeAuxiliary();
00384: }
00385: };
00386: private final Action _moveAllToAuxiliaryAction = new AbstractAction(
00387: "Include All With Project") {
00388: { /* initalization block */
00389: String msg = "<html>Open these documents each time this project is opened.<br>"
00390: + "These files would then be compiled and tested with the<br>"
00391: + "rest of the project.</html>";
00392: putValue(Action.SHORT_DESCRIPTION, msg);
00393: }
00394:
00395: public void actionPerformed(ActionEvent ae) {
00396: _moveAllToAuxiliary();
00397: }
00398: };
00399: private final Action _removeAllAuxiliaryAction = new AbstractAction(
00400: "Do Not Include Any With Project") {
00401: {
00402: putValue(Action.SHORT_DESCRIPTION,
00403: "Do not open these documents next time this project is opened.");
00404: }
00405:
00406: public void actionPerformed(ActionEvent ae) {
00407: _removeAllAuxiliary();
00408: }
00409: };
00410:
00411: /** Creates a new blank document and select it in the definitions pane. */
00412: private final Action _newAction = new AbstractAction("New") {
00413: public void actionPerformed(ActionEvent ae) {
00414: // System.out.println("------------------new----------------------");
00415: _new();
00416: }
00417: };
00418:
00419: private final Action _newProjectAction = new AbstractAction("New") {
00420: public void actionPerformed(ActionEvent ae) {
00421: _newProject();
00422: }
00423: };
00424:
00425: private volatile AbstractAction _runProjectAction = new AbstractAction(
00426: "Run Main Document of Project") {
00427: public void actionPerformed(ActionEvent ae) {
00428: _runProject();
00429: }
00430: };
00431:
00432: /** The jar options dialog. */
00433: private final JarOptionsDialog _jarOptionsDialog;
00434:
00435: /** Initializes the "Create Jar from Project dialog. */
00436: private void initJarOptionsDialog() {
00437: if (DrJava.getConfig().getSetting(
00438: DIALOG_JAROPTIONS_STORE_POSITION).booleanValue())
00439: _jarOptionsDialog.setFrameState(DrJava.getConfig()
00440: .getSetting(DIALOG_JAROPTIONS_STATE));
00441: }
00442:
00443: /** Reset the position of the "Create Jar from Project" dialog. */
00444: public void resetJarOptionsDialogPosition() {
00445: _jarOptionsDialog.setFrameState("default");
00446: if (DrJava.getConfig().getSetting(
00447: DIALOG_JAROPTIONS_STORE_POSITION).booleanValue()) {
00448: DrJava.getConfig().setSetting(DIALOG_JAROPTIONS_STATE,
00449: "default");
00450: }
00451: }
00452:
00453: private final Action _jarProjectAction = new AbstractAction(
00454: "Create Jar File from Project...") {
00455: public void actionPerformed(ActionEvent ae) {
00456: _jarOptionsDialog.setVisible(true);
00457: }
00458: };
00459:
00460: /** Sets the document in the definitions pane to a new templated junit test class. */
00461: private final Action _newJUnitTestAction = new AbstractAction(
00462: "New JUnit Test Case...") {
00463: public void actionPerformed(ActionEvent ae) {
00464: String testName = JOptionPane
00465: .showInputDialog(MainFrame.this ,
00466: "Please enter a name for the test class:",
00467: "New JUnit Test Case",
00468: JOptionPane.QUESTION_MESSAGE);
00469: if (testName != null) {
00470: String ext;
00471: for (int i = 0; i < DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS.length; i++) {
00472: ext = "." + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[i];
00473: if (testName.endsWith(ext))
00474: testName = testName.substring(0, testName
00475: .length()
00476: - ext.length());
00477: }
00478: // For now, don't include setUp and tearDown
00479: _model.newTestCase(testName, false, false);
00480: }
00481: }
00482: };
00483:
00484: /** Asks user for file name and and reads that file into the definitions pane. */
00485: private final Action _openAction = new AbstractAction("Open...") {
00486: public void actionPerformed(ActionEvent ae) {
00487: _open();
00488: _findReplace.updateFirstDocInSearch();
00489: }
00490: };
00491:
00492: /** Asks user for directory name and and reads it's files (and subdirectories files, on request) to
00493: * the definitions pane.
00494: */
00495: private final Action _openFolderAction = new AbstractAction(
00496: "Open Folder...") {
00497: public void actionPerformed(ActionEvent ae) {
00498: _openFolder();
00499: _findReplace.updateFirstDocInSearch();
00500: }
00501: };
00502:
00503: /** Asks user for file name and and reads that file into the definitions pane. */
00504: private final Action _openFileOrProjectAction = new AbstractAction(
00505: "Open...") {
00506: public void actionPerformed(ActionEvent ae) {
00507: _openFileOrProject();
00508: _findReplace.updateFirstDocInSearch();
00509: }
00510: };
00511:
00512: /** Asks user for project file name and and reads the associated files into the file navigator (and places the first
00513: * source file in the editor pane)
00514: */
00515: private final Action _openProjectAction = new AbstractAction(
00516: "Open...") {
00517: public void actionPerformed(ActionEvent ae) {
00518: _openProject();
00519: }
00520: };
00521:
00522: private final Action _closeProjectAction = new AbstractAction(
00523: "Close") {
00524: public void actionPerformed(ActionEvent ae) {
00525: closeProject();
00526: _findReplace.updateFirstDocInSearch();
00527: }
00528: };
00529:
00530: /** Closes the current active document, prompting to save if necessary. */
00531: private final Action _closeAction = new AbstractAction("Close") {
00532: public void actionPerformed(ActionEvent ae) {
00533: _close();
00534: _findReplace.updateFirstDocInSearch();
00535: }
00536: };
00537:
00538: /** Closes all open documents, prompting to save if necessary. */
00539: private final Action _closeAllAction = new AbstractAction(
00540: "Close All") {
00541: public void actionPerformed(ActionEvent ae) {
00542: _closeAll();
00543: _findReplace.updateFirstDocInSearch();
00544: }
00545: };
00546:
00547: /** Closes all open documents, prompting to save if necessary. */
00548: private final Action _closeFolderAction = new AbstractAction(
00549: "Close Folder") {
00550: public void actionPerformed(ActionEvent ae) {
00551: _closeFolder();
00552: _findReplace.updateFirstDocInSearch();
00553: }
00554: };
00555:
00556: /** Opens all the files in the current folder. */
00557: private final Action _openAllFolderAction = new AbstractAction(
00558: "Open All Files") {
00559: public void actionPerformed(ActionEvent ae) {
00560: // now works with multiple selected folders
00561: java.util.List<File> l = _model.getDocumentNavigator()
00562: .getSelectedFolders();
00563: for (File f : l) {
00564: File fAbs = new File(_model.getProjectRoot(), f
00565: .toString());
00566: _openFolder(fAbs, false);
00567: }
00568:
00569: // The following does not apply anymore:
00570: // Get the Folder that was clicked on by the user. When the user clicks on a directory component in the
00571: // navigation pane, the current directory is updated in the openChooser JFileChooser component. So the
00572: // clicked on directory is obtained in this way
00573: // File dir = _openChooser.getCurrentDirectory();
00574: // _openFolder(dir, false);
00575: _findReplace.updateFirstDocInSearch();
00576: }
00577: };
00578:
00579: /** Opens a files in the current folder. */
00580: private final Action _openOneFolderAction = new AbstractAction(
00581: "Open File in Folder") {
00582: public void actionPerformed(ActionEvent ae) {
00583: _open();
00584: _findReplace.updateFirstDocInSearch();
00585: }
00586: };
00587:
00588: /** Creates a new untitled, empty file in the current folder. */
00589: public final Action _newFileFolderAction = new AbstractAction(
00590: "Create New File in Folder") {
00591: public void actionPerformed(ActionEvent ae) {
00592: //make this new document the document in the document pane
00593: _new();
00594: _findReplace.updateFirstDocInSearch();
00595: }
00596: };
00597:
00598: /** Tests all the files in a folder. */
00599: private volatile AbstractAction _junitFolderAction = new AbstractAction(
00600: "Test Folder") {
00601: public final void actionPerformed(ActionEvent ae) {
00602: _junitFolder();
00603: }
00604: };
00605:
00606: /** Saves the current document. */
00607: private final Action _saveAction = new AbstractAction("Save") {
00608: public final void actionPerformed(ActionEvent ae) {
00609: _save();
00610: }
00611: };
00612:
00613: /** Ensures that pack() is run in the event thread. Only used in test code */
00614: public void pack() {
00615: Utilities.invokeAndWait(new Runnable() {
00616: public void run() {
00617: packHelp();
00618: }
00619: });
00620: }
00621:
00622: /** Helper method that provides access to super.pack() within the anonymous class new Runnable() {...} above */
00623: private void packHelp() {
00624: super .pack();
00625: }
00626:
00627: /** Supports MainFrameTest.*/
00628: public boolean saveEnabledHuh() {
00629: return _saveAction.isEnabled();
00630: }
00631:
00632: /** Asks the user for a file name and saves the document
00633: * currently in the definitions pane to that file.
00634: */
00635: private final Action _saveAsAction = new AbstractAction(
00636: "Save As...") {
00637: public void actionPerformed(ActionEvent ae) {
00638: _saveAs();
00639: }
00640: };
00641:
00642: /** Asks the user for a file name and renames and saves the document
00643: * currently in the definitions pane to that file.
00644: */
00645: private final Action _renameAction = new AbstractAction("Rename") {
00646: public void actionPerformed(ActionEvent ae) {
00647: _rename();
00648: }
00649: };
00650:
00651: private final Action _saveProjectAction = new AbstractAction("Save") {
00652: public void actionPerformed(ActionEvent ae) {
00653: _saveAll(); // saves project file and all modified project source files; does not save external files
00654: }
00655: };
00656:
00657: private final Action _saveProjectAsAction = new AbstractAction(
00658: "Save As...") {
00659: public void actionPerformed(ActionEvent ae) {
00660: if (_saveProjectAs()) { // asks the user for a new project file name; sets _projectFile in global model to this value
00661: _saveAll(); // performs a save all operation using this new project file name, but ONLY if the "Save as" was not cancelled
00662: }
00663: }
00664: };
00665:
00666: /** Reverts the current document. */
00667: private final Action _revertAction = new AbstractAction(
00668: "Revert to Saved") {
00669: public void actionPerformed(ActionEvent ae) {
00670: String title = "Revert to Saved?";
00671:
00672: // update message to reflect the number of files
00673: int count = _model.getDocumentNavigator()
00674: .getDocumentSelectedCount();
00675: String message;
00676: if (count == 1) {
00677: message = "Are you sure you want to revert the current "
00678: + "file to the version on disk?";
00679: } else {
00680: message = "Are you sure you want to revert the "
00681: + count
00682: + " selected files to the versions on disk?";
00683: }
00684:
00685: int rc = JOptionPane.showConfirmDialog(MainFrame.this ,
00686: message, title, JOptionPane.YES_NO_OPTION);
00687: if (rc == JOptionPane.YES_OPTION) {
00688: _revert();
00689: }
00690: }
00691: };
00692:
00693: /** Reverts all open documents.
00694: * (not working yet)
00695: private Action _revertAllAction = new AbstractAction("Revert All to Saved") {
00696: public void actionPerformed(ActionEvent ae) {
00697: String title = "Revert All to Saved?";
00698:
00699: String message = "Are you sure you want to revert all open " +
00700: "files to the versions on disk?";
00701:
00702: int rc = JOptionPane.showConfirmDialog(MainFrame.this,
00703: message,
00704: title,
00705: JOptionPane.YES_NO_OPTION);
00706: if (rc == JOptionPane.YES_OPTION) {
00707: _revertAll();
00708: }
00709: }
00710: };*/
00711:
00712: /** Saves all documents, prompting for file names as necessary. */
00713: final Action _saveAllAction = new AbstractAction("Save All") {
00714: public void actionPerformed(ActionEvent ae) {
00715: _saveAll();
00716: }
00717: };
00718:
00719: /** Prints the current document. */
00720: private final Action _printDefDocAction = new AbstractAction(
00721: "Print...") {
00722: public void actionPerformed(ActionEvent ae) {
00723: _printDefDoc();
00724: }
00725: };
00726:
00727: /** Prints the console document. */
00728: private final Action _printConsoleAction = new AbstractAction(
00729: "Print Console...") {
00730: public void actionPerformed(ActionEvent ae) {
00731: _printConsole();
00732: }
00733: };
00734:
00735: /** Prints the interactions document. */
00736: private final Action _printInteractionsAction = new AbstractAction(
00737: "Print Interactions...") {
00738: public void actionPerformed(ActionEvent ae) {
00739: _printInteractions();
00740: }
00741: };
00742:
00743: /** Opens the print preview window. */
00744: private final Action _printDefDocPreviewAction = new AbstractAction(
00745: "Print Preview...") {
00746: public void actionPerformed(ActionEvent ae) {
00747: _printDefDocPreview();
00748: }
00749: };
00750:
00751: /** Opens the print preview window. */
00752: private final Action _printConsolePreviewAction = new AbstractAction(
00753: "Print Preview...") {
00754: public void actionPerformed(ActionEvent ae) {
00755: _printConsolePreview();
00756: }
00757: };
00758:
00759: /** Opens the print preview window. */
00760: private final Action _printInteractionsPreviewAction = new AbstractAction(
00761: "Print Preview...") {
00762: public void actionPerformed(ActionEvent ae) {
00763: _printInteractionsPreview();
00764: }
00765: };
00766:
00767: /** Opens the page setup window. */
00768: private final Action _pageSetupAction = new AbstractAction(
00769: "Page Setup...") {
00770: public void actionPerformed(ActionEvent ae) {
00771: _pageSetup();
00772: }
00773: };
00774:
00775: // /** Compiles all the project. */
00776: // private Action _compileOpenProjectAction = new AbstractAction("Compile Open Project Files") {
00777: // public void actionPerformed(ActionEvent ae) { _compileAll(); } // right now, it's the same as compile all
00778: // };
00779:
00780: /** Compiles the document in the definitions pane. */
00781: private final Action _compileAction = new AbstractAction(
00782: "Compile Current Document") {
00783: public void actionPerformed(ActionEvent ae) {
00784: if (_mainSplit.getDividerLocation() > _mainSplit
00785: .getMaximumDividerLocation())
00786: _mainSplit.resetToPreferredSizes();
00787: updateStatusField("Compiling " + _fileTitle);
00788: _compile();
00789: updateStatusField("Compilation of current document completed");
00790: }
00791: };
00792:
00793: /** Compiles all the project. */
00794: private volatile AbstractAction _compileProjectAction = new AbstractAction(
00795: "Compile Project") {
00796: public void actionPerformed(ActionEvent ae) {
00797: if (_mainSplit.getDividerLocation() > _mainSplit
00798: .getMaximumDividerLocation())
00799: _mainSplit.resetToPreferredSizes();
00800: updateStatusField("Compiling all source files in open project");
00801: _compileProject();
00802: _findReplace.updateFirstDocInSearch();
00803: updateStatusField("Compilation of open project completed");
00804: }
00805: };
00806:
00807: /** Compiles all documents in the navigators active group. */
00808: private volatile AbstractAction _compileFolderAction = new AbstractAction(
00809: "Compile Folder") {
00810: public void actionPerformed(ActionEvent ae) {
00811: if (_mainSplit.getDividerLocation() > _mainSplit
00812: .getMaximumDividerLocation())
00813: _mainSplit.resetToPreferredSizes();
00814: updateStatusField("Compiling all sources in current folder");
00815: _compileFolder();
00816: _findReplace.updateFirstDocInSearch();
00817: updateStatusField("Compilation of folder completed");
00818: }
00819: };
00820:
00821: /** Compiles all open documents. */
00822: private volatile AbstractAction _compileAllAction = new AbstractAction(
00823: "Compile All Documents") {
00824: public void actionPerformed(ActionEvent ae) {
00825: if (_mainSplit.getDividerLocation() > _mainSplit
00826: .getMaximumDividerLocation())
00827: _mainSplit.resetToPreferredSizes();
00828: _compileAll();
00829: _findReplace.updateFirstDocInSearch();
00830: }
00831: };
00832:
00833: /** cleans the build directory */
00834: private volatile AbstractAction _cleanAction = new AbstractAction(
00835: "Clean Build Directory") {
00836: public void actionPerformed(ActionEvent ae) {
00837: _clean();
00838: }
00839: };
00840:
00841: /** Finds and runs the main method of the current document, if it exists. */
00842: private volatile AbstractAction _runAction = new AbstractAction(
00843: "Run Document's Main Method") {
00844: public void actionPerformed(ActionEvent ae) {
00845: _runMain();
00846: }
00847: };
00848:
00849: /** Runs JUnit on the document in the definitions pane. */
00850: private volatile AbstractAction _junitAction = new AbstractAction(
00851: "Test Current Document") {
00852: public void actionPerformed(ActionEvent ae) {
00853: if (_mainSplit.getDividerLocation() > _mainSplit
00854: .getMaximumDividerLocation())
00855: _mainSplit.resetToPreferredSizes();
00856: _junit();
00857: }
00858: };
00859:
00860: /** Runs JUnit over all open JUnit tests. */
00861: private volatile AbstractAction _junitAllAction = new AbstractAction(
00862: "Test All Documents") {
00863: public void actionPerformed(ActionEvent e) {
00864: if (_mainSplit.getDividerLocation() > _mainSplit
00865: .getMaximumDividerLocation())
00866: _mainSplit.resetToPreferredSizes();
00867: _junitAll();
00868: _findReplace.updateFirstDocInSearch();
00869: }
00870:
00871: };
00872:
00873: /** Runs JUnit over all open JUnit tests in the project directory. */
00874: private volatile AbstractAction _junitProjectAction = new AbstractAction(
00875: "Test Project") {
00876: public void actionPerformed(ActionEvent e) {
00877: if (_mainSplit.getDividerLocation() > _mainSplit
00878: .getMaximumDividerLocation())
00879: _mainSplit.resetToPreferredSizes();
00880: _junitProject();
00881: _findReplace.updateFirstDocInSearch();
00882: }
00883: };
00884:
00885: // /** JUnit a directory. */
00886: // private final Action _junitProjectAction = new AbstractAction("Test Project") {
00887: // public void actionPerformed(ActionEvent e) {
00888: // new Thread("Running JUnit Tests") {
00889: // public void run() {
00890: // if (_model.isProjectActive()) {
00891: // try {
00892: // // hourglassOn(); // also done in junitStarted
00893: // _model.junitAll();
00894: // }
00895: // finally {
00896: // // hourglassOff(); // also done in junitEnded
00897: // }
00898: // }
00899: // }
00900: // }.start();
00901: // }
00902: // };
00903:
00904: /** Runs Javadoc on all open documents (and the files in their packages). */
00905: private final Action _javadocAllAction = new AbstractAction(
00906: "Javadoc All Documents") {
00907: public void actionPerformed(ActionEvent ae) {
00908: if (_mainSplit.getDividerLocation() > _mainSplit
00909: .getMaximumDividerLocation())
00910: _mainSplit.resetToPreferredSizes();
00911: try {
00912: // hourglassOn();
00913: JavadocModel jm = _model.getJavadocModel();
00914: File suggestedDir = jm.suggestJavadocDestination(_model
00915: .getActiveDocument());
00916: _javadocSelector.setSuggestedDir(suggestedDir);
00917: jm.javadocAll(_javadocSelector, _saveSelector);
00918: } catch (IOException ioe) {
00919: _showIOError(ioe);
00920: } finally {
00921: // hourglassOff();
00922: }
00923: }
00924: };
00925:
00926: /** Runs Javadoc on the current document. */
00927: private final Action _javadocCurrentAction = new AbstractAction(
00928: "Preview Javadoc for Current Document") {
00929: public void actionPerformed(ActionEvent ae) {
00930: if (_mainSplit.getDividerLocation() > _mainSplit
00931: .getMaximumDividerLocation())
00932: _mainSplit.resetToPreferredSizes();
00933: try {
00934: _model.getActiveDocument().generateJavadoc(
00935: _saveSelector);
00936: } catch (IOException ioe) {
00937: _showIOError(ioe);
00938: }
00939: }
00940: };
00941:
00942: /** Default cut action. Returns focus to the correct pane. */
00943: final Action cutAction = new DefaultEditorKit.CutAction() {
00944: public void actionPerformed(ActionEvent e) {
00945: Component c = MainFrame.this .getFocusOwner();
00946: super .actionPerformed(e);
00947: if (_currentDefPane.hasFocus()) {
00948: String s = Utilities.getClipboardSelection(c);
00949: if (s != null && s.length() != 0) {
00950: ClipboardHistoryModel.singleton().put(s);
00951: }
00952: }
00953: if (c != null)
00954: c.requestFocusInWindow();
00955: }
00956: };
00957:
00958: /** Default copy action. Returns focus to the correct pane. */
00959: final Action copyAction = new DefaultEditorKit.CopyAction() {
00960: public void actionPerformed(ActionEvent e) {
00961: Component c = MainFrame.this .getFocusOwner();
00962: super .actionPerformed(e);
00963: if (_currentDefPane.hasFocus()
00964: && _currentDefPane.getSelectedText() != null) {
00965: String s = Utilities.getClipboardSelection(c);
00966: if (s != null && s.length() != 0) {
00967: ClipboardHistoryModel.singleton().put(s);
00968: }
00969: }
00970: if (c != null)
00971: c.requestFocusInWindow();
00972: }
00973: };
00974:
00975: /** We lost ownership of what we put in the clipboard. */
00976: public void lostOwnership(Clipboard clipboard, Transferable contents) {
00977: // ignore
00978: }
00979:
00980: /** Default paste action. Returns focus to the correct pane. */
00981: final Action pasteAction = new DefaultEditorKit.PasteAction() {
00982: public void actionPerformed(ActionEvent e) {
00983: Component c = MainFrame.this .getFocusOwner();
00984: if (_currentDefPane.hasFocus()) {
00985: _currentDefPane.endCompoundEdit();
00986: // CompoundUndoManager undoMan = _model.getActiveDocument().getUndoManager(); // French keyboard fix
00987: // int key = undoMan.startCompoundEdit(); // French keyboard fix
00988: super .actionPerformed(e);
00989: _currentDefPane.endCompoundEdit(); // replaced line below for French keyboard fix
00990: // undoMan.endCompoundEdit(key); // French keyboard fix
00991: } else
00992: super .actionPerformed(e);
00993:
00994: if (c != null)
00995: c.requestFocusInWindow();
00996: }
00997: };
00998:
00999: /** Reset the position of the "Clipboard History" dialog. */
01000: public void resetClipboardHistoryDialogPosition() {
01001: if (DrJava.getConfig().getSetting(
01002: DIALOG_CLIPBOARD_HISTORY_STORE_POSITION).booleanValue()) {
01003: DrJava.getConfig().setSetting(
01004: DIALOG_CLIPBOARD_HISTORY_STATE, "default");
01005: }
01006: }
01007:
01008: /** The "Clipboard History" dialog. */
01009: private ClipboardHistoryFrame _clipboardHistoryDialog = null;
01010:
01011: /** Asks the user for a file name and goes there. */
01012: private final Action _pasteHistoryAction = new AbstractAction(
01013: "Paste from History...") {
01014: public void actionPerformed(final ActionEvent ae) {
01015: final ClipboardHistoryFrame.CloseAction cancelAction = new ClipboardHistoryFrame.CloseAction() {
01016: public Object apply(String s) {
01017: // "Clipboard History" dialog position and size.
01018: if ((DrJava.getConfig().getSetting(
01019: DIALOG_CLIPBOARD_HISTORY_STORE_POSITION)
01020: .booleanValue())
01021: && (_clipboardHistoryDialog != null)
01022: && (_clipboardHistoryDialog.getFrameState() != null)) {
01023: DrJava.getConfig().setSetting(
01024: DIALOG_CLIPBOARD_HISTORY_STATE,
01025: (_clipboardHistoryDialog
01026: .getFrameState().toString()));
01027: } else {
01028: // Reset to defaults to restore pristine behavior.
01029: DrJava.getConfig().setSetting(
01030: DIALOG_CLIPBOARD_HISTORY_STATE,
01031: DIALOG_CLIPBOARD_HISTORY_STATE
01032: .getDefault());
01033: }
01034: return null;
01035: }
01036: };
01037: ClipboardHistoryFrame.CloseAction okAction = new ClipboardHistoryFrame.CloseAction() {
01038: public Object apply(String s) {
01039: cancelAction.apply(null);
01040:
01041: StringSelection ssel = new StringSelection(s);
01042: Clipboard cb = MainFrame.this .getToolkit()
01043: .getSystemClipboard();
01044: if (cb != null) {
01045: cb.setContents(ssel, MainFrame.this );
01046: pasteAction.actionPerformed(ae);
01047: }
01048: return null;
01049: }
01050: };
01051:
01052: _clipboardHistoryDialog = new ClipboardHistoryFrame(
01053: MainFrame.this , "Clipboard History",
01054: ClipboardHistoryModel.singleton(), okAction,
01055: cancelAction);
01056: if (DrJava.getConfig().getSetting(
01057: DIALOG_CLIPBOARD_HISTORY_STORE_POSITION)
01058: .booleanValue()) {
01059: _clipboardHistoryDialog.setFrameState(DrJava
01060: .getConfig().getSetting(
01061: DIALOG_CLIPBOARD_HISTORY_STATE));
01062: }
01063: _clipboardHistoryDialog.setVisible(true);
01064: }
01065: };
01066:
01067: /** Copies whatever is currently in the interactions pane at the prompt to the definitions pane. If the
01068: * current string is empty, then it will attempt to return the last entry from the interactions pane's history.
01069: */
01070: private final Action _copyInteractionToDefinitionsAction = new AbstractAction(
01071: "Lift Current Interaction to Definitions") {
01072: public void actionPerformed(ActionEvent a) {
01073: String text = _interactionsController.getDocument()
01074: .getCurrentInput();
01075: if (!text.equals("")) {
01076: _putTextIntoDefinitions(text + "\n");
01077: return;
01078: }
01079: try {
01080: text = _interactionsController.getDocument()
01081: .lastEntry();
01082: } catch (Exception e) {
01083: return;
01084: } // no entry to promote
01085:
01086: //It is assumed that empty strings are not put into the history
01087: _putTextIntoDefinitions(text + "\n");
01088: return;
01089: }
01090: };
01091:
01092: /** Action that copies the previous interaction to the definitions pane.
01093: * Is there a good way to get the last history element without perturbing the current document?
01094: Action copyPreviousInteractionToDefinitionsAction = new AbstractAction("Copy previous interaction to definitions") {
01095: public void actionPerformed(ActionEvent e) {
01096: _putTextIntoDefinitions(_interactionsController.getDocument().getCurrentInput() + "\n");
01097: }
01098: };*/
01099:
01100: /** Undoes the last change to the active definitions document. */
01101: private final DelegatingAction _undoAction = new DelegatingAction() {
01102: public void actionPerformed(ActionEvent e) {
01103: _currentDefPane.endCompoundEdit();
01104: super .actionPerformed(e);
01105: _currentDefPane.requestFocusInWindow();
01106: OpenDefinitionsDocument doc = _model.getActiveDocument();
01107: // Utilities.showDebug("isModifiedSinceSave() = " + doc.isModifiedSinceSave());
01108: _saveAction.setEnabled(doc.isModifiedSinceSave()
01109: || doc.isUntitled());
01110: // Utilities.showDebug("check status");
01111: }
01112: };
01113:
01114: /** Redoes the last undo to the active definitions document. */
01115: private final DelegatingAction _redoAction = new DelegatingAction() {
01116: public void actionPerformed(ActionEvent e) {
01117: super .actionPerformed(e);
01118: _currentDefPane.requestFocusInWindow();
01119: OpenDefinitionsDocument doc = _model.getActiveDocument();
01120: _saveAction.setEnabled(doc.isModifiedSinceSave()
01121: || doc.isUntitled());
01122: }
01123: };
01124:
01125: /** Quits DrJava. Optionally displays a prompt before quitting. */
01126: private final Action _quitAction = new AbstractAction("Quit") {
01127: public void actionPerformed(ActionEvent ae) {
01128: _quit();
01129: }
01130: };
01131:
01132: /** Quits DrJava. Optionally displays a prompt before quitting. */
01133: private final Action _forceQuitAction = new AbstractAction(
01134: "Force Quit") {
01135: public void actionPerformed(ActionEvent ae) {
01136: _forceQuit();
01137: }
01138: };
01139:
01140: /** Selects all text in window. */
01141: private final Action _selectAllAction = new AbstractAction(
01142: "Select All") {
01143: public void actionPerformed(ActionEvent ae) {
01144: _selectAll();
01145: }
01146: };
01147:
01148: private void _showFindReplaceTab() {
01149: if (_mainSplit.getDividerLocation() > _mainSplit
01150: .getMaximumDividerLocation())
01151: _mainSplit.resetToPreferredSizes();
01152: if (!_findReplace.isDisplayed()) {
01153: showTab(_findReplace);
01154: _findReplace.beginListeningTo(_currentDefPane);
01155: }
01156: _findReplace.setVisible(true);
01157: _tabbedPane.setSelectedComponent(_findReplace);
01158: }
01159:
01160: /** Shows the find/replace tab. */
01161: private final Action _findReplaceAction = new AbstractAction(
01162: "Find/Replace") {
01163: public void actionPerformed(ActionEvent ae) {
01164: _showFindReplaceTab();
01165: // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
01166: EventQueue.invokeLater(new Runnable() {
01167: public void run() {
01168: _findReplace.requestFocusInWindow();
01169: }
01170: });
01171: }
01172: };
01173:
01174: /** Find the next instance of the find word. */
01175: private final Action _findNextAction = new AbstractAction(
01176: "Find Next") {
01177: public void actionPerformed(ActionEvent ae) {
01178: _showFindReplaceTab();
01179: if (!DrJava.getConfig().getSetting(
01180: FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
01181: // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
01182: EventQueue.invokeLater(new Runnable() {
01183: public void run() {
01184: _findReplace.requestFocusInWindow();
01185: }
01186: });
01187: }
01188: _findReplace.findNext();
01189: _currentDefPane.requestFocusInWindow();
01190: // atempt to fix intermittent bug where _currentDefPane listens but does not echo and won't undo!
01191: }
01192: };
01193:
01194: /** Does the find next in the opposite direction. If the direction is backward it searches forward. */
01195: private final Action _findPrevAction = new AbstractAction(
01196: "Find Previous") {
01197: public void actionPerformed(ActionEvent ae) {
01198: _showFindReplaceTab();
01199: if (!DrJava.getConfig().getSetting(
01200: FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
01201: // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _findReplace tab has been selected
01202: EventQueue.invokeLater(new Runnable() {
01203: public void run() {
01204: _findReplace.requestFocusInWindow();
01205: }
01206: });
01207: }
01208: _findReplace.findPrevious();
01209: _currentDefPane.requestFocusInWindow();
01210: }
01211: };
01212:
01213: /** Asks the user for a line number and goes there. */
01214: private final Action _gotoLineAction = new AbstractAction(
01215: "Go to Line...") {
01216: public void actionPerformed(ActionEvent ae) {
01217: int pos = _gotoLine();
01218: _currentDefPane.requestFocusInWindow();
01219: if (pos != -1)
01220: _currentDefPane.setCaretPosition(pos);
01221: // The preceding is a brute force attempt to fix intermittent failure to display caret
01222: }
01223: };
01224:
01225: /** Wrapper class for the "Go to File" dialog list entries. Provides the ability to have the same
01226: * OpenDefinitionsDocument in there multiple times with different toString() results.
01227: */
01228: private static class GoToFileListEntry implements
01229: Comparable<GoToFileListEntry> {
01230: public final OpenDefinitionsDocument doc;
01231: private final String str;
01232:
01233: public GoToFileListEntry(OpenDefinitionsDocument d, String s) {
01234: doc = d;
01235: str = s;
01236: }
01237:
01238: public String toString() {
01239: return str;
01240: }
01241:
01242: public int compareTo(GoToFileListEntry other) {
01243: return str.toLowerCase().compareTo(other.str.toLowerCase());
01244: }
01245:
01246: public boolean equals(Object other) {
01247: if (!(other instanceof GoToFileListEntry))
01248: return false;
01249: return str.equals(((GoToFileListEntry) other).str);
01250: }
01251:
01252: public int hashCode() {
01253: return str.hashCode();
01254: }
01255: }
01256:
01257: /** Reset the position of the "Go to File" dialog. */
01258: public void resetGotoFileDialogPosition() {
01259: initGotoFileDialog();
01260: _gotoFileDialog.setFrameState("default");
01261: if (DrJava.getConfig().getSetting(
01262: DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) {
01263: DrJava.getConfig().setSetting(DIALOG_GOTOFILE_STATE,
01264: "default");
01265: }
01266: }
01267:
01268: /** Initialize dialog if necessary. */
01269: void initGotoFileDialog() {
01270: if (_gotoFileDialog == null) {
01271: PredictiveInputFrame.InfoSupplier<GoToFileListEntry> info = new PredictiveInputFrame.InfoSupplier<GoToFileListEntry>() {
01272: public String apply(GoToFileListEntry entry) {
01273: final StringBuilder sb = new StringBuilder();
01274:
01275: if (entry.doc != null) {
01276: try {
01277: try {
01278: sb.append(FileOps.makeRelativeTo(
01279: entry.doc.getRawFile(),
01280: entry.doc.getSourceRoot()));
01281: } catch (IOException e) {
01282: sb.append(entry.doc.getFile());
01283: }
01284: } catch (edu.rice.cs.drjava.model.FileMovedException e) {
01285: sb.append(entry + " was moved");
01286: } catch (java.lang.IllegalStateException e) {
01287: sb.append(entry);
01288: } catch (InvalidPackageException e) {
01289: sb.append(entry);
01290: }
01291: } else
01292: sb.append(entry);
01293: return sb.toString();
01294: }
01295: };
01296: PredictiveInputFrame.CloseAction<GoToFileListEntry> okAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
01297: public Object apply(
01298: PredictiveInputFrame<GoToFileListEntry> p) {
01299: if (p.getItem() != null) {
01300: final OpenDefinitionsDocument newDoc = p
01301: .getItem().doc;
01302: // final boolean docChanged = ! newDoc.equals(_model.getActiveDocument());
01303: // if (docChanged) addToBrowserHistory();
01304: final boolean docSwitch = _model
01305: .getActiveDocument() != newDoc;
01306: if (docSwitch)
01307: _model.setActiveDocument(newDoc);
01308: final int curLine = newDoc.getCurrentLine();
01309: final String t = p.getText();
01310: final int last = t.lastIndexOf(':');
01311: if (last >= 0) {
01312: try {
01313: String end = t.substring(last + 1);
01314: int val = Integer.parseInt(end);
01315:
01316: final int lineNum = Math.max(1, val);
01317: Runnable command = new Runnable() {
01318: public void run() {
01319: try {
01320: _jumpToLine(lineNum);
01321: } catch (RuntimeException e) {
01322: _jumpToLine(curLine);
01323: }
01324: }
01325: };
01326: if (docSwitch) {
01327: // postpone running command until after document switch, which is pending in the event queue
01328: EventQueue.invokeLater(command);
01329: } else
01330: command.run();
01331: } catch (RuntimeException e) { /* ignore */
01332: }
01333: }
01334: // if (docChanged) {
01335: // // defer executing this code until after active document switch (if any) is complete
01336: // EventQueue.invokeLater(new Runnable() {
01337: // public void run() {
01338: // addToBrowserHistory();
01339: // }
01340: // });
01341: // }
01342: }
01343: hourglassOff();
01344: return null;
01345: }
01346: };
01347: PredictiveInputFrame.CloseAction<GoToFileListEntry> cancelAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
01348: public Object apply(
01349: PredictiveInputFrame<GoToFileListEntry> p) {
01350: hourglassOff();
01351: return null;
01352: }
01353: };
01354: java.util.ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>> strategies = new java.util.ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>>();
01355: strategies
01356: .add(new PredictiveInputModel.FragmentLineNumStrategy<GoToFileListEntry>());
01357: strategies
01358: .add(new PredictiveInputModel.PrefixLineNumStrategy<GoToFileListEntry>());
01359: strategies
01360: .add(new PredictiveInputModel.RegExLineNumStrategy<GoToFileListEntry>());
01361: _gotoFileDialog = new PredictiveInputFrame<GoToFileListEntry>(
01362: MainFrame.this , "Go to File",
01363: true, // force
01364: true, // ignore case
01365: info, strategies, okAction, cancelAction,
01366: new GoToFileListEntry(null, "dummy")) {
01367: public void setOwnerEnabled(boolean b) {
01368: if (b) {
01369: hourglassOff();
01370: } else {
01371: hourglassOn();
01372: }
01373: }
01374: };
01375: // putting one dummy entry in the list; it will be changed later anyway
01376:
01377: if (DrJava.getConfig().getSetting(
01378: DIALOG_GOTOFILE_STORE_POSITION).booleanValue()) {
01379: _gotoFileDialog.setFrameState(DrJava.getConfig()
01380: .getSetting(DIALOG_GOTOFILE_STATE));
01381: }
01382: }
01383: }
01384:
01385: /** The "Go to File" dialog instance. */
01386: volatile PredictiveInputFrame<GoToFileListEntry> _gotoFileDialog = null;
01387:
01388: /** Asks the user for a file name and goes there. */
01389: private final Action _gotoFileAction = new AbstractAction(
01390: "Go to File...") {
01391: public void actionPerformed(ActionEvent ae) {
01392: initGotoFileDialog();
01393: List<OpenDefinitionsDocument> docs = _model
01394: .getOpenDefinitionsDocuments();
01395: if (docs == null || docs.size() == 0) {
01396: return; // do nothing
01397: }
01398: GoToFileListEntry currentEntry = null;
01399: ArrayList<GoToFileListEntry> list;
01400: if (DrJava.getConfig().getSetting(
01401: DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) {
01402: list = new ArrayList<GoToFileListEntry>(2 * docs.size());
01403: } else {
01404: list = new ArrayList<GoToFileListEntry>(docs.size());
01405: }
01406: for (OpenDefinitionsDocument d : docs) {
01407: GoToFileListEntry entry = new GoToFileListEntry(d, d
01408: .toString());
01409: if (d.equals(_model.getActiveDocument())) {
01410: currentEntry = entry;
01411: }
01412: list.add(entry);
01413: if (DrJava.getConfig().getSetting(
01414: DIALOG_GOTOFILE_FULLY_QUALIFIED).booleanValue()) {
01415: try {
01416: try {
01417: File relative = FileOps.makeRelativeTo(d
01418: .getFile(), d.getSourceRoot());
01419: if (!relative.toString().equals(
01420: d.toString())) {
01421: list.add(new GoToFileListEntry(d, d
01422: .getPackageName()
01423: + "." + d.toString()));
01424: }
01425: } catch (IOException e) {
01426: // ignore
01427: } catch (edu.rice.cs.drjava.model.definitions.InvalidPackageException e) {
01428: // ignore
01429: }
01430: } catch (IllegalStateException e) {
01431: // ignore
01432: }
01433: }
01434: }
01435: _gotoFileDialog.setItems(true, list); // ignore case
01436: if (currentEntry != null) {
01437: _gotoFileDialog.setCurrentItem(currentEntry);
01438: }
01439: hourglassOn();
01440: /* if (! Utilities.TEST_MODE) */
01441: _gotoFileDialog.setVisible(true);
01442: }
01443: };
01444:
01445: /** Goes to the file specified by the word the cursor is on. */
01446: void _gotoFileUnderCursor() {
01447: // Utilities.show("Calling gotoFileUnderCursor()");
01448: List<OpenDefinitionsDocument> docs = _model
01449: .getOpenDefinitionsDocuments();
01450: if ((docs == null) || (docs.size() == 0))
01451: return; // do nothing
01452:
01453: GoToFileListEntry currentEntry = null;
01454: ArrayList<GoToFileListEntry> list;
01455: list = new ArrayList<GoToFileListEntry>(docs.size());
01456: for (OpenDefinitionsDocument d : docs) {
01457: GoToFileListEntry entry = new GoToFileListEntry(d, d
01458: .toString());
01459: if (d.equals(_model.getActiveDocument()))
01460: currentEntry = entry;
01461: list.add(entry);
01462: }
01463:
01464: PredictiveInputModel<GoToFileListEntry> pim = new PredictiveInputModel<GoToFileListEntry>(
01465: true,
01466: new PredictiveInputModel.PrefixStrategy<GoToFileListEntry>(),
01467: list);
01468: OpenDefinitionsDocument odd = getCurrentDefPane()
01469: .getOpenDefDocument();
01470: odd.acquireReadLock();
01471: String mask = "";
01472: try {
01473: int loc = getCurrentDefPane().getCaretPosition();
01474: String s = odd.getText();
01475: // find start
01476: int start = loc;
01477: while (start > 0) {
01478: if (!Character
01479: .isJavaIdentifierPart(s.charAt(start - 1))) {
01480: break;
01481: }
01482: --start;
01483: }
01484: while ((start < s.length())
01485: && (!Character.isJavaIdentifierStart(s
01486: .charAt(start))) && (start < loc)) {
01487: ++start;
01488: }
01489: // find end
01490: int end = loc - 1;
01491: while (end < s.length() - 1) {
01492: if (!Character.isJavaIdentifierPart(s.charAt(end + 1))) {
01493: break;
01494: }
01495: ++end;
01496: }
01497: if ((start >= 0) && (end < s.length())) {
01498: mask = s.substring(start, end + 1);
01499: pim.setMask(mask);
01500: }
01501: } finally {
01502: odd.releaseReadLock();
01503: }
01504:
01505: // Utilities.show("Matching items are: " + pim.getMatchingItems());
01506:
01507: if (pim.getMatchingItems().size() == 1) {
01508: // exactly one match, go to file
01509: if (pim.getCurrentItem() != null) {
01510: // boolean docChanged = !pim.getCurrentItem().doc.equals(_model.getActiveDocument());
01511: // if (docChanged) { addToBrowserHistory(); }
01512: _model.setActiveDocument(pim.getCurrentItem().doc);
01513: // if (docChanged) {
01514: // // defer executing this code until after active document switch (if any) is complete
01515: // EventQueue.invokeLater(new Runnable() {
01516: // public void run() { addToBrowserHistory(); } });
01517: // }
01518: }
01519: } else {
01520: // try appending ".java" and see if it's unique
01521: pim.extendMask(".java");
01522: if (pim.getMatchingItems().size() == 1) {
01523: // exactly one match with ".java" appended, go to file
01524: if (pim.getCurrentItem() != null) {
01525: // boolean docChanged = !pim.getCurrentItem().doc.equals(_model.getActiveDocument());
01526: // if (docChanged) { addToBrowserHistory(); }
01527: _model.setActiveDocument(pim.getCurrentItem().doc);
01528: // if (docChanged) {
01529: // // defer executing this code until after active document switch (if any) is complete
01530: // EventQueue.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
01531: // }
01532: }
01533: } else {
01534: // not exactly one match
01535: pim.setMask(mask);
01536: if (pim.getMatchingItems().size() == 0) {
01537: // if there are no matches, shorten the mask until there is at least one
01538: mask = pim.getMask();
01539: while (mask.length() > 0) {
01540: mask = mask.substring(0, mask.length() - 1);
01541: pim.setMask(mask);
01542: if (pim.getMatchingItems().size() > 0) {
01543: break;
01544: }
01545: }
01546: }
01547: initGotoFileDialog();
01548: _gotoFileDialog.setModel(true, pim); // ignore case
01549: if (currentEntry != null)
01550: _gotoFileDialog.setCurrentItem(currentEntry);
01551: hourglassOn();
01552: /* The following predicate suppresses the display of the dialog during unit testing. If the unit test is revised
01553: * to confirm that the dialog is displayed, this test must be removed. */
01554: if (MainFrame.this .isVisible())
01555: _gotoFileDialog.setVisible(true); // predicate suppresses display in unit tests
01556: }
01557: }
01558: }
01559:
01560: /** Goes to the file specified by the word the cursor is on. */
01561: final Action gotoFileUnderCursorAction = new AbstractAction(
01562: "Go to File Under Cursor") {
01563: public void actionPerformed(ActionEvent ae) {
01564: _gotoFileUnderCursor();
01565: }
01566: };
01567:
01568: /** Wrapper class for the "Open Javadoc" and "Auto Import" dialog list entries.
01569: * Provides the ability to have the same class name in there multiple times in different packages.
01570: */
01571: private static class JavaAPIListEntry implements
01572: Comparable<JavaAPIListEntry> {
01573: private final String str, fullStr;
01574: private final URL url;
01575:
01576: public JavaAPIListEntry(String s, String full, URL u) {
01577: str = s;
01578: fullStr = full;
01579: url = u;
01580: }
01581:
01582: public String toString() {
01583: return str;
01584: }
01585:
01586: public String getFullString() {
01587: return fullStr;
01588: }
01589:
01590: public URL getURL() {
01591: return url;
01592: }
01593:
01594: public int compareTo(JavaAPIListEntry other) {
01595: return str.toLowerCase().compareTo(other.str.toLowerCase());
01596: }
01597:
01598: public boolean equals(Object other) {
01599: if (!(other instanceof JavaAPIListEntry))
01600: return false;
01601: return fullStr.equals(((JavaAPIListEntry) other).fullStr);
01602: }
01603:
01604: public int hashCode() {
01605: return fullStr.hashCode();
01606: }
01607: }
01608:
01609: /** Reset the position of the "Open Javadoc" dialog. */
01610: public void resetOpenJavadocDialogPosition() {
01611: initOpenJavadocDialog();
01612: _openJavadocDialog.setFrameState("default");
01613: if (DrJava.getConfig().getSetting(
01614: DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) {
01615: DrJava.getConfig().setSetting(DIALOG_OPENJAVADOC_STATE,
01616: "default");
01617: }
01618: }
01619:
01620: /** Initialize dialog if necessary. */
01621: void initOpenJavadocDialog() {
01622: if (_openJavadocDialog == null) {
01623: PredictiveInputFrame.InfoSupplier<JavaAPIListEntry> info = new PredictiveInputFrame.InfoSupplier<JavaAPIListEntry>() {
01624: public String apply(JavaAPIListEntry entry) {
01625: return entry.getFullString();
01626: }
01627: };
01628: PredictiveInputFrame.CloseAction<JavaAPIListEntry> okAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() {
01629: public Object apply(
01630: PredictiveInputFrame<JavaAPIListEntry> p) {
01631: if (p.getItem() != null) {
01632: PlatformFactory.ONLY.openURL(p.getItem()
01633: .getURL());
01634: }
01635: hourglassOff();
01636: return null;
01637: }
01638: };
01639: PredictiveInputFrame.CloseAction<JavaAPIListEntry> cancelAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() {
01640: public Object apply(
01641: PredictiveInputFrame<JavaAPIListEntry> p) {
01642: hourglassOff();
01643: return null;
01644: }
01645: };
01646: java.util.ArrayList<PredictiveInputModel.MatchingStrategy<JavaAPIListEntry>> strategies = new java.util.ArrayList<PredictiveInputModel.MatchingStrategy<JavaAPIListEntry>>();
01647: strategies
01648: .add(new PredictiveInputModel.FragmentStrategy<JavaAPIListEntry>());
01649: strategies
01650: .add(new PredictiveInputModel.PrefixStrategy<JavaAPIListEntry>());
01651: strategies
01652: .add(new PredictiveInputModel.RegExStrategy<JavaAPIListEntry>());
01653: _openJavadocDialog = new PredictiveInputFrame<JavaAPIListEntry>(
01654: MainFrame.this ,
01655: "Open Java API Javadoc Webpage",
01656: true, // force
01657: true, // ignore case
01658: info, strategies, okAction, cancelAction,
01659: new JavaAPIListEntry("dummy", "dummy", null)) {
01660: public void setOwnerEnabled(boolean b) {
01661: if (b) {
01662: hourglassOff();
01663: } else {
01664: hourglassOn();
01665: }
01666: }
01667: };
01668: // putting one dummy entry in the list; it will be changed later anyway
01669:
01670: if (DrJava.getConfig().getSetting(
01671: DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue()) {
01672: _openJavadocDialog.setFrameState(DrJava.getConfig()
01673: .getSetting(DIALOG_OPENJAVADOC_STATE));
01674: }
01675: generateJavaAPIList();
01676: }
01677: }
01678:
01679: /** Generate Java API class list. */
01680: public void generateJavaAPIList() {
01681: if (_javaAPIList == null) {
01682: // generate list
01683: String linkVersion = DrJava.getConfig().getSetting(
01684: JAVADOC_LINK_VERSION);
01685: String base = "";
01686: String suffix = "";
01687: if (linkVersion.equals(JAVADOC_1_3_TEXT)) {
01688: base = DrJava.getConfig().getSetting(JAVADOC_1_3_LINK);
01689: suffix = "/allclasses-1.3.html";
01690: } else if (linkVersion.equals(JAVADOC_1_4_TEXT)) {
01691: base = DrJava.getConfig().getSetting(JAVADOC_1_4_LINK);
01692: suffix = "/allclasses-1.4.html";
01693: } else if (linkVersion.equals(JAVADOC_1_5_TEXT)) {
01694: base = DrJava.getConfig().getSetting(JAVADOC_1_5_LINK);
01695: suffix = "/allclasses-1.5.html";
01696: } else {
01697: // no valid Javadoc URL
01698: return;
01699: }
01700: // TODO: put this in an AsyncTask
01701: try {
01702: _javaAPIList = new ArrayList<JavaAPIListEntry>();
01703: URL url = MainFrame.class
01704: .getResource("/edu/rice/cs/drjava/docs/javaapi"
01705: + suffix);
01706: BufferedReader br = new BufferedReader(
01707: new InputStreamReader(url.openStream()));
01708: String line = br.readLine();
01709: while (line != null) {
01710: final String aText = "<a href=\"";
01711: int aPos = line.toLowerCase().indexOf(aText);
01712: int aEndPos = line.toLowerCase().indexOf(
01713: ".html\" ", aPos);
01714: if ((aPos >= 0) && (aEndPos >= 0)) {
01715: String link = line.substring(aPos
01716: + aText.length(), aEndPos);
01717: String fullClassName = link.replace('/', '.');
01718: String simpleClassName = fullClassName;
01719: int lastDot = fullClassName.lastIndexOf('.');
01720: if (lastDot >= 0) {
01721: simpleClassName = fullClassName
01722: .substring(lastDot + 1);
01723: }
01724: try {
01725: _javaAPIList
01726: .add(new JavaAPIListEntry(
01727: simpleClassName,
01728: fullClassName, new URL(base
01729: + "/" + link
01730: + ".html")));
01731: } catch (MalformedURLException mue) { /* ignore, we'll just not put this class in the list */
01732: }
01733: }
01734: line = br.readLine();
01735: }
01736: } catch (IOException ioe) { /* ignore, we'll just have an incomplete list */
01737: }
01738: if (_javaAPIList.size() == 0) {
01739: _javaAPIList = null;
01740: }
01741: }
01742: }
01743:
01744: /** The "Open Javadoc" dialog instance. */
01745: PredictiveInputFrame<JavaAPIListEntry> _openJavadocDialog = null;
01746:
01747: /** The list of Java API classes. */
01748: List<JavaAPIListEntry> _javaAPIList = null;
01749:
01750: /** Asks the user for a file name and goes there. */
01751: private Action _openJavadocAction = new AbstractAction(
01752: "Open Java API Javadoc...") {
01753: public void actionPerformed(ActionEvent ae) {
01754: initOpenJavadocDialog();
01755: _openJavadocDialog.setItems(true, _javaAPIList); // ignore case
01756: hourglassOn();
01757: _openJavadocDialog.setVisible(true);
01758: }
01759: };
01760:
01761: /** Opens the Javadoc specified by the word the cursor is on. */
01762: void _openJavadocUnderCursor() {
01763: generateJavaAPIList();
01764: if (_javaAPIList == null) {
01765: // Utilities.show("Cannot load Java API class list. No network connectivity?");
01766: return;
01767: }
01768: PredictiveInputModel<JavaAPIListEntry> pim = new PredictiveInputModel<JavaAPIListEntry>(
01769: true,
01770: new PredictiveInputModel.PrefixStrategy<JavaAPIListEntry>(),
01771: _javaAPIList);
01772: OpenDefinitionsDocument odd = getCurrentDefPane()
01773: .getOpenDefDocument();
01774: odd.acquireReadLock();
01775: String mask = "";
01776: try {
01777: int loc = getCurrentDefPane().getCaretPosition();
01778: String s = odd.getText();
01779: // find start
01780: int start = loc;
01781: while (start > 0) {
01782: if (!Character
01783: .isJavaIdentifierPart(s.charAt(start - 1))) {
01784: break;
01785: }
01786: --start;
01787: }
01788: while ((start < s.length())
01789: && (!Character.isJavaIdentifierStart(s
01790: .charAt(start))) && (start < loc)) {
01791: ++start;
01792: }
01793: // find end
01794: int end = loc - 1;
01795: while (end < s.length() - 1) {
01796: if (!Character.isJavaIdentifierPart(s.charAt(end + 1))) {
01797: break;
01798: }
01799: ++end;
01800: }
01801: if ((start >= 0) && (end < s.length())) {
01802: mask = s.substring(start, end + 1);
01803: pim.setMask(mask);
01804: }
01805: } finally {
01806: odd.releaseReadLock();
01807: }
01808:
01809: // Utilities.show("Matching items are: " + pim.getMatchingItems());
01810:
01811: if (pim.getMatchingItems().size() == 1) {
01812: // exactly one match, go to file
01813: if (pim.getCurrentItem() != null) {
01814: PlatformFactory.ONLY.openURL(pim.getCurrentItem()
01815: .getURL());
01816: }
01817: } else {
01818: // try appending ".java" and see if it's unique
01819: pim.extendMask(".java");
01820: if (pim.getMatchingItems().size() == 1) {
01821: // exactly one match with ".java" appended, go to file
01822: if (pim.getCurrentItem() != null) {
01823: PlatformFactory.ONLY.openURL(pim.getCurrentItem()
01824: .getURL());
01825: }
01826: } else {
01827: // not exactly one match
01828: pim.setMask(mask);
01829: JavaAPIListEntry foundItem = null;
01830: int found = 0;
01831: if (pim.getMatchingItems().size() == 0) {
01832: // if there are no matches, shorten the mask until there is at least one
01833: mask = pim.getMask();
01834: while (mask.length() > 0) {
01835: mask = mask.substring(0, mask.length() - 1);
01836: pim.setMask(mask);
01837: if (pim.getMatchingItems().size() > 0) {
01838: break;
01839: }
01840: }
01841: } else {
01842: // there are several matches, see if there is an exact match
01843: for (JavaAPIListEntry e : pim.getMatchingItems()) {
01844: if (e.toString().equalsIgnoreCase(mask)) {
01845: ++found;
01846: foundItem = e;
01847: }
01848: }
01849: }
01850: if (found == 1) {
01851: // open unique item and return
01852: PlatformFactory.ONLY.openURL(pim.getCurrentItem()
01853: .getURL());
01854: } else {
01855: initOpenJavadocDialog();
01856: _openJavadocDialog.setModel(true, pim); // ignore case
01857: hourglassOn();
01858: _openJavadocDialog.setVisible(true);
01859: }
01860: }
01861: }
01862: }
01863:
01864: /** Open Javadoc page specified by the word the cursor is on. */
01865: final Action _openJavadocUnderCursorAction = new AbstractAction(
01866: "Open Java API Javadoc for Word Under Cursor...") {
01867: public void actionPerformed(ActionEvent ae) {
01868: _openJavadocUnderCursor();
01869: }
01870: };
01871:
01872: /** Reset the position of the "Complete Word" dialog. */
01873: public void resetCompleteWordDialogPosition() {
01874: initCompleteWordDialog();
01875: _completeWordDialog.setFrameState("default");
01876: if (DrJava.getConfig().getSetting(
01877: DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) {
01878: DrJava.getConfig().setSetting(DIALOG_COMPLETE_WORD_STATE,
01879: "default");
01880: }
01881: }
01882:
01883: /** Initialize dialog if necessary. */
01884: void initCompleteWordDialog() {
01885: if (_completeWordDialog == null) {
01886: PredictiveInputFrame.CloseAction<GoToFileListEntry> okAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
01887: public Object apply(
01888: PredictiveInputFrame<GoToFileListEntry> p) {
01889: if (p.getItem() != null) {
01890: OpenDefinitionsDocument odd = getCurrentDefPane()
01891: .getOpenDefDocument();
01892: try {
01893: String mask = "";
01894: int loc = getCurrentDefPane()
01895: .getCaretPosition();
01896: String s = odd.getText(
01897: AbstractDJDocument.DOCSTART, loc);
01898:
01899: // check that we're at the end of a word
01900: if ((loc < s.length())
01901: && (!Character.isWhitespace(s
01902: .charAt(loc)))
01903: && ("()[]{}<>.,:;/*+-!~&|%"
01904: .indexOf(s.charAt(loc)) == -1))
01905: return null;
01906:
01907: // find start
01908: int start = loc;
01909: while (start > 0) {
01910: if (!Character.isJavaIdentifierPart(s
01911: .charAt(start - 1))) {
01912: break;
01913: }
01914: --start;
01915: }
01916: while ((start < s.length())
01917: && (!Character
01918: .isJavaIdentifierStart(s
01919: .charAt(start)))
01920: && (start < loc)) {
01921: ++start;
01922: }
01923:
01924: if (!s.substring(start, loc).equals(
01925: p.getItem().toString())) {
01926: odd.remove(start, loc - start);
01927: odd.insertString(start, p.getItem()
01928: .toString(), null);
01929: }
01930: } catch (BadLocationException ble) { /* ignore, just don't auto-complete */
01931: } finally {
01932: odd.releaseWriteLock();
01933: }
01934: }
01935: hourglassOff();
01936: return null;
01937: }
01938: };
01939: PredictiveInputFrame.CloseAction<GoToFileListEntry> cancelAction = new PredictiveInputFrame.CloseAction<GoToFileListEntry>() {
01940: public Object apply(
01941: PredictiveInputFrame<GoToFileListEntry> p) {
01942: hourglassOff();
01943: return null;
01944: }
01945: };
01946: java.util.ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>> strategies = new java.util.ArrayList<PredictiveInputModel.MatchingStrategy<GoToFileListEntry>>();
01947: strategies
01948: .add(new PredictiveInputModel.FragmentStrategy<GoToFileListEntry>());
01949: strategies
01950: .add(new PredictiveInputModel.PrefixStrategy<GoToFileListEntry>());
01951: strategies
01952: .add(new PredictiveInputModel.RegExStrategy<GoToFileListEntry>());
01953: _completeWordDialog = new PredictiveInputFrame<GoToFileListEntry>(
01954: MainFrame.this , "Auto-Complete Word",
01955: true, // force
01956: true, // ignore case
01957: null, strategies, okAction, cancelAction,
01958: new GoToFileListEntry(null, "dummy")) {
01959: public void setOwnerEnabled(boolean b) {
01960: if (b) {
01961: hourglassOff();
01962: } else {
01963: hourglassOn();
01964: }
01965: }
01966: };
01967: // putting one dummy entry in the list; it will be changed later anyway
01968:
01969: if (DrJava.getConfig().getSetting(
01970: DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue()) {
01971: _completeWordDialog.setFrameState(DrJava.getConfig()
01972: .getSetting(DIALOG_COMPLETE_WORD_STATE));
01973: }
01974: }
01975: }
01976:
01977: /** The "Complete File" dialog instance. */
01978: volatile PredictiveInputFrame<GoToFileListEntry> _completeFileDialog = null;
01979: /** The "Complete Word" dialog instance. */
01980: volatile PredictiveInputFrame<GoToFileListEntry> _completeWordDialog = null;
01981:
01982: /** Complete the word the cursor is on. */
01983: void _completeWordUnderCursor() {
01984: List<OpenDefinitionsDocument> docs = _model
01985: .getOpenDefinitionsDocuments();
01986: if ((docs == null) || (docs.size() == 0))
01987: return; // do nothing
01988:
01989: GoToFileListEntry currentEntry = null;
01990: ArrayList<GoToFileListEntry> list;
01991: if ((DrJava.getConfig().getSetting(
01992: DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue())
01993: && (_completeClassList.size() > 0)) {
01994: list = _completeClassList;
01995: } else {
01996: list = new ArrayList<GoToFileListEntry>(docs.size());
01997: for (OpenDefinitionsDocument d : docs) {
01998: if (d.isUntitled())
01999: continue;
02000: String str = d.toString();
02001: if (str.lastIndexOf('.') >= 0) {
02002: str = str.substring(0, str.lastIndexOf('.'));
02003: }
02004: GoToFileListEntry entry = new GoToFileListEntry(d, str);
02005: if (d.equals(_model.getActiveDocument()))
02006: currentEntry = entry;
02007: list.add(entry);
02008: }
02009: }
02010:
02011: PredictiveInputModel<GoToFileListEntry> pim = new PredictiveInputModel<GoToFileListEntry>(
02012: true,
02013: new PredictiveInputModel.PrefixStrategy<GoToFileListEntry>(),
02014: list);
02015: OpenDefinitionsDocument odd = getCurrentDefPane()
02016: .getOpenDefDocument();
02017: odd.acquireWriteLock();
02018: boolean uniqueMatch = true;
02019: try {
02020: String mask = "";
02021: int loc = getCurrentDefPane().getCaretPosition();
02022: String s = odd.getText(AbstractDJDocument.DOCSTART, loc);
02023:
02024: // check that we're at the end of a word
02025: if ((loc < s.length())
02026: && (!Character.isWhitespace(s.charAt(loc)))
02027: && ("()[]{}<>.,:;/*+-!~&|%".indexOf(s.charAt(loc)) == -1))
02028: return;
02029:
02030: // find start
02031: int start = loc;
02032: while (start > 0) {
02033: if (!Character
02034: .isJavaIdentifierPart(s.charAt(start - 1))) {
02035: break;
02036: }
02037: --start;
02038: }
02039: while ((start < s.length())
02040: && (!Character.isJavaIdentifierStart(s
02041: .charAt(start))) && (start < loc)) {
02042: ++start;
02043: }
02044:
02045: int end = loc - 1;
02046:
02047: if ((start >= 0) && (end < s.length())) {
02048: mask = s.substring(start, end + 1);
02049: pim.setMask(mask);
02050: }
02051:
02052: if (pim.getMatchingItems().size() == 1) {
02053: if (pim.getCurrentItem() != null) {
02054: // exactly one match, auto-complete
02055: if (!s.substring(start, loc).equals(
02056: pim.getCurrentItem().toString())) {
02057: odd.remove(start, loc - start);
02058: odd.insertString(start, pim.getCurrentItem()
02059: .toString(), null);
02060: }
02061: return;
02062: }
02063: } else {
02064: // not exactly one match
02065: uniqueMatch = false;
02066: pim.setMask(mask);
02067: if (pim.getMatchingItems().size() == 0) {
02068: // if there are no matches, shorten the mask until there is at least one
02069: mask = pim.getMask();
02070: while (mask.length() > 0) {
02071: mask = mask.substring(0, mask.length() - 1);
02072: pim.setMask(mask);
02073: if (pim.getMatchingItems().size() > 0) {
02074: break;
02075: }
02076: }
02077: }
02078: initCompleteWordDialog();
02079: _completeWordDialog.setModel(true, pim); // ignore case
02080: _completeWordDialog.selectStrategy();
02081: if (currentEntry != null)
02082: _completeWordDialog.setCurrentItem(currentEntry);
02083: hourglassOn();
02084: _completeWordDialog.setVisible(true);
02085: }
02086: } catch (BadLocationException ble) { /* ignore, just don't auto-complete */
02087: } finally {
02088: if (uniqueMatch) {
02089: odd.releaseWriteLock();
02090: }
02091: }
02092: }
02093:
02094: /** Auto-completes word the cursor is on. */
02095: final Action completeWordUnderCursorAction = new AbstractAction(
02096: "Auto-Complete Word Under Cursor") {
02097: public void actionPerformed(ActionEvent ae) {
02098: _completeWordUnderCursor();
02099: }
02100: };
02101:
02102: /** Indents the current selection. */
02103: private final Action _indentLinesAction = new AbstractAction(
02104: "Indent Line(s)") {
02105: public void actionPerformed(ActionEvent ae) {
02106: _currentDefPane.endCompoundEdit();
02107: _currentDefPane.indent();
02108: }
02109: };
02110:
02111: /** Action for commenting out a block of text using wing comments. */
02112: private final Action _commentLinesAction = new AbstractAction(
02113: "Comment Line(s)") {
02114: public void actionPerformed(ActionEvent ae) {
02115: hourglassOn();
02116: try {
02117: commentLines();
02118: } finally {
02119: hourglassOff();
02120: }
02121: }
02122: };
02123:
02124: /** Action for un-commenting a block of commented text. */
02125: private final Action _uncommentLinesAction = new AbstractAction(
02126: "Uncomment Line(s)") {
02127: public void actionPerformed(ActionEvent ae) {
02128: hourglassOn();
02129: try {
02130: uncommentLines();
02131: } finally {
02132: hourglassOff();
02133: }
02134: }
02135: };
02136:
02137: /** Clears DrJava's output console. */
02138: private final Action _clearConsoleAction = new AbstractAction(
02139: "Clear Console") {
02140: public void actionPerformed(ActionEvent ae) {
02141: _model.resetConsole();
02142: }
02143: };
02144:
02145: /** Shows the DebugConsole. */
02146: private final Action _showDebugConsoleAction = new AbstractAction(
02147: "Show DrJava Debug Console") {
02148: public void actionPerformed(ActionEvent e) {
02149: DrJavaRoot.showDrJavaDebugConsole(MainFrame.this );
02150: }
02151: };
02152:
02153: /* Enables the reset interactions command. Not currently used, since this action is NEVER disabled. */
02154: public void enableResetInteractions() {
02155: _resetInteractionsAction.setEnabled(true);
02156: }
02157:
02158: /** Resets the Interactions pane. */
02159: private final Action _resetInteractionsAction = new AbstractAction(
02160: "Reset Interactions") {
02161: public void actionPerformed(ActionEvent ae) {
02162: if (!DrJava.getConfig().getSetting(
02163: INTERACTIONS_RESET_PROMPT).booleanValue()) {
02164: _doResetInteractions();
02165: return;
02166: }
02167:
02168: String title = "Confirm Reset Interactions";
02169: String message = "Are you sure you want to reset the Interactions Pane?";
02170: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
02171: MainFrame.this , title, message);
02172: int rc = dialog.show();
02173: if (rc == JOptionPane.YES_OPTION) {
02174: _doResetInteractions();
02175:
02176: if (dialog.getCheckBoxValue()) {
02177: DrJava.getConfig().setSetting(
02178: INTERACTIONS_RESET_PROMPT, Boolean.FALSE);
02179: }
02180: }
02181: }
02182: };
02183:
02184: private void _doResetInteractions() {
02185: _tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
02186: updateStatusField("Resetting Interactions");
02187:
02188: _model.getInteractionsModel().enableRestart();
02189: // Lots of work, so use another thread
02190: new Thread(new Runnable() {
02191: public void run() {
02192: _model.resetInteractions(_model.getWorkingDirectory(),
02193: true);
02194: }
02195: }).start();
02196: }
02197:
02198: /** Defines actions that displays the interactions classpath. */
02199: private final Action _viewInteractionsClassPathAction = new AbstractAction(
02200: "View Interactions Classpath...") {
02201: public void actionPerformed(ActionEvent e) {
02202: viewInteractionsClassPath();
02203: }
02204: };
02205:
02206: /** Displays the interactions classpath. */
02207: public void viewInteractionsClassPath() {
02208: String cp = IterUtil.multilineToString(_model
02209: .getInteractionsClassPath());
02210: new DrJavaScrollableDialog(this , "Interactions Classpath",
02211: "Current Interpreter Classpath", cp).show();
02212: }
02213:
02214: /** Shows the user documentation. */
02215: private final Action _helpAction = new AbstractAction("Help") {
02216: public void actionPerformed(ActionEvent ae) {
02217: // Create frame if we haven't yet
02218: // if (_helpFrame == null) {
02219: // _helpFrame = new HelpFrame();
02220: // }
02221: _helpFrame.setVisible(true);
02222: }
02223: };
02224:
02225: /** Shows the quick start documentation. */
02226: private final Action _quickStartAction = new AbstractAction(
02227: "QuickStart") {
02228: public void actionPerformed(ActionEvent ae) {
02229: // Create frame if we haven't yet
02230: // if (_quickStartFrame == null) {
02231: // _quickStartFrame = new QuickStartFrame();
02232: // }
02233: _quickStartFrame.setVisible(true);
02234: }
02235: };
02236:
02237: /** Pops up an info dialog. */
02238: private final Action _aboutAction = new AbstractAction("About") {
02239: public void actionPerformed(ActionEvent ae) {
02240: // Create dialog if we haven't yet
02241: // if (_aboutDialog == null) _aboutDialog = new AboutDialog(MainFrame.this);
02242: Point p = MainFrame.this .getLocation();
02243: _aboutDialog.setVisible(true);
02244: // _aboutDialog.setLocation(p.x+(MainFrame.this.getWidth() - _aboutDialog.getWidth())/2,
02245: // p.y+(MainFrame.this.getHeight()-_aboutDialog.getHeight())/2);
02246:
02247: }
02248: };
02249:
02250: /** Pops up the DrJava errors dialog. */
02251: private final Action _errorsAction = new AbstractAction(
02252: "DrJava Errors") {
02253: public void actionPerformed(ActionEvent ae) {
02254: setPopupLoc(DrJavaErrorWindow.singleton());
02255: DrJavaErrorWindow.singleton().setVisible(true);
02256: }
02257: };
02258:
02259: /** Switches to next document. */
02260: private final Action _switchToNextAction = new AbstractAction(
02261: "Next Document") {
02262: public void actionPerformed(ActionEvent ae) {
02263: this .setEnabled(false);
02264: if (_docSplitPane.getDividerLocation() < _docSplitPane
02265: .getMinimumDividerLocation())
02266: _docSplitPane.setDividerLocation(DrJava.getConfig()
02267: .getSetting(DOC_LIST_WIDTH).intValue());
02268: //disables switching documents while the next one is opening up, in order to prevent out of control switching
02269: // addToBrowserHistory();
02270: _model.setActiveNextDocument();
02271: _findReplace.updateFirstDocInSearch();
02272: this .setEnabled(true);
02273: // // defer executing this code until after active document switch (if any) is complete
02274: // EventQueue.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
02275: }
02276: };
02277:
02278: /** Switches to previous document. */
02279: private final Action _switchToPrevAction = new AbstractAction(
02280: "Previous Document") {
02281: public void actionPerformed(ActionEvent ae) {
02282: this .setEnabled(false);
02283: if (_docSplitPane.getDividerLocation() < _docSplitPane
02284: .getMinimumDividerLocation())
02285: _docSplitPane.setDividerLocation(DrJava.getConfig()
02286: .getSetting(DOC_LIST_WIDTH).intValue());
02287: // addToBrowserHistory();
02288: _model.setActivePreviousDocument();
02289: _findReplace.updateFirstDocInSearch();
02290: this .setEnabled(true);
02291: // // defer executing this code until after active document switch (if any) is complete
02292: // EventQueue.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
02293: }
02294: };
02295:
02296: /** Switches focus to next pane. */
02297: private final Action _switchToNextPaneAction = new AbstractAction(
02298: "Next Pane") {
02299: public void actionPerformed(ActionEvent ae) {
02300: if (_mainSplit.getDividerLocation() > _mainSplit
02301: .getMaximumDividerLocation())
02302: _mainSplit.resetToPreferredSizes();
02303: this .setEnabled(false);
02304: _switchPaneFocus(true);
02305: this .setEnabled(true);
02306: }
02307: };
02308:
02309: /** Browse back in the browser history. */
02310: private final Action _browseBackAction = new AbstractAction(
02311: "Browse Back") {
02312: public void actionPerformed(ActionEvent ae) {
02313: updateStatusField("Browsing Back");
02314: this .setEnabled(false);
02315: if (_docSplitPane.getDividerLocation() < _docSplitPane
02316: .getMinimumDividerLocation())
02317: _docSplitPane.setDividerLocation(DrJava.getConfig()
02318: .getSetting(DOC_LIST_WIDTH).intValue());
02319: //disables switching documents while the next one is opening up, in order to prevent out of control switching
02320:
02321: RegionManager rm = _model.getBrowserHistoryManager();
02322:
02323: // add current location to history
02324: addToBrowserHistory();
02325:
02326: // then move back
02327: DocumentRegion r = rm.prevCurrentRegion();
02328: scrollToDocumentAndOffset(r.getDocument(), r
02329: .getStartOffset(), false, false);
02330:
02331: this .setEnabled(true);
02332: }
02333: };
02334:
02335: /** Browse forward in the browser history. */
02336: private final Action _browseForwardAction = new AbstractAction(
02337: "Browse Forward") {
02338: public void actionPerformed(ActionEvent ae) {
02339: updateStatusField("Browsing Forward");
02340: this .setEnabled(false);
02341: if (_docSplitPane.getDividerLocation() < _docSplitPane
02342: .getMinimumDividerLocation())
02343: _docSplitPane.setDividerLocation(DrJava.getConfig()
02344: .getSetting(DOC_LIST_WIDTH).intValue());
02345: //disables switching documents while the next one is opening up, in order to prevent out of control switching
02346:
02347: RegionManager rm = _model.getBrowserHistoryManager();
02348:
02349: // add current location to history
02350: addToBrowserHistory();
02351:
02352: // then move forward
02353: DocumentRegion r = rm.nextCurrentRegion();
02354: scrollToDocumentAndOffset(r.getDocument(), r
02355: .getStartOffset(), false, false);
02356:
02357: this .setEnabled(true);
02358: }
02359: };
02360:
02361: /** Switches focus to previous pane. */
02362: private final Action _switchToPreviousPaneAction = new AbstractAction(
02363: "Previous Pane") {
02364: public void actionPerformed(ActionEvent ae) {
02365: if (_mainSplit.getDividerLocation() > _mainSplit
02366: .getMaximumDividerLocation())
02367: _mainSplit.resetToPreferredSizes();
02368: this .setEnabled(false);
02369: _switchPaneFocus(false);
02370: this .setEnabled(true);
02371: }
02372: };
02373:
02374: /** Go to the closing brace. ReadLock omitted because it only runs on definitions documents in the event thread. */
02375: private final Action _gotoClosingBraceAction = new AbstractAction(
02376: "Go to Closing Brace") {
02377: public void actionPerformed(ActionEvent ae) {
02378: OpenDefinitionsDocument odd = getCurrentDefPane()
02379: .getOpenDefDocument();
02380: // odd.acquireReadLock();
02381: try {
02382: int pos = odd.findNextEnclosingBrace(
02383: getCurrentDefPane().getCaretPosition(), '{',
02384: '}');
02385: if (pos != AbstractDJDocument.ERROR_INDEX) {
02386: getCurrentDefPane().setCaretPosition(pos);
02387: }
02388: } catch (BadLocationException ble) { /* just ignore and don't move */
02389: }
02390: // finally { odd.releaseReadLock(); }
02391: }
02392: };
02393:
02394: /** Go to the opening brace. ReadLock omitted because it only runs on definitions documents in the event thread. */
02395: private final Action _gotoOpeningBraceAction = new AbstractAction(
02396: "Go to Opening Brace") {
02397: public void actionPerformed(ActionEvent ae) {
02398: OpenDefinitionsDocument odd = getCurrentDefPane()
02399: .getOpenDefDocument();
02400: // odd.acquireReadLock();
02401: try {
02402: int pos = odd.findPrevEnclosingBrace(
02403: getCurrentDefPane().getCaretPosition(), '{',
02404: '}');
02405: if (pos != AbstractDJDocument.ERROR_INDEX) {
02406: getCurrentDefPane().setCaretPosition(pos);
02407: }
02408: } catch (BadLocationException ble) { /* just ignore and don't move */
02409: }
02410: // finally { odd.releaseReadLock(); }
02411: }
02412: };
02413:
02414: /** This takes a component and gives it focus, showing it if it's a tab. The interactionsPane and consolePane
02415: * are wrapped in scrollpanes, so we have to specifically check for those and unwrap them.
02416: * @param c the pane to switch focus to
02417: */
02418: private void _switchToPane(Component c) {
02419: Component newC = c;
02420: // if (c == _interactionsContainer) newC = _interactionsPane;
02421: // if (c == _consoleScroll) newC = _consolePane;
02422: showTab(newC);
02423: }
02424:
02425: /** This method allows the user to cycle through the definitions pane and all of the open tabs.
02426: * @param next true if we want to go to the next pane, false if the previous.
02427: */
02428: private void _switchPaneFocus(boolean next) {
02429: int numTabs = _tabbedPane.getTabCount();
02430:
02431: /* If next, then we go to the next tab */
02432: if (next)
02433: _switchToPane(_tabbedPane.getComponentAt((numTabs
02434: + _tabbedPane.getSelectedIndex() + 1)
02435: % numTabs));
02436: else
02437: _switchToPane(_tabbedPane.getComponentAt((numTabs
02438: + _tabbedPane.getSelectedIndex() - 1)
02439: % numTabs));
02440: }
02441:
02442: /** Calls the ConfigFrame to edit preferences */
02443:
02444: private final Action _editPreferencesAction = new AbstractAction(
02445: "Preferences ...") {
02446:
02447: public void actionPerformed(ActionEvent ae) {
02448: // Create frame if we haven't yet
02449: // if (_configFrame == null) {
02450: // _configFrame = new ConfigFrame(MainFrame.this);
02451: // }
02452: _configFrame.setUp();
02453: setPopupLoc(_configFrame);
02454: _configFrame.setVisible(true);
02455: _configFrame.toFront();
02456: }
02457: };
02458:
02459: private volatile AbstractAction _projectPropertiesAction = new AbstractAction(
02460: "Project Properties") {
02461: public void actionPerformed(ActionEvent ae) {
02462: _editProject();
02463: }
02464: };
02465:
02466: /** Enables the debugger */
02467: private final Action _toggleDebuggerAction = new AbstractAction(
02468: "Debug Mode") {
02469: public void actionPerformed(ActionEvent ae) {
02470: this .setEnabled(false);
02471: debuggerToggle();
02472: this .setEnabled(true);
02473: }
02474: };
02475:
02476: /** Resumes debugging */
02477: private final Action _resumeDebugAction = new AbstractAction(
02478: "Resume Debugger") {
02479: public void actionPerformed(ActionEvent ae) {
02480: try {
02481: debuggerResume();
02482: } catch (DebugException de) {
02483: _showDebugError(de);
02484: }
02485: }
02486: };
02487:
02488: /** Steps into the next method call */
02489: private final Action _stepIntoDebugAction = new AbstractAction(
02490: "Step Into") {
02491: public void actionPerformed(ActionEvent ae) {
02492: debuggerStep(Debugger.StepType.STEP_INTO);
02493: }
02494: };
02495:
02496: /** Runs the next line, without stepping into methods */
02497: private final Action _stepOverDebugAction = new AbstractAction(
02498: "Step Over") {
02499: public void actionPerformed(ActionEvent ae) {
02500: debuggerStep(Debugger.StepType.STEP_OVER);
02501: }
02502: };
02503:
02504: /** Steps out of the next method call */
02505: private final Action _stepOutDebugAction = new AbstractAction(
02506: "Step Out") {
02507: public void actionPerformed(ActionEvent ae) {
02508: debuggerStep(Debugger.StepType.STEP_OUT);
02509: }
02510: };
02511:
02512: /** Suspend debugging */
02513: /*private Action _suspendDebugAction =
02514: new AbstractAction("Suspend Debugger")
02515: {
02516: public void actionPerformed(ActionEvent ae) {
02517: _debugSuspend();
02518: }
02519: };*/
02520:
02521: /** Toggles a breakpoint on the current line */
02522: final Action _toggleBreakpointAction = new AbstractAction(
02523: "Toggle Breakpoint on Current Line") {
02524: public void actionPerformed(ActionEvent ae) {
02525: debuggerToggleBreakpoint();
02526: }
02527: };
02528:
02529: /** Clears all breakpoints */
02530: private final Action _clearAllBreakpointsAction = new AbstractAction(
02531: "Clear All Breakpoints") {
02532: public void actionPerformed(ActionEvent ae) {
02533: debuggerClearAllBreakpoints();
02534: }
02535: };
02536:
02537: /** Shows the breakpoints tab. */
02538: private final Action _breakpointsPanelAction = new AbstractAction(
02539: "Breakpoints") {
02540: public void actionPerformed(ActionEvent ae) {
02541: if (_mainSplit.getDividerLocation() > _mainSplit
02542: .getMaximumDividerLocation())
02543: _mainSplit.resetToPreferredSizes();
02544: if (!_breakpointsPanel.isDisplayed()) {
02545: showTab(_breakpointsPanel);
02546: }
02547: _breakpointsPanel.setVisible(true);
02548: _tabbedPane.setSelectedComponent(_breakpointsPanel);
02549: // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _breakpointsPanel has been selected
02550: EventQueue.invokeLater(new Runnable() {
02551: public void run() {
02552: _breakpointsPanel.requestFocusInWindow();
02553: }
02554: });
02555: }
02556: };
02557:
02558: /** Shows the bookmarks tab. */
02559: private final Action _bookmarksPanelAction = new AbstractAction(
02560: "Bookmarks") {
02561: public void actionPerformed(ActionEvent ae) {
02562: if (_mainSplit.getDividerLocation() > _mainSplit
02563: .getMaximumDividerLocation())
02564: _mainSplit.resetToPreferredSizes();
02565: if (!_bookmarksPanel.isDisplayed()) {
02566: showTab(_bookmarksPanel);
02567: }
02568: _bookmarksPanel.setVisible(true);
02569: _tabbedPane.setSelectedComponent(_bookmarksPanel);
02570: // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the _bookmarksPanel has been selected
02571: EventQueue.invokeLater(new Runnable() {
02572: public void run() {
02573: _bookmarksPanel.requestFocusInWindow();
02574: }
02575: });
02576: }
02577: };
02578:
02579: /** Toggles a bookmark. */
02580: private final Action _toggleBookmarkAction = new AbstractAction(
02581: "Toggle Bookmark") {
02582: public void actionPerformed(ActionEvent ae) {
02583: toggleBookmark();
02584: }
02585: };
02586:
02587: /** Toggle a bookmark. */
02588: public void toggleBookmark() {
02589: assert EventQueue.isDispatchThread();
02590: addToBrowserHistory();
02591: final OpenDefinitionsDocument doc = _model.getActiveDocument();
02592:
02593: int startSel = _currentDefPane.getSelectionStart();
02594: int endSel = _currentDefPane.getSelectionEnd();
02595: // doc.acquireReadLock();
02596: try {
02597: if (startSel > endSel) {
02598: int temp = startSel;
02599: startSel = endSel;
02600: endSel = temp;
02601: } else if (startSel == endSel) {
02602: // nothing selected
02603: endSel = doc.getLineEndPos(startSel);
02604: startSel = doc.getLineStartPos(startSel);
02605: }
02606: DocumentRegion r = _model.getBookmarkManager()
02607: .getRegionOverlapping(doc, startSel, endSel);
02608: if (r == null) {
02609: final Position startPos = doc.createPosition(startSel);
02610: final Position endPos = doc.createPosition(endSel);
02611: SimpleDocumentRegion newR = new SimpleDocumentRegion(
02612: doc, doc.getFile(), startPos.getOffset(),
02613: endPos.getOffset());
02614: _model.getBookmarkManager().addRegion(newR);
02615: } else {
02616: _model.getBookmarkManager().removeRegion(r);
02617: }
02618: } catch (FileMovedException fme) {
02619: throw new UnexpectedException(fme);
02620: } catch (BadLocationException ble) {
02621: throw new UnexpectedException(ble);
02622: }
02623: // finally { doc.releaseReadLock(); }
02624: }
02625:
02626: /** Add the current location to the browser history. */
02627: public void addToBrowserHistory() {
02628: _model.addToBrowserHistory();
02629: }
02630:
02631: /** Create a new find results tab.
02632: * @param rm the region manager that will contain the regions
02633: * @param title the title for the panel
02634: * @return new find results tab. */
02635: public FindResultsPanel createFindResultsPanel(
02636: final RegionManager<MovingDocumentRegion> rm, String title) {
02637: final FindResultsPanel panel = new FindResultsPanel(this , rm,
02638: title);
02639: final Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights = new Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>();
02640: Pair<FindResultsPanel, Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair = new Pair<FindResultsPanel, Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>>(
02641: panel, highlights);
02642: _findResults.add(pair);
02643:
02644: // hook highlighting listener to find results manager
02645: rm
02646: .addListener(new RegionManagerListener<MovingDocumentRegion>() {
02647: public void regionAdded(MovingDocumentRegion r,
02648: int index) {
02649: DefinitionsPane bpPane = getDefPaneGivenODD(r
02650: .getDocument());
02651: highlights.put(r, bpPane.getHighlightManager()
02652: .addHighlight(r.getStartOffset(),
02653: r.getEndOffset(),
02654: panel.getSelectedPainter()));
02655: }
02656:
02657: public void regionChanged(MovingDocumentRegion r,
02658: int index) {
02659: regionRemoved(r);
02660: regionAdded(r, index);
02661: }
02662:
02663: public void regionRemoved(MovingDocumentRegion r) {
02664: HighlightManager.HighlightInfo highlight = highlights
02665: .get(r);
02666: if (highlight != null)
02667: highlight.remove();
02668: highlights.remove(r);
02669: // close the panel when all regions have been removed.
02670: if (rm.getRegions().size() == 0) {
02671: panel._close();
02672: }
02673: }
02674: });
02675:
02676: _tabs.addLast(panel);
02677: panel.getMainPanel().addFocusListener(new FocusAdapter() {
02678: public void focusGained(FocusEvent e) {
02679: _lastFocusOwner = panel;
02680: }
02681: });
02682:
02683: return panel;
02684: }
02685:
02686: /** Shows a find results tab. Only runs in event thread. */
02687: public void showFindResultsPanel(final FindResultsPanel panel) {
02688: assert EventQueue.isDispatchThread();
02689: if (_mainSplit.getDividerLocation() > _mainSplit
02690: .getMaximumDividerLocation())
02691: _mainSplit.resetToPreferredSizes();
02692: if (!panel.isDisplayed())
02693: showTab(panel);
02694: panel.setVisible(true);
02695: _tabbedPane.setSelectedComponent(panel);
02696: // Use SwingUtilties.invokeLater to ensure that focus is set AFTER the findResultsPanel has been selected
02697: EventQueue.invokeLater(new Runnable() {
02698: public void run() {
02699: panel.requestFocusInWindow();
02700: }
02701: });
02702: };
02703:
02704: /** Cuts from the caret to the end of the current line to the clipboard. */
02705: protected final Action _cutLineAction = new AbstractAction(
02706: "Cut Line") {
02707: public void actionPerformed(ActionEvent ae) {
02708: ActionMap _actionMap = _currentDefPane.getActionMap();
02709: int oldCol = _model.getActiveDocument().getCurrentCol();
02710: _actionMap.get(DefaultEditorKit.selectionEndLineAction)
02711: .actionPerformed(ae);
02712: // if oldCol is equal to the current column, then selectionEndLine did
02713: // nothing, so we're at the end of the line and should remove the newline
02714: // character
02715: if (oldCol == _model.getActiveDocument().getCurrentCol()) {
02716: // Puts newline character on the clipboard also, not just content as before.
02717: _actionMap.get(DefaultEditorKit.selectionForwardAction)
02718: .actionPerformed(ae);
02719: cutAction.actionPerformed(ae);
02720: } else
02721: cutAction.actionPerformed(ae);
02722: }
02723: };
02724:
02725: /** Deletes text from the caret to the end of the current line. */
02726: protected final Action _clearLineAction = new AbstractAction(
02727: "Clear Line") {
02728: public void actionPerformed(ActionEvent ae) {
02729: ActionMap _actionMap = _currentDefPane.getActionMap();
02730: _actionMap.get(DefaultEditorKit.selectionEndLineAction)
02731: .actionPerformed(ae);
02732: _actionMap.get(DefaultEditorKit.deleteNextCharAction)
02733: .actionPerformed(ae);
02734: }
02735: };
02736:
02737: /** Moves the caret to the "intelligent" beginning of the line.
02738: * @see #_getBeginLinePos
02739: */
02740: private final Action _beginLineAction = new AbstractAction(
02741: "Begin Line") {
02742: public void actionPerformed(ActionEvent ae) {
02743: int beginLinePos = _getBeginLinePos();
02744: _currentDefPane.setCaretPosition(beginLinePos);
02745: }
02746: };
02747:
02748: /** Selects to the "intelligent" beginning of the line.
02749: * @see #_getBeginLinePos
02750: */
02751: private final Action _selectionBeginLineAction = new AbstractAction(
02752: "Select to Beginning of Line") {
02753: public void actionPerformed(ActionEvent ae) {
02754: int beginLinePos = _getBeginLinePos();
02755: _currentDefPane.moveCaretPosition(beginLinePos);
02756: }
02757: };
02758:
02759: /** Returns the "intelligent" beginning of line. If the caret is to fhe right of the first non-whitespace character,
02760: * the position of the first non-whitespace character is returned. If the caret is on or to the left of the first
02761: * non-whitespace character, the beginning of the line is returned.
02762: */
02763: private int _getBeginLinePos() {
02764: try {
02765: int currPos = _currentDefPane.getCaretPosition();
02766: OpenDefinitionsDocument openDoc = _model
02767: .getActiveDocument();
02768: openDoc.setCurrentLocation(currPos);
02769: return openDoc.getIntelligentBeginLinePos(currPos);
02770: } catch (BadLocationException ble) {
02771: // Shouldn't happen: we're using a legal position
02772: throw new UnexpectedException(ble);
02773: }
02774: }
02775:
02776: private final FileOpenSelector _interactionsHistoryFileSelector = new FileOpenSelector() {
02777: public File[] getFiles() throws OperationCanceledException {
02778: return getOpenFiles(_interactionsHistoryChooser);
02779: }
02780: };
02781:
02782: /** Interprets the commands in a file in the interactions window. */
02783: private final Action _executeHistoryAction = new AbstractAction(
02784: "Execute Interactions History...") {
02785: public void actionPerformed(ActionEvent ae) {
02786: // Show interactions tab
02787: _tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
02788:
02789: _interactionsHistoryChooser
02790: .setDialogTitle("Execute Interactions History");
02791: try {
02792: _model.loadHistory(_interactionsHistoryFileSelector);
02793: } catch (FileNotFoundException fnf) {
02794: _showFileNotFoundError(fnf);
02795: } catch (IOException ioe) {
02796: _showIOError(ioe);
02797: }
02798: _interactionsPane.requestFocusInWindow();
02799: }
02800: };
02801:
02802: /** Closes the currently executing interactions script, if there is one. */
02803: private void _closeInteractionsScript() {
02804: if (_interactionsScriptController != null) {
02805: _interactionsContainer.remove(_interactionsScriptPane);
02806: _interactionsScriptController = null;
02807: _interactionsScriptPane = null;
02808: _tabbedPane.invalidate();
02809: _tabbedPane.repaint();
02810: }
02811: }
02812:
02813: /** Action to load an interactions history as a replayable script. */
02814: private final Action _loadHistoryScriptAction = new AbstractAction(
02815: "Load Interactions History as Script...") {
02816: public void actionPerformed(ActionEvent e) {
02817: try {
02818: _interactionsHistoryChooser
02819: .setDialogTitle("Load Interactions History");
02820: InteractionsScriptModel ism = _model
02821: .loadHistoryAsScript(_interactionsHistoryFileSelector);
02822: _interactionsScriptController = new InteractionsScriptController(
02823: ism, new AbstractAction("Close") {
02824: public void actionPerformed(ActionEvent e) {
02825: _closeInteractionsScript();
02826: _interactionsPane
02827: .requestFocusInWindow();
02828: }
02829: }, _interactionsPane);
02830: _interactionsScriptPane = _interactionsScriptController
02831: .getPane();
02832: _interactionsContainer.add(_interactionsScriptPane,
02833: BorderLayout.EAST);
02834: _tabbedPane.invalidate();
02835: _tabbedPane.repaint();
02836: } catch (FileNotFoundException fnf) {
02837: _showFileNotFoundError(fnf);
02838: } catch (IOException ioe) {
02839: _showIOError(ioe);
02840: } catch (OperationCanceledException oce) {
02841: }
02842: }
02843: };
02844:
02845: /** Save the commands in the interactions window's history to a file */
02846: private final Action _saveHistoryAction = new AbstractAction(
02847: "Save Interactions History...") {
02848: public void actionPerformed(ActionEvent ae) {
02849: String[] options = { "Yes", "No", "Cancel" };
02850: int resp = JOptionPane.showOptionDialog(MainFrame.this ,
02851: "Edit interactions history before saving?",
02852: "Edit History?", JOptionPane.YES_NO_CANCEL_OPTION,
02853: JOptionPane.QUESTION_MESSAGE, null, options,
02854: options[1]);
02855: // Cancel
02856: if (resp == 2 || resp == JOptionPane.CLOSED_OPTION)
02857: return;
02858:
02859: String history = _model.getHistoryAsStringWithSemicolons();
02860:
02861: // Edit the history
02862: if (resp == 0)
02863: history = (new HistorySaveDialog(MainFrame.this ))
02864: .editHistory(history);
02865: if (history == null)
02866: return; // save cancelled
02867:
02868: _interactionsHistoryChooser
02869: .setDialogTitle("Save Interactions History");
02870: FileSaveSelector selector = new FileSaveSelector() {
02871: public File getFile() throws OperationCanceledException {
02872: // Don't try to set the fileName with getSaveFile;
02873: // just display the dialog and get file with getChosenFile, otherwise
02874: // the suggested file name will be whatever document is open.
02875: // ED (8.14.03): Had to add this next block of code from getSaveFile to
02876: // fix bug #788311 "NullPointer when saving history"
02877: File selection = _interactionsHistoryChooser
02878: .getSelectedFile();//_saveChooser.getSelectedFile();
02879: if (selection != null) {
02880: _interactionsHistoryChooser
02881: .setSelectedFile(selection
02882: .getParentFile());
02883: _interactionsHistoryChooser
02884: .setSelectedFile(selection);
02885: _interactionsHistoryChooser
02886: .setSelectedFile(null);
02887: }
02888: // return getSaveFile(_interactionsHistoryChooser);
02889: int rc = _interactionsHistoryChooser
02890: .showSaveDialog(MainFrame.this );
02891: File c = getChosenFile(_interactionsHistoryChooser,
02892: rc);
02893: //Moved from history itself to here to account for bug #989232, non-existant default
02894: //history file found
02895: if (c.getName().indexOf('.') == -1)
02896: c = new File(
02897: c.getAbsolutePath()
02898: + "."
02899: + InteractionsHistoryFilter.HIST_EXTENSION);
02900: _interactionsHistoryChooser.setSelectedFile(c);
02901: return c;
02902: }
02903:
02904: public boolean warnFileOpen(File f) {
02905: return true;
02906: }
02907:
02908: public boolean verifyOverwrite() {
02909: return _verifyOverwrite();
02910: }
02911:
02912: public boolean shouldSaveAfterFileMoved(
02913: OpenDefinitionsDocument doc, File oldFile) {
02914: return true;
02915: }
02916: };
02917:
02918: try {
02919: _model.saveHistory(selector, history);
02920: } catch (IOException ioe) {
02921: _showIOError(new IOException(
02922: "An error occured writing the history to a file"));
02923: }
02924: _interactionsPane.requestFocusInWindow();
02925: }
02926: };
02927:
02928: /** Clears the commands in the interaction history. */
02929: private final Action _clearHistoryAction = new AbstractAction(
02930: "Clear Interactions History") {
02931: public void actionPerformed(ActionEvent ae) {
02932: _model.clearHistory();
02933: _interactionsPane.requestFocusInWindow();
02934: }
02935: };
02936:
02937: /** How DrJava responds to window events. */
02938: private final WindowListener _windowCloseListener = new WindowAdapter() {
02939: public void windowActivated(WindowEvent ev) {
02940: }
02941:
02942: public void windowClosed(WindowEvent ev) {
02943: }
02944:
02945: public void windowClosing(WindowEvent ev) {
02946: _quit();
02947: }
02948:
02949: public void windowDeactivated(WindowEvent ev) {
02950: }
02951:
02952: public void windowDeiconified(WindowEvent ev) {
02953: try {
02954: _model.getActiveDocument().revertIfModifiedOnDisk();
02955: } catch (FileMovedException fme) {
02956: _showFileMovedError(fme);
02957: } catch (IOException e) {
02958: _showIOError(e);
02959: }
02960: }
02961:
02962: public void windowIconified(WindowEvent ev) {
02963: }
02964:
02965: public void windowOpened(WindowEvent ev) {
02966: _currentDefPane.requestFocusInWindow();
02967: }
02968: };
02969:
02970: private final MouseListener _resetFindReplaceListener = new MouseListener() {
02971: public void mouseClicked(MouseEvent e) {
02972: }
02973:
02974: public void mousePressed(MouseEvent e) {
02975: }
02976:
02977: //as mouseReleased event so that it happens after the document has been set in the model and defPane
02978: public void mouseReleased(MouseEvent e) {
02979: _findReplace.updateFirstDocInSearch();
02980: }
02981:
02982: public void mouseEntered(MouseEvent e) {
02983: }
02984:
02985: public void mouseExited(MouseEvent e) {
02986: }
02987: };
02988:
02989: // ------------- File Display Managers for File Icons ------------
02990:
02991: private static final DJFileDisplayManager _djFileDisplayManager20;
02992: private static final DJFileDisplayManager _djFileDisplayManager30;
02993: private static final OddDisplayManager _oddDisplayManager20;
02994: private static final OddDisplayManager _oddDisplayManager30;
02995: private static final Icon _djProjectIcon;
02996:
02997: static {
02998: Icon java, dj0, dj1, dj2, other, star, jup, juf;
02999:
03000: java = MainFrame.getIcon("JavaIcon20.gif");
03001: dj0 = MainFrame.getIcon("ElementaryIcon20.gif");
03002: dj1 = MainFrame.getIcon("IntermediateIcon20.gif");
03003: dj2 = MainFrame.getIcon("AdvancedIcon20.gif");
03004: other = MainFrame.getIcon("OtherIcon20.gif");
03005: _djFileDisplayManager20 = new DJFileDisplayManager(java, dj0,
03006: dj1, dj2, other);
03007:
03008: java = MainFrame.getIcon("JavaIcon30.gif");
03009: dj0 = MainFrame.getIcon("ElementaryIcon30.gif");
03010: dj1 = MainFrame.getIcon("IntermediateIcon30.gif");
03011: dj2 = MainFrame.getIcon("AdvancedIcon30.gif");
03012: other = MainFrame.getIcon("OtherIcon30.gif");
03013: _djFileDisplayManager30 = new DJFileDisplayManager(java, dj0,
03014: dj1, dj2, other);
03015:
03016: star = MainFrame.getIcon("ModStar20.gif");
03017: jup = MainFrame.getIcon("JUnitPass20.gif");
03018: juf = MainFrame.getIcon("JUnitFail20.gif");
03019: _oddDisplayManager20 = new OddDisplayManager(
03020: _djFileDisplayManager20, star, jup, juf);
03021:
03022: star = MainFrame.getIcon("ModStar30.gif");
03023: jup = MainFrame.getIcon("JUnitPass30.gif");
03024: juf = MainFrame.getIcon("JUnitFail30.gif");
03025: _oddDisplayManager30 = new OddDisplayManager(
03026: _djFileDisplayManager30, star, jup, juf);
03027:
03028: _djProjectIcon = MainFrame.getIcon("ProjectIcon.gif");
03029: }
03030:
03031: /** This manager is meant to retrieve the correct icons for the given filename. The only files recognized
03032: * are the files obviously listed below in the function (.java, .dj0, .dj1, .dj2). The icons that represent
03033: * each filetype are given into the managers constructor upon instantiation. This class is static since
03034: * it currently does not depend of the main frame for information.
03035: */
03036: private static class DJFileDisplayManager extends
03037: DefaultFileDisplayManager {
03038: private final Icon _java;
03039: private final Icon _dj0;
03040: private final Icon _dj1;
03041: private final Icon _dj2;
03042: private final Icon _other;
03043:
03044: public DJFileDisplayManager(Icon java, Icon dj0, Icon dj1,
03045: Icon dj2, Icon other) {
03046: _java = java;
03047: _dj0 = dj0;
03048: _dj1 = dj1;
03049: _dj2 = dj2;
03050: _other = other;
03051: }
03052:
03053: /** This method chooses the custom icon only for the known filetypes. If these filetypes are not receiving
03054: * the correct icons, make sure the filenames are correct and that the icons are present in the ui/icons
03055: * directory.
03056: */
03057: public Icon getIcon(File f) {
03058: if (f == null)
03059: return _other;
03060: Icon ret = null;
03061: if (!f.isDirectory()) {
03062: String name = f.getName().toLowerCase();
03063: if (name.endsWith(".java"))
03064: ret = _java;
03065: if (name.endsWith(".dj0"))
03066: ret = _dj0;
03067: if (name.endsWith(".dj1"))
03068: ret = _dj1;
03069: if (name.endsWith(".dj2"))
03070: ret = _dj2;
03071: }
03072: if (ret == null) {
03073: ret = super .getIcon(f);
03074: if (ret.getIconHeight() < _java.getIconHeight()) {
03075: ret = new CenteredIcon(ret, _java.getIconWidth(),
03076: _java.getIconHeight());
03077: }
03078: }
03079: return ret;
03080: }
03081: }
03082:
03083: /** This class wraps the file display managers by superimposing any notification icons on top of the base
03084: * file icon. Currently, only the modified star is allowed, but everything is set up to add notification
03085: * icons for whether a document has passed the junit test (for display in the tree). This class is static
03086: * for now. It may be necessary to make it dynamic when implementing the junit notifications.
03087: */
03088: private static class OddDisplayManager implements
03089: DisplayManager<OpenDefinitionsDocument> {
03090: private final Icon _star;
03091: // private Icon _juPass;
03092: // private Icon _juFail;
03093: private final FileDisplayManager _default;
03094:
03095: /** Standard constructor.
03096: * @param star The star icon will be put flush to the left 1/4 the way down
03097: * @param junitPass indicator of junit success, placed at bottom right
03098: * @param junitFail indicator of junit failure, placed at bottom right
03099: */
03100: public OddDisplayManager(FileDisplayManager fdm, Icon star,
03101: Icon junitPass, Icon junitFail) {
03102: _star = star;
03103: // _juPass = junitPass;
03104: // _juFail = junitFail;
03105: _default = fdm;
03106: }
03107:
03108: public Icon getIcon(OpenDefinitionsDocument odd) {
03109: File f = null;
03110: try {
03111: f = odd.getFile();
03112: } catch (FileMovedException fme) { /* do nothing */
03113: }
03114:
03115: if (odd.isModifiedSinceSave())
03116: return makeLayeredIcon(_default.getIcon(f), _star);
03117: return _default.getIcon(f);
03118: }
03119:
03120: public String getName(OpenDefinitionsDocument doc) {
03121: return doc.getFileName();
03122: }
03123:
03124: private LayeredIcon makeLayeredIcon(Icon base, Icon star) {
03125: return new LayeredIcon(new Icon[] { base, star },
03126: new int[] { 0, 0 }, new int[] { 0,
03127: (base.getIconHeight() / 4) });
03128: }
03129: };
03130:
03131: /** This is what is given to the JTreeSortNavigator. This simply resolves the INavItem to an OpenDefDoc
03132: * using the model and forwards it to the OddDisplayManager for size 20.
03133: */
03134: private final DisplayManager<INavigatorItem> _navPaneDisplayManager = new DisplayManager<INavigatorItem>() {
03135: public Icon getIcon(INavigatorItem item) {
03136: OpenDefinitionsDocument odd = (OpenDefinitionsDocument) item; // FIX THIS!
03137: return _oddDisplayManager20.getIcon(odd);
03138: }
03139:
03140: public String getName(INavigatorItem name) {
03141: return name.getName();
03142: }
03143: };
03144:
03145: public static DJFileDisplayManager getFileDisplayManager20() {
03146: return _djFileDisplayManager20;
03147: }
03148:
03149: public static DJFileDisplayManager getFileDisplayManager30() {
03150: return _djFileDisplayManager30;
03151: }
03152:
03153: public static OddDisplayManager getOddDisplayManager20() {
03154: return _oddDisplayManager20;
03155: }
03156:
03157: public static OddDisplayManager getOddDisplayManager30() {
03158: return _oddDisplayManager30;
03159: }
03160:
03161: public DisplayManager<INavigatorItem> getNavPaneDisplayManager() {
03162: return _navPaneDisplayManager;
03163: }
03164:
03165: /* ----------------------- Constructor is here! --------------------------- */
03166:
03167: /** Creates the main window, and shows it. */
03168: public MainFrame() {
03169:
03170: // Cache the config object, since we use it many, many times.
03171: final Configuration config = DrJava.getConfig();
03172:
03173: // Utilities.show("MainFrame starting");
03174:
03175: // create our model
03176: _model = new DefaultGlobalModel();
03177:
03178: _showDebugger = _model.getDebugger().isAvailable();
03179: _findReplace = new FindReplacePanel(this , _model);
03180:
03181: if (_showDebugger) {
03182: _debugPanel = new DebugPanel(this );
03183: _breakpointsPanel = new BreakpointsPanel(this );
03184: } else {
03185: _debugPanel = null;
03186: _breakpointsPanel = null;
03187: }
03188:
03189: _compilerErrorPanel = new CompilerErrorPanel(_model, this );
03190: _consoleController = new ConsoleController(_model
03191: .getConsoleDocument(), _model.getSwingConsoleDocument());
03192: _consolePane = _consoleController.getPane();
03193:
03194: _consoleScroll = new BorderlessScrollPane(_consolePane) {
03195: public boolean requestFocusInWindow() {
03196: super .requestFocusInWindow();
03197: return _consolePane.requestFocusInWindow();
03198: }
03199: };
03200:
03201: _interactionsController = new InteractionsController(_model
03202: .getInteractionsModel(), _model
03203: .getSwingInteractionsDocument());
03204:
03205: _interactionsPane = _interactionsController.getPane();
03206: _interactionsController.setCachedCaretPos(0);
03207: _interactionsController.setCachedPromptPos(_model
03208: .getConsoleDocument().getPromptPos());
03209:
03210: _interactionsContainer = new JPanel(new BorderLayout()); /* {
03211: public boolean requestFocusInWindow() {
03212: super.requestFocusInWindow();
03213: return _interactionsPane.requestFocusInWindow();
03214: }
03215: };*/
03216:
03217: _lastFocusOwner = _interactionsContainer;
03218:
03219: _junitErrorPanel = new JUnitPanel(_model, this );
03220: _javadocErrorPanel = new JavadocErrorPanel(_model, this );
03221:
03222: _bookmarksPanel = new BookmarksPanel(this );
03223:
03224: // Initialize the status bar
03225: _setUpStatusBar();
03226:
03227: // Preliminary layout
03228:
03229: /* Definitions Pane */
03230:
03231: /* Ensure that DefinitionsPane uses the correct EditorKit! This has to be stored as a static field on
03232: * DefinitionsPane because the JEditorPane constructor uses it before we get a chance to assign it to an instance
03233: * field ... */
03234: DefinitionsPane.setEditorKit(_model.getEditorKit());
03235:
03236: _defScrollPanes = new Hashtable<OpenDefinitionsDocument, JScrollPane>();
03237:
03238: /* Other panes */
03239: _tabbedPane = new JTabbedPane();
03240: _tabbedPane.addFocusListener(new FocusListener() {
03241: public void focusGained(FocusEvent e) {
03242: Component c = _tabbedPane.getSelectedComponent();
03243: // System.err.println("focus gained in tabbed pane with selected tab " + c + " with paramString " + e.paramString());
03244: if (c == _interactionsContainer) {
03245: _interactionsPane.requestFocusInWindow();
03246: // System.err.println("Selected tab was interactions container");
03247: } else if (c == _findReplace)
03248: _findReplace.getFindField().requestFocusInWindow();
03249: }
03250:
03251: public void focusLost(FocusEvent e) {
03252: }
03253: });
03254:
03255: JScrollPane defScroll = _createDefScrollPane(_model
03256: .getActiveDocument());
03257:
03258: _docSplitPane = new BorderlessSplitPane(
03259: JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(
03260: _model.getDocumentNavigator().asContainer()),
03261: defScroll);
03262: _debugSplitPane = new BorderlessSplitPane(
03263: JSplitPane.VERTICAL_SPLIT, true);
03264: _mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true,
03265: _docSplitPane, _tabbedPane);
03266:
03267: // Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
03268: // // The OptionListener for LIGHTWEIGHT_PARSING_ENABLED.
03269: // OptionListener<Boolean> parsingEnabledListener = new OptionListener<Boolean>() {
03270: // public void optionChanged(OptionEvent<Boolean> oce) {
03271: // if (oce.value) {
03272: // _model.getParsingControl().addListener(new LightWeightParsingListener() {
03273: // public void enclosingClassNameUpdated(OpenDefinitionsDocument doc, String old, String updated) {
03274: // if (doc==_model.getActiveDocument()) { updateStatusField(); }
03275: // }
03276: // });
03277: // }
03278: // _model.getParsingControl().reset();
03279: // _model.getParsingControl().setAutomaticUpdates(oce.value);
03280: // updateStatusField();
03281: // }
03282: // };
03283: // DrJava.getConfig().addOptionListener(LIGHTWEIGHT_PARSING_ENABLED, parsingEnabledListener);
03284: // parsingEnabledListener.optionChanged(new OptionEvent<Boolean>(LIGHTWEIGHT_PARSING_ENABLED,
03285: // DrJava.getConfig().getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()));
03286:
03287: // Utilities.show("Global Model started");
03288:
03289: _model.getDocumentNavigator().asContainer().addKeyListener(
03290: _historyListener);
03291: _model.getDocumentNavigator().asContainer().addFocusListener(
03292: _focusListenerForRecentDocs);
03293:
03294: /* Listens for clicks in the document navigator to reset the first document in an all-documents search for wrapping
03295: * purposes. */
03296: _model.getDocumentNavigator().asContainer().addMouseListener(
03297: _resetFindReplaceListener);
03298:
03299: if (_showDebugger)
03300: _model.getDebugger().addListener(new UIDebugListener()); // add listener to debug manager
03301:
03302: // Timer to display a message if a debugging step takes a long time
03303: _debugStepTimer = new Timer(DEBUG_STEP_TIMER_VALUE,
03304: new ActionListener() {
03305: public void actionPerformed(ActionEvent e) {
03306: _model.printDebugMessage("Stepping...");
03307: }
03308: });
03309: _debugStepTimer.setRepeats(false);
03310:
03311: // Working directory is default place to start (bug #895998).
03312: File workDir = _model.getMasterWorkingDirectory();
03313:
03314: // Overrides JFileChooser to display the full path of the directory
03315: _openChooser = new JFileChooser() {
03316: public void setCurrentDirectory(File dir) {
03317: //next two lines are order dependent!
03318: super .setCurrentDirectory(dir);
03319: setDialogTitle("Open: " + getCurrentDirectory());
03320: }
03321: };
03322: _openChooser.setPreferredSize(new Dimension(650, 410));
03323: _openChooser.setCurrentDirectory(workDir);
03324: _openChooser.setFileFilter(_javaSourceFilter);
03325: _openChooser.setMultiSelectionEnabled(true);
03326:
03327: _openRecursiveCheckBox = new JCheckBox(
03328: "Open folders recursively");
03329: _openRecursiveCheckBox.setSelected(config.getSetting(
03330: OptionConstants.OPEN_FOLDER_RECURSIVE).booleanValue());
03331:
03332: _folderChooser = makeFolderChooser(workDir);
03333:
03334: //Get most recently opened project for filechooser
03335: Vector<File> recentProjects = config
03336: .getSetting(RECENT_PROJECTS);
03337: _openProjectChooser = new JFileChooser();
03338: _openProjectChooser.setPreferredSize(new Dimension(650, 410));
03339:
03340: if (recentProjects.size() > 0
03341: && recentProjects.elementAt(0).getParentFile() != null)
03342: _openProjectChooser.setCurrentDirectory(recentProjects
03343: .elementAt(0).getParentFile());
03344: else
03345: _openProjectChooser.setCurrentDirectory(workDir);
03346:
03347: _openProjectChooser.setFileFilter(_projectFilter);
03348: _openProjectChooser.setMultiSelectionEnabled(false);
03349: _saveChooser = new JFileChooser() {
03350: public void setCurrentDirectory(File dir) {
03351: //next two lines are order dependent!
03352: super .setCurrentDirectory(dir);
03353: setDialogTitle("Save: " + getCurrentDirectory());
03354: }
03355: };
03356: _saveChooser.setPreferredSize(new Dimension(650, 410));
03357: _saveChooser.setCurrentDirectory(workDir);
03358: _saveChooser.setFileFilter(_javaSourceFilter);
03359:
03360: _interactionsHistoryChooser = new JFileChooser();
03361: _interactionsHistoryChooser.setPreferredSize(new Dimension(650,
03362: 410));
03363: _interactionsHistoryChooser.setCurrentDirectory(workDir);
03364: _interactionsHistoryChooser
03365: .setFileFilter(new InteractionsHistoryFilter());
03366: _interactionsHistoryChooser.setMultiSelectionEnabled(true);
03367:
03368: //set up the hourglass cursor
03369: setGlassPane(new GlassPane());
03370: setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
03371:
03372: // Set up listeners
03373: addWindowListener(_windowCloseListener);
03374:
03375: // Create the main model listener and attach it to the global model
03376: _mainListener = new ModelListener();
03377: _model.addListener(_mainListener);
03378:
03379: // Initialize tabs before DefPane
03380: _setUpTabs();
03381:
03382: // DefinitionsPane
03383: _recentDocFrame = new RecentDocFrame(this );
03384: _recentDocFrame.pokeDocument(_model.getActiveDocument());
03385: _currentDefPane = (DefinitionsPane) defScroll.getViewport()
03386: .getView();
03387: _currentDefPane.notifyActive();
03388:
03389: // Get proper cross-platform mask.
03390: int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
03391:
03392: // set up key-bindings
03393: KeyBindingManager.Singleton.setMainFrame(this );
03394: KeyBindingManager.Singleton.setActionMap(_currentDefPane
03395: .getActionMap());
03396: _setUpKeyBindingMaps();
03397:
03398: _posListener.updateLocation();
03399:
03400: // Need to set undo/redo actions to point to the initial def pane
03401: // on switching documents later these pointers will also switch
03402: _undoAction.setDelegatee(_currentDefPane.getUndoAction());
03403: _redoAction.setDelegatee(_currentDefPane.getRedoAction());
03404:
03405: _compilerErrorPanel.reset();
03406: _junitErrorPanel.reset();
03407: _javadocErrorPanel.reset();
03408:
03409: // Create menubar and menus
03410: _menuBar = new MenuBar();
03411: _fileMenu = _setUpFileMenu(mask);
03412: _editMenu = _setUpEditMenu(mask);
03413: _toolsMenu = _setUpToolsMenu(mask);
03414: _projectMenu = _setUpProjectMenu(mask);
03415:
03416: if (_showDebugger)
03417: _debugMenu = _setUpDebugMenu(mask);
03418: _languageLevelMenu = _setUpLanguageLevelMenu(mask);
03419: _helpMenu = _setUpHelpMenu(mask);
03420:
03421: // initialize menu bar and actions
03422: _setUpActions();
03423: _setUpMenuBar();
03424:
03425: // _setUpDocumentSelector();
03426: _setUpContextMenus();
03427:
03428: // Create toolbar and buttons
03429:
03430: _toolBar = new JToolBar();
03431: _undoButton = _createManualToolbarButton(_undoAction);
03432: _redoButton = _createManualToolbarButton(_redoAction);
03433:
03434: // initialize _toolBar
03435:
03436: _setUpToolBar();
03437:
03438: // add recent file and project manager
03439:
03440: _recentFileManager = new RecentFileManager(_fileMenu
03441: .getItemCount() - 2, _fileMenu,
03442: new RecentFileManager.RecentFileAction() {
03443: public void actionPerformed(
03444: FileOpenSelector selector) {
03445: open(selector);
03446: }
03447: }, OptionConstants.RECENT_FILES);
03448:
03449: _recentProjectManager = new RecentFileManager(_projectMenu
03450: .getItemCount() - 2, _projectMenu,
03451: new RecentFileManager.RecentFileAction() {
03452: public void actionPerformed(
03453: FileOpenSelector selector) {
03454: openProject(selector);
03455: }
03456: }, OptionConstants.RECENT_PROJECTS);
03457:
03458: // Set frame icon
03459: setIconImage(getIcon("drjava64.png").getImage());
03460:
03461: // Size and position
03462: int x = config.getSetting(WINDOW_X).intValue();
03463: int y = config.getSetting(WINDOW_Y).intValue();
03464: int width = config.getSetting(WINDOW_WIDTH).intValue();
03465: int height = config.getSetting(WINDOW_HEIGHT).intValue();
03466: int state = config.getSetting(WINDOW_STATE).intValue();
03467:
03468: // Bounds checking.
03469: // suggested from zaq@nosi.com, to keep the frame on the screen!
03470: Dimension screenSize = Toolkit.getDefaultToolkit()
03471: .getScreenSize();
03472:
03473: final int menubarHeight = 24;
03474: if (height > screenSize.height - menubarHeight)
03475: height = screenSize.height - menubarHeight; // Too tall, so resize
03476:
03477: if (width > screenSize.width)
03478: width = screenSize.width; // Too wide, so resize
03479:
03480: // I assume that we want to be contained on the default screen.
03481: // TODO: support spanning screens in multi-screen setups.
03482: Rectangle bounds = GraphicsEnvironment
03483: .getLocalGraphicsEnvironment().getDefaultScreenDevice()
03484: .getDefaultConfiguration().getBounds();
03485:
03486: if (x == Integer.MAX_VALUE)
03487: x = (bounds.width - width + bounds.x) / 2; // magic value for "not set" - center.
03488: if (y == Integer.MAX_VALUE)
03489: y = (bounds.height - height + bounds.y) / 2; // magic value for "not set" - center.
03490: if (x < bounds.x)
03491: x = bounds.x; // Too far left, move to left edge.
03492: if (y < bounds.y)
03493: y = bounds.y; // Too far up, move to top edge.
03494: if ((x + width) > (bounds.x + bounds.width))
03495: x = bounds.width - width + bounds.x;
03496: // Too far right, move to right edge.
03497: if ((y + height) > (bounds.y + bounds.height))
03498: y = bounds.height - height + bounds.y;
03499: // Too far down, move to bottom edge.
03500:
03501: //ensure that we don't set window state to minimized
03502: state &= ~Frame.ICONIFIED;
03503:
03504: if (!Toolkit.getDefaultToolkit().isFrameStateSupported(state)) {
03505: //we have a bad state, so reset to default
03506: state = WINDOW_STATE.getDefault();
03507: }
03508:
03509: // Set to the new correct size and location
03510: setBounds(x, y, width, height);
03511:
03512: //Work-aroung for Java bug #6365898?
03513: //setExtendedState does not work until the window in shown on Linux.
03514: final int stateCopy = state;
03515: addWindowListener(new WindowAdapter() {
03516: public void windowOpened(WindowEvent e) {
03517: setExtendedState(stateCopy);
03518: //this is a one-off listener
03519: removeWindowListener(this );
03520: }
03521: });
03522:
03523: _setUpPanes();
03524: updateStatusField();
03525:
03526: _promptBeforeQuit = config.getSetting(QUIT_PROMPT)
03527: .booleanValue();
03528:
03529: // Set the fonts
03530: _setMainFont();
03531: Font doclistFont = config.getSetting(FONT_DOCLIST);
03532: _model.getDocCollectionWidget().setFont(doclistFont);
03533:
03534: // Set the colors
03535: _updateNormalColor();
03536: _updateBackgroundColor();
03537:
03538: // Add OptionListeners for the colors.
03539: config.addOptionListener(DEFINITIONS_NORMAL_COLOR,
03540: new NormalColorOptionListener());
03541: config.addOptionListener(DEFINITIONS_BACKGROUND_COLOR,
03542: new BackgroundColorOptionListener());
03543:
03544: /* Add option listeners for changes to config options. NOTE: We should only add listeners to view-related (or view-
03545: * dependent) config options here. Model options should go in DefaultGlobalModel._registerOptionListeners(). */
03546: config.addOptionListener(FONT_MAIN,
03547: new MainFontOptionListener());
03548: config.addOptionListener(FONT_LINE_NUMBERS,
03549: new LineNumbersFontOptionListener());
03550: config.addOptionListener(FONT_DOCLIST,
03551: new DoclistFontOptionListener());
03552: config.addOptionListener(FONT_TOOLBAR,
03553: new ToolbarFontOptionListener());
03554: config.addOptionListener(TOOLBAR_ICONS_ENABLED,
03555: new ToolbarOptionListener());
03556: config.addOptionListener(TOOLBAR_TEXT_ENABLED,
03557: new ToolbarOptionListener());
03558: config.addOptionListener(TOOLBAR_ENABLED,
03559: new ToolbarOptionListener());
03560: config.addOptionListener(LINEENUM_ENABLED,
03561: new LineEnumOptionListener());
03562: config.addOptionListener(QUIT_PROMPT,
03563: new QuitPromptOptionListener());
03564: config.addOptionListener(RECENT_FILES_MAX_SIZE,
03565: new RecentFilesOptionListener());
03566:
03567: config.addOptionListener(LOOK_AND_FEEL,
03568: new OptionListener<String>() {
03569: public void optionChanged(OptionEvent<String> oe) {
03570: // try {
03571: // UIManager.setLookAndFeel(oe.value);
03572: // SwingUtilities.updateComponentTreeUI(MainFrame.this);
03573: // if (_debugPanel != null) {
03574: // SwingUtilities.updateComponentTreeUI(_debugPanel);
03575: // }
03576: // if (_configFrame != null) {
03577: // SwingUtilities.updateComponentTreeUI(_configFrame);
03578: // }
03579: // if (_helpFrame != null) {
03580: // SwingUtilities.updateComponentTreeUI(_helpFrame);
03581: // }
03582: // if (_aboutDialog != null) {
03583: // SwingUtilities.updateComponentTreeUI(_aboutDialog);
03584: // }
03585: // SwingUtilities.updateComponentTreeUI(_navPanePopupMenu);
03586: // SwingUtilities.updateComponentTreeUI(_interactionsPanePopupMenu);
03587: // SwingUtilities.updateComponentTreeUI(_consolePanePopupMenu);
03588: // SwingUtilities.updateComponentTreeUI(_openChooser);
03589: // SwingUtilities.updateComponentTreeUI(_saveChooser);
03590: // Iterator<TabbedPanel> it = _tabs.iterator();
03591: // while (it.hasNext()) {
03592: // SwingUtilities.updateComponentTreeUI(it.next());
03593: // }
03594: // }
03595: // catch (Exception ex) {
03596: // _showError(ex, "Could Not Set Look and Feel",
03597: // "An error occurred while trying to set the look and feel.");
03598: // }
03599:
03600: String title = "Apply Look and Feel";
03601: String msg = "Look and feel changes will take effect when you restart DrJava.";
03602: if (config.getSetting(WARN_CHANGE_LAF)
03603: .booleanValue()) {
03604: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
03605: _configFrame, title, msg,
03606: "Do not show this message again",
03607: JOptionPane.INFORMATION_MESSAGE,
03608: JOptionPane.DEFAULT_OPTION);
03609: if (dialog.show() == JOptionPane.OK_OPTION
03610: && dialog.getCheckBoxValue()) {
03611: config.setSetting(WARN_CHANGE_LAF,
03612: Boolean.FALSE);
03613: }
03614: }
03615: }
03616: });
03617:
03618: config.addOptionListener(SLAVE_JVM_ARGS,
03619: new OptionListener<String>() {
03620: public void optionChanged(OptionEvent<String> oe) {
03621: if (!oe.value.equals("")) {
03622: int result = JOptionPane
03623: .showConfirmDialog(
03624: _configFrame,
03625: "Specifying Interations JVM Args is an advanced option. Invalid arguments may cause\n"
03626: + "the Interactions Pane to stop working.\n"
03627: + "Are you sure you want to set this option?\n"
03628: + "(You will have to reset the interactions pane before changes take effect.)",
03629: "Confirm Interactions JVM Arguments",
03630: JOptionPane.YES_NO_OPTION);
03631: if (result != JOptionPane.YES_OPTION)
03632: config.setSetting(oe.option, "");
03633: }
03634: }
03635: });
03636:
03637: config.addOptionListener(MASTER_JVM_ARGS,
03638: new OptionListener<String>() {
03639: public void optionChanged(OptionEvent<String> oe) {
03640: if (!oe.value.equals("")) {
03641: int result = JOptionPane
03642: .showConfirmDialog(
03643: _configFrame,
03644: "Specifying Main JVM Args is an advanced option. Invalid arguments may cause\n"
03645: + "DrJava to fail on start up. You may need to edit or delete your .drjava preferences file\n"
03646: + "to recover.\n Are you sure you want to set this option?\n"
03647: + "(You will have to restart Drjava before changes take effect.)",
03648: "Confirm Main JVM Arguments",
03649: JOptionPane.YES_NO_OPTION);
03650: if (result != JOptionPane.YES_OPTION)
03651: config.setSetting(oe.option, "");
03652: }
03653: }
03654: });
03655:
03656: config.addOptionListener(ALLOW_PRIVATE_ACCESS,
03657: new OptionListener<Boolean>() {
03658: public void optionChanged(OptionEvent<Boolean> oce) {
03659: _model.getInteractionsModel()
03660: .setPrivateAccessible(
03661: oce.value.booleanValue());
03662: }
03663: });
03664:
03665: config.addOptionListener(FORCE_TEST_SUFFIX,
03666: new OptionListener<Boolean>() {
03667: public void optionChanged(OptionEvent<Boolean> oce) {
03668: _model.getJUnitModel().setForceTestSuffix(
03669: oce.value.booleanValue());
03670: }
03671: });
03672:
03673: // The OptionListener for JAVADOC_LINK_VERSION.
03674: OptionListener<String> choiceOptionListener = new OptionListener<String>() {
03675: public void optionChanged(OptionEvent<String> oce) {
03676: _javaAPIList = null;
03677: _openJavadocAction.setEnabled(!oce.value
03678: .equals(JAVADOC_NONE_TEXT));
03679: _openJavadocUnderCursorAction.setEnabled(!oce.value
03680: .equals(JAVADOC_NONE_TEXT));
03681: }
03682: };
03683: DrJava.getConfig().addOptionListener(JAVADOC_LINK_VERSION,
03684: choiceOptionListener);
03685:
03686: // The OptionListener for JAVADOC_XXX_LINK.
03687: OptionListener<String> link13OptionListener = new OptionListener<String>() {
03688: public void optionChanged(OptionEvent<String> oce) {
03689: String linkVersion = DrJava.getConfig().getSetting(
03690: JAVADOC_LINK_VERSION);
03691: if (linkVersion.equals(JAVADOC_1_3_TEXT)) {
03692: _javaAPIList = null;
03693: }
03694: }
03695: };
03696: DrJava.getConfig().addOptionListener(JAVADOC_1_3_LINK,
03697: link13OptionListener);
03698: OptionListener<String> link14OptionListener = new OptionListener<String>() {
03699: public void optionChanged(OptionEvent<String> oce) {
03700: String linkVersion = DrJava.getConfig().getSetting(
03701: JAVADOC_LINK_VERSION);
03702: if (linkVersion.equals(JAVADOC_1_4_TEXT)) {
03703: _javaAPIList = null;
03704: }
03705: }
03706: };
03707: DrJava.getConfig().addOptionListener(JAVADOC_1_4_LINK,
03708: link14OptionListener);
03709: OptionListener<String> link15OptionListener = new OptionListener<String>() {
03710: public void optionChanged(OptionEvent<String> oce) {
03711: String linkVersion = DrJava.getConfig().getSetting(
03712: JAVADOC_LINK_VERSION);
03713: if (linkVersion.equals(JAVADOC_1_5_TEXT)) {
03714: _javaAPIList = null;
03715: }
03716: }
03717: };
03718: DrJava.getConfig().addOptionListener(JAVADOC_1_5_LINK,
03719: link15OptionListener);
03720:
03721: // Initialize DocumentRegion highlights hashtables, for easy removal of highlights
03722: _documentBreakpointHighlights = new Hashtable<Breakpoint, HighlightManager.HighlightInfo>();
03723: _documentBookmarkHighlights = new Hashtable<DocumentRegion, HighlightManager.HighlightInfo>();
03724:
03725: // Initialize cached frames and dialogs
03726: _configFrame = new ConfigFrame(this );
03727: _helpFrame = new HelpFrame();
03728: _aboutDialog = new AboutDialog(MainFrame.this );
03729: _quickStartFrame = new QuickStartFrame();
03730: _interactionsScriptController = null;
03731: _jarOptionsDialog = new JarOptionsDialog(MainFrame.this );
03732: initJarOptionsDialog();
03733: // _projectPropertiesFrame = null;
03734:
03735: // If any errors occurred while parsing config file, show them
03736: _showConfigException();
03737:
03738: KeyBindingManager.Singleton.setShouldCheckConflict(false);
03739:
03740: // Platform-specific UI setup.
03741: PlatformFactory.ONLY.afterUISetup(_aboutAction,
03742: _editPreferencesAction, _quitAction);
03743: setUpKeys();
03744:
03745: // discard ` character if it was used for the next/prev recent doc feature
03746: KeyboardFocusManager.getCurrentKeyboardFocusManager()
03747: .addKeyEventDispatcher(new KeyEventDispatcher() {
03748: public boolean dispatchKeyEvent(KeyEvent e) {
03749: boolean discardEvent = false;
03750:
03751: if ((e.getID() == KeyEvent.KEY_TYPED)
03752: && (e.getKeyChar() == '`')
03753: && (((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) || ((e
03754: .getModifiersEx() & (InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) == (InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)))
03755: && (e.getComponent().getClass()
03756: .equals(DefinitionsPane.class))) {
03757: // System.out.println("discarding `, modifiers = "+e.getModifiersEx()+": "+e.getComponent());
03758: discardEvent = true;
03759: }
03760:
03761: return discardEvent;
03762: }
03763: });
03764:
03765: if (DrJava
03766: .getConfig()
03767: .getSetting(
03768: edu.rice.cs.drjava.config.OptionConstants.REMOTE_CONTROL_ENABLED)) {
03769: // start remote control server if no server is running
03770: try {
03771: if (!RemoteControlClient.isServerRunning()) {
03772: edu.rice.cs.drjava.RemoteControlServer rcServer = new edu.rice.cs.drjava.RemoteControlServer(
03773: this );
03774: }
03775: } catch (IOException ioe) {
03776: try {
03777: RemoteControlClient.openFile(null);
03778: } catch (IOException ignored) {
03779: // ignore
03780: }
03781: if (!System.getProperty("user.name").equals(
03782: RemoteControlClient.getServerUser())) {
03783: Object[] options = { "Disable", "Ignore" };
03784: String msg = "<html>Could not start DrJava's remote control server";
03785: if (RemoteControlClient.getServerUser() != null) {
03786: msg += "<br>because user "
03787: + RemoteControlClient.getServerUser()
03788: + " is already using the same port";
03789: }
03790: msg += ".<br>Please select an unused port in the Preferences dialog.<br>"
03791: + "In the meantime, do you want to disable the remote control feature?";
03792: int n = JOptionPane.showOptionDialog(
03793: MainFrame.this , msg,
03794: "Could Not Start Remote Control Server",
03795: JOptionPane.YES_NO_OPTION,
03796: JOptionPane.QUESTION_MESSAGE, null,
03797: options, options[1]);
03798: if (n == JOptionPane.YES_OPTION) {
03799: DrJava
03800: .getConfig()
03801: .setSetting(
03802: edu.rice.cs.drjava.config.OptionConstants.REMOTE_CONTROL_ENABLED,
03803: false);
03804: }
03805: }
03806: }
03807: }
03808: } // End of MainFrame constructor
03809:
03810: public void setVisible(boolean b) {
03811: _updateToolBarVisible();
03812: super .setVisible(b);
03813: }
03814:
03815: /** Set a new painters for existing breakpoint highlights. */
03816: void refreshBreakpointHighlightPainter() {
03817: for (java.util.Map.Entry<Breakpoint, HighlightManager.HighlightInfo> pair : _documentBreakpointHighlights
03818: .entrySet()) {
03819: if (pair.getKey().isEnabled()) {
03820: pair.getValue().refresh(
03821: DefinitionsPane.BREAKPOINT_PAINTER);
03822: } else {
03823: pair.getValue().refresh(
03824: DefinitionsPane.DISABLED_BREAKPOINT_PAINTER);
03825: }
03826: }
03827: }
03828:
03829: /** Set new painter for existing bookmark highlights. */
03830: void refreshBookmarkHighlightPainter() {
03831: for (HighlightManager.HighlightInfo hi : _documentBookmarkHighlights
03832: .values()) {
03833: hi.refresh(DefinitionsPane.BOOKMARK_PAINTER);
03834: }
03835: }
03836:
03837: /** Set new painter for existing find results highlights. */
03838: void refreshFindResultsHighlightPainter(FindResultsPanel panel,
03839: ReverseHighlighter.DefaultUnderlineHighlightPainter painter) {
03840: for (Pair<FindResultsPanel, Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair : _findResults) {
03841: if (pair.first() == panel) {
03842: Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo> highlights = pair
03843: .second();
03844: for (HighlightManager.HighlightInfo hi : highlights
03845: .values()) {
03846: hi.refresh(painter);
03847: }
03848: }
03849: }
03850: }
03851:
03852: /** Creates the folder chooser during MainFrame initialization which does not run in event thread. */
03853: private DirectoryChooser makeFolderChooser(final File workDir) {
03854: final DirectoryChooser dc = new DirectoryChooser(this );
03855: /* The following code fragement was moved to the event thread because setSelectedFile occasionally generates an
03856: * ArrayOutOfBoundsException otherwise. */
03857: Utilities.invokeLater(new Runnable() {
03858: public void run() {
03859: dc.setSelectedFile(workDir);
03860: dc.setApproveButtonText("Select");
03861: dc.setDialogTitle("Open Folder");
03862: dc.setAccessory(_openRecursiveCheckBox);
03863: }
03864: });
03865: return dc;
03866: }
03867:
03868: //
03869: // private JFileChooser makeFolderChooser(File workDir) {
03870: // _folderChooser = new JFileChooser();
03871: // _folderChooser.setMultiSelectionEnabled(false);
03872: // _folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
03873: // _folderChooser.setCurrentDirectory(workDir);
03874: // _folderChooser.setApproveButtonText("Select");
03875: // _folderChooser.setFileFilter(new DirectoryFilter());
03876: // _folderChooser.setDialogTitle("Open Folder");
03877: //
03878: //
03879: // Container button_row = (Container)findButtonContainer(_folderChooser, _folderChooser.getApproveButtonText());
03880: // Container buttons = (Container) button_row.getParent();
03881: //
03882: //// Component c2 = ((BorderLayout)_folderChooser.getLayout()).getLayoutComponent(BorderLayout.SOUTH);
03883: //
03884: //// System.out.println("c1: " + c1);
03885: //// System.out.println("c2: " + c2);
03886: //
03887: //
03888: //// JPanel buttons = (JPanel)c2;
03889: //// JPanel button_row = (JPanel)buttons.getComponent(3);
03890: // JPanel bottom_row = new JPanel();
03891: // bottom_row.setLayout(new BorderLayout());
03892: // bottom_row.add(new JCheckBox("Recursive Open"), BorderLayout.CENTER);
03893: // bottom_row.add(button_row, BorderLayout.EAST);
03894: // buttons.add(bottom_row);
03895: //
03896: // return _folderChooser;
03897: // }
03898:
03899: // private Container findButtonContainer(Container container, String buttonText) {
03900: // Container answer = null;
03901: // Component[] cs = container.getComponents();
03902: // for(Component c: cs) {
03903: // if (c instanceof JButton && ((JButton)c).getText().equals(buttonText)) {
03904: // return container;
03905: // }else if (c instanceof Container) {
03906: // answer = findButtonContainer((Container)c, buttonText);
03907: // }
03908: //
03909: // if (answer != null) break;
03910: // }
03911: // return answer;
03912: // }
03913:
03914: /** Sets up the ctrl-tab listener. */
03915: private void setUpKeys() {
03916: setFocusTraversalKeysEnabled(false);
03917: }
03918:
03919: /** Relying on inherited dispose() method. */
03920:
03921: /** @return The model providing the logic for this view. */
03922: public SingleDisplayModel getModel() {
03923: return _model;
03924: }
03925:
03926: /** Returns the frame's interactions pane. (Package private accessor) */
03927: InteractionsPane getInteractionsPane() {
03928: return _interactionsPane;
03929: }
03930:
03931: /** Returns the frame's interactions controller. (Package private accessor) */
03932: InteractionsController getInteractionsController() {
03933: return _interactionsController;
03934: }
03935:
03936: /** @return The frame's close button (Package private accessor). */
03937: JButton getCloseButton() {
03938: return _closeButton;
03939: }
03940:
03941: /** For testing purposes.
03942: * @return The frame's compileAll button (Package private accessor)
03943: */
03944: JButton getCompileAllButton() {
03945: return _compileButton;
03946: }
03947:
03948: private volatile int _hourglassNestLevel = 0;
03949:
03950: /** Make the cursor an hourglass. Only runs in the event thread. */
03951: public void hourglassOn() {
03952: assert EventQueue.isDispatchThread();
03953: _hourglassNestLevel++;
03954: if (_hourglassNestLevel == 1) {
03955: getGlassPane().setVisible(true);
03956: _currentDefPane.setEditable(false);
03957: setAllowKeyEvents(false);
03958: }
03959: }
03960:
03961: /** Return the cursor to normal. Only runs in the event thread. */
03962: public void hourglassOff() {
03963: assert EventQueue.isDispatchThread();
03964: _hourglassNestLevel--;
03965: if (_hourglassNestLevel == 0) {
03966: getGlassPane().setVisible(false);
03967: _currentDefPane.setEditable(true);
03968: setAllowKeyEvents(true);
03969: }
03970: }
03971:
03972: private volatile boolean _allowKeyEvents = true;
03973:
03974: public void setAllowKeyEvents(boolean a) {
03975: _allowKeyEvents = a;
03976: }
03977:
03978: public boolean getAllowKeyEvents() {
03979: return _allowKeyEvents;
03980: }
03981:
03982: /** Toggles whether the debugger is enabled or disabled, and updates the display accordingly. Only runs in the
03983: * event thread. */
03984: public void debuggerToggle() {
03985: assert EventQueue.isDispatchThread();
03986: // Make sure the debugger is available
03987: Debugger debugger = _model.getDebugger();
03988: if (!debugger.isAvailable())
03989: return;
03990:
03991: updateStatusField("Toggling Debugger Mode");
03992:
03993: try {
03994: if (isDebuggerReady())
03995: debugger.shutdown();
03996: else {
03997: // Turn on debugger
03998: hourglassOn();
03999: try {
04000: debugger.startUp(); // may kick active document (if unmodified) out of memory!
04001: _model.refreshActiveDocument();
04002: _updateDebugStatus();
04003: } finally {
04004: hourglassOff();
04005: }
04006: }
04007: } catch (DebugException de) {
04008: _showError(de, "Debugger Error",
04009: "Could not start the debugger.");
04010: } catch (NoClassDefFoundError err) {
04011: _showError(
04012: err,
04013: "Debugger Error",
04014: "Unable to find the JPDA package for the debugger.\n"
04015: + "Please make sure either tools.jar or jpda.jar is\n"
04016: + "in your classpath when you start DrJava.");
04017: _setDebugMenuItemsEnabled(false);
04018: }
04019: }
04020:
04021: /** Display the debugger tab and update the Debug menu accordingly. */
04022: public void showDebugger() {
04023: _setDebugMenuItemsEnabled(true);
04024: _showDebuggerPanel();
04025: }
04026:
04027: /** Hide the debugger tab and update the Debug menu accordingly. */
04028: public void hideDebugger() {
04029: _setDebugMenuItemsEnabled(false);
04030: _hideDebuggerPanel();
04031: }
04032:
04033: private void _showDebuggerPanel() {
04034: _debugSplitPane.setTopComponent(_docSplitPane);
04035: _mainSplit.setTopComponent(_debugSplitPane);
04036: _debugPanel.updateData();
04037: _lastFocusOwner.requestFocusInWindow();
04038: }
04039:
04040: private void _hideDebuggerPanel() {
04041: _mainSplit.setTopComponent(_docSplitPane);
04042: _lastFocusOwner.requestFocusInWindow();
04043: }
04044:
04045: /** ONLY executes in event thread. */
04046: public void updateStatusField(String text) {
04047: assert EventQueue.isDispatchThread();
04048: _statusField.setText(text);
04049: _statusField.paint(getGraphics()); // force an immediate repaint
04050: }
04051:
04052: /** Updates the status field with the current status of the Definitions Pane. */
04053: public void updateStatusField() {
04054: OpenDefinitionsDocument doc = _model.getActiveDocument();
04055: String fileName = doc.getCompletePath();
04056: if (!fileName.equals(_fileTitle)) {
04057: _fileTitle = fileName;
04058: setTitle(fileName);
04059: _model.getDocCollectionWidget().repaint();
04060: }
04061: String path = doc.getCompletePath();
04062:
04063: String text = "Editing " + path;
04064:
04065: // Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
04066: // if (DrJava.getConfig().getSetting(LIGHTWEIGHT_PARSING_ENABLED).booleanValue()) {
04067: // String temp = _model.getParsingControl().getEnclosingClassName(doc);
04068: // if ((temp != null) && (temp.length() > 0)) { text = text + " - " + temp; }
04069:
04070: // _statusField.setToolTipText("Full path for file: " + path);
04071:
04072: if (!_statusField.getText().equals(text)) {
04073: _statusField.setText(text);
04074: _statusField.paint(getGraphics()); // force immediate painting of the _statusField
04075: }
04076: }
04077:
04078: /** Prompt the user to select a place to open files from, then load them. Ask the user if they'd like to save
04079: * previous changes (if the current document has been modified) before opening.
04080: * @param jfc the open dialog from which to extract information
04081: * @return an array of the files that were chosen
04082: */
04083: public File[] getOpenFiles(JFileChooser jfc)
04084: throws OperationCanceledException {
04085: int rc = jfc.showOpenDialog(this );
04086: return getChosenFiles(jfc, rc);
04087: }
04088:
04089: /** Prompt the user to select a place to save the current document. */
04090: public File getSaveFile(JFileChooser jfc)
04091: throws OperationCanceledException {
04092: // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X!
04093: // File selection = jfc.getSelectedFile();//_saveChooser.getSelectedFile();
04094: // if (selection != null) {
04095: // jfc.setSelectedFile(selection.getParentFile());
04096: // jfc.setSelectedFile(selection);
04097: // jfc.setSelectedFile(null);
04098: // }
04099:
04100: OpenDefinitionsDocument active = _model.getActiveDocument();
04101:
04102: // Fill in class name
04103: //if (active.isUntitled()) {
04104: try {
04105: String className = active.getFirstTopLevelClassName();
04106: if (!className.equals("")) {
04107: jfc.setSelectedFile(new File(jfc.getCurrentDirectory(),
04108: className));
04109: }
04110: } catch (ClassNameNotFoundException e) {
04111: // Don't set selected file
04112: }
04113:
04114: _saveChooser.removeChoosableFileFilter(_projectFilter);
04115: _saveChooser.removeChoosableFileFilter(_javaSourceFilter);
04116: _saveChooser.setFileFilter(_javaSourceFilter);
04117: int rc = jfc.showSaveDialog(this );
04118: return getChosenFile(jfc, rc);
04119: }
04120:
04121: /** Returns the current DefinitionsPane. */
04122: public DefinitionsPane getCurrentDefPane() {
04123: return _currentDefPane;
04124: }
04125:
04126: /** Returns the currently shown error panel if there is one. Otherwise returns null. */
04127: public ErrorPanel getSelectedErrorPanel() {
04128: Component c = _tabbedPane.getSelectedComponent();
04129: if (c instanceof ErrorPanel)
04130: return (ErrorPanel) c;
04131: return null;
04132: }
04133:
04134: /** Returns whether the compiler output tab is currently showing. */
04135: public boolean isCompilerTabSelected() {
04136: return _tabbedPane.getSelectedComponent() == _compilerErrorPanel;
04137: }
04138:
04139: /** Returns whether the test output tab is currently showing. */
04140: public boolean isTestTabSelected() {
04141: return _tabbedPane.getSelectedComponent() == _junitErrorPanel;
04142: }
04143:
04144: /** Returns whether the JavaDoc output tab is currently showing. */
04145: public boolean isJavadocTabSelected() {
04146: return _tabbedPane.getSelectedComponent() == _javadocErrorPanel;
04147: }
04148:
04149: /** Makes sure save and compile buttons and menu items are enabled and disabled appropriately after document
04150: * modifications.
04151: */
04152: private void _installNewDocumentListener(
04153: final OpenDefinitionsDocument d) {
04154: d.addDocumentListener(new DocumentUIListener() {
04155: public void changedUpdate(DocumentEvent e) {
04156:
04157: // Commented out because the only attributes that affect the status of buttons are inserts and removes
04158: // Utilities.invokeLater(new Runnable() {
04159: // public void run() {
04160: // OpenDefinitionsDocument doc = _model.getActiveDocument();
04161: // if (doc.isModifiedSinceSave()) {
04162: // _saveAction.setEnabled(true);
04163: // if (isDebuggerReady() && _debugPanel.getStatusText().equals(""))
04164: // _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
04165: // updateStatusField();
04166: // }
04167: // }
04168: // });
04169: }
04170:
04171: public void insertUpdate(DocumentEvent e) {
04172: Utilities.invokeLater(new Runnable() {
04173: public void run() {
04174: _saveAction.setEnabled(true);
04175: if (isDebuggerReady()
04176: && _debugPanel.getStatusText().equals(
04177: ""))
04178: _debugPanel
04179: .setStatusText(DEBUGGER_OUT_OF_SYNC);
04180: // updateStatusField(); // file title not changed by insert operation
04181: }
04182: });
04183: }
04184:
04185: public void removeUpdate(DocumentEvent e) {
04186: Utilities.invokeLater(new Runnable() {
04187: public void run() {
04188: _saveAction.setEnabled(true);
04189: if (isDebuggerReady()
04190: && _debugPanel.getStatusText().equals(
04191: ""))
04192: _debugPanel
04193: .setStatusText(DEBUGGER_OUT_OF_SYNC);
04194: // updateStatusField(); // file title not changed by remove operation
04195: }
04196: });
04197: }
04198: });
04199: }
04200:
04201: /** Changes the message text toward the right of the status bar
04202: * @param msg The message to place in the status bar
04203: */
04204: public void setStatusMessage(String msg) {
04205: _statusReport.setText(msg);
04206: }
04207:
04208: /** Sets the message text in the status bar to the null string. */
04209: public void clearStatusMessage() {
04210: _statusReport.setText("");
04211: }
04212:
04213: /** Sets the font of the status bar message
04214: * @param f The new font of the status bar message
04215: */
04216: public void setStatusMessageFont(Font f) {
04217: _statusReport.setFont(f);
04218: }
04219:
04220: /** Sets the color of the text in the status bar message
04221: * @param c The color of the text
04222: */
04223: public void setStatusMessageColor(Color c) {
04224: _statusReport.setForeground(c);
04225: }
04226:
04227: // Made package protected rather than private in order to facilitate the ProjectMenuTest.testSaveProject
04228: void _moveToAuxiliary() {
04229: // now works with multiple files
04230: java.util.List<OpenDefinitionsDocument> l = _model
04231: .getDocumentNavigator().getSelectedDocuments();
04232: for (OpenDefinitionsDocument d : l) {
04233: if (d != null) {
04234: if (!d.isUntitled()) {
04235: _model.addAuxiliaryFile(d);
04236: try {
04237: _model.getDocumentNavigator().refreshDocument(
04238: d,
04239: _model.fixPathForNavigator(d.getFile()
04240: .getCanonicalPath()));
04241: } catch (IOException e) { /* do nothing */
04242: }
04243: }
04244: }
04245: }
04246: }
04247:
04248: private void _removeAuxiliary() {
04249: // now works with multiple files
04250:
04251: for (OpenDefinitionsDocument d : _model.getDocumentNavigator()
04252: .getSelectedDocuments()) {
04253: // OpenDefinitionsDocument d = _model.getDocumentNavigator().getCurrent();
04254: if (d != null) {
04255: if (!d.isUntitled()) {
04256: _model.removeAuxiliaryFile(d);
04257: try {
04258: _model.getDocumentNavigator().refreshDocument(
04259: d,
04260: _model.fixPathForNavigator(d.getFile()
04261: .getCanonicalPath()));
04262: } catch (IOException e) { /* do nothing */
04263: }
04264: }
04265: }
04266: }
04267: }
04268:
04269: void _moveAllToAuxiliary() {
04270: // move all external files to auxiliary files
04271: OpenDefinitionsDocument d;
04272: Enumeration<OpenDefinitionsDocument> e = _model
04273: .getDocumentNavigator().getDocumentsInBin(
04274: _model.getExternalBinTitle());
04275: while (e.hasMoreElements()) {
04276: d = e.nextElement();
04277: if (d != null) {
04278: if (!d.isUntitled()) {
04279: _model.addAuxiliaryFile(d);
04280: try {
04281: _model.getDocumentNavigator().refreshDocument(
04282: d,
04283: _model.fixPathForNavigator(d.getFile()
04284: .getCanonicalPath()));
04285: } catch (IOException ex) { /* do nothing */
04286: }
04287: }
04288: }
04289: }
04290: Utilities.invokeLater(new Runnable() {
04291: public void run() {
04292: _model.getDocumentNavigator().setActiveDoc(
04293: _model.getActiveDocument());
04294: }
04295: });
04296: }
04297:
04298: private void _removeAllAuxiliary() {
04299: // move all auxiliary files to external files
04300: OpenDefinitionsDocument d;
04301: Enumeration<OpenDefinitionsDocument> e = _model
04302: .getDocumentNavigator().getDocumentsInBin(
04303: _model.getAuxiliaryBinTitle());
04304: while (e.hasMoreElements()) {
04305: d = e.nextElement();
04306: if (d != null) {
04307: if (!d.isUntitled()) {
04308: _model.removeAuxiliaryFile(d);
04309: try {
04310: _model.getDocumentNavigator().refreshDocument(
04311: d,
04312: _model.fixPathForNavigator(d.getFile()
04313: .getCanonicalPath()));
04314: } catch (IOException ex) { /* do nothing */
04315: }
04316: }
04317: }
04318: }
04319: Utilities.invokeLater(new Runnable() {
04320: public void run() {
04321: _model.getDocumentNavigator().setActiveDoc(
04322: _model.getActiveDocument());
04323: }
04324: });
04325: }
04326:
04327: private void _new() {
04328: updateStatusField("Creating a new Untitled Document");
04329: _model.newFile();
04330: }
04331:
04332: private void _open() {
04333: updateStatusField("Opening File");
04334: open(_openSelector);
04335: }
04336:
04337: private void _openFolder() {
04338: openFolder(_folderChooser);
04339: }
04340:
04341: private void _openFileOrProject() {
04342: try {
04343: final File[] fileList = _openFileOrProjectSelector
04344: .getFiles();
04345:
04346: FileOpenSelector fos = new FileOpenSelector() {
04347: public File[] getFiles() {
04348: return fileList;
04349: }
04350: };
04351:
04352: if (_openChooser.getFileFilter().equals(_projectFilter))
04353: openProject(fos);
04354: else
04355: open(fos);
04356: } catch (OperationCanceledException oce) { /* do nothing */
04357: }
04358: }
04359:
04360: /** Puts the given text into the current definitions pane at the current caret position. */
04361: private void _putTextIntoDefinitions(String text) {
04362: int caretPos = _currentDefPane.getCaretPosition();
04363:
04364: try {
04365: _model.getActiveDocument().insertString(caretPos, text,
04366: null);
04367: } catch (BadLocationException ble) {
04368: throw new UnexpectedException(ble);
04369: }
04370: }
04371:
04372: /** Sets the left navigator pane to the correct component as dictated by the model. */
04373: private void _resetNavigatorPane() {
04374: if (_model.getDocumentNavigator() instanceof JTreeSortNavigator) {
04375: JTreeSortNavigator<?> nav = (JTreeSortNavigator<?>) _model
04376: .getDocumentNavigator();
04377: nav.setDisplayManager(getNavPaneDisplayManager());
04378: nav.setRootIcon(_djProjectIcon);
04379: }
04380: _docSplitPane.remove(_docSplitPane.getLeftComponent());
04381: _docSplitPane.setLeftComponent(new JScrollPane(_model
04382: .getDocumentNavigator().asContainer()));
04383: Font doclistFont = DrJava.getConfig().getSetting(FONT_DOCLIST);
04384: _model.getDocCollectionWidget().setFont(doclistFont);
04385: _updateNormalColor();
04386: _updateBackgroundColor();
04387: }
04388:
04389: /** Asks the user to select the project file to open and starts the process of opening the project. */
04390: private void _openProject() {
04391: openProject(_openProjectSelector);
04392: }
04393:
04394: public void openProject(FileOpenSelector projectSelector) {
04395:
04396: try {
04397: final File[] files = projectSelector.getFiles();
04398: if (files.length < 1)
04399: throw new IllegalStateException(
04400: "Open project file selection not canceled but no project file was selected.");
04401: final File file = files[0];
04402:
04403: updateStatusField("Opening project " + file);
04404:
04405: try {
04406: hourglassOn();
04407: // make sure there are no open projects
04408: if (!_model.isProjectActive()
04409: || (_model.isProjectActive() && _closeProject()))
04410: _openProjectHelper(file);
04411: } catch (Exception e) {
04412: e.printStackTrace(System.out);
04413: } finally {
04414: hourglassOff();
04415: }
04416: } catch (OperationCanceledException oce) { /* do nothing, we just won't open anything */
04417: }
04418:
04419: }
04420:
04421: /** Oversees the opening of the project by delegating to the model to parse and initialize the project
04422: * while resetting the navigator pane and opening up the files itself.
04423: * @param projectFile the file of the project to open
04424: */
04425: private void _openProjectHelper(File projectFile) {
04426: _currentProjFile = projectFile;
04427: try {
04428: _mainListener.resetFNFCount();
04429: _model.openProject(projectFile);
04430: if (_mainListener.someFilesNotFound())
04431: _model.setProjectChanged(true);
04432: _completeClassList = new ArrayList<GoToFileListEntry>(); // reset auto-completion list
04433: } catch (MalformedProjectFileException e) {
04434: _showProjectFileParseError(e); // add to an error adapter
04435: return;
04436: } catch (FileNotFoundException e) {
04437: _showFileNotFoundError(e); // add to an error adapter
04438: return;
04439: } catch (IOException e) {
04440: _showIOError(e); // add to an error adapter
04441: return;
04442: }
04443: }
04444:
04445: private void _openProjectUpdate() {
04446: if (_model.isProjectActive()) {
04447: _closeProjectAction.setEnabled(true);
04448: _saveProjectAction.setEnabled(true);
04449: _saveProjectAsAction.setEnabled(true);
04450: _projectPropertiesAction.setEnabled(true);
04451: // _junitProjectAction.setEnabled(true);
04452: _junitProjectAction.setEnabled(true);
04453: // _compileOpenProjectAction.setEnabled(true);
04454: _compileProjectAction.setEnabled(true);
04455: _jarProjectAction.setEnabled(true);
04456: if (_model.getBuildDirectory() != null)
04457: _cleanAction.setEnabled(true);
04458: _resetNavigatorPane();
04459: // _compileButton.setToolTipText("<html>Compile all documents in the project.source tree<br>Auxiliary and external files are excluded.</html>");
04460: }
04461: }
04462:
04463: boolean _closeProject() {
04464: _completeClassList = new ArrayList<GoToFileListEntry>(); // reset auto-completion list
04465: _autoImportClassList = new ArrayList<JavaAPIListEntry>(); // reset auto-import list
04466: return _closeProject(false);
04467: }
04468:
04469: /** Closes project when DrJava is not in the process of quitting.
04470: * @return true if the project is closed, false if cancelled.
04471: */
04472: boolean closeProject() {
04473: updateStatusField("Closing current project");
04474: return _closeProject();
04475: }
04476:
04477: /** Saves the project file; closes all open project files; and calls _model.closeProject(quitting) the
04478: * clean up the state of the global model. It also restores the list view navigator
04479: * @ param quitting whether the project is being closed as part of quitting DrJava
04480: * @return true if the project is closed, false if cancelled
04481: */
04482: boolean _closeProject(boolean quitting) {
04483: if (_checkProjectClose()) {
04484: List<OpenDefinitionsDocument> projDocs = _model
04485: .getProjectDocuments();
04486: // System.err.println("projDocs = " + projDocs);
04487: boolean couldClose = _model.closeFiles(projDocs);
04488: if (!couldClose)
04489: return false;
04490: // project file has been saved and all files closed
04491: if (quitting)
04492: return true;
04493: _model.closeProject(quitting);
04494:
04495: Component renderer = _model.getDocumentNavigator()
04496: .getRenderer();
04497: new ForegroundColorListener(renderer);
04498: new BackgroundColorListener(renderer);
04499: _resetNavigatorPane();
04500: if (_model.getDocumentCount() == 1) {
04501: _model.setActiveFirstDocument();
04502: }
04503: _closeProjectAction.setEnabled(false);
04504: _saveProjectAction.setEnabled(false);
04505: _saveProjectAsAction.setEnabled(false);
04506: _projectPropertiesAction.setEnabled(false);
04507: // _junitProjectAction.setEnabled(false);
04508: _jarProjectAction.setEnabled(false);
04509: _junitProjectAction.setEnabled(false);
04510: // _compileOpenProjectAction.setEnabled(false);
04511: _compileProjectAction.setEnabled(false);
04512: _setUpContextMenus();
04513: _currentProjFile = null;
04514: // _compileButton.setToolTipText("Compile all open documents");
04515: return true;
04516: } else
04517: return false; // Project closing cancelled in _checkProjectClose dialog
04518: }
04519:
04520: private boolean _checkProjectClose() {
04521: if (_model.isProjectChanged()) {
04522: String fname = _model.getProjectFile().getName();
04523: String text = fname
04524: + " has been modified. Would you like to save it?";
04525: int rc = JOptionPane.showConfirmDialog(MainFrame.this ,
04526: text, "Save " + fname + "?",
04527: JOptionPane.YES_NO_CANCEL_OPTION);
04528: switch (rc) {
04529: case JOptionPane.YES_OPTION:
04530: _saveProject();
04531: return true;
04532: case JOptionPane.NO_OPTION:
04533: return true;
04534: case JOptionPane.CLOSED_OPTION:
04535: case JOptionPane.CANCEL_OPTION:
04536: return false;
04537: default:
04538: throw new RuntimeException("Invalid rc: " + rc);
04539: }
04540: }
04541: return true;
04542: }
04543:
04544: public File getCurrentProject() {
04545: return _currentProjFile;
04546: }
04547:
04548: /** Opens all the files returned by the FileOpenSelector prompting the user to handle the cases where files are
04549: * already open, files are missing, or the action was canceled by the user
04550: * @param openSelector the selector that returns the files to open
04551: */
04552: public void open(FileOpenSelector openSelector) {
04553: try {
04554: hourglassOn();
04555: _model.openFiles(openSelector);
04556: } catch (AlreadyOpenException aoe) {
04557: OpenDefinitionsDocument[] openDocs = aoe.getOpenDocuments();
04558: for (OpenDefinitionsDocument openDoc : openDocs) {
04559: String fileName;
04560: try {
04561: fileName = openDoc.getFile().getName();
04562: } catch (IllegalStateException ise) {
04563: // Can't happen: this open document must have a file
04564: throw new UnexpectedException(ise);
04565: } catch (FileMovedException fme) {
04566: // File was deleted, but use the same name anyway
04567: fileName = fme.getFile().getName();
04568: }
04569: try {
04570: File f = openDoc.getFile();
04571: if (!_model.inProject(f))
04572: _recentFileManager.updateOpenFiles(f);
04573: } catch (IllegalStateException ise) {
04574: // Impossible: saved => has a file
04575: throw new UnexpectedException(ise);
04576: } catch (FileMovedException fme) {
04577: File f = fme.getFile();
04578: // Recover, show it in the list anyway
04579: if (!_model.inProject(f))
04580: _recentFileManager.updateOpenFiles(f);
04581: }
04582: }
04583: } catch (OperationCanceledException oce) { /* do not open file */
04584: } catch (FileNotFoundException fnf) {
04585: _showFileNotFoundError(fnf);
04586: } catch (IOException ioe) {
04587: _showIOError(ioe);
04588: } finally {
04589: hourglassOff();
04590: }
04591: }
04592:
04593: /** Opens all the files in the directory returned by the FolderSelector.
04594: * @param chooser the selector that returns the files to open
04595: */
04596: public void openFolder(DirectoryChooser chooser) {
04597: String type = "'."
04598: + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[DrJava
04599: .getConfig().getSetting(LANGUAGE_LEVEL)] + "' ";
04600: chooser.setDialogTitle("Open All " + type + "Files in ...");
04601:
04602: File openDir = null;
04603: try {
04604: File activeFile = _model.getActiveDocument().getFile();
04605: if (activeFile != null)
04606: openDir = activeFile.getParentFile();
04607: else
04608: openDir = _model.getProjectRoot();
04609: } catch (FileMovedException e) { /* do nothing */
04610: }
04611:
04612: int result = chooser.showDialog(openDir);
04613: if (result != DirectoryChooser.APPROVE_OPTION)
04614: return; // canceled or error
04615:
04616: File dir = chooser.getSelectedDirectory();
04617: boolean rec = _openRecursiveCheckBox.isSelected();
04618: DrJava.getConfig().setSetting(
04619: OptionConstants.OPEN_FOLDER_RECURSIVE,
04620: Boolean.valueOf(rec));
04621: updateStatusField("Opening folder " + dir);
04622: _openFolder(dir, rec);
04623: }
04624:
04625: /** Opens all the files in the specified directory; it opens all files in nested folders if rec is true.
04626: * @param dir the specified directory
04627: * @param rec true if files in nested folders should be opened
04628: */
04629: private void _openFolder(File dir, boolean rec) {
04630: hourglassOn();
04631: try {
04632: _model.openFolder(dir, rec);
04633: } catch (AlreadyOpenException e) { /* do nothing */
04634: } catch (IOException e) {
04635: _showIOError(e);
04636: } catch (OperationCanceledException oce) { /* do nothing */
04637: } finally {
04638: hourglassOff();
04639: }
04640: }
04641:
04642: /** Delegates directly to the model to close the active document */
04643: private void _close() {
04644: // LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
04645: // l.add(_model.getActiveDocument());
04646: // _model.closeFiles(l);
04647:
04648: // this works with multiple selected files now
04649: java.util.List<OpenDefinitionsDocument> l = _model
04650: .getDocumentNavigator().getSelectedDocuments();
04651: boolean queryNecessary = false; // is a query necessary because the files are project or auxiliary files?
04652: for (OpenDefinitionsDocument doc : l) {
04653: if ((_model.isProjectActive() && doc.inProjectPath())
04654: || doc.isAuxiliaryFile()) {
04655: queryNecessary = true;
04656: break;
04657: }
04658: }
04659: if (queryNecessary) {
04660: int rc;
04661: String fileName = null;
04662: Object[] options = { "Yes", "No" };
04663: if (l.size() == 1) {
04664: OpenDefinitionsDocument doc = l.get(0);
04665: try {
04666: if (doc.isUntitled())
04667: fileName = "File";
04668: else
04669: fileName = _model.getActiveDocument().getFile()
04670: .getName();
04671: } catch (FileMovedException e) {
04672: fileName = e.getFile().getName();
04673: }
04674: String text = "Closing this file will permanently remove it from the current project."
04675: + "\nAre you sure that you want to close this file?";
04676:
04677: rc = JOptionPane.showOptionDialog(MainFrame.this , text,
04678: "Close " + fileName + "?",
04679: JOptionPane.YES_NO_OPTION,
04680: JOptionPane.QUESTION_MESSAGE, null, options,
04681: options[1]);
04682: } else {
04683: fileName = l.size() + " files";
04684: String text = "Closing these "
04685: + fileName
04686: + " will permanently remove them from the current project."
04687: + "\nAre you sure that you want to close these files?";
04688:
04689: rc = JOptionPane.showOptionDialog(MainFrame.this , text,
04690: "Close " + l.size() + " files?",
04691: JOptionPane.YES_NO_OPTION,
04692: JOptionPane.QUESTION_MESSAGE, null, options,
04693: options[1]);
04694: }
04695: if (rc != JOptionPane.YES_OPTION)
04696: return;
04697:
04698: updateStatusField("Closing " + fileName);
04699: _model.setProjectChanged(true);
04700: }
04701: // Either this is an external file or user actually wants to close it
04702: for (OpenDefinitionsDocument doc : l) {
04703: _model.closeFile(doc);
04704: }
04705: }
04706:
04707: private void _closeFolder() {
04708: OpenDefinitionsDocument d;
04709: Enumeration<OpenDefinitionsDocument> e = _model
04710: .getDocumentNavigator().getDocuments();
04711: final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
04712: if (_model.getDocumentNavigator().isGroupSelected()) {
04713: while (e.hasMoreElements()) {
04714: d = e.nextElement();
04715: if (_model.getDocumentNavigator().isSelectedInGroup(d)) {
04716: l.add(d);
04717: }
04718: }
04719: _model.closeFiles(l);
04720: if (!l.isEmpty())
04721: _model.setProjectChanged(true);
04722: }
04723: }
04724:
04725: private void _printDefDoc() {
04726: try {
04727: _model.getActiveDocument().print();
04728: } catch (FileMovedException fme) {
04729: _showFileMovedError(fme);
04730: } catch (PrinterException e) {
04731: _showError(e, "Print Error",
04732: "An error occured while printing.");
04733: } catch (BadLocationException e) {
04734: _showError(e, "Print Error",
04735: "An error occured while printing.");
04736: }
04737: }
04738:
04739: private void _printConsole() {
04740: try {
04741: _model.getConsoleDocument().print();
04742: } catch (PrinterException e) {
04743: _showError(e, "Print Error",
04744: "An error occured while printing.");
04745: }
04746: }
04747:
04748: private void _printInteractions() {
04749: try {
04750: _model.getInteractionsDocument().print();
04751: } catch (PrinterException e) {
04752: _showError(e, "Print Error",
04753: "An error occured while printing.");
04754: }
04755: }
04756:
04757: /** Opens a new PrintPreview frame. */
04758: private void _printDefDocPreview() {
04759: try {
04760: _model.getActiveDocument().preparePrintJob();
04761: new PreviewDefDocFrame(_model, this );
04762: } catch (FileMovedException fme) {
04763: _showFileMovedError(fme);
04764: } catch (BadLocationException e) {
04765: _showError(e, "Print Error",
04766: "An error occured while preparing the print preview.");
04767: } catch (IllegalStateException e) {
04768: _showError(e, "Print Error",
04769: "An error occured while preparing the print preview.");
04770: }
04771: }
04772:
04773: private void _printConsolePreview() {
04774: try {
04775: _model.getConsoleDocument().preparePrintJob();
04776: new PreviewConsoleFrame(_model, this , false);
04777: } catch (IllegalStateException e) {
04778: _showError(e, "Print Error",
04779: "An error occured while preparing the print preview.");
04780: }
04781: }
04782:
04783: private void _printInteractionsPreview() {
04784: try {
04785: _model.getInteractionsDocument().preparePrintJob();
04786: new PreviewConsoleFrame(_model, this , true);
04787: } catch (IllegalStateException e) {
04788: _showError(e, "Print Error",
04789: "An error occured while preparing the print preview.");
04790: }
04791: }
04792:
04793: private void _pageSetup() {
04794: PrinterJob job = PrinterJob.getPrinterJob();
04795: _model.setPageFormat(job.pageDialog(_model.getPageFormat()));
04796: }
04797:
04798: //Called by testCases
04799: void closeAll() {
04800: _closeAll();
04801: }
04802:
04803: private void _closeAll() {
04804: updateStatusField("Closing All Files");
04805: if (!_model.isProjectActive() || _model.isProjectActive()
04806: && _closeProject())
04807: _model.closeAllFiles();
04808: }
04809:
04810: private boolean _save() {
04811: updateStatusField("Saving File");
04812: try {
04813: // now works with multiple files
04814: List<OpenDefinitionsDocument> l = _model
04815: .getDocumentNavigator().getSelectedDocuments();
04816: boolean success = false;
04817: for (OpenDefinitionsDocument doc : l) {
04818: if (doc.saveFile(_saveSelector)) {
04819: getDefPaneGivenODD(doc).hasWarnedAboutModified(
04820: false);
04821: success = true;
04822: }
04823: }
04824: // _model.refreshActiveDocument() is not sufficient here; it does not re-select
04825: // the same document in flat-file mode
04826: _model.setActiveDocument(_model.getActiveDocument());
04827: return success;
04828: // if (_model.getActiveDocument().saveFile(_saveSelector)) {
04829: // _currentDefPane.hasWarnedAboutModified(false);
04830: //
04831: // /**This highlights the document in the navigator */
04832: // _model.setActiveDocument(_model.getActiveDocument());
04833: //
04834: // return true;
04835: // }
04836: // else return false;
04837: } catch (IOException ioe) {
04838: _showIOError(ioe);
04839: return false;
04840: }
04841: }
04842:
04843: private boolean _saveAs() {
04844: updateStatusField("Saving File Under New Name");
04845: try {
04846: boolean toReturn = _model.getActiveDocument().saveFileAs(
04847: _saveAsSelector);
04848: /** this highlights the document in the navigator */
04849: _model.setActiveDocument(_model.getActiveDocument());
04850: return toReturn;
04851: } catch (IOException ioe) {
04852: _showIOError(ioe);
04853: return false;
04854: }
04855: }
04856:
04857: private boolean _rename() {
04858: try {
04859: if (!_model.getActiveDocument().fileExists())
04860: return _saveAs();
04861: else {
04862: File fileToDelete;
04863: try {
04864: fileToDelete = _model.getActiveDocument().getFile();
04865: } catch (FileMovedException fme) {
04866: return _saveAs();
04867: }
04868: boolean toReturn = _model.getActiveDocument()
04869: .saveFileAs(_saveAsSelector);
04870: /** Delete the old file if save was successful */
04871: if (toReturn
04872: && !_model.getActiveDocument().getFile()
04873: .equals(fileToDelete))
04874: fileToDelete.delete();
04875: /** this highlights the document in the navigator */
04876: _model.setActiveDocument(_model.getActiveDocument());
04877: return toReturn;
04878: }
04879: } catch (IOException ioe) {
04880: _showIOError(ioe);
04881: return false;
04882: }
04883: }
04884:
04885: /* Package private to allow use in MainFrameTest. */
04886: void _saveAll() {
04887: hourglassOn();
04888: try {
04889: if (_model.isProjectActive())
04890: _saveProject();
04891: _model.saveAllFiles(_saveSelector);
04892: } catch (IOException ioe) {
04893: _showIOError(ioe);
04894: } finally {
04895: hourglassOff();
04896: }
04897: }
04898:
04899: // Called by the ProjectPropertiesFrame
04900: void saveProject() {
04901: _saveProject();
04902: }
04903:
04904: private void _saveProject() {
04905: //File file = _model.getProjectFile();
04906: _saveProjectHelper(_currentProjFile);
04907: }
04908:
04909: /** Edit project frame. */
04910: private void _editProject() {
04911: ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(this );
04912: ppf.setVisible(true);
04913: ppf.reset();
04914: ppf.toFront(); // ppf actions save state of ppf in global model
04915: }
04916:
04917: /** Closes all files and makes a new project. */
04918: private void _newProject() {
04919:
04920: _closeProject(true); // suppress resetting interactions; it will be done in _model.newProject() below
04921: _saveChooser.setFileFilter(_projectFilter);
04922: int rc = _saveChooser.showSaveDialog(this );
04923: if (rc == JFileChooser.APPROVE_OPTION) {
04924: File pf = _saveChooser.getSelectedFile(); // project file
04925: if (pf.exists() && !_verifyOverwrite()) {
04926: return;
04927: }
04928:
04929: String fileName = pf.getName();
04930: // ensure that saved file has extesion ".pjt"
04931: if (!fileName.endsWith(".pjt")) {
04932: int lastIndex = fileName.lastIndexOf(".");
04933: if (lastIndex == -1)
04934: pf = new File(pf.getAbsolutePath() + ".pjt");
04935: else
04936: pf = new File(fileName.substring(0, lastIndex)
04937: + ".pjt");
04938: }
04939:
04940: _model.createNewProject(pf); // sets model to a new FileGroupingState for project file pf
04941: // ProjectPropertiesFrame ppf = new ProjectPropertiesFrame(MainFrame.this, file);
04942: // ppf.saveSettings(); // Saves new project profile in global model
04943: _editProject(); // edits the properties of the new FileGroupingState
04944: try {
04945: _model.configNewProject();
04946: } // configures the new project in the model
04947: catch (IOException e) {
04948: throw new UnexpectedException(e);
04949: }
04950: _currentProjFile = pf;
04951: }
04952: }
04953:
04954: /** Pops up the _saveChooser dialog, asks the user for a new project file name, and sets the project file to the
04955: * specified file. Nothing is written in the file system; this action is performed by a subsequent _saveAll().
04956: * @return false if the user canceled the action */
04957: private boolean _saveProjectAs() {
04958:
04959: // // This redundant-looking hack is necessary for JDK 1.3.1 on Mac OS X!
04960: _saveChooser.removeChoosableFileFilter(_projectFilter);
04961: _saveChooser.removeChoosableFileFilter(_javaSourceFilter);
04962: _saveChooser.setFileFilter(_projectFilter);
04963: // File selection = _saveChooser.getSelectedFile();
04964: // if (selection != null) { // what is this block of commands for?
04965: // _saveChooser.setSelectedFile(selection.getParentFile());
04966: // _saveChooser.setSelectedFile(selection);
04967: // _saveChooser.setSelectedFile(null);
04968: // }
04969:
04970: if (_currentProjFile != null)
04971: _saveChooser.setSelectedFile(_currentProjFile);
04972:
04973: int rc = _saveChooser.showSaveDialog(this );
04974: if (rc == JFileChooser.APPROVE_OPTION) {
04975: File file = _saveChooser.getSelectedFile();
04976: if (!file.exists() || _verifyOverwrite()) {
04977: _model.setProjectFile(file);
04978: _currentProjFile = file;
04979: }
04980: }
04981:
04982: return (rc == JFileChooser.APPROVE_OPTION);
04983: }
04984:
04985: void _saveProjectHelper(File file) {
04986: try {
04987: if (file.getName().indexOf(".") == -1)
04988: file = new File(file.getAbsolutePath() + ".pjt");
04989: String fileName = file.getCanonicalPath();
04990: _model.saveProject(file, gatherProjectDocInfo());
04991: // if (!(_model.getDocumentNavigator() instanceof JTreeSortNavigator)) {
04992: // _openProjectHelper(file);
04993: // }
04994: } catch (IOException ioe) {
04995: _showIOError(ioe);
04996: }
04997: _recentProjectManager.updateOpenFiles(file);
04998: _model.setProjectChanged(false);
04999: }
05000:
05001: public Hashtable<OpenDefinitionsDocument, DocumentInfoGetter> gatherProjectDocInfo() {
05002: Hashtable<OpenDefinitionsDocument, DocumentInfoGetter> map = new Hashtable<OpenDefinitionsDocument, DocumentInfoGetter>();
05003: List<OpenDefinitionsDocument> docs = _model
05004: .getProjectDocuments();
05005: for (OpenDefinitionsDocument doc : docs) {
05006: map.put(doc, _makeInfoGetter(doc));
05007: }
05008: return map;
05009: }
05010:
05011: /** Gets the information to be save for a project document.
05012: * Implementation may change if the scroll/selection information is later stored in a place other than the
05013: * definitions pane. Hopefully this info will eventually be backed up in the OpenDefinitionsDocument in which
05014: * case all this code should be refactored into the model's _saveProject method
05015: */
05016: private DocumentInfoGetter _makeInfoGetter(
05017: final OpenDefinitionsDocument doc) {
05018: JScrollPane s = _defScrollPanes.get(doc);
05019: if (s == null) {
05020: s = _createDefScrollPane(doc);
05021: }
05022: final JScrollPane scroller = s;
05023: final DefinitionsPane pane = (DefinitionsPane) scroller
05024: .getViewport().getView();
05025:
05026: return new DocumentInfoGetter() {
05027: public Pair<Integer, Integer> getSelection() {
05028: Integer selStart = new Integer(pane.getSelectionStart());
05029: Integer selEnd = new Integer(pane.getSelectionEnd());
05030: if (pane.getCaretPosition() == selStart)
05031: return new Pair<Integer, Integer>(selEnd, selStart);
05032: return new Pair<Integer, Integer>(selStart, selEnd);
05033: }
05034:
05035: public Pair<Integer, Integer> getScroll() {
05036: Integer scrollv = new Integer(pane.getVerticalScroll());
05037: Integer scrollh = new Integer(pane
05038: .getHorizontalScroll());
05039: return new Pair<Integer, Integer>(scrollv, scrollh);
05040: }
05041:
05042: public File getFile() {
05043: return doc.getRawFile();
05044: }
05045:
05046: public String getPackage() {
05047: return doc.getPackageName();
05048: }
05049:
05050: public boolean isActive() {
05051: return _model.getActiveDocument() == doc;
05052: }
05053:
05054: public boolean isUntitled() {
05055: return doc.isUntitled();
05056: }
05057: };
05058: }
05059:
05060: private void _revert() {
05061: // this works with multiple selected files now
05062: java.util.List<OpenDefinitionsDocument> l = _model
05063: .getDocumentNavigator().getSelectedDocuments();
05064: for (OpenDefinitionsDocument d : l) {
05065: _revert(d);
05066: }
05067: }
05068:
05069: private void _revert(OpenDefinitionsDocument doc) {
05070: try {
05071: doc.revertFile();
05072: } catch (FileMovedException fme) {
05073: _showFileMovedError(fme);
05074: } catch (IOException ioe) {
05075: _showIOError(ioe);
05076: }
05077: }
05078:
05079: /**
05080: private void _revertAll() {
05081: try {
05082: _model.revertAllFiles();
05083: }
05084: catch (FileMovedException fme) {
05085: _showFileMovedError(fme);
05086: }
05087: catch (IOException ioe) {
05088: _showIOError(ioe);
05089: }
05090: }
05091: */
05092:
05093: private void _quit() {
05094: // AbstractGlobalModel._log.log("MainFrame.quit() called");
05095: if (_promptBeforeQuit) {
05096: String title = "Quit DrJava?";
05097: String message = "Are you sure you want to quit DrJava?";
05098: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
05099: MainFrame.this , title, message);
05100: int rc = dialog.show();
05101: if (rc != JOptionPane.YES_OPTION)
05102: return;
05103: else {
05104: // Only remember the checkbox if they say yes
05105: if (dialog.getCheckBoxValue() == true) {
05106: DrJava.getConfig().setSetting(QUIT_PROMPT,
05107: Boolean.FALSE);
05108: }
05109: }
05110: }
05111: // tried passing false here. seemed to help with bug
05112: // [ 1478796 ] DrJava Does Not Shut Down With Project Open
05113: // on HP tc1100 and Toshiba Portege tablet PCs, but did not help in all cases
05114: if (!_closeProject(true)) {
05115: return; /* if user pressed cancel, do not quit */
05116: }
05117:
05118: _recentFileManager.saveRecentFiles();
05119: _recentProjectManager.saveRecentFiles();
05120: if (!_model.closeAllFilesOnQuit()) {
05121: return; /* if user pressed cancel, do not quit */
05122: }
05123: _storePositionInfo();
05124:
05125: // Save recent files, but only if there wasn't a problem at startUp
05126: // (Don't want to overwrite a custom config file with a simple typo.)
05127: if (!DrJava.getConfig().hadStartupException()) {
05128: try {
05129: DrJava.getConfig().saveConfiguration();
05130: } catch (IOException ioe) {
05131: _showIOError(ioe);
05132: }
05133: }
05134: //DrJava.consoleOut().println("Quitting DrJava...");
05135: dispose(); // Free GUI elements of this frame
05136: _model.quit();
05137: }
05138:
05139: private void _forceQuit() {
05140: _model.forceQuit();
05141: }
05142:
05143: /** Stores the current position and size info for window and panes to the config framework. */
05144: private void _storePositionInfo() {
05145: Configuration config = DrJava.getConfig();
05146:
05147: // Window bounds.
05148: if (config.getSetting(WINDOW_STORE_POSITION).booleanValue()) {
05149: Rectangle bounds = getBounds();
05150: config
05151: .setSetting(WINDOW_HEIGHT, new Integer(
05152: bounds.height));
05153: config.setSetting(WINDOW_WIDTH, new Integer(bounds.width));
05154: config.setSetting(WINDOW_X, new Integer(bounds.x));
05155: config.setSetting(WINDOW_Y, new Integer(bounds.y));
05156: config.setSetting(WINDOW_STATE, new Integer(
05157: getExtendedState()));
05158: } else {
05159: // Reset to defaults to restore pristine behavior.
05160: config
05161: .setSetting(WINDOW_HEIGHT, WINDOW_HEIGHT
05162: .getDefault());
05163: config.setSetting(WINDOW_WIDTH, WINDOW_WIDTH.getDefault());
05164: config.setSetting(WINDOW_X, WINDOW_X.getDefault());
05165: config.setSetting(WINDOW_Y, WINDOW_Y.getDefault());
05166: config.setSetting(WINDOW_STATE, WINDOW_STATE.getDefault());
05167: }
05168:
05169: // "Go to File" dialog position and size.
05170: if ((DrJava.getConfig().getSetting(
05171: DIALOG_GOTOFILE_STORE_POSITION).booleanValue())
05172: && (_gotoFileDialog != null)
05173: && (_gotoFileDialog.getFrameState() != null)) {
05174: config.setSetting(DIALOG_GOTOFILE_STATE, (_gotoFileDialog
05175: .getFrameState().toString()));
05176: } else {
05177: // Reset to defaults to restore pristine behavior.
05178: config.setSetting(DIALOG_GOTOFILE_STATE,
05179: DIALOG_GOTOFILE_STATE.getDefault());
05180: }
05181:
05182: // "Open Javadoc" dialog position and size.
05183: if ((DrJava.getConfig().getSetting(
05184: DIALOG_OPENJAVADOC_STORE_POSITION).booleanValue())
05185: && (_openJavadocDialog != null)
05186: && (_openJavadocDialog.getFrameState() != null)) {
05187: config.setSetting(DIALOG_OPENJAVADOC_STATE,
05188: (_openJavadocDialog.getFrameState().toString()));
05189: } else {
05190: // Reset to defaults to restore pristine behavior.
05191: config.setSetting(DIALOG_OPENJAVADOC_STATE,
05192: DIALOG_OPENJAVADOC_STATE.getDefault());
05193: }
05194:
05195: // "Complete Word" dialog position and size.
05196: if ((DrJava.getConfig().getSetting(
05197: DIALOG_COMPLETE_WORD_STORE_POSITION).booleanValue())
05198: && (_completeWordDialog != null)
05199: && (_completeWordDialog.getFrameState() != null)) {
05200: config.setSetting(DIALOG_COMPLETE_WORD_STATE,
05201: (_completeWordDialog.getFrameState().toString()));
05202: } else {
05203: // Reset to defaults to restore pristine behavior.
05204: config.setSetting(DIALOG_COMPLETE_WORD_STATE,
05205: DIALOG_COMPLETE_WORD_STATE.getDefault());
05206: }
05207:
05208: // "Create Jar from Project" dialog position and size.
05209: if ((DrJava.getConfig().getSetting(
05210: DIALOG_JAROPTIONS_STORE_POSITION).booleanValue())
05211: && (_jarOptionsDialog != null)
05212: && (_jarOptionsDialog.getFrameState() != null)) {
05213: config.setSetting(DIALOG_JAROPTIONS_STATE,
05214: (_jarOptionsDialog.getFrameState().toString()));
05215: } else {
05216: // Reset to defaults to restore pristine behavior.
05217: config.setSetting(DIALOG_JAROPTIONS_STATE,
05218: DIALOG_JAROPTIONS_STATE.getDefault());
05219: }
05220:
05221: // Panel heights.
05222: if (_showDebugger)
05223: config.setSetting(DEBUG_PANEL_HEIGHT, new Integer(
05224: _debugPanel.getHeight()));
05225:
05226: // Doc list width.
05227: config.setSetting(DOC_LIST_WIDTH, new Integer(_docSplitPane
05228: .getDividerLocation()));
05229: }
05230:
05231: private void _cleanUpForCompile() {
05232: if (isDebuggerReady())
05233: _model.getDebugger().shutdown();
05234: }
05235:
05236: private void _compile() {
05237: // now works with multiple files
05238: _cleanUpForCompile();
05239: hourglassOn();
05240: try {
05241: // final OpenDefinitionsDocument doc = _model.getActiveDocument();
05242: try {
05243: _model.getCompilerModel().compile(
05244: _model.getDocumentNavigator()
05245: .getSelectedDocuments());
05246: } catch (FileMovedException fme) {
05247: _showFileMovedError(fme);
05248: } catch (IOException ioe) {
05249: _showIOError(ioe);
05250: }
05251: } finally {
05252: hourglassOff();
05253: }
05254: // update(getGraphics());
05255: }
05256:
05257: private void _compileFolder() {
05258: _cleanUpForCompile();
05259: hourglassOn();
05260: try {
05261: OpenDefinitionsDocument d;
05262: Enumeration<OpenDefinitionsDocument> e = _model
05263: .getDocumentNavigator().getDocuments();
05264: final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
05265: if (_model.getDocumentNavigator().isGroupSelected()) {
05266: while (e.hasMoreElements()) {
05267: d = e.nextElement();
05268: if (_model.getDocumentNavigator()
05269: .isSelectedInGroup(d))
05270: l.add(d);
05271: }
05272:
05273: // new Thread("Compile Folder") {
05274: // public void run() {
05275: try {
05276: _model.getCompilerModel().compile(l);
05277: } catch (FileMovedException fme) {
05278: _showFileMovedError(fme);
05279: } catch (IOException ioe) {
05280: _showIOError(ioe);
05281: }
05282: // }
05283: // }.start();
05284: }
05285: } finally {
05286: hourglassOff();
05287: }
05288: // update(getGraphics());
05289: }
05290:
05291: private void _compileProject() {
05292: _cleanUpForCompile();
05293: // new Thread("Compile All") {
05294: // public void run() {
05295: hourglassOn();
05296: try {
05297: _model.getCompilerModel().compileProject();
05298: } catch (FileMovedException fme) {
05299: _showFileMovedError(fme);
05300: } catch (IOException ioe) {
05301: _showIOError(ioe);
05302: } finally {
05303: hourglassOff();
05304: }
05305: // }
05306: // }.start();
05307: // update(getGraphics());
05308: }
05309:
05310: private void _compileAll() {
05311: _cleanUpForCompile();
05312: // new Thread("Compile All") {
05313: // public void run() {
05314: hourglassOn();
05315: try {
05316: _model.getCompilerModel().compileAll();
05317: } catch (FileMovedException fme) {
05318: _showFileMovedError(fme);
05319: } catch (IOException ioe) {
05320: _showIOError(ioe);
05321: } finally {
05322: hourglassOff();
05323: }
05324: // }
05325: // }.start();
05326: // update(getGraphics());
05327: }
05328:
05329: private boolean showCleanWarning() {
05330: if (DrJava.getConfig().getSetting(PROMPT_BEFORE_CLEAN)
05331: .booleanValue()) {
05332: String buildDirTxt = "";
05333: try {
05334: buildDirTxt = _model.getBuildDirectory()
05335: .getCanonicalPath();
05336: } catch (Exception e) {
05337: buildDirTxt = _model.getBuildDirectory().getPath();
05338: }
05339: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
05340: MainFrame.this ,
05341: "Clean Build Directory?",
05342: "Cleaning your build directory will delete all\n"
05343: + "class files and empty folders within that directory.\n"
05344: + "Are you sure you want to clean\n"
05345: + buildDirTxt + "?",
05346: "Do not show this message again");
05347: int rc = dialog.show();
05348: switch (rc) {
05349: case JOptionPane.YES_OPTION:
05350: _saveAll();
05351: // Only remember checkbox if they say yes
05352: if (dialog.getCheckBoxValue()) {
05353: DrJava.getConfig().setSetting(PROMPT_BEFORE_CLEAN,
05354: Boolean.FALSE);
05355: }
05356: return true;
05357: case JOptionPane.NO_OPTION:
05358: return false;
05359: case JOptionPane.CANCEL_OPTION:
05360: return false;
05361: case JOptionPane.CLOSED_OPTION:
05362: return false;
05363: default:
05364: throw new RuntimeException(
05365: "Invalid rc from showConfirmDialog: " + rc);
05366: }
05367: }
05368: return true;
05369: }
05370:
05371: // private void _clean() {
05372: // final SwingWorker worker = new SwingWorker() {
05373: // public Object construct() {
05374: // if (showCleanWarning()) {
05375: // try {
05376: // hourglassOn();
05377: // _model.cleanBuildDirectory();
05378: // }
05379: // catch (FileMovedException fme) { _showFileMovedError(fme); }
05380: // catch (IOException ioe) { _showIOError(ioe); }
05381: // finally { hourglassOff(); }
05382: // }
05383: // return null;
05384: // }
05385: // };
05386: // worker.start();
05387: // }
05388:
05389: private void _clean() {
05390: _model.cleanBuildDirectory(); // The model performs this as an AsyncTask
05391: }
05392:
05393: /** List with entries for the complete dialog. */
05394: ArrayList<GoToFileListEntry> _completeClassList = new ArrayList<GoToFileListEntry>();
05395:
05396: /** List with entries for the auto-import dialog. */
05397: ArrayList<JavaAPIListEntry> _autoImportClassList = new ArrayList<JavaAPIListEntry>();
05398:
05399: /** Scan the build directory for class files and update the auto-completion list. */
05400: private void _scanClassFiles() {
05401: Thread t = new Thread(new Runnable() {
05402: public void run() {
05403: File buildDir = _model.getBuildDirectory();
05404: HashSet<GoToFileListEntry> hs = new HashSet<GoToFileListEntry>();
05405: HashSet<JavaAPIListEntry> hs2 = new HashSet<JavaAPIListEntry>();
05406: if (buildDir != null) {
05407: List<File> classFiles = _model.getClassFiles();
05408: DummyOpenDefDoc dummyDoc = new DummyOpenDefDoc();
05409: for (File f : classFiles) {
05410: String s = f.toString();
05411: if (s.lastIndexOf(java.io.File.separatorChar) >= 0) {
05412: s = s
05413: .substring(s
05414: .lastIndexOf(java.io.File.separatorChar) + 1);
05415: }
05416: s = s.substring(0, s.lastIndexOf(".class"));
05417: s = s.replace('$', '.');
05418: int pos = 0;
05419: boolean ok = true;
05420: while ((pos = s.indexOf('.', pos)) >= 0) {
05421: if ((s.length() <= pos + 1)
05422: || (Character.isDigit(s
05423: .charAt(pos + 1)))) {
05424: ok = false;
05425: break;
05426: }
05427: ++pos;
05428: }
05429: if (ok) {
05430: if (s.lastIndexOf('.') >= 0) {
05431: s = s.substring(s.lastIndexOf('.') + 1);
05432: }
05433: GoToFileListEntry entry = new GoToFileListEntry(
05434: dummyDoc, s);
05435: hs.add(entry);
05436: try {
05437: File rel = FileOps.makeRelativeTo(f,
05438: buildDir);
05439: String full = rel
05440: .toString()
05441: .replace(
05442: java.io.File.separatorChar,
05443: '.');
05444: full = full.substring(0, full
05445: .lastIndexOf(".class"));
05446: if (full.indexOf('$') < 0) {
05447: // no $ in the name means not an inner class
05448: // we do not support inner classes, because that would mean
05449: // having to determine public static scope
05450: hs2.add(new JavaAPIListEntry(s,
05451: full, null));
05452: }
05453: } catch (IOException ioe) { /* ignore, just don't add this one */
05454: } catch (SecurityException se) { /* ignore, just don't add this one */
05455: }
05456: }
05457: }
05458: }
05459: _completeClassList = new ArrayList<GoToFileListEntry>(
05460: hs);
05461: _autoImportClassList = new ArrayList<JavaAPIListEntry>(
05462: hs2);
05463: }
05464: });
05465: t.setPriority(Thread.MIN_PRIORITY);
05466: t.start();
05467: }
05468:
05469: private void _runProject() {
05470: if (_model.isProjectActive()) {
05471: try {
05472: final File f = _model.getMainClass();
05473: if (f != null) {
05474: updateStatusField("Running Open Project");
05475: OpenDefinitionsDocument doc = _model
05476: .getDocumentForFile(f);
05477: doc.runMain();
05478: }
05479: } catch (ClassNameNotFoundException e) {
05480: // Display a warning message if a class name can't be found.
05481: String msg = "DrJava could not find the top level class name in the\n"
05482: + "current document, so it could not run the class. Please\n"
05483: + "make sure that the class is properly defined first.";
05484:
05485: JOptionPane.showMessageDialog(MainFrame.this , msg,
05486: "No Class Found", JOptionPane.ERROR_MESSAGE);
05487: } catch (FileMovedException fme) {
05488: _showFileMovedError(fme);
05489: } catch (IOException ioe) {
05490: _showIOError(ioe);
05491: }
05492: } else
05493: _runMain();
05494: }
05495:
05496: /** Internal helper method to run the main method of the current document in the interactions pane. */
05497: private void _runMain() {
05498: updateStatusField("Running main Method of Current Document");
05499:
05500: try {
05501: _model.getActiveDocument().runMain();
05502: }
05503:
05504: catch (ClassNameNotFoundException e) {
05505: // Display a warning message if a class name can't be found.
05506: String msg = "DrJava could not find the top level class name in the\n"
05507: + "current document, so it could not run the class. Please\n"
05508: + "make sure that the class is properly defined first.";
05509:
05510: JOptionPane.showMessageDialog(MainFrame.this , msg,
05511: "No Class Found", JOptionPane.ERROR_MESSAGE);
05512: } catch (FileMovedException fme) {
05513: _showFileMovedError(fme);
05514: } catch (IOException ioe) {
05515: _showIOError(ioe);
05516: }
05517: }
05518:
05519: private void _junit() {
05520: hourglassOn(); // turned off in JUnitStarted/NonTestCase
05521: new Thread("Run JUnit on Current Document") {
05522: public void run() {
05523: _disableJUnitActions();
05524: // now also works with multiple documents
05525: // hourglassOn(); // moved into the prelude before this thread start
05526: try {
05527: _model.getJUnitModel().junitDocs(
05528: _model.getDocumentNavigator()
05529: .getSelectedDocuments());
05530: // _model.getActiveDocument().startJUnit(); // Equivalent to preceding
05531: }
05532:
05533: // catch (FileMovedException fme) { _showFileMovedError(fme); }
05534: // catch (IOException ioe) { _showIOError(ioe); }
05535: // catch (ClassNotFoundException cnfe) { _showClassNotFoundError(cnfe); }
05536: catch (NoClassDefFoundError ncde) {
05537: _showNoClassDefError(ncde);
05538: }
05539: }
05540: }.start();
05541: }
05542:
05543: private void _junitFolder() {
05544: updateStatusField("Running Unit Tests in Current Folder");
05545: hourglassOn(); // turned off when JUnitStarted event is fired
05546: new Thread("Run JUnit on specified folder") {
05547: public void run() {
05548: INavigatorItem n;
05549: _disableJUnitActions();
05550: // hourglassOn(); // turned off when JUnitStarted event is fired
05551: if (_model.getDocumentNavigator().isGroupSelected()) {
05552: Enumeration<OpenDefinitionsDocument> docs = _model
05553: .getDocumentNavigator().getDocuments();
05554: final LinkedList<OpenDefinitionsDocument> l = new LinkedList<OpenDefinitionsDocument>();
05555: while (docs.hasMoreElements()) {
05556: OpenDefinitionsDocument doc = docs
05557: .nextElement();
05558: if (_model.getDocumentNavigator()
05559: .isSelectedInGroup(doc))
05560: l.add(doc);
05561: }
05562: try {
05563: _model.getJUnitModel().junitDocs(l);
05564: } catch (UnexpectedException e) {
05565: _junitInterrupted(e);
05566: }
05567: }
05568: }
05569: }.start();
05570: }
05571:
05572: /** Tests the documents in the project source tree. Assumes that DrJava is in project mode. */
05573: private void _junitProject() {
05574: updateStatusField("Running JUnit Tests in Project");
05575: hourglassOn(); // turned off in JUnitStarted/NonTestCase event
05576: new Thread("Running Junit Tests") {
05577: public void run() {
05578: _disableJUnitActions();
05579: // hourglassOn(); // turned off in JUnitStarted/NonTestCase event
05580: try {
05581: _model.getJUnitModel().junitProject();
05582: } catch (UnexpectedException e) {
05583: _junitInterrupted(e);
05584: }
05585: }
05586: }.start();
05587: }
05588:
05589: /** Tests all open documents. */
05590: private void _junitAll() {
05591: updateStatusField("Running All Open Unit Tests");
05592: hourglassOn(); // turned off in JUnitStarted/NonTestCase event
05593: new Thread("Running Junit Tests") {
05594: public void run() {
05595: _disableJUnitActions();
05596: // hourglassOn(); // turned off in JUnitStarted/NonTestCase event
05597: try {
05598: _model.getJUnitModel().junitAll();
05599: } catch (UnexpectedException e) {
05600: _junitInterrupted(e);
05601: }
05602: }
05603: }.start();
05604: }
05605:
05606: /* These are used to save the state of the enabled property of the actions disabled during junit testing. */
05607: private volatile DecoratedAction _junit_compileProjectDecoratedAction;
05608: private volatile DecoratedAction _junit_compileAllDecoratedAction;
05609: private volatile DecoratedAction _junit_compileFolderDecoratedAction;
05610: private volatile DecoratedAction _junit_junitFolderDecoratedAction;
05611: private volatile DecoratedAction _junit_junitAllDecoratedAction;
05612: private volatile DecoratedAction _junit_junitDecoratedAction;
05613: private volatile DecoratedAction _junit_junitOpenProjectFilesDecoratedAction;
05614: private volatile DecoratedAction _junit_cleanDecoratedAction;
05615: private volatile DecoratedAction _junit_projectPropertiesDecoratedAction;
05616: private volatile DecoratedAction _junit_runProjectDecoratedAction;
05617: private volatile DecoratedAction _junit_runDecoratedAction;
05618:
05619: /** An AbstractAction that prevents changes to the decoree's enabled flag. */
05620: private class DecoratedAction extends AbstractAction {
05621: /** The AbstractAction that is being decorated. */
05622: AbstractAction _decoree;
05623: /** The "shallow" enabled flag. */
05624: boolean _shallowEnabled;
05625:
05626: /** Create an action decorating the specified action, then sets the decoree's enabled flag to b. */
05627: public DecoratedAction(AbstractAction a, boolean b) {
05628: super ((String) a.getValue("Name"));
05629: _decoree = a;
05630: _shallowEnabled = _decoree.isEnabled();
05631: _decoree.setEnabled(b);
05632: }
05633:
05634: public void actionPerformed(ActionEvent ae) {
05635: _decoree.actionPerformed(ae);
05636: }
05637:
05638: /** Do not change the decoree's enabled flag, but cache this value in the shallow enabled flag. */
05639: public void setEnabled(boolean b) {
05640: _shallowEnabled = b;
05641: }
05642:
05643: /** Write the shallow enabled flag to the decoree, then return the decoree */
05644: public AbstractAction getUpdatedDecoree() {
05645: _decoree.setEnabled(_shallowEnabled);
05646: return _decoree;
05647: }
05648: }
05649:
05650: /** Sets the enabled status to false of all actions that could conflict with JUnit while its is running a test.
05651: * This method saves aside the previous enable state of each action so that when the test is finished, any action
05652: * disabled before the test will remain disabled afterward.
05653: */
05654: private void _disableJUnitActions() {
05655: // _compileProjectActionEnabled = _compileProjectAction.isEnabled();
05656: // _compileAllActionEnabled = _compileAllAction.isEnabled();
05657: //_compileFolderActionEnabled = _compileFolderAction.isEnabled();
05658: //_junitFolderActionEnabled = _junitFolderAction.isEnabled();
05659: //_junitAllActionEnabled = _junitAllAction.isEnabled();
05660: //_junitActionEnabled = _junitAction.isEnabled();
05661: //_junitProjectActionEnabled = _junitProjectAction.isEnabled();
05662: //_cleanActionEnabled = _cleanAction.isEnabled();
05663: //_projectPropertiesActionEnabled = _projectPropertiesAction.isEnabled();
05664: //_runProjectActionEnabled = _runProjectAction.isEnabled();
05665:
05666: // _compileProjectAction.setEnabled(false);
05667: //_compileAllAction.setEnabled(false);
05668: //_compileFolderAction.setEnabled(false);
05669: //_junitFolderAction.setEnabled(false);
05670: //_junitAllAction.setEnabled(false);
05671: //_junitAction.setEnabled(false);
05672: //_junitProjectAction.setEnabled(false);
05673: //_cleanAction.setEnabled(false);
05674: //_projectPropertiesAction.setEnabled(false);
05675: //_runProjectAction.setEnabled(false);
05676:
05677: _compileProjectAction = _junit_compileProjectDecoratedAction = new DecoratedAction(
05678: _compileProjectAction, false);
05679: _compileAllAction = _junit_compileAllDecoratedAction = new DecoratedAction(
05680: _compileAllAction, false);
05681: _compileFolderAction = _junit_compileFolderDecoratedAction = new DecoratedAction(
05682: _compileFolderAction, false);
05683: _junitFolderAction = _junit_junitFolderDecoratedAction = new DecoratedAction(
05684: _junitFolderAction, false);
05685: _junitAllAction = _junit_junitAllDecoratedAction = new DecoratedAction(
05686: _junitAllAction, false);
05687: _junitAction = _junit_junitDecoratedAction = new DecoratedAction(
05688: _junitAction, false);
05689: _junitProjectAction = _junit_junitOpenProjectFilesDecoratedAction = new DecoratedAction(
05690: _junitProjectAction, false);
05691: _cleanAction = _junit_cleanDecoratedAction = new DecoratedAction(
05692: _cleanAction, false);
05693: _projectPropertiesAction = _junit_projectPropertiesDecoratedAction = new DecoratedAction(
05694: _projectPropertiesAction, false);
05695: _runProjectAction = _junit_runProjectDecoratedAction = new DecoratedAction(
05696: _runProjectAction, false);
05697: _runAction = _junit_runDecoratedAction = new DecoratedAction(
05698: _runAction, false);
05699: }
05700:
05701: private void _restoreJUnitActionsEnabled() {
05702: // _compileProjectAction.setEnabled(_compileProjectActionEnabled);
05703: // _compileAllAction.setEnabled(_compileAllActionEnabled);
05704: // //_compileOpenProjectAction.setEnabled(_compileOpenProjectActionEnabled);
05705: // _compileFolderAction.setEnabled(_compileFolderActionEnabled);
05706: // _junitFolderAction.setEnabled(_junitFolderActionEnabled);
05707: // _junitAllAction.setEnabled(_junitAllActionEnabled);
05708: // _junitAction.setEnabled(_junitActionEnabled);
05709: // _junitProjectAction.setEnabled(_junitProjectActionEnabled);
05710: // //_junitProjectAction.setEnabled(_junitProjectActionEnabled);
05711: // _cleanAction.setEnabled(_cleanActionEnabled);
05712: // _projectPropertiesAction.setEnabled(_projectPropertiesActionEnabled);
05713: // _runProjectAction.setEnabled(_runProjectActionEnabled);
05714:
05715: _compileProjectAction = _junit_compileProjectDecoratedAction
05716: .getUpdatedDecoree();
05717: _compileAllAction = _junit_compileAllDecoratedAction
05718: .getUpdatedDecoree();
05719: _compileFolderAction = _junit_compileFolderDecoratedAction
05720: .getUpdatedDecoree();
05721: _junitFolderAction = _junit_junitFolderDecoratedAction
05722: .getUpdatedDecoree();
05723: _junitAllAction = _junit_junitAllDecoratedAction
05724: .getUpdatedDecoree();
05725: _junitAction = _junit_junitDecoratedAction.getUpdatedDecoree();
05726: _junitProjectAction = _junit_junitOpenProjectFilesDecoratedAction
05727: .getUpdatedDecoree();
05728: _cleanAction = _junit_cleanDecoratedAction.getUpdatedDecoree();
05729: _projectPropertiesAction = _junit_projectPropertiesDecoratedAction
05730: .getUpdatedDecoree();
05731: _runProjectAction = _junit_runProjectDecoratedAction
05732: .getUpdatedDecoree();
05733: _runAction = _junit_runDecoratedAction.getUpdatedDecoree();
05734: }
05735:
05736: // /**
05737: // * Suspends the current execution of the debugger
05738: // */
05739: // private void debuggerSuspend() throws DebugException {
05740: // if (isDebuggerReady())
05741: // _model.getDebugger().suspend();
05742: // }
05743:
05744: /** Resumes the debugger's current execution. */
05745: void debuggerResume() throws DebugException {
05746: if (isDebuggerReady()) {
05747: _model.getDebugger().resume();
05748: _removeThreadLocationHighlight();
05749: }
05750: }
05751:
05752: /** Steps in the debugger. */
05753: void debuggerStep(Debugger.StepType type) {
05754: if (isDebuggerReady()) {
05755: try {
05756: _model.getDebugger().step(type);
05757: } catch (IllegalStateException ise) {
05758: // This may happen if the user if stepping very frequently,
05759: // and is even more likely if they are using both hotkeys
05760: // and UI buttons. Ignore it in this case.
05761: // Hopefully, there are no other situations where
05762: // the user can be trying to step while there are no
05763: // suspended threads.
05764: } catch (DebugException de) {
05765: _showError(de, "Debugger Error",
05766: "Could not create a step request.");
05767: }
05768: }
05769: }
05770:
05771: /** Toggles a breakpoint on the current line. */
05772: void debuggerToggleBreakpoint() {
05773: addToBrowserHistory();
05774: OpenDefinitionsDocument doc = _model.getActiveDocument();
05775:
05776: boolean isUntitled = doc.isUntitled();
05777: if (isUntitled) {
05778: JOptionPane.showMessageDialog(this ,
05779: "You must save and compile this document before you can\n"
05780: + "set a breakpoint in it.",
05781: "Must Save and Compile", JOptionPane.ERROR_MESSAGE);
05782: return;
05783: }
05784:
05785: boolean isModified = doc.isModifiedSinceSave();
05786: if (isDebuggerReady()
05787: && isModified
05788: && !_currentDefPane.hasWarnedAboutModified()
05789: && DrJava.getConfig().getSetting(
05790: WARN_BREAKPOINT_OUT_OF_SYNC).booleanValue()) {
05791: String message = "This document has been modified and may be out of sync\n"
05792: + "with the debugger. It is recommended that you first\n"
05793: + "save and recompile before continuing to use the debugger,\n"
05794: + "to avoid any unexpected errors. Would you still like to\n"
05795: + "toggle the breakpoint on the specified line?";
05796: String title = "Toggle breakpoint on modified file?";
05797:
05798: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
05799: this , title, message);
05800: int rc = dialog.show();
05801: switch (rc) {
05802: case JOptionPane.YES_OPTION:
05803: _currentDefPane.hasWarnedAboutModified(true);
05804: if (dialog.getCheckBoxValue()) {
05805: DrJava.getConfig().setSetting(
05806: WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE);
05807: }
05808: break;
05809:
05810: case JOptionPane.NO_OPTION:
05811: if (dialog.getCheckBoxValue())
05812: DrJava.getConfig().setSetting(
05813: WARN_BREAKPOINT_OUT_OF_SYNC, Boolean.FALSE);
05814: return;
05815:
05816: case JOptionPane.CANCEL_OPTION:
05817: case JOptionPane.CLOSED_OPTION:
05818: // do nothing
05819: return;
05820:
05821: default:
05822: throw new RuntimeException(
05823: "Invalid rc from showConfirmDialog: " + rc);
05824: }
05825: }
05826:
05827: try {
05828: Debugger debugger = _model.getDebugger();
05829: debugger.toggleBreakpoint(doc, _currentDefPane
05830: .getCaretPosition(), _currentDefPane
05831: .getCurrentLine(), true);
05832: } catch (DebugException de) {
05833: _showError(de, "Debugger Error",
05834: "Could not set a breakpoint at the current line.");
05835: }
05836: }
05837:
05838: // private void _getText(String name) { _field = name; }
05839:
05840: // /** Adds a watch to a given variable or field. */
05841: // void debuggerAddWatch() {
05842: // if (isDebuggerReady()) {
05843: // //final String field;
05844: // OpenDefinitionsDocument doc = _model.getActiveDocument();
05845: // final JDialog getFieldDialog = new JDialog(this, "Choose Field to be Watched", true);
05846: // //getFieldDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
05847: // final JTextField fieldName = new JTextField();
05848: // getFieldDialog.setSize(new Dimension(150, 60));
05849: // getFieldDialog.getContentPane().add(fieldName);
05850: // fieldName.addActionListener(new ActionListener() {
05851: // public void actionPerformed(ActionEvent ae) {
05852: // _getText(fieldName.getText());
05853: // getFieldDialog.dispose();
05854: // }
05855: // });
05856: // getFieldDialog.setLocation(300,300);
05857: // getFieldDialog.show();
05858: // Debugger debugger = _model.getDebugger();
05859: // debugger.addWatch(_field);
05860: // }
05861: // }
05862:
05863: // /** Displays all breakpoints currently set in the debugger. */
05864: // void _printBreakpoints() { _model.getDebugger().printBreakpoints(); }
05865:
05866: /** Clears all breakpoints from the debugger. */
05867: void debuggerClearAllBreakpoints() {
05868: _model.getBreakpointManager().clearRegions();
05869: }
05870:
05871: void _showFileMovedError(FileMovedException fme) {
05872: try {
05873: File f = fme.getFile();
05874: OpenDefinitionsDocument doc = _model.getDocumentForFile(f);
05875: if (doc != null
05876: && _saveSelector.shouldSaveAfterFileMoved(doc, f))
05877: _saveAs();
05878: } catch (IOException ioe) { /* Couldn't find the document, so ignore the FME */
05879: }
05880: }
05881:
05882: void _showProjectFileParseError(MalformedProjectFileException mpfe) {
05883: _showError(mpfe, "Invalid Project File",
05884: "DrJava could not read the given project file.");
05885: }
05886:
05887: void _showFileNotFoundError(FileNotFoundException fnf) {
05888: _showError(fnf, "File Not Found",
05889: "The specified file was not found on disk.");
05890: }
05891:
05892: void _showIOError(IOException ioe) {
05893: _showError(ioe, "Input/output error",
05894: "An I/O exception occurred during the last operation.");
05895: }
05896:
05897: void _showClassNotFoundError(ClassNotFoundException cnfe) {
05898: _showError(
05899: cnfe,
05900: "Class Not Found",
05901: "A ClassNotFound exception occurred during the last operation.\n"
05902: + "Please check that your classpath includes all relevant directories.\n\n");
05903: }
05904:
05905: void _showNoClassDefError(NoClassDefFoundError ncde) {
05906: _showError(
05907: ncde,
05908: "No Class Def",
05909: "A NoClassDefFoundError occurred during the last operation.\n"
05910: + "Please check that your classpath includes all relevant paths.\n\n");
05911: }
05912:
05913: void _showDebugError(DebugException de) {
05914: _showError(de, "Debug Error",
05915: "A Debugger error occurred in the last operation.\n\n");
05916: }
05917:
05918: void _showJUnitInterrupted(UnexpectedException e) {
05919: _showWarning(
05920: e.getCause(),
05921: "JUnit Testing Interrupted",
05922: "The slave JVM has thrown a RemoteException probably indicating that it has been reset.\n\n");
05923: }
05924:
05925: private void _showError(Throwable e, String title, String message) {
05926: JOptionPane.showMessageDialog(this , message + "\n" + e, title,
05927: JOptionPane.ERROR_MESSAGE);
05928: }
05929:
05930: private void _showWarning(Throwable e, String title, String message) {
05931: JOptionPane.showMessageDialog(this , message + "\n" + e, title,
05932: JOptionPane.WARNING_MESSAGE);
05933: }
05934:
05935: /** Check if any errors occurred while parsing the config file, and display a message if necessary. */
05936: private void _showConfigException() {
05937: if (DrJava.getConfig().hadStartupException()) {
05938: Exception e = DrJava.getConfig().getStartupException();
05939: _showError(
05940: e,
05941: "Error in Config File",
05942: "Could not read the '.drjava' configuration file\n"
05943: + "in your home directory. Starting with default\n"
05944: + "values instead.\n\n"
05945: + "The problem was:\n");
05946: }
05947: }
05948:
05949: /** Returns the File selected by the JFileChooser.
05950: * @param fc File chooser presented to the user
05951: * @param choice return value from fc
05952: * @return Selected File
05953: * @throws OperationCanceledException if file choice canceled
05954: * @throws RuntimeException if fc returns a bad file or choice
05955: */
05956: private File getChosenFile(JFileChooser fc, int choice)
05957: throws OperationCanceledException {
05958: switch (choice) {
05959: case JFileChooser.CANCEL_OPTION:
05960: case JFileChooser.ERROR_OPTION:
05961: throw new OperationCanceledException();
05962: case JFileChooser.APPROVE_OPTION:
05963: File chosen = fc.getSelectedFile();
05964: if (chosen != null) {
05965: //append the appropriate language level extension if not written by user
05966: if (fc.getFileFilter() instanceof JavaSourceFilter) {
05967: if (chosen.getName().indexOf(".") == -1)
05968: return new File(
05969: chosen.getAbsolutePath()
05970: + "."
05971: + DrJavaRoot.LANGUAGE_LEVEL_EXTENSIONS[DrJava
05972: .getConfig()
05973: .getSetting(
05974: LANGUAGE_LEVEL)]);
05975: }
05976: return chosen;
05977: } else
05978: throw new RuntimeException(
05979: "Filechooser returned null file");
05980: default: // impossible since rc must be one of these
05981: throw new RuntimeException("Filechooser returned bad rc "
05982: + choice);
05983: }
05984: }
05985:
05986: /**
05987: * Returns the Files selected by the JFileChooser.
05988: * @param fc File chooser presented to the user
05989: * @param choice return value from fc
05990: * @return Selected Files - this array will be size 1 for single-selection dialogs.
05991: * @throws OperationCanceledException if file choice canceled
05992: * @throws RuntimeException if fc returns a bad file or choice
05993: */
05994: private File[] getChosenFiles(JFileChooser fc, int choice)
05995: throws OperationCanceledException {
05996: switch (choice) {
05997: case JFileChooser.CANCEL_OPTION:
05998: case JFileChooser.ERROR_OPTION:
05999: throw new OperationCanceledException();
06000: case JFileChooser.APPROVE_OPTION:
06001: File[] chosen = fc.getSelectedFiles();
06002: if (chosen == null)
06003: throw new UnexpectedException(
06004: new OperationCanceledException(),
06005: "filechooser returned null file");
06006:
06007: // Following code reviewed for bug 70902-- JVF
06008: // If this is a single-selection dialog, getSelectedFiles() will always
06009: // return a zero-size array -- handle it differently.
06010: if (chosen.length == 0) {
06011: if (!fc.isMultiSelectionEnabled()) {
06012: return new File[] { fc.getSelectedFile() };
06013: } else {
06014: /* This is the workaround for bug 70902: sometimes Mac OS X will return
06015: * APPROVE_OPTION when the user clicks the close (x) control button
06016: * on the dialog window, even though nothing is selected.
06017: */
06018: throw new OperationCanceledException();
06019: }
06020: } else {
06021: return chosen;
06022: }
06023:
06024: default: // impossible since rc must be one of these
06025: throw new UnexpectedException(
06026: new OperationCanceledException(),
06027: "filechooser returned bad rc " + choice);
06028: }
06029: }
06030:
06031: private void _selectAll() {
06032: _currentDefPane.selectAll();
06033: }
06034:
06035: /** Jump to the specified line and return the offset. Only runs in event thread.
06036: * @return offset */
06037: public int _jumpToLine(int lineNum) {
06038: int pos = _model.getActiveDocument().gotoLine(lineNum);
06039: _currentDefPane.setCaretPosition(pos);
06040: _currentDefPane.centerViewOnOffset(pos);
06041: return pos;
06042: }
06043:
06044: /** Ask the user what line they'd like to jump to, then go there. */
06045: private int _gotoLine() {
06046: final String msg = "What line would you like to go to?";
06047: final String title = "Go to Line";
06048: String lineStr = JOptionPane.showInputDialog(this , msg, title,
06049: JOptionPane.QUESTION_MESSAGE);
06050: try {
06051: if (lineStr != null) {
06052: int lineNum = Integer.parseInt(lineStr);
06053: return _jumpToLine(lineNum);
06054: }
06055: } catch (NumberFormatException nfe) {
06056: // invalid input for line number
06057: Toolkit.getDefaultToolkit().beep();
06058: // Do nothing.
06059: }
06060: //catch (BadLocationException ble) { }
06061: return -1;
06062: }
06063:
06064: /** Removes the ErrorCaretListener corresponding to the given document, after that document has been closed.
06065: * (Allows pane and listener to be garbage collected...)
06066: */
06067: private void _removeErrorListener(OpenDefinitionsDocument doc) {
06068: JScrollPane scroll = _defScrollPanes.get(doc);
06069: if (scroll != null) {
06070: DefinitionsPane pane = (DefinitionsPane) scroll
06071: .getViewport().getView();
06072: pane.removeCaretListener(pane.getErrorCaretListener());
06073: }
06074: }
06075:
06076: /** Initializes all action objects. Adds icons and descriptions to several of the actions. Note: this
06077: * initialization will later be done in the constructor of each action, which will subclass AbstractAction.
06078: */
06079: private void _setUpActions() {
06080: _setUpAction(_newAction, "New", "Create a new document");
06081: _setUpAction(_newJUnitTestAction, "New",
06082: "Create a new JUnit test case class");
06083: _setUpAction(_newProjectAction, "New", "Make a new project");
06084: _setUpAction(_openAction, "Open", "Open an existing file");
06085: _setUpAction(_openFolderAction, "Open Folder", "OpenAll",
06086: "Open all files within a directory");
06087: _setUpAction(_openFileOrProjectAction, "Open",
06088: "Open an existing file or project");
06089: _setUpAction(_openProjectAction, "Open",
06090: "Open an existing project");
06091: _setUpAction(_saveAction, "Save", "Save the current document");
06092: _setUpAction(_saveAsAction, "Save As", "SaveAs",
06093: "Save the current document with a new name");
06094: _setUpAction(_renameAction, "Rename", "Rename",
06095: "Rename the current document");
06096: _setUpAction(_saveProjectAction, "Save", "Save",
06097: "Save the current project");
06098: _saveProjectAction.setEnabled(false);
06099: _setUpAction(_saveProjectAsAction, "Save As", "SaveAs",
06100: "Save current project to new project file");
06101: _saveProjectAsAction.setEnabled(false);
06102: _setUpAction(_revertAction, "Revert",
06103: "Revert the current document to the saved version");
06104: // No longer used
06105: // _setUpAction(_revertAllAction, "Revert All", "RevertAll",
06106: // "Revert all open documents to the saved versions");
06107:
06108: _setUpAction(_closeAction, "Close",
06109: "Close the current document");
06110: _setUpAction(_closeAllAction, "Close All", "CloseAll",
06111: "Close all documents");
06112: _setUpAction(_closeProjectAction, "Close", "CloseAll",
06113: "Close the current project");
06114: _closeProjectAction.setEnabled(false);
06115:
06116: _setUpAction(_projectPropertiesAction, "Project Properties",
06117: "Preferences", "Edit Project Properties");
06118: _projectPropertiesAction.setEnabled(false);
06119:
06120: // _setUpAction(_junitProjectAction, "Test", "Test", "Test the current project");
06121: // _junitProjectAction.setEnabled(false);
06122: _setUpAction(_junitProjectAction, "Test Project",
06123: "Test the documents in the project source tree");
06124: _junitProjectAction.setEnabled(false);
06125:
06126: // _setUpAction(_compileOpenProjectAction, "Compile", "Compile", "Compile the open project documents");
06127: _setUpAction(_compileProjectAction, "Compile Project",
06128: "Compile the documents in the project source tree");
06129: // _compileOpenProjectAction.setEnabled(false);
06130: _compileProjectAction.setEnabled(false);
06131:
06132: _setUpAction(_runProjectAction, "Run Project",
06133: "Run the project's main method");
06134: _runProjectAction.setEnabled(false);
06135:
06136: _setUpAction(_jarProjectAction, "Jar",
06137: "Create a jar archive from this project");
06138: _jarProjectAction.setEnabled(false);
06139:
06140: _setUpAction(_saveAllAction, "Save All", "SaveAll",
06141: "Save all open documents");
06142:
06143: _setUpAction(_cleanAction, "Clean", "Clean Build directory");
06144: _cleanAction.setEnabled(false);
06145: _setUpAction(_compileAction, "Compile Current Document",
06146: "Compile the current document");
06147: _setUpAction(_compileAllAction, "Compile",
06148: "Compile all open documents");
06149: _setUpAction(_printDefDocAction, "Print",
06150: "Print the current main document");
06151: _setUpAction(_printConsoleAction, "Print",
06152: "Print the Console pane");
06153: _setUpAction(_printInteractionsAction, "Print",
06154: "Print the Interactions pane");
06155: _setUpAction(_pageSetupAction, "Page Setup", "PageSetup",
06156: "Change the printer settings");
06157: _setUpAction(_printDefDocPreviewAction, "Print Preview",
06158: "PrintPreview",
06159: "Preview how the document will be printed");
06160: _setUpAction(_printConsolePreviewAction, "Print Preview",
06161: "PrintPreview",
06162: "Preview how the console document will be printed");
06163: _setUpAction(_printInteractionsPreviewAction, "Print Preview",
06164: "PrintPreview",
06165: "Preview how the interactions document will be printed");
06166:
06167: _setUpAction(_quitAction, "Quit", "Quit", "Quit DrJava");
06168:
06169: _setUpAction(_undoAction, "Undo", "Undo previous command");
06170: _setUpAction(_redoAction, "Redo", "Redo last undo");
06171: _undoAction.putValue(Action.NAME, "Undo Previous Command");
06172: _redoAction.putValue(Action.NAME, "Redo Last Undo");
06173:
06174: _setUpAction(cutAction, "Cut",
06175: "Cut selected text to the clipboard");
06176: _setUpAction(copyAction, "Copy",
06177: "Copy selected text to the clipboard");
06178: _setUpAction(pasteAction, "Paste",
06179: "Paste text from the clipboard");
06180: _setUpAction(_pasteHistoryAction, "Paste from History",
06181: "Paste text from the clipboard history");
06182: _setUpAction(_selectAllAction, "Select All", "Select all text");
06183:
06184: cutAction.putValue(Action.NAME, "Cut");
06185: copyAction.putValue(Action.NAME, "Copy");
06186: pasteAction.putValue(Action.NAME, "Paste");
06187: _pasteHistoryAction.putValue(Action.NAME, "Paste from History");
06188:
06189: _setUpAction(_indentLinesAction, "Indent Lines",
06190: "Indent all selected lines");
06191: _setUpAction(_commentLinesAction, "Comment Lines",
06192: "Comment out all selected lines");
06193: _setUpAction(_uncommentLinesAction, "Uncomment Lines",
06194: "Uncomment all selected lines");
06195:
06196: _setUpAction(completeWordUnderCursorAction,
06197: "Auto-Complete Word Under Cursor",
06198: "Auto-complete the word the cursor is currently located on");
06199: _setUpAction(_bookmarksPanelAction, "Bookmarks",
06200: "Display the bookmarks panel");
06201: _setUpAction(_toggleBookmarkAction, "Toggle Bookmark",
06202: "Toggle the bookmark at the current cursor location");
06203:
06204: _setUpAction(_findReplaceAction, "Find",
06205: "Find or replace text in the document");
06206: _setUpAction(_findNextAction, "Find Next",
06207: "Repeats the last find");
06208: _setUpAction(_findPrevAction, "Find Previous",
06209: "Repeats the last find in the opposite direction");
06210: _setUpAction(_gotoLineAction, "Go to line",
06211: "Go to a line number in the document");
06212: _setUpAction(_gotoFileAction, "Go to File",
06213: "Go to a file specified by its name");
06214: _setUpAction(gotoFileUnderCursorAction,
06215: "Go to File Under Cursor",
06216: "Go to the file specified by the word the cursor is located on");
06217:
06218: _setUpAction(_switchToPrevAction, "Previous Document", "Up",
06219: "Switch to the previous document");
06220: _setUpAction(_switchToNextAction, "Next Document", "Down",
06221: "Switch to the next document");
06222:
06223: _setUpAction(_browseBackAction, "Back", "Back",
06224: "Move back in the browser history");
06225: _setUpAction(_browseForwardAction, "Forward", "Forward",
06226: "Move forward in the browser history");
06227:
06228: _setUpAction(_switchToPreviousPaneAction, "Previous Pane",
06229: "Switch focus to the previous pane");
06230: _setUpAction(_switchToNextPaneAction, "Next Pane",
06231: "Switch focus to the next pane");
06232: _setUpAction(_gotoOpeningBraceAction, "Go to Opening Brace",
06233: "Go th the opening brace of the block enclosing the cursor");
06234: _setUpAction(_gotoClosingBraceAction, "Go to Closing Brace",
06235: "Go th the closing brace of the block enclosing the cursor");
06236:
06237: _setUpAction(_editPreferencesAction, "Preferences",
06238: "Edit configurable settings in DrJava");
06239:
06240: _setUpAction(_junitAction, "Test Current",
06241: "Run JUnit over the current document");
06242: _setUpAction(_junitAllAction, "Test",
06243: "Run JUnit over all open JUnit tests");
06244: _setUpAction(_javadocAllAction, "Javadoc",
06245: "Create and save Javadoc for the packages of all open documents");
06246: _setUpAction(_javadocCurrentAction, "Preview Javadoc Current",
06247: "Preview the Javadoc for the current document");
06248: _setUpAction(_runAction, "Run",
06249: "Run the main method of the current document");
06250:
06251: _setUpAction(_openJavadocAction, "Open Java API Javadoc...",
06252: "Open the Java API Javadoc Web page for a class");
06253: _setUpAction(
06254: _openJavadocUnderCursorAction,
06255: "Open Java API Javadoc for Word Under Cursor...",
06256: "Open the Java API "
06257: + "Javadoc Web page for the word under the cursor");
06258:
06259: _setUpAction(_executeHistoryAction, "Execute History",
06260: "Load and execute a history of interactions from a file");
06261: _setUpAction(_loadHistoryScriptAction,
06262: "Load History as Script",
06263: "Load a history from a file as a series of interactions");
06264: _setUpAction(_saveHistoryAction, "Save History",
06265: "Save the history of interactions to a file");
06266: _setUpAction(_clearHistoryAction, "Clear History",
06267: "Clear the current history of interactions");
06268:
06269: //_setUpAction(_abortInteractionAction, "Break", "Abort the current interaction");
06270: _setUpAction(_resetInteractionsAction, "Reset",
06271: "Reset the Interactions Pane");
06272: _resetInteractionsAction.setEnabled(true);
06273:
06274: _setUpAction(_viewInteractionsClassPathAction,
06275: "View Interactions Classpath",
06276: "Display the classpath in use by the Interactions Pane");
06277: _setUpAction(_copyInteractionToDefinitionsAction,
06278: "Lift Current Interaction",
06279: "Copy the current interaction into the Definitions Pane");
06280:
06281: _setUpAction(_clearConsoleAction, "Clear Console",
06282: "Clear all text in the Console Pane");
06283: _setUpAction(
06284: _showDebugConsoleAction,
06285: "Show DrJava Debug Console",
06286: "<html>Show a console for debugging DrJava<br>"
06287: + "(with \"mainFrame\", \"model\", and \"config\" variables defined)</html>");
06288:
06289: if (_model.getDebugger().isAvailable()) {
06290: _setUpAction(_toggleDebuggerAction, "Debug Mode",
06291: "Enable or disable DrJava's debugger");
06292: _setUpAction(_toggleBreakpointAction, "Toggle Breakpoint",
06293: "Set or clear a breakpoint on the current line");
06294: _setUpAction(_clearAllBreakpointsAction,
06295: "Clear Breakpoints",
06296: "Clear all breakpoints in all classes");
06297: _setUpAction(_resumeDebugAction, "Resume",
06298: "Resume the current suspended thread");
06299: _setUpAction(_stepIntoDebugAction, "Step Into",
06300: "Step into the current line or method call");
06301: _setUpAction(_stepOverDebugAction, "Step Over",
06302: "Step over the current line or method call");
06303: _setUpAction(_stepOutDebugAction, "Step Out",
06304: "Step out of the current method");
06305: _setUpAction(_breakpointsPanelAction, "Breakpoints",
06306: "Display the breakpoints panel");
06307: }
06308:
06309: _setUpAction(_helpAction, "Help",
06310: "Show documentation on how to use DrJava");
06311: _setUpAction(_quickStartAction, "Help",
06312: "View Quick Start Guide for DrJava");
06313: _setUpAction(_aboutAction, "About", "About DrJava");
06314: _setUpAction(_errorsAction, "DrJava Errors", "drjavaerror",
06315: "Show a window with internal DrJava errors");
06316: _setUpAction(_forceQuitAction, "Force Quit",
06317: "Force DrJava to quit without cleaning up");
06318: }
06319:
06320: private void _setUpAction(Action a, String name, String icon,
06321: String shortDesc) {
06322: a.putValue(Action.SMALL_ICON, _getIcon(icon + "16.gif"));
06323: a.putValue(Action.DEFAULT, name);
06324: a.putValue(Action.SHORT_DESCRIPTION, shortDesc);
06325: }
06326:
06327: private void _setUpAction(Action a, String icon, String shortDesc) {
06328: _setUpAction(a, icon, icon, shortDesc);
06329: }
06330:
06331: /** Returns the icon with the given name. All icons are assumed to reside in the /edu/rice/cs/drjava/ui/icons
06332: * directory.
06333: * @param name Name of icon image file
06334: * @return ImageIcon object constructed from the file
06335: */
06336: private ImageIcon _getIcon(String name) {
06337: return getIcon(name);
06338: }
06339:
06340: public static ImageIcon getIcon(String name) {
06341: URL url = MainFrame.class.getResource(ICON_PATH + name);
06342: if (url != null)
06343: return new ImageIcon(url);
06344:
06345: return null;
06346: }
06347:
06348: /** This allows us to intercept key events when compiling testing and turn them off when the glass pane is up. */
06349: private class MenuBar extends JMenuBar {
06350: public boolean processKeyBinding(KeyStroke ks, KeyEvent e,
06351: int condition, boolean pressed) {
06352: if (MainFrame.this .getAllowKeyEvents())
06353: return super .processKeyBinding(ks, e, condition,
06354: pressed);
06355: return false;
06356: }
06357: }
06358:
06359: /** Sets up the components of the menu bar and links them to the private fields within MainFrame. This method
06360: * serves to make the code more legible on the higher calling level, i.e., the constructor.
06361: */
06362: private void _setUpMenuBar() {
06363:
06364: _menuBar.add(_fileMenu);
06365: _menuBar.add(_editMenu);
06366: _menuBar.add(_toolsMenu);
06367: _menuBar.add(_projectMenu);
06368: if (_showDebugger)
06369: _menuBar.add(_debugMenu);
06370: _menuBar.add(_languageLevelMenu);
06371: _menuBar.add(_helpMenu);
06372: setJMenuBar(_menuBar);
06373: }
06374:
06375: /** Adds an Action as a menu item to the given menu, using the specified configurable keystroke.
06376: * @param menu Menu to add item to
06377: * @param a Action for the menu item
06378: * @param opt Configurable keystroke for the menu item
06379: */
06380: private void _addMenuItem(JMenu menu, Action a,
06381: Option<KeyStroke> opt) {
06382: JMenuItem item;
06383: item = menu.add(a);
06384: _setMenuShortcut(item, a, opt);
06385: }
06386:
06387: /** Sets the given menu item to have the specified configurable keystroke.
06388: * @param item Menu item containing the action
06389: * @param a Action for the menu item
06390: * @param opt Configurable keystroke for the menu item
06391: */
06392: private void _setMenuShortcut(JMenuItem item, Action a,
06393: Option<KeyStroke> opt) {
06394: KeyStroke ks = DrJava.getConfig().getSetting(opt);
06395: // Checks that "a" is the action associated with the keystroke.
06396: // Need to check in case two actions were assigned to the same
06397: // key in the config file.
06398: // Also check that the keystroke isn't the NULL_KEYSTROKE, which
06399: // can strangely be triggered by certain keys in Windows.
06400: KeyBindingManager.Singleton.put(opt, a, item, item.getText());
06401: if ((ks != KeyStrokeOption.NULL_KEYSTROKE)
06402: && (KeyBindingManager.Singleton.get(ks) == a)) {
06403: item.setAccelerator(ks);
06404: //KeyBindingManager.Singleton.addListener(opt, item);
06405: }
06406: }
06407:
06408: /** Creates and returns a file menu. Side effects: sets values for _saveMenuItem. */
06409: private JMenu _setUpFileMenu(int mask) {
06410: JMenu fileMenu = new JMenu("File");
06411: fileMenu.setMnemonic(KeyEvent.VK_F);
06412: // New, open
06413: _addMenuItem(fileMenu, _newAction, KEY_NEW_FILE);
06414: _addMenuItem(fileMenu, _newJUnitTestAction, KEY_NEW_TEST);
06415: _addMenuItem(fileMenu, _openAction, KEY_OPEN_FILE);
06416: _addMenuItem(fileMenu, _openFolderAction, KEY_OPEN_FOLDER);
06417: //_addMenuItem(fileMenu, _openProjectAction, KEY_OPEN_PROJECT);
06418:
06419: fileMenu.addSeparator();
06420:
06421: _addMenuItem(fileMenu, _saveAction, KEY_SAVE_FILE);
06422: _saveAction.setEnabled(true);
06423: _addMenuItem(fileMenu, _saveAsAction, KEY_SAVE_FILE_AS);
06424: _addMenuItem(fileMenu, _saveAllAction, KEY_SAVE_ALL_FILES);
06425: _addMenuItem(fileMenu, _renameAction, KEY_RENAME_FILE);
06426: _renameAction.setEnabled(false);
06427: // fileMenu.add(_saveProjectAsAction);
06428:
06429: _addMenuItem(fileMenu, _revertAction, KEY_REVERT_FILE);
06430: _revertAction.setEnabled(false);
06431: //tmpItem = fileMenu.add(_revertAllAction);
06432:
06433: // Close, Close all
06434: fileMenu.addSeparator();
06435: _addMenuItem(fileMenu, _closeAction, KEY_CLOSE_FILE);
06436: _addMenuItem(fileMenu, _closeAllAction, KEY_CLOSE_ALL_FILES);
06437: //_addMenuItem(fileMenu, _closeProjectAction, KEY_CLOSE_PROJECT);
06438:
06439: // Page setup, print preview, print
06440: fileMenu.addSeparator();
06441: _addMenuItem(fileMenu, _pageSetupAction, KEY_PAGE_SETUP);
06442: _addMenuItem(fileMenu, _printDefDocPreviewAction,
06443: KEY_PRINT_PREVIEW);
06444: _addMenuItem(fileMenu, _printDefDocAction, KEY_PRINT);
06445:
06446: // Quit
06447: fileMenu.addSeparator();
06448: _addMenuItem(fileMenu, _quitAction, KEY_QUIT);
06449:
06450: return fileMenu;
06451: }
06452:
06453: /** Creates and returns a edit menu. */
06454: private JMenu _setUpEditMenu(int mask) {
06455: JMenu editMenu = new JMenu("Edit");
06456: editMenu.setMnemonic(KeyEvent.VK_E);
06457: // Undo, redo
06458: _addMenuItem(editMenu, _undoAction, KEY_UNDO);
06459: _addMenuItem(editMenu, _redoAction, KEY_REDO);
06460:
06461: // Cut, copy, paste, select all
06462: editMenu.addSeparator();
06463: _addMenuItem(editMenu, cutAction, KEY_CUT);
06464: _addMenuItem(editMenu, copyAction, KEY_COPY);
06465: _addMenuItem(editMenu, pasteAction, KEY_PASTE);
06466: _addMenuItem(editMenu, _pasteHistoryAction,
06467: KEY_PASTE_FROM_HISTORY);
06468: _addMenuItem(editMenu, _selectAllAction, KEY_SELECT_ALL);
06469:
06470: // Indent lines, comment lines
06471: editMenu.addSeparator();
06472: //_addMenuItem(editMenu, _indentLinesAction, KEY_INDENT);
06473: JMenuItem editItem = editMenu.add(_indentLinesAction);
06474: editItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
06475: 0));
06476: _addMenuItem(editMenu, _commentLinesAction, KEY_COMMENT_LINES);
06477: _addMenuItem(editMenu, _uncommentLinesAction,
06478: KEY_UNCOMMENT_LINES);
06479: _addMenuItem(editMenu, completeWordUnderCursorAction,
06480: KEY_COMPLETE_FILE);
06481:
06482: // Find/replace, goto
06483: editMenu.addSeparator();
06484: _addMenuItem(editMenu, _findReplaceAction, KEY_FIND_REPLACE);
06485: _addMenuItem(editMenu, _findNextAction, KEY_FIND_NEXT);
06486: _addMenuItem(editMenu, _findPrevAction, KEY_FIND_PREV);
06487: _addMenuItem(editMenu, _gotoLineAction, KEY_GOTO_LINE);
06488: _addMenuItem(editMenu, _gotoFileAction, KEY_GOTO_FILE);
06489: _addMenuItem(editMenu, gotoFileUnderCursorAction,
06490: KEY_GOTO_FILE_UNDER_CURSOR);
06491:
06492: // Next, prev doc
06493: editMenu.addSeparator();
06494: _addMenuItem(editMenu, _switchToPrevAction,
06495: KEY_PREVIOUS_DOCUMENT);
06496: _addMenuItem(editMenu, _switchToNextAction, KEY_NEXT_DOCUMENT);
06497: _addMenuItem(editMenu, _browseBackAction, KEY_BROWSE_BACK);
06498: _addMenuItem(editMenu, _browseForwardAction, KEY_BROWSE_FORWARD);
06499: _addMenuItem(editMenu, _switchToPreviousPaneAction,
06500: KEY_PREVIOUS_PANE);
06501: _addMenuItem(editMenu, _switchToNextPaneAction, KEY_NEXT_PANE);
06502: _addMenuItem(editMenu, _gotoOpeningBraceAction,
06503: KEY_OPENING_BRACE);
06504: _addMenuItem(editMenu, _gotoClosingBraceAction,
06505: KEY_CLOSING_BRACE);
06506:
06507: // access to configurations GUI
06508: editMenu.addSeparator();
06509: _addMenuItem(editMenu, _editPreferencesAction, KEY_PREFERENCES);
06510:
06511: // Add the menus to the menu bar
06512: return editMenu;
06513: }
06514:
06515: /** Creates and returns a tools menu. */
06516: private JMenu _setUpToolsMenu(int mask) {
06517: JMenu toolsMenu = new JMenu("Tools");
06518: toolsMenu.setMnemonic(KeyEvent.VK_T);
06519:
06520: // Compile, Test, Javadoc
06521: _addMenuItem(toolsMenu, _compileAllAction, KEY_COMPILE_ALL);
06522: _addMenuItem(toolsMenu, _compileAction, KEY_COMPILE);
06523: _addMenuItem(toolsMenu, _junitAllAction, KEY_TEST_ALL);
06524: _addMenuItem(toolsMenu, _junitAction, KEY_TEST);
06525: _addMenuItem(toolsMenu, _javadocAllAction, KEY_JAVADOC_ALL);
06526: _addMenuItem(toolsMenu, _javadocCurrentAction,
06527: KEY_JAVADOC_CURRENT);
06528: toolsMenu.addSeparator();
06529:
06530: // Open Javadoc
06531: _addMenuItem(toolsMenu, _openJavadocAction, KEY_OPEN_JAVADOC);
06532: _addMenuItem(toolsMenu, _openJavadocUnderCursorAction,
06533: KEY_OPEN_JAVADOC_UNDER_CURSOR);
06534: toolsMenu.addSeparator();
06535:
06536: // Run
06537: _addMenuItem(toolsMenu, _runAction, KEY_RUN);
06538: toolsMenu.addSeparator();
06539:
06540: _addMenuItem(toolsMenu, _executeHistoryAction,
06541: KEY_EXECUTE_HISTORY);
06542: _addMenuItem(toolsMenu, _loadHistoryScriptAction,
06543: KEY_LOAD_HISTORY_SCRIPT);
06544: _addMenuItem(toolsMenu, _saveHistoryAction, KEY_SAVE_HISTORY);
06545: _addMenuItem(toolsMenu, _clearHistoryAction, KEY_CLEAR_HISTORY);
06546: toolsMenu.addSeparator();
06547:
06548: // Abort/reset interactions, clear console
06549: /*
06550: _abortInteractionAction.setEnabled(false);
06551: _addMenuItem(toolsMenu, _abortInteractionAction, KEY_ABORT_INTERACTION);
06552: */
06553: _addMenuItem(toolsMenu, _resetInteractionsAction,
06554: KEY_RESET_INTERACTIONS);
06555: _addMenuItem(toolsMenu, _viewInteractionsClassPathAction,
06556: KEY_VIEW_INTERACTIONS_CLASSPATH);
06557: _addMenuItem(toolsMenu, _copyInteractionToDefinitionsAction,
06558: KEY_LIFT_CURRENT_INTERACTION);
06559: _addMenuItem(toolsMenu, _printInteractionsAction,
06560: KEY_PRINT_INTERACTIONS);
06561: toolsMenu.addSeparator();
06562:
06563: _addMenuItem(toolsMenu, _clearConsoleAction, KEY_CLEAR_CONSOLE);
06564: _addMenuItem(toolsMenu, _printConsoleAction, KEY_PRINT_CONSOLE);
06565: if (DrJava.getConfig().getSetting(SHOW_DEBUG_CONSOLE)
06566: .booleanValue()) {
06567: toolsMenu.add(_showDebugConsoleAction);
06568: }
06569:
06570: toolsMenu.addSeparator();
06571: _addMenuItem(toolsMenu, _bookmarksPanelAction,
06572: KEY_BOOKMARKS_PANEL);
06573: _addMenuItem(toolsMenu, _toggleBookmarkAction,
06574: KEY_BOOKMARKS_TOGGLE);
06575:
06576: // Add the menus to the menu bar
06577: return toolsMenu;
06578: }
06579:
06580: /** Creates and returns a project menu. */
06581: private JMenu _setUpProjectMenu(int mask) {
06582: JMenu projectMenu = new JMenu("Project");
06583: projectMenu.setMnemonic(KeyEvent.VK_P);
06584: // New, open
06585: projectMenu.add(_newProjectAction);
06586: _addMenuItem(projectMenu, _openProjectAction, KEY_OPEN_PROJECT);
06587:
06588: //Save
06589: projectMenu.add(_saveProjectAction);
06590: //SaveAs
06591: projectMenu.add(_saveProjectAsAction);
06592:
06593: // Close
06594: _addMenuItem(projectMenu, _closeProjectAction,
06595: KEY_CLOSE_PROJECT);
06596:
06597: projectMenu.addSeparator();
06598: // run project
06599: projectMenu.add(_cleanAction);
06600: // projectMenu.add(_compileOpenProjectAction);
06601: projectMenu.add(_compileProjectAction);
06602: projectMenu.add(_jarProjectAction);
06603: projectMenu.add(_runProjectAction);
06604: projectMenu.add(_junitProjectAction);
06605: // projectMenu.add(_junitProjectAction);
06606:
06607: projectMenu.addSeparator();
06608: // eventually add project options
06609: projectMenu.add(_projectPropertiesAction);
06610:
06611: return projectMenu;
06612: }
06613:
06614: /** Creates and returns a debug menu. */
06615: private JMenu _setUpDebugMenu(int mask) {
06616: JMenu debugMenu = new JMenu("Debugger");
06617: debugMenu.setMnemonic(KeyEvent.VK_D);
06618: // Enable debugging item
06619: _debuggerEnabledMenuItem = _newCheckBoxMenuItem(_toggleDebuggerAction);
06620: _debuggerEnabledMenuItem.setSelected(false);
06621: _setMenuShortcut(_debuggerEnabledMenuItem,
06622: _toggleDebuggerAction, KEY_DEBUG_MODE_TOGGLE);
06623: debugMenu.add(_debuggerEnabledMenuItem);
06624: debugMenu.addSeparator();
06625:
06626: _addMenuItem(debugMenu, _toggleBreakpointAction,
06627: KEY_DEBUG_BREAKPOINT_TOGGLE);
06628: //_printBreakpointsMenuItem = debugMenu.add(_printBreakpointsAction);
06629: //_clearAllBreakpointsMenuItem =
06630: _addMenuItem(debugMenu, _clearAllBreakpointsAction,
06631: KEY_DEBUG_CLEAR_ALL_BREAKPOINTS);
06632: _addMenuItem(debugMenu, _breakpointsPanelAction,
06633: KEY_DEBUG_BREAKPOINT_PANEL);
06634: debugMenu.addSeparator();
06635:
06636: //_addMenuItem(debugMenu, _suspendDebugAction, KEY_DEBUG_SUSPEND);
06637: _addMenuItem(debugMenu, _resumeDebugAction, KEY_DEBUG_RESUME);
06638: _addMenuItem(debugMenu, _stepIntoDebugAction,
06639: KEY_DEBUG_STEP_INTO);
06640: _addMenuItem(debugMenu, _stepOverDebugAction,
06641: KEY_DEBUG_STEP_OVER);
06642: _addMenuItem(debugMenu, _stepOutDebugAction, KEY_DEBUG_STEP_OUT);
06643:
06644: // Start off disabled
06645: _setDebugMenuItemsEnabled(false);
06646:
06647: // Add the menu to the menu bar
06648: return debugMenu;
06649: }
06650:
06651: /**
06652: * Called every time the debug mode checkbox is toggled. The resume and step
06653: * functions should always be disabled.
06654: */
06655: private void _setDebugMenuItemsEnabled(boolean isEnabled) {
06656:
06657: _debuggerEnabledMenuItem.setSelected(isEnabled);
06658: //_suspendDebugAction.setEnabled(false);
06659: _resumeDebugAction.setEnabled(false);
06660: _stepIntoDebugAction.setEnabled(false);
06661: _stepOverDebugAction.setEnabled(false);
06662: _stepOutDebugAction.setEnabled(false);
06663:
06664: if (_showDebugger)
06665: _debugPanel.disableButtons();
06666: }
06667:
06668: /** Enables and disables the appropriate menu items in the debug menu depending upon the state of the current thread.
06669: * @param isSuspended is true when the current thread has just been suspended
06670: * false if the current thread has just been resumed
06671: */
06672: private void _setThreadDependentDebugMenuItems(boolean isSuspended) {
06673: //_suspendDebugAction.setEnabled(!isSuspended);
06674: _resumeDebugAction.setEnabled(isSuspended);
06675: _stepIntoDebugAction.setEnabled(isSuspended);
06676: _stepOverDebugAction.setEnabled(isSuspended);
06677: _stepOutDebugAction.setEnabled(isSuspended);
06678: _debugPanel.setThreadDependentButtons(isSuspended);
06679: }
06680:
06681: /** Creates and returns the language levels menu. */
06682: private JMenu _setUpLanguageLevelMenu(int mask) {
06683: JMenu languageLevelMenu = new JMenu("Language Level");
06684: languageLevelMenu.setMnemonic(KeyEvent.VK_L);
06685: ButtonGroup group = new ButtonGroup();
06686:
06687: final Configuration config = DrJava.getConfig();
06688: int currentLanguageLevel = config.getSetting(LANGUAGE_LEVEL);
06689: JRadioButtonMenuItem rbMenuItem;
06690: rbMenuItem = new JRadioButtonMenuItem("Full Java");
06691: rbMenuItem.setToolTipText("Use full Java syntax");
06692: if (currentLanguageLevel == DrJavaRoot.FULL_JAVA) {
06693: rbMenuItem.setSelected(true);
06694: }
06695: rbMenuItem.addActionListener(new ActionListener() {
06696: public void actionPerformed(ActionEvent e) {
06697: config.setSetting(LANGUAGE_LEVEL, DrJavaRoot.FULL_JAVA);
06698: }
06699: });
06700: group.add(rbMenuItem);
06701: languageLevelMenu.add(rbMenuItem);
06702: languageLevelMenu.addSeparator();
06703:
06704: rbMenuItem = new JRadioButtonMenuItem("Elementary");
06705: rbMenuItem
06706: .setToolTipText("Use Elementary language-level features");
06707: if (currentLanguageLevel == DrJavaRoot.ELEMENTARY_LEVEL) {
06708: rbMenuItem.setSelected(true);
06709: }
06710: rbMenuItem.addActionListener(new ActionListener() {
06711: public void actionPerformed(ActionEvent e) {
06712: config.setSetting(LANGUAGE_LEVEL,
06713: DrJavaRoot.ELEMENTARY_LEVEL);
06714: }
06715: });
06716: group.add(rbMenuItem);
06717: languageLevelMenu.add(rbMenuItem);
06718:
06719: rbMenuItem = new JRadioButtonMenuItem("Intermediate");
06720: rbMenuItem
06721: .setToolTipText("Use Intermediate language-level features");
06722: if (currentLanguageLevel == DrJavaRoot.INTERMEDIATE_LEVEL) {
06723: rbMenuItem.setSelected(true);
06724: }
06725: rbMenuItem.addActionListener(new ActionListener() {
06726: public void actionPerformed(ActionEvent e) {
06727: config.setSetting(LANGUAGE_LEVEL,
06728: DrJavaRoot.INTERMEDIATE_LEVEL);
06729: }
06730: });
06731: group.add(rbMenuItem);
06732: languageLevelMenu.add(rbMenuItem);
06733:
06734: rbMenuItem = new JRadioButtonMenuItem("Advanced");
06735: rbMenuItem
06736: .setToolTipText("Use Advanced language-level features");
06737: if (currentLanguageLevel == DrJavaRoot.ADVANCED_LEVEL) {
06738: rbMenuItem.setSelected(true);
06739: }
06740: rbMenuItem.addActionListener(new ActionListener() {
06741: public void actionPerformed(ActionEvent e) {
06742: config.setSetting(LANGUAGE_LEVEL,
06743: DrJavaRoot.ADVANCED_LEVEL);
06744: }
06745: });
06746: group.add(rbMenuItem);
06747: languageLevelMenu.add(rbMenuItem);
06748: return languageLevelMenu;
06749: }
06750:
06751: /** Creates and returns a help menu. */
06752: private JMenu _setUpHelpMenu(int mask) {
06753: JMenu helpMenu = new JMenu("Help");
06754: helpMenu.setMnemonic(KeyEvent.VK_H);
06755: _addMenuItem(helpMenu, _helpAction, KEY_HELP);
06756: _addMenuItem(helpMenu, _quickStartAction, KEY_QUICKSTART);
06757: _addMenuItem(helpMenu, _aboutAction, KEY_ABOUT);
06758: _addMenuItem(helpMenu, _errorsAction, KEY_DRJAVA_ERRORS);
06759: _addMenuItem(helpMenu, _forceQuitAction, KEY_FORCE_QUIT);
06760: return helpMenu;
06761: }
06762:
06763: /** Creates a toolbar button for undo and redo, which behave differently. */
06764: JButton _createManualToolbarButton(Action a) {
06765: final JButton ret;
06766:
06767: Font buttonFont = DrJava.getConfig().getSetting(FONT_TOOLBAR);
06768:
06769: // Check whether icons should be shown
06770: boolean useIcon = DrJava.getConfig().getSetting(
06771: TOOLBAR_ICONS_ENABLED).booleanValue();
06772: boolean useText = DrJava.getConfig().getSetting(
06773: TOOLBAR_TEXT_ENABLED).booleanValue();
06774: final Icon icon = (useIcon) ? (Icon) a
06775: .getValue(Action.SMALL_ICON) : null;
06776: if (icon == null) {
06777: ret = new UnfocusableButton((String) a
06778: .getValue(Action.DEFAULT));
06779: } else {
06780: ret = new UnfocusableButton(icon);
06781: if (useText)
06782: ret.setText((String) a.getValue(Action.DEFAULT));
06783: }
06784: ret.setEnabled(false);
06785: ret.addActionListener(a);
06786: ret.setToolTipText((String) a
06787: .getValue(Action.SHORT_DESCRIPTION));
06788: ret.setFont(buttonFont);
06789: Boolean test = a instanceof DelegatingAction;
06790: a.addPropertyChangeListener(new PropertyChangeListener() {
06791: public void propertyChange(PropertyChangeEvent evt) {
06792: if ("enabled".equals(evt.getPropertyName())) {
06793: Boolean val = (Boolean) evt.getNewValue();
06794: ret.setEnabled(val.booleanValue());
06795: }
06796: }
06797: });
06798:
06799: return ret;
06800: }
06801:
06802: /** Sets up all buttons for the toolbar except for undo and redo, which use _createManualToolbarButton. */
06803: public JButton _createToolbarButton(Action a) {
06804: boolean useText = DrJava.getConfig().getSetting(
06805: TOOLBAR_TEXT_ENABLED).booleanValue();
06806: boolean useIcons = DrJava.getConfig().getSetting(
06807: TOOLBAR_ICONS_ENABLED).booleanValue();
06808: Font buttonFont = DrJava.getConfig().getSetting(FONT_TOOLBAR);
06809:
06810: final JButton result = new UnfocusableButton(a);
06811: result.setText((String) a.getValue(Action.DEFAULT));
06812: result.setFont(buttonFont);
06813: if (!useIcons)
06814: result.setIcon(null);
06815: if (!useText && (result.getIcon() != null))
06816: result.setText("");
06817: return result;
06818: }
06819:
06820: /** Removes the button b from the toolbar and creates new button in its place. */
06821: public JButton _updateToolbarButton(JButton b, Action a) {
06822: final JButton result = _createToolbarButton(a);
06823:
06824: int index = _toolBar.getComponentIndex(b);
06825: _toolBar.remove(b);
06826: _toolBar.add(result, index);
06827:
06828: _fixToolbarHeights();
06829:
06830: return result;
06831: }
06832:
06833: /** Sets up the toolbar with several useful buttons. Most buttons are always enabled, but those that are not are
06834: * maintained in fields to allow enabling and disabling.
06835: */
06836: private void _setUpToolBar() {
06837:
06838: _toolBar.setFloatable(false);
06839:
06840: // _toolBar.addSeparator();
06841:
06842: // New, open, save, close
06843: _toolBar.add(_createToolbarButton(_newAction));
06844: _toolBar.add(_createToolbarButton(_openFileOrProjectAction));
06845: _toolBar.add(_createToolbarButton(_saveAction));
06846: _closeButton = _createToolbarButton(_closeAction);
06847: _toolBar.add(_closeButton);
06848:
06849: // Cut, copy, paste
06850: _toolBar.addSeparator();
06851: _toolBar.add(_createToolbarButton(cutAction));
06852: _toolBar.add(_createToolbarButton(copyAction));
06853: _toolBar.add(_createToolbarButton(pasteAction));
06854:
06855: // Undo, redo
06856: // Simple workaround, for now, for bug # 520742:
06857: // Undo/Redo button text in JDK 1.3
06858: // We just manually create the JButtons, and we *don't* set up
06859: // PropertyChangeListeners on the action's name.
06860: //_toolBar.addSeparator();
06861:
06862: _toolBar.add(_undoButton);
06863: _toolBar.add(_redoButton);
06864:
06865: // Find
06866: _toolBar.addSeparator();
06867: _toolBar.add(_createToolbarButton(_findReplaceAction));
06868:
06869: // Compile, reset, abort
06870: _toolBar.addSeparator();
06871: _toolBar
06872: .add(_compileButton = _createToolbarButton(_compileAllAction));
06873: _toolBar.add(_createToolbarButton(_resetInteractionsAction));
06874: //_toolBar.add(_createToolbarButton(_abortInteractionAction));
06875:
06876: // Run, Junit, and JavaDoc
06877: _toolBar.addSeparator();
06878:
06879: _toolBar.add(_runButton = _createToolbarButton(_runAction));
06880: _toolBar
06881: .add(_junitButton = _createToolbarButton(_junitAllAction));
06882: _toolBar.add(_createToolbarButton(_javadocAllAction));
06883:
06884: // DrJava Errors
06885: _toolBar.addSeparator();
06886: final JButton errorsButton = _createToolbarButton(_errorsAction);
06887: errorsButton.setVisible(false);
06888: errorsButton.setBackground(DrJava.getConfig().getSetting(
06889: DRJAVA_ERRORS_BUTTON_COLOR));
06890: DrJavaErrorHandler.setButton(errorsButton);
06891: _toolBar.add(errorsButton);
06892: /** The OptionListener for DRJAVA_ERRORS_BUTTON_COLOR. */
06893: OptionListener<Color> errBtnColorOptionListener = new OptionListener<Color>() {
06894: public void optionChanged(OptionEvent<Color> oce) {
06895: errorsButton.setBackground(oce.value);
06896: }
06897: };
06898: DrJava.getConfig().addOptionListener(
06899: DRJAVA_ERRORS_BUTTON_COLOR, errBtnColorOptionListener);
06900:
06901: // Correct the vertical height of the buttons.
06902: _fixToolbarHeights();
06903:
06904: getContentPane().add(_toolBar, BorderLayout.NORTH);
06905: // _updateToolBarVisible(); // created a visible GUI component during initialization!
06906: }
06907:
06908: /** Sets the toolbar as either visible or invisible based on the config option. */
06909: private void _updateToolBarVisible() {
06910: _toolBar.setVisible(DrJava.getConfig().getSetting(
06911: TOOLBAR_ENABLED));
06912: }
06913:
06914: /** Update the toolbar's buttons, following any change to TOOLBAR_ICONS_ENABLED, TOOLBAR_TEXT_ENABLED, or
06915: * FONT_TOOLBAR (name, style, text)
06916: */
06917: private void _updateToolbarButtons() {
06918: _updateToolBarVisible();
06919: Component[] buttons = _toolBar.getComponents();
06920:
06921: Font toolbarFont = DrJava.getConfig().getSetting(FONT_TOOLBAR);
06922: boolean iconsEnabled = DrJava.getConfig().getSetting(
06923: TOOLBAR_ICONS_ENABLED).booleanValue();
06924: boolean textEnabled = DrJava.getConfig().getSetting(
06925: TOOLBAR_TEXT_ENABLED).booleanValue();
06926:
06927: for (int i = 0; i < buttons.length; i++) {
06928:
06929: if (buttons[i] instanceof JButton) {
06930:
06931: JButton b = (JButton) buttons[i];
06932: Action a = b.getAction();
06933:
06934: // Work-around for strange configuration of undo/redo buttons
06935: /*
06936: if (a == null) {
06937: ActionListener[] al = b.getActionListeners(); // 1.4 only
06938:
06939: for (int j=0; j<al.length; j++) {
06940: if (al[j] instanceof Action) {
06941: a = (Action) al[j];
06942: break;
06943: }
06944: }
06945: }
06946: */
06947:
06948: b.setFont(toolbarFont);
06949:
06950: if (a == null) {
06951: if (b == _undoButton)
06952: a = _undoAction;
06953: else if (b == _redoButton)
06954: a = _redoAction;
06955: else
06956: continue;
06957: }
06958:
06959: if (b.getIcon() == null) {
06960: if (iconsEnabled)
06961: b.setIcon((Icon) a.getValue(Action.SMALL_ICON));
06962: } else if (!iconsEnabled && b.getText().equals(""))
06963: b.setIcon(null);
06964:
06965: if (b.getText().equals("")) {
06966: if (textEnabled)
06967: b.setText((String) a.getValue(Action.DEFAULT));
06968: } else if (!textEnabled && b.getIcon() != null)
06969: b.setText("");
06970:
06971: }
06972: }
06973:
06974: // Correct the vertical height of the buttons.
06975: _fixToolbarHeights();
06976: }
06977:
06978: /** Ensures that all toolbar buttons have the same height. */
06979: private void _fixToolbarHeights() {
06980: Component[] buttons = _toolBar.getComponents();
06981:
06982: // First, find the maximum height of all the buttons.
06983: int max = 0;
06984: for (int i = 0; i < buttons.length; i++) {
06985: // We only care about the JButtons.
06986: if (buttons[i] instanceof JButton) {
06987: JButton b = (JButton) buttons[i];
06988:
06989: // reset any preferred size we have set
06990: b.setPreferredSize(null);
06991:
06992: // get the preferred height, since that's what we want to use
06993: Dimension d = b.getPreferredSize();
06994: int cur = (int) d.getHeight();
06995: if (cur > max) {
06996: max = cur;
06997: }
06998: }
06999: }
07000:
07001: // Now set all button heights to the max.
07002: for (int i = 0; i < buttons.length; i++) {
07003: // We only care about the JButtons.
07004: if (buttons[i] instanceof JButton) {
07005: JButton b = (JButton) buttons[i];
07006: Dimension d = new Dimension((int) b.getPreferredSize()
07007: .getWidth(), max);
07008:
07009: // JToolBar inexplicably uses the max size
07010: // also set preferred size for consistency
07011: b.setPreferredSize(d);
07012: b.setMaximumSize(d);
07013: }
07014: }
07015:
07016: // _toolbar.revalidate();
07017: }
07018:
07019: /** Sets up the status bar with the filename field. Only called from MainFrame constructor. */
07020: private void _setUpStatusBar() {
07021:
07022: // Initialize the 3 labels:
07023:
07024: _statusField.setFont(_statusField.getFont().deriveFont(
07025: Font.PLAIN));
07026: _statusReport.setHorizontalAlignment(SwingConstants.RIGHT);
07027:
07028: JPanel fileNameAndMessagePanel = new JPanel(new BorderLayout());
07029: fileNameAndMessagePanel.add(_statusField, BorderLayout.CENTER);
07030: fileNameAndMessagePanel.add(_statusReport, BorderLayout.EAST);
07031:
07032: _currLocationField.setFont(_currLocationField.getFont()
07033: .deriveFont(Font.PLAIN));
07034: _currLocationField.setHorizontalAlignment(SwingConstants.RIGHT);
07035: _currLocationField.setPreferredSize(new Dimension(165, 12));
07036: // _currLocationField.setVisible(true);
07037:
07038: // Initialize the status bar panel
07039: // SpringLayout layout = new SpringLayout();
07040: _statusBar.add(fileNameAndMessagePanel, BorderLayout.CENTER);
07041: // _statusBar.add( sbMessagePanel, BorderLayout.CENTER );
07042: _statusBar.add(_currLocationField, BorderLayout.EAST);
07043: _statusBar.setBorder(new CompoundBorder(new EmptyBorder(2, 2,
07044: 2, 2), new CompoundBorder(new BevelBorder(
07045: BevelBorder.LOWERED), new EmptyBorder(2, 2, 2, 2))));
07046: getContentPane().add(_statusBar, BorderLayout.SOUTH);
07047:
07048: // //Adjust constraints for the fileName label so it's next to the left edge.
07049: // layout.getConstraints(_statusField).setX(Spring.constant(0));
07050: //
07051: // //Adjust constraints for the message label so it's spaced a bit from the right.
07052: // //and doesn't interfere with the left-most label
07053: // layout.putConstraint(SpringLayout.EAST, _statusReport, -65,
07054: // SpringLayout.EAST, _statusBar);
07055: //
07056: // //Adjust constraints for the location label so it's next to the right edge.
07057: // layout.putConstraint(SpringLayout.EAST, _currLocationField, 0,
07058: // SpringLayout.EAST, _statusBar);
07059: //
07060: // //Adjust constraints for the panel to set its size
07061: // layout.putConstraint(SpringLayout.SOUTH, _statusBar, 0,
07062: // SpringLayout.SOUTH, _currLocationField);
07063: }
07064:
07065: /** Inner class to handle updating the current position in the document. Registered with the DefinitionsPane. **/
07066: private class PositionListener implements CaretListener {
07067:
07068: /* Cached caret coordinates */
07069: private int _offset;
07070: private int _line;
07071: private int _col;
07072:
07073: // The following method only runs in the event thread because it is called from DefinitionsPane
07074: public void caretUpdate(final CaretEvent ce) {
07075: OpenDefinitionsDocument doc = _model.getActiveDocument();
07076: int offset = ce.getDot();
07077: try {
07078: if (offset == _offset + 1
07079: && doc.getText(_offset, 1).charAt(0) != '\n') {
07080: _col += 1;
07081: updateLocation(_line, _col);
07082: return;
07083: }
07084: } catch (BadLocationException e) { /* fall through */
07085: }
07086:
07087: Element root = doc.getDefaultRootElement();
07088: int line = root.getElementIndex(offset);
07089: _line = line + 1; // line numbers are 1-based
07090: _col = offset - root.getElement(line).getStartOffset();
07091: updateLocation(_line, _col);
07092: }
07093:
07094: // This method appears safe outside the event thread
07095: public void updateLocation() {
07096: OpenDefinitionsDocument doc = _model.getActiveDocument();
07097: doc.acquireReadLock(); // lock to ensure consistency of two reads from doc
07098: try {
07099: updateLocation(doc.getCurrentLine(), doc
07100: .getCurrentCol());
07101: } finally {
07102: doc.releaseReadLock();
07103: }
07104: }
07105:
07106: private void updateLocation(int line, int col) { // Not run in event thread because setText is thread safe.
07107: _currLocationField.setText(line + ":" + col + " \t"); // Space before "\t" required on Mac to avoid obscuring
07108: // Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
07109: // _model.getParsingControl().delay();
07110: }
07111: }
07112:
07113: /* Only called from MainFrame constructor. */
07114: private void _setUpTabs() {
07115:
07116: // Interactions
07117: _interactionsController
07118: .setPrevPaneAction(_switchToPreviousPaneAction);
07119: _interactionsController
07120: .setNextPaneAction(_switchToNextPaneAction);
07121:
07122: JScrollPane interactionsScroll = new BorderlessScrollPane(
07123: _interactionsPane,
07124: JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
07125: JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
07126: _interactionsContainer.add(interactionsScroll,
07127: BorderLayout.CENTER);
07128:
07129: if (_showDebugger) {
07130: // hook highlighting listener to breakpoint manager
07131: _model.getBreakpointManager().addListener(
07132: new RegionManagerListener<Breakpoint>() {
07133: /* Called when a breakpoint is added. Only runs in event thread. */
07134: public void regionAdded(final Breakpoint bp,
07135: int index) {
07136: DefinitionsPane bpPane = getDefPaneGivenODD(bp
07137: .getDocument());
07138: _documentBreakpointHighlights
07139: .put(
07140: bp,
07141: bpPane
07142: .getHighlightManager()
07143: .addHighlight(
07144: bp
07145: .getStartOffset(),
07146: bp
07147: .getEndOffset(),
07148: bp
07149: .isEnabled() ? DefinitionsPane.BREAKPOINT_PAINTER
07150: : DefinitionsPane.DISABLED_BREAKPOINT_PAINTER));
07151: _updateDebugStatus();
07152: }
07153:
07154: /** Called when a breakpoint is changed. Only runs in event thread. */
07155: public void regionChanged(Breakpoint bp,
07156: int index) {
07157: regionRemoved(bp);
07158: regionAdded(bp, index);
07159: }
07160:
07161: /** Called when a breakpoint is removed. Only runs in event thread. */
07162: public void regionRemoved(final Breakpoint bp) {
07163: HighlightManager.HighlightInfo highlight = _documentBreakpointHighlights
07164: .get(bp);
07165: if (highlight != null)
07166: highlight.remove();
07167: _documentBreakpointHighlights.remove(bp);
07168: }
07169: });
07170: }
07171:
07172: // hook highlighting listener to bookmark manager
07173: _model.getBookmarkManager().addListener(
07174: new RegionManagerListener<DocumentRegion>() {
07175: // listener methods only run in the event thread
07176: public void regionAdded(DocumentRegion r, int index) {
07177: DefinitionsPane bpPane = getDefPaneGivenODD(r
07178: .getDocument());
07179: _documentBookmarkHighlights
07180: .put(
07181: r,
07182: bpPane
07183: .getHighlightManager()
07184: .addHighlight(
07185: r
07186: .getStartOffset(),
07187: r
07188: .getEndOffset(),
07189: DefinitionsPane.BOOKMARK_PAINTER));
07190: }
07191:
07192: public void regionChanged(DocumentRegion r,
07193: int index) {
07194: regionRemoved(r);
07195: regionAdded(r, index);
07196: }
07197:
07198: public void regionRemoved(DocumentRegion r) {
07199: HighlightManager.HighlightInfo highlight = _documentBookmarkHighlights
07200: .get(r);
07201: if (highlight != null)
07202: highlight.remove();
07203: _documentBookmarkHighlights.remove(r);
07204: }
07205: });
07206:
07207: _tabbedPane.addChangeListener(new ChangeListener() {
07208: public void stateChanged(ChangeEvent e) {
07209: // System.err.println("_tabbedPane.stateChanged called with event " + e);
07210: clearStatusMessage();
07211:
07212: if (_tabbedPane.getSelectedIndex() == INTERACTIONS_TAB) {
07213: // Use SwingUtilities because this action must execute AFTER all pending events in the event queue
07214: // System.err.println("Interactions Container Selected");
07215: _interactionsContainer.setVisible(true); // kluge to overcome subtle focus bug
07216: EventQueue.invokeLater(new Runnable() {
07217: public void run() {
07218: _interactionsContainer
07219: .requestFocusInWindow();
07220: }
07221: });
07222: } else if (_tabbedPane.getSelectedIndex() == CONSOLE_TAB) {
07223: // Use SwingUtilities because this action must execute AFTER all pending events in the event queue
07224: // System.err.println("Console Scroll Selected");
07225: EventQueue.invokeLater(new Runnable() {
07226: public void run() {
07227: _consoleScroll.requestFocusInWindow();
07228: }
07229: });
07230: }
07231: // Update error highlights?
07232: if (_currentDefPane != null) {
07233: int pos = _currentDefPane.getCaretPosition();
07234: _currentDefPane.removeErrorHighlight(); //this line removes the highlighting whenever the current tabbed pane is switched
07235: _currentDefPane.getErrorCaretListener()
07236: .updateHighlight(pos);
07237: }
07238: }
07239: });
07240:
07241: _tabbedPane.add("Interactions", _interactionsContainer);
07242: _tabbedPane.add("Console", _consoleScroll);
07243:
07244: _tabs.addLast(_compilerErrorPanel);
07245: _tabs.addLast(_junitErrorPanel);
07246: _tabs.addLast(_javadocErrorPanel);
07247: _tabs.addLast(_findReplace);
07248: if (_showDebugger) {
07249: _tabs.addLast(_breakpointsPanel);
07250: }
07251: _tabs.addLast(_bookmarksPanel);
07252:
07253: _interactionsContainer.addFocusListener(new FocusAdapter() {
07254: public void focusGained(FocusEvent e) {
07255: EventQueue.invokeLater(new Runnable() {
07256: public void run() {
07257: // System.err.println("Requesting focus in interactions pane");
07258: _interactionsPane.requestFocusInWindow();
07259: }
07260: });
07261: }
07262: });
07263:
07264: _interactionsPane.addFocusListener(new FocusAdapter() {
07265: public void focusGained(FocusEvent e) {
07266: _lastFocusOwner = _interactionsContainer;
07267: }
07268: });
07269: _consolePane.addFocusListener(new FocusAdapter() {
07270: public void focusGained(FocusEvent e) {
07271: _lastFocusOwner = _consoleScroll;
07272: }
07273: });
07274: _compilerErrorPanel.getMainPanel().addFocusListener(
07275: new FocusAdapter() {
07276: public void focusGained(FocusEvent e) {
07277: _lastFocusOwner = _compilerErrorPanel;
07278: }
07279: });
07280: _junitErrorPanel.getMainPanel().addFocusListener(
07281: new FocusAdapter() {
07282: public void focusGained(FocusEvent e) {
07283: _lastFocusOwner = _junitErrorPanel;
07284: }
07285: });
07286: _javadocErrorPanel.getMainPanel().addFocusListener(
07287: new FocusAdapter() {
07288: public void focusGained(FocusEvent e) {
07289: _lastFocusOwner = _javadocErrorPanel;
07290: }
07291: });
07292: _findReplace.getFindField().addFocusListener(
07293: new FocusAdapter() {
07294: public void focusGained(FocusEvent e) {
07295: _lastFocusOwner = _findReplace;
07296: }
07297: });
07298: if (_showDebugger) {
07299: _breakpointsPanel.getMainPanel().addFocusListener(
07300: new FocusAdapter() {
07301: public void focusGained(FocusEvent e) {
07302: _lastFocusOwner = _breakpointsPanel;
07303: }
07304: });
07305: }
07306: _bookmarksPanel.getMainPanel().addFocusListener(
07307: new FocusAdapter() {
07308: public void focusGained(FocusEvent e) {
07309: _lastFocusOwner = _bookmarksPanel;
07310: }
07311: });
07312: }
07313:
07314: /** Realizes this MainFrame by setting it visibile and configures the tabbed Pane. */
07315: public void start() {
07316:
07317: // Make the MainFrame visible and show the compiler tab
07318: EventQueue.invokeLater(new Runnable() {
07319: public void run() {
07320: setVisible(true);
07321: _compilerErrorPanel.setVisible(true);
07322: showTab(_compilerErrorPanel);
07323: /* The following two step sequence was laboriously developed by trial and error; without it the _tabbedPane
07324: * does not display properly. */
07325: _tabbedPane.invalidate();
07326: _tabbedPane.repaint();
07327: }
07328: });
07329: }
07330:
07331: /** Sets up the context menu to show in the document pane. */
07332: private void _setUpContextMenus() {
07333: // pop-up menu for a folder in tree view
07334: // _navPaneFolderPopupMenu = new JPopupMenu();
07335: /*
07336: * Phil Repicky -smallproj
07337: * 2/14/2005
07338: * Make these do something:
07339: * _navPaneFolderPopupMenu.add("Open a File in this Folder Action");
07340: * _navPaneFolderPopupMenu.add("Make a New File in this Folder Action");
07341: */
07342: // _navPaneFolderPopupMenu.add(_newFileFolderAction);
07343: // _navPaneFolderPopupMenu.add(_openOneFolderAction);
07344: // _navPaneFolderPopupMenu.add(_openAllFolderAction);
07345: // _navPaneFolderPopupMenu.add(_closeFolderAction);
07346: // _navPaneFolderPopupMenu.add(_compileFolderAction);
07347: // _navPaneFolderPopupMenu.add(_junitFolderAction);
07348: // _navPanePopupMenuForRoot = new JPopupMenu();
07349: // _navPanePopupMenuForRoot.add(_saveProjectAction);
07350: // _navPanePopupMenuForRoot.add(_closeProjectAction);
07351: // _navPanePopupMenuForRoot.addSeparator();
07352: // _navPanePopupMenuForRoot.add(_compileProjectAction);
07353: // _navPanePopupMenuForRoot.add(_runProjectAction);
07354: // _navPanePopupMenuForRoot.add(_junitProjectAction);
07355: // _navPanePopupMenuForRoot.addSeparator();
07356: // _navPanePopupMenuForRoot.add(_projectPropertiesAction);
07357: // _navPanePopupMenuForExternal = new JPopupMenu();
07358: // _navPanePopupMenuForExternal.add(_saveAction);
07359: // _navPanePopupMenuForExternal.add(_saveAsAction);
07360: // _navPanePopupMenuForExternal.add(_renameAction);
07361: // _navPanePopupMenuForExternal.add(_revertAction);
07362: // _navPanePopupMenuForExternal.addSeparator();
07363: // _navPanePopupMenuForExternal.add(_closeAction);
07364: // _navPanePopupMenuForExternal.addSeparator();
07365: // _navPanePopupMenuForExternal.add(_printDefDocAction);
07366: // _navPanePopupMenuForExternal.add(_printDefDocPreviewAction);
07367: // _navPanePopupMenuForExternal.addSeparator();
07368: // _navPanePopupMenuForExternal.add(_compileAction);
07369: // _navPanePopupMenuForExternal.add(_junitAction);
07370: // _navPanePopupMenuForExternal.add(_javadocCurrentAction);
07371: // _navPanePopupMenuForExternal.add(_runAction);
07372: // _navPanePopupMenuForExternal.addSeparator();
07373: // _navPanePopupMenuForExternal.add(_moveToAuxiliaryAction);
07374: // _navPanePopupMenuForAuxiliary = new JPopupMenu();
07375: // _navPanePopupMenuForAuxiliary.add(_saveAction);
07376: // _navPanePopupMenuForAuxiliary.add(_saveAsAction);
07377: // _navPanePopupMenuForAuxiliary.add(_renameAction);
07378: // _navPanePopupMenuForAuxiliary.add(_revertAction);
07379: // _navPanePopupMenuForAuxiliary.addSeparator();
07380: // _navPanePopupMenuForAuxiliary.add(_closeAction);
07381: // _navPanePopupMenuForAuxiliary.addSeparator();
07382: // _navPanePopupMenuForAuxiliary.add(_printDefDocAction);
07383: // _navPanePopupMenuForAuxiliary.add(_printDefDocPreviewAction);
07384: // _navPanePopupMenuForAuxiliary.addSeparator();
07385: // _navPanePopupMenuForAuxiliary.add(_compileAction);
07386: // _navPanePopupMenuForAuxiliary.add(_junitAction);
07387: // _navPanePopupMenuForAuxiliary.add(_javadocCurrentAction);
07388: // _navPanePopupMenuForAuxiliary.add(_runAction);
07389: // _navPanePopupMenuForAuxiliary.addSeparator();
07390: // _navPanePopupMenuForAuxiliary.add(_removeAuxiliaryAction);
07391: // NavPane menu
07392: // _navPanePopupMenu = new JPopupMenu();
07393: // _navPanePopupMenu.add(_saveAction);
07394: // _navPanePopupMenu.add(_saveAsAction);
07395: // _navPanePopupMenu.add(_renameAction);
07396: // _navPanePopupMenu.add(_revertAction);
07397: // _navPanePopupMenu.addSeparator();
07398: // _navPanePopupMenu.add(_closeAction);
07399: // _navPanePopupMenu.addSeparator();
07400: // _navPanePopupMenu.add(_printDefDocAction);
07401: // _navPanePopupMenu.add(_printDefDocPreviewAction);
07402: // _navPanePopupMenu.addSeparator();
07403: // _navPanePopupMenu.add(_compileAction);
07404: // _navPanePopupMenu.add(_junitAction);
07405: // _navPanePopupMenu.add(_javadocCurrentAction);
07406: // _navPanePopupMenu.add(_runAction);
07407: _model.getDocCollectionWidget().addMouseListener(
07408: new RightClickMouseAdapter() {
07409: protected void _popupAction(MouseEvent e) {
07410: boolean showContextMenu = true;
07411: if (!_model.getDocumentNavigator()
07412: .isSelectedAt(e.getX(), e.getY())) {
07413: // click on a item that wasn't selected, change selection
07414: showContextMenu = _model
07415: .getDocumentNavigator()
07416: .selectDocumentAt(e.getX(),
07417: e.getY());
07418: }
07419: if (showContextMenu) {
07420: boolean rootSelected = _model
07421: .getDocumentNavigator()
07422: .isRootSelected();
07423: boolean folderSelected = false;
07424: boolean docSelected = false;
07425: boolean externalSelected = false;
07426: boolean auxiliarySelected = false;
07427: boolean externalBinSelected = false;
07428: boolean auxiliaryBinSelected = false;
07429:
07430: final int docSelectedCount = _model
07431: .getDocumentNavigator()
07432: .getDocumentSelectedCount();
07433: final int groupSelectedCount = _model
07434: .getDocumentNavigator()
07435: .getGroupSelectedCount();
07436: try {
07437: java.util.Set<String> groupNames = _model
07438: .getDocumentNavigator()
07439: .getNamesOfSelectedTopLevelGroup();
07440:
07441: if (docSelectedCount > 0) {
07442: // when documents are selected, ignore all other options and only deal with documents
07443: rootSelected = false;
07444: if (groupNames.contains(_model
07445: .getSourceBinTitle())) {
07446: // a document in the "[ Source Files ]" bin is selected
07447: docSelected = true;
07448: }
07449: if (groupNames.contains(_model
07450: .getExternalBinTitle())) {
07451: // a document in the "[ External Files ]" bin is selected
07452: externalSelected = true;
07453: }
07454: if (groupNames.contains(_model
07455: .getAuxiliaryBinTitle())) {
07456: // a document in the "[ Included External Files ]" bin is selected
07457: auxiliarySelected = true;
07458: }
07459: } else {
07460: // no document selected, check other options
07461: if (groupSelectedCount > 0) {
07462: // at least one folder is selected
07463: if (!_model
07464: .getDocumentNavigator()
07465: .isTopLevelGroupSelected()) {
07466: // it is really a folder and not a top level bin, e.g. "[ Source Files ]"
07467: folderSelected = true;
07468: } else {
07469: // it is a top level bin, e.g. "[ Source Files ]"
07470: if (groupNames
07471: .contains(_model
07472: .getSourceBinTitle())) {
07473: // the "[ Source Files ]" bin is selected, treat as normal folder
07474: folderSelected = true;
07475: }
07476: if (groupNames
07477: .contains(_model
07478: .getExternalBinTitle())) {
07479: // the "[ External Files ]" bin is selected
07480: externalBinSelected = true;
07481: }
07482: if (groupNames
07483: .contains(_model
07484: .getAuxiliaryBinTitle())) {
07485: // the "[ Included External Files ]" bin is selected
07486: auxiliaryBinSelected = true;
07487: }
07488: }
07489: }
07490: }
07491: } catch (GroupNotSelectedException ex) {
07492: // we're looking at the root of the tree, or we're in list view...
07493: if (_model.isProjectActive()) {
07494: // project view, so the root has been selected
07495: rootSelected = true;
07496: } else {
07497: // list view, so treat it as simple documents
07498: docSelected = true;
07499: rootSelected = false;
07500: folderSelected = false;
07501: externalSelected = false;
07502: auxiliarySelected = false;
07503: externalBinSelected = false;
07504: auxiliaryBinSelected = false;
07505: }
07506: }
07507:
07508: if (!rootSelected && !folderSelected
07509: && !docSelected
07510: && !externalSelected
07511: && !auxiliarySelected
07512: && !externalBinSelected
07513: && !auxiliaryBinSelected) {
07514: // nothing selected, don't display anything
07515: return;
07516: }
07517:
07518: final JPopupMenu m = new JPopupMenu();
07519: if (docSelectedCount == 0) {
07520: docSelected = externalSelected = auxiliarySelected = false;
07521: }
07522: if (groupSelectedCount == 0) {
07523: folderSelected = false;
07524: }
07525:
07526: if (rootSelected) {
07527: // root selected
07528: m.add(Utilities.createDelegateAction(
07529: "Save Project",
07530: _saveProjectAction));
07531: m.add(Utilities.createDelegateAction(
07532: "Close Project",
07533: _closeProjectAction));
07534: m.add(_compileProjectAction);
07535: m.add(_runProjectAction);
07536: m.add(_junitProjectAction);
07537: m.add(_projectPropertiesAction);
07538: }
07539: if (folderSelected) {
07540: // folder selected
07541: if (m.getComponentCount() > 0) {
07542: m.addSeparator();
07543: }
07544: if (groupSelectedCount == 1) {
07545: // "New File in Folder" and "Open File in Folder" only work if exactly
07546: // one folder is selected
07547: m.add(_newFileFolderAction);
07548: m.add(_openOneFolderAction);
07549:
07550: // get singular/plural right
07551: m
07552: .add(Utilities
07553: .createDelegateAction(
07554: "Open All Files in Folder",
07555: _openAllFolderAction));
07556: m.add(_closeFolderAction);
07557: m.add(_compileFolderAction);
07558: m.add(_junitFolderAction);
07559: } else if (groupSelectedCount > 1) {
07560: if (!externalBinSelected
07561: && !auxiliaryBinSelected) {
07562: // open only makes sense if it's real folders, and not
07563: // the external or auxiliary bins
07564: m
07565: .add(Utilities
07566: .createDelegateAction(
07567: "Open All Files in All Folders ("
07568: + groupSelectedCount
07569: + ")",
07570: _openAllFolderAction));
07571: }
07572: m
07573: .add(Utilities
07574: .createDelegateAction(
07575: "Close All Folders ("
07576: + groupSelectedCount
07577: + ")",
07578: _closeFolderAction));
07579: m
07580: .add(Utilities
07581: .createDelegateAction(
07582: "Compile All Folders ("
07583: + groupSelectedCount
07584: + ")",
07585: _compileFolderAction));
07586: m
07587: .add(Utilities
07588: .createDelegateAction(
07589: "Test All Folders ("
07590: + groupSelectedCount
07591: + ")",
07592: _junitFolderAction));
07593:
07594: }
07595: }
07596: if (docSelected || externalSelected
07597: || auxiliarySelected) {
07598: // some kind of document selected
07599: if (m.getComponentCount() > 0) {
07600: m.addSeparator();
07601: }
07602: if (docSelectedCount == 1) {
07603: m.add(Utilities
07604: .createDelegateAction(
07605: "Save File",
07606: _saveAction));
07607: m.add(Utilities
07608: .createDelegateAction(
07609: "Save File As...",
07610: _saveAsAction));
07611: m.add(Utilities
07612: .createDelegateAction(
07613: "Rename File",
07614: _renameAction));
07615: m
07616: .add(Utilities
07617: .createDelegateAction(
07618: "Revert File to Saved",
07619: _revertAction));
07620: m.add(Utilities
07621: .createDelegateAction(
07622: "Close File",
07623: _closeAction));
07624: m
07625: .add(Utilities
07626: .createDelegateAction(
07627: "Print File...",
07628: _printDefDocAction));
07629: m
07630: .add(Utilities
07631: .createDelegateAction(
07632: "Print File Preview...",
07633: _printDefDocPreviewAction));
07634: m.add(Utilities
07635: .createDelegateAction(
07636: "Compile File",
07637: _compileAction));
07638: m.add(Utilities
07639: .createDelegateAction(
07640: "Test File",
07641: _junitAction));
07642: m
07643: .add(Utilities
07644: .createDelegateAction(
07645: "Preview Javadoc for File",
07646: _javadocCurrentAction));
07647: m
07648: .add(Utilities
07649: .createDelegateAction(
07650: "Run File's Main Method",
07651: _runAction));
07652: } else if (docSelectedCount > 1) {
07653: m
07654: .add(Utilities
07655: .createDelegateAction(
07656: "Save All Files ("
07657: + docSelectedCount
07658: + ")",
07659: _saveAction));
07660: m
07661: .add(Utilities
07662: .createDelegateAction(
07663: "Revert All Files to Saved ("
07664: + docSelectedCount
07665: + ")",
07666: _revertAction));
07667: m
07668: .add(Utilities
07669: .createDelegateAction(
07670: "Close All Files ("
07671: + docSelectedCount
07672: + ")",
07673: _closeAction));
07674: m
07675: .add(Utilities
07676: .createDelegateAction(
07677: "Compile All Files ("
07678: + docSelectedCount
07679: + ")",
07680: _compileAction));
07681: m
07682: .add(Utilities
07683: .createDelegateAction(
07684: "Test All Files ("
07685: + docSelectedCount
07686: + ")",
07687: _junitAction));
07688: }
07689: }
07690: if (externalSelected && !docSelected
07691: && !auxiliarySelected) {
07692: // external document selected, but no regular or auxiliary documents
07693: if (m.getComponentCount() > 0) {
07694: m.addSeparator();
07695: }
07696: if (docSelectedCount == 1) {
07697: m
07698: .add(Utilities
07699: .createDelegateAction(
07700: "Include File With Project",
07701: _moveToAuxiliaryAction));
07702: } else if (docSelectedCount > 1) {
07703: m
07704: .add(Utilities
07705: .createDelegateAction(
07706: "Include All Files With Project ("
07707: + docSelectedCount
07708: + ")",
07709: _moveToAuxiliaryAction));
07710: }
07711: }
07712: if (auxiliarySelected && !docSelected
07713: && !externalSelected) {
07714: // auxiliary document selected, but no regular or external documents
07715: if (m.getComponentCount() > 0) {
07716: m.addSeparator();
07717: }
07718: if (docSelectedCount == 1) {
07719: m
07720: .add(Utilities
07721: .createDelegateAction(
07722: "Do Not Include File With Project",
07723: _removeAuxiliaryAction));
07724: } else if (docSelectedCount > 1) {
07725: m
07726: .add(Utilities
07727: .createDelegateAction(
07728: "Do Not Include Any Files With Project ("
07729: + docSelectedCount
07730: + ")",
07731: _removeAuxiliaryAction));
07732: }
07733: }
07734: if (!folderSelected
07735: && (externalBinSelected || auxiliaryBinSelected)) {
07736: // external or auxiliary bin selected, but no regular folder
07737: if (m.getComponentCount() > 0) {
07738: m.addSeparator();
07739: }
07740: m.add(Utilities.createDelegateAction(
07741: "Close All Files",
07742: _closeFolderAction));
07743: m.add(Utilities.createDelegateAction(
07744: "Compile All Files",
07745: _compileFolderAction));
07746: m.add(Utilities.createDelegateAction(
07747: "Test All Files",
07748: _junitFolderAction));
07749: }
07750: if (externalBinSelected
07751: && !auxiliaryBinSelected) {
07752: // external bin selected
07753: m
07754: .add(Utilities
07755: .createDelegateAction(
07756: "Include All Files With Project",
07757: _moveAllToAuxiliaryAction));
07758: }
07759: if (auxiliaryBinSelected
07760: && !externalBinSelected) {
07761: // auxiliary bin selected
07762: m
07763: .add(Utilities
07764: .createDelegateAction(
07765: "Do Not Include Any Files With Project",
07766: _removeAllAuxiliaryAction));
07767: }
07768:
07769: m
07770: .show(e.getComponent(), e.getX(), e
07771: .getY());
07772: }
07773: }
07774: });
07775: // _model.getDocCollectionWidget().addMouseListener(new RightClickMouseAdapter() {
07776: // protected void _popupAction(MouseEvent e) {
07777: // if (_model.getDocumentNavigator().selectDocumentAt(e.getX(), e.getY())) {
07778: // if (_model.getDocumentNavigator().isGroupSelected())
07779: // _navPaneFolderPopupMenu.show(e.getComponent(), e.getX(), e.getY());
07780: //
07781: // else {
07782: // try {
07783: // String groupName = _model.getDocumentNavigator().getNameOfSelectedTopLevelGroup();
07784: // if (groupName.equals(_model.getSourceBinTitle()))
07785: // _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY());
07786: // else if (groupName.equals(_model.getExternalBinTitle())) {
07787: // INavigatorItem n = _model.getDocumentNavigator().getCurrent();
07788: // if (n != null) {
07789: // OpenDefinitionsDocument d = (OpenDefinitionsDocument) n;
07790: // if (d.isUntitled()) { _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY()); }
07791: // else _navPanePopupMenuForExternal.show(e.getComponent(), e.getX(), e.getY());
07792: // }
07793: // }
07794: // else if (groupName.equals(_model.getAuxiliaryBinTitle()))
07795: // _navPanePopupMenuForAuxiliary.show(e.getComponent(), e.getX(), e.getY());
07796: // }
07797: // catch(GroupNotSelectedException ex) {
07798: // // we're looking at the root of the tree, or we're in list view...
07799: // if (_model.isProjectActive())
07800: // _navPanePopupMenuForRoot.show(e.getComponent(), e.getX(), e.getY());
07801: // else _navPanePopupMenu.show(e.getComponent(), e.getX(), e.getY());
07802: // }
07803: // }
07804: // }
07805: // }
07806: // });
07807:
07808: // Interactions pane menu
07809: _interactionsPanePopupMenu = new JPopupMenu();
07810: _interactionsPanePopupMenu.add(cutAction);
07811: _interactionsPanePopupMenu.add(copyAction);
07812: _interactionsPanePopupMenu.add(pasteAction);
07813: _interactionsPanePopupMenu.addSeparator();
07814: _interactionsPanePopupMenu.add(_printInteractionsAction);
07815: _interactionsPanePopupMenu.add(_printInteractionsPreviewAction);
07816: _interactionsPanePopupMenu.addSeparator();
07817: _interactionsPanePopupMenu.add(_executeHistoryAction);
07818: _interactionsPanePopupMenu.add(_loadHistoryScriptAction);
07819: _interactionsPanePopupMenu.add(_saveHistoryAction);
07820: _interactionsPanePopupMenu.add(_clearHistoryAction);
07821: _interactionsPanePopupMenu.addSeparator();
07822: _interactionsPanePopupMenu.add(_resetInteractionsAction);
07823: _interactionsPanePopupMenu
07824: .add(_viewInteractionsClassPathAction);
07825: _interactionsPanePopupMenu
07826: .add(_copyInteractionToDefinitionsAction);
07827: _interactionsPane
07828: .addMouseListener(new RightClickMouseAdapter() {
07829: protected void _popupAction(MouseEvent e) {
07830: _interactionsPane.requestFocusInWindow();
07831: _interactionsPanePopupMenu.show(e
07832: .getComponent(), e.getX(), e.getY());
07833: }
07834: });
07835:
07836: // This listener updates the _cachedCaretPosition in the _interactionsController when the cursor is manually set.
07837: _interactionsPane.addMouseListener(new MouseInputAdapter() {
07838: public void mouseClicked(MouseEvent e) {
07839: _interactionsController
07840: .setCachedCaretPos(_interactionsPane
07841: .viewToModel(e.getPoint()));
07842: }
07843: });
07844: _consolePanePopupMenu = new JPopupMenu();
07845: _consolePanePopupMenu.add(_clearConsoleAction);
07846: _consolePanePopupMenu.addSeparator();
07847: _consolePanePopupMenu.add(_printConsoleAction);
07848: _consolePanePopupMenu.add(_printConsolePreviewAction);
07849: _consolePane.addMouseListener(new RightClickMouseAdapter() {
07850: protected void _popupAction(MouseEvent e) {
07851: _consolePane.requestFocusInWindow();
07852: _consolePanePopupMenu.show(e.getComponent(), e.getX(),
07853: e.getY());
07854: }
07855: });
07856: }
07857:
07858: private void nextRecentDoc() {
07859: if (_recentDocFrame.isVisible())
07860: _recentDocFrame.next();
07861: else
07862: _recentDocFrame.setVisible(true);
07863: }
07864:
07865: private void prevRecentDoc() {
07866: if (_recentDocFrame.isVisible())
07867: _recentDocFrame.prev();
07868: else
07869: _recentDocFrame.setVisible(true);
07870: }
07871:
07872: private void hideRecentDocFrame() {
07873: if (_recentDocFrame.isVisible()) {
07874: _recentDocFrame.setVisible(false);
07875: OpenDefinitionsDocument doc = _recentDocFrame.getDocument();
07876: if (doc != null) {
07877: // addToBrowserHistory();
07878: _model.setActiveDocument(doc);
07879: // addToBrowserHistory();
07880: }
07881: }
07882: }
07883:
07884: KeyListener _historyListener = new KeyListener() {
07885: public void keyPressed(KeyEvent e) {
07886: if (e.getKeyCode() == java.awt.event.KeyEvent.VK_BACK_QUOTE
07887: && e.isControlDown() && !e.isShiftDown())
07888: nextRecentDoc();
07889: if (e.getKeyCode() == java.awt.event.KeyEvent.VK_BACK_QUOTE
07890: && e.isControlDown() && e.isShiftDown())
07891: prevRecentDoc();
07892: // else if (e.getKeyCode()==java.awt.event.KeyEvent.VK_BACK_QUOTE) {
07893: // transferFocusUpCycle();
07894: // }
07895: }
07896:
07897: public void keyReleased(KeyEvent e) {
07898: if (e.getKeyCode() == java.awt.event.KeyEvent.VK_CONTROL)
07899: hideRecentDocFrame();
07900: }
07901:
07902: public void keyTyped(KeyEvent e) { /* noop */
07903: }
07904: };
07905:
07906: FocusListener _focusListenerForRecentDocs = new FocusListener() {
07907: public void focusLost(FocusEvent e) {
07908: hideRecentDocFrame();
07909: }
07910:
07911: public void focusGained(FocusEvent e) {
07912: }
07913: };
07914:
07915: /** Create a new DefinitionsPane and JScrollPane for an open definitions document. Package private for testing purposes.
07916: * @param doc The open definitions document to wrap
07917: * @return JScrollPane containing a DefinitionsPane for the given document.
07918: */
07919: JScrollPane _createDefScrollPane(OpenDefinitionsDocument doc) {
07920: DefinitionsPane pane = new DefinitionsPane(this , doc);
07921:
07922: pane.addKeyListener(_historyListener);
07923: pane.addFocusListener(_focusListenerForRecentDocs);
07924:
07925: // Add listeners
07926: _installNewDocumentListener(doc);
07927: ErrorCaretListener caretListener = new ErrorCaretListener(doc,
07928: pane, this );
07929: pane.addErrorCaretListener(caretListener);
07930:
07931: // Limiting line numbers to just lines existing in the document.
07932: doc.addDocumentListener(new DocumentUIListener() {
07933: private void updateUI() {
07934: EventQueue.invokeLater(new Runnable() { // ?? Why EventQueue?
07935: public void run() {
07936: // revalidateLineNums();
07937: if ((_breakpointsPanel != null)
07938: && (_breakpointsPanel
07939: .isDisplayed())) {
07940: _breakpointsPanel.repaint();
07941: }
07942: if ((_bookmarksPanel != null)
07943: && (_bookmarksPanel
07944: .isDisplayed())) {
07945: _bookmarksPanel.repaint();
07946: }
07947: for (Pair<FindResultsPanel, Hashtable<MovingDocumentRegion, HighlightManager.HighlightInfo>> pair : _findResults) {
07948: FindResultsPanel panel = pair
07949: .first();
07950: if ((panel != null)
07951: && (panel.isDisplayed())) {
07952: panel.repaint();
07953: }
07954: }
07955: }
07956: });
07957: }
07958:
07959: public void changedUpdate(DocumentEvent e) { /* updateUI(); */
07960: } // only attribute changes that matter are inserts and removes
07961:
07962: public void insertUpdate(DocumentEvent e) {
07963: updateUI();
07964: }
07965:
07966: public void removeUpdate(DocumentEvent e) {
07967: updateUI();
07968: }
07969: });
07970:
07971: // add a listener to update line and column.
07972: pane.addCaretListener(_posListener);
07973:
07974: // add a focus listener to this definitions pane.
07975: pane.addFocusListener(new LastFocusListener());
07976:
07977: // Add to a scroll pane
07978: final JScrollPane scroll = new BorderlessScrollPane(pane,
07979: JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
07980: JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
07981: pane.setScrollPane(scroll);
07982: //scroll.setBorder(null); // removes all default borders (MacOS X installs default borders)
07983:
07984: if (DrJava.getConfig().getSetting(LINEENUM_ENABLED)
07985: .booleanValue()) {
07986: scroll.setRowHeaderView(new LineEnumRule(pane));
07987: }
07988:
07989: _defScrollPanes.put(doc, scroll);
07990:
07991: return scroll;
07992: }
07993:
07994: private void _setUpPanes() {
07995: // DefinitionsPane
07996: JScrollPane defScroll = _defScrollPanes.get(_model
07997: .getActiveDocument());
07998:
07999: // Try to create debug panel (see if JSwat is around)
08000: if (_showDebugger) {
08001: try {
08002: // Set the panel's size.
08003: int debugHeight = DrJava.getConfig().getSetting(
08004: DEBUG_PANEL_HEIGHT).intValue();
08005: Dimension debugMinSize = _debugPanel.getMinimumSize();
08006:
08007: // TODO: check bounds compared to entire window.
08008: if ((debugHeight > debugMinSize.height))
08009: debugMinSize.height = debugHeight;
08010: _debugPanel.setPreferredSize(debugMinSize);
08011: } catch (NoClassDefFoundError e) {
08012: // Don't use the debugger
08013: _showDebugger = false;
08014: }
08015: }
08016:
08017: _debugSplitPane.setBottomComponent(_debugPanel);
08018: _mainSplit.setResizeWeight(1.0);
08019: _debugSplitPane.setResizeWeight(1.0);
08020: getContentPane().add(_mainSplit, BorderLayout.CENTER);
08021: // This is annoyingly order-dependent. Since split contains _docSplitPane,
08022: // we need to get split's divider set up first to give _docSplitPane an
08023: // overall size. Then we can set _docSplitPane's divider. Ahh, Swing.
08024: // Also, according to the Swing docs, we need to set these dividers AFTER
08025: // we have shown the window. How annoying.
08026: // int tabHeight = DrJava.getConfig().getSetting(TABS_HEIGHT).intValue();
08027:
08028: // 2*getHeight()/3
08029: _mainSplit.setDividerLocation(_mainSplit.getHeight() - 132);
08030: // _mainSplit.setDividerLocation(_mainSplit.getHeight() - tabHeight);
08031: _mainSplit.setOneTouchExpandable(true);
08032: _debugSplitPane.setOneTouchExpandable(true);
08033:
08034: int docListWidth = DrJava.getConfig()
08035: .getSetting(DOC_LIST_WIDTH).intValue();
08036:
08037: // TODO: Check bounds.
08038: _docSplitPane.setDividerLocation(docListWidth);
08039: _docSplitPane.setOneTouchExpandable(true);
08040: }
08041:
08042: /** Switch to the JScrollPane containing the DefinitionsPane for the active document. Must run in event thread.*/
08043: void _switchDefScrollPane() {
08044: // demoted to package private protection to test the disabling editing while compiling functionality.
08045: // and to support brute force fix to DefinitionsPane bug on return from compile with errors
08046: // Added 2004-May-27
08047: // Notify the definitions pane that is being replaced (becoming inactive)
08048: _currentDefPane.notifyInactive();
08049:
08050: // Utilities.showDebug("_switchDefScrollPane called");
08051: // Utilities.showDebug("Right before getting the scrollPane");
08052: OpenDefinitionsDocument doc = _model.getActiveDocument();
08053: JScrollPane scroll = _defScrollPanes.get(doc);
08054:
08055: if (scroll == null)
08056: scroll = _createDefScrollPane(doc);
08057: // Fix OS X scrollbar bug before switching
08058:
08059: _reenableScrollBar();
08060:
08061: int oldLocation = _docSplitPane.getDividerLocation();
08062: _docSplitPane.setRightComponent(scroll); //crazy line
08063: _docSplitPane.setDividerLocation(oldLocation);
08064:
08065: // if the current def pane is uneditable, that means we arrived here from a compile with errors. We're
08066: // guaranteed to make it editable again when we return from the compilation, so we take the state
08067: // with us. We guarantee only one definitions pane is un-editable at any time.
08068: if (_currentDefPane.isEditable()) {
08069: _currentDefPane = (DefinitionsPane) scroll.getViewport()
08070: .getView();
08071: _currentDefPane.notifyActive();
08072: } else {
08073: try {
08074: _currentDefPane.setEditable(true);
08075: } catch (NoSuchDocumentException e) { /* It's OK */
08076: }
08077:
08078: _currentDefPane = (DefinitionsPane) scroll.getViewport()
08079: .getView();
08080: _currentDefPane.notifyActive();
08081: _currentDefPane.setEditable(false);
08082: }
08083: // reset the undo/redo menu items
08084: resetUndo();
08085: _updateDebugStatus();
08086: }
08087:
08088: /** Refresh the JScrollPane containing the DefinitionsPane for the active document. Must run in event thread.*/
08089: private void _refreshDefScrollPane() {
08090: // Added 2004-May-27
08091: // Notify the definitions pane that is being replaced (becoming inactive)
08092: _currentDefPane.notifyInactive();
08093:
08094: // Utilities.showDebug("_switchDefScrollPane called");
08095: // Utilities.showDebug("Right before getting the scrollPane");
08096: OpenDefinitionsDocument doc = _model.getActiveDocument();
08097: JScrollPane scroll = _defScrollPanes.get(doc);
08098:
08099: // if (scroll == null) scroll = _createDefScrollPane(doc);
08100: // Fix OS X scrollbar bug before switching
08101:
08102: _reenableScrollBar();
08103:
08104: int oldLocation = _docSplitPane.getDividerLocation();
08105: _docSplitPane.setRightComponent(scroll); //crazy line
08106: _docSplitPane.setDividerLocation(oldLocation);
08107:
08108: // // if the current def pane is uneditable, that means we arrived here from a compile with errors. We're
08109: // // guaranteed to make it editable again when we return from the compilation, so we take the state
08110: // // with us. We guarantee only one definitions pane is un-editable at any time.
08111: // if (_currentDefPane.isEditable()) {
08112: // _currentDefPane = (DefinitionsPane) scroll.getViewport().getView();
08113: _currentDefPane.notifyActive();
08114: // }
08115: // else {
08116: // try { _currentDefPane.setEditable(true); }
08117: // catch(NoSuchDocumentException e) { /* It's OK */ }
08118: //
08119: // _currentDefPane = (DefinitionsPane) scroll.getViewport().getView();
08120: // _currentDefPane.notifyActive();
08121: // _currentDefPane.setEditable(false);
08122: // }
08123: // // reset the undo/redo menu items
08124: resetUndo();
08125: _updateDebugStatus();
08126: }
08127:
08128: /** Resets the undo/redo menu items */
08129: public void resetUndo() {
08130: _undoAction.setDelegatee(_currentDefPane.getUndoAction());
08131: _redoAction.setDelegatee(_currentDefPane.getRedoAction());
08132: }
08133:
08134: public DefinitionsPane getDefPaneGivenODD(
08135: OpenDefinitionsDocument doc) {
08136: JScrollPane scroll = _defScrollPanes.get(doc);
08137: if (scroll == null) {
08138: throw new UnexpectedException(new Exception(
08139: "Region set in a closed document."));
08140: }
08141:
08142: DefinitionsPane pane = (DefinitionsPane) scroll.getViewport()
08143: .getView();
08144: return pane;
08145: }
08146:
08147: /** Addresses Mac OS X bug where the scrollbars are disabled in one document after opening another. */
08148: private void _reenableScrollBar() {
08149: JScrollPane scroll = _defScrollPanes.get(_model
08150: .getActiveDocument());
08151: if (scroll == null)
08152: throw new UnexpectedException(new Exception(
08153: "Current definitions scroll pane not found."));
08154:
08155: JScrollBar oldbar = scroll.getVerticalScrollBar();
08156: JScrollBar newbar = scroll.createVerticalScrollBar();
08157: newbar.setMinimum(oldbar.getMinimum());
08158: newbar.setMaximum(oldbar.getMaximum());
08159: newbar.setValue(oldbar.getValue());
08160: newbar.setVisibleAmount(oldbar.getVisibleAmount());
08161: newbar.setEnabled(true);
08162: newbar.revalidate();
08163: scroll.setVerticalScrollBar(newbar);
08164:
08165: // This needs to be repeated for the horizontal scrollbar
08166: oldbar = scroll.getHorizontalScrollBar();
08167: newbar = scroll.createHorizontalScrollBar();
08168: newbar.setMinimum(oldbar.getMinimum());
08169: newbar.setMaximum(oldbar.getMaximum());
08170: newbar.setValue(oldbar.getValue());
08171: newbar.setVisibleAmount(oldbar.getVisibleAmount());
08172: newbar.setEnabled(true);
08173: newbar.revalidate();
08174: scroll.setHorizontalScrollBar(newbar);
08175: scroll.revalidate();
08176: }
08177:
08178: /** Returns a JRadioButtonMenuItem that looks like a JCheckBoxMenuItem. This is a workaround for a known
08179: * bug on OS X's version of Java. (See http://developer.apple.com/qa/qa2001/qa1154.html)
08180: * @param action Action for the menu item
08181: * @return JRadioButtonMenuItem with a checkbox icon
08182: */
08183: private JMenuItem _newCheckBoxMenuItem(Action action) {
08184: String RADIO_ICON_KEY = "RadioButtonMenuItem.checkIcon";
08185: String CHECK_ICON_KEY = "CheckBoxMenuItem.checkIcon";
08186:
08187: // Store the default radio button icon to put back later
08188: Object radioIcon = UIManager.get(RADIO_ICON_KEY);
08189:
08190: // Replace radio button's checkIcon with that of JCheckBoxMenuItem
08191: // so that our menu item looks like a checkbox
08192: UIManager.put(RADIO_ICON_KEY, UIManager.get(CHECK_ICON_KEY));
08193: JRadioButtonMenuItem pseudoCheckBox = new JRadioButtonMenuItem(
08194: action);
08195:
08196: // Put original radio button checkIcon back.
08197: UIManager.put(RADIO_ICON_KEY, radioIcon);
08198:
08199: return pseudoCheckBox;
08200: }
08201:
08202: /** Gets the absolute file, or if necessary, the canonical file.
08203: * @param f the file for which to get the full path
08204: * @return the file representing the full path to the given file
08205: */
08206: private File _getFullFile(File f) throws IOException {
08207: if (PlatformFactory.ONLY.isWindowsPlatform()
08208: && ((f.getAbsolutePath().indexOf("..") != -1)
08209: || (f.getAbsolutePath().indexOf("./") != -1) || (f
08210: .getAbsolutePath().indexOf(".\\") != -1))) {
08211: return f.getCanonicalFile();
08212: }
08213: return f.getAbsoluteFile();
08214: }
08215:
08216: /** Sets the current directory to be that of the given file. */
08217: private void _setCurrentDirectory(File file) {
08218: /* We want to use absolute paths whenever possible, since canonical paths resolve symbolic links and can be quite
08219: * long and unintuitive. However, Windows blows up if you set the current directory of a JFileChooser to an
08220: * absolute path with ".." in it. In that case, we'll use the canonical path for the file chooser. (Fix for
08221: * bug 707734) Extended this to fix "./" and ".\" also (bug 774896)
08222: */
08223: try {
08224: file = _getFullFile(file);
08225: _openChooser.setCurrentDirectory(file);
08226: _saveChooser.setCurrentDirectory(file);
08227: DrJava.getConfig().setSetting(LAST_DIRECTORY, file);
08228: } catch (IOException ioe) {
08229: // If getCanonicalFile throws an IOException, we can't set the directory of the file chooser. Oh well.
08230: }
08231: }
08232:
08233: /** Sets the current directory to be that of document's file. */
08234: private void _setCurrentDirectory(OpenDefinitionsDocument doc) {
08235: try {
08236: File file = doc.getFile();
08237: if (file != null)
08238: _setCurrentDirectory(file); // if no file, leave in current directory
08239: } catch (FileMovedException fme) {
08240: // file was deleted, but try to go the directory
08241: _setCurrentDirectory(fme.getFile());
08242: }
08243: }
08244:
08245: /** Sets the font of all panes and panels to the main font. */
08246: private void _setMainFont() {
08247:
08248: Font f = DrJava.getConfig().getSetting(FONT_MAIN);
08249:
08250: for (JScrollPane scroll : _defScrollPanes.values()) {
08251: if (scroll != null) {
08252: DefinitionsPane pane = (DefinitionsPane) scroll
08253: .getViewport().getView();
08254: pane.setFont(f);
08255: // Update the font of the line enumeration rule
08256: if (DrJava.getConfig().getSetting(LINEENUM_ENABLED)
08257: .booleanValue()) {
08258: scroll.setRowHeaderView(new LineEnumRule(pane));
08259: }
08260: }
08261: }
08262:
08263: // Update Interactions Pane
08264: _interactionsPane.setFont(f);
08265: _interactionsController.setDefaultFont(f);
08266:
08267: // Update Console Pane
08268: _consolePane.setFont(f);
08269: _consoleController.setDefaultFont(f);
08270:
08271: _findReplace.setFieldFont(f);
08272: _compilerErrorPanel.setListFont(f);
08273: _junitErrorPanel.setListFont(f);
08274: _javadocErrorPanel.setListFont(f);
08275: }
08276:
08277: /** Updates the text color for the doc list. */
08278: private void _updateNormalColor() {
08279: // Get the new value.
08280: Color norm = DrJava.getConfig().getSetting(
08281: DEFINITIONS_NORMAL_COLOR);
08282:
08283: // Change the text (foreground) color for the doc list.
08284: _model.getDocCollectionWidget().setForeground(norm);
08285:
08286: // We also need to immediately repaint the foremost scroll pane.
08287: _repaintLineNums();
08288: }
08289:
08290: /** Updates the background color for the doc list. */
08291: private void _updateBackgroundColor() {
08292: // Get the new value.
08293: Color back = DrJava.getConfig().getSetting(
08294: DEFINITIONS_BACKGROUND_COLOR);
08295:
08296: // Change the background color for the doc list.
08297: _model.getDocCollectionWidget().setBackground(back);
08298:
08299: // We also need to immediately repaint the foremost scroll pane.
08300: _repaintLineNums();
08301: }
08302:
08303: /** Updates the font and colors of the line number display. */
08304: private void _updateLineNums() {
08305: if (DrJava.getConfig().getSetting(LINEENUM_ENABLED)
08306: .booleanValue()) {
08307:
08308: // Update the font for all line number displays
08309: for (JScrollPane spane : _defScrollPanes.values()) {
08310:
08311: LineEnumRule ler = (LineEnumRule) spane.getRowHeader()
08312: .getView();
08313: ler.updateFont();
08314: ler.revalidate();
08315: }
08316:
08317: // We also need to immediately repaint the foremost scroll pane.
08318: _repaintLineNums();
08319: }
08320: }
08321:
08322: /** Repaints the line numbers on the active scroll pane. */
08323: private void _repaintLineNums() {
08324: JScrollPane front = _defScrollPanes.get(_model
08325: .getActiveDocument());
08326: if (front != null) {
08327: JViewport rhvport = front.getRowHeader();
08328:
08329: if (rhvport != null) {
08330: Component view = rhvport.getView();
08331: if (view != null) {
08332: view.repaint();
08333: }
08334: }
08335: }
08336: }
08337:
08338: // /** Revalidate the line numers, i.e. also redraw the ones not currently visible. */
08339: // public void revalidateLineNums() {
08340: // if (DrJava.getConfig().getSetting(LINEENUM_ENABLED).booleanValue()) {
08341: // JScrollPane sp = _defScrollPanes.get(_model.getActiveDocument());
08342: // if (sp!=null) {
08343: // LineEnumRule ler = (LineEnumRule)sp.getRowHeader().getView();
08344: // ler.revalidate();
08345: // _repaintLineNums();
08346: // }
08347: // }
08348: // }
08349:
08350: /** Update the row header (line number enumeration) for the definitions scroll pane. */
08351: private void _updateDefScrollRowHeader() {
08352: boolean ruleEnabled = DrJava.getConfig().getSetting(
08353: LINEENUM_ENABLED).booleanValue();
08354:
08355: for (JScrollPane scroll : _defScrollPanes.values()) {
08356: if (scroll != null) {
08357: DefinitionsPane pane = (DefinitionsPane) scroll
08358: .getViewport().getView();
08359: if (scroll.getRowHeader() == null
08360: || scroll.getRowHeader().getView() == null) {
08361: if (ruleEnabled)
08362: scroll.setRowHeaderView(new LineEnumRule(pane));
08363: } else if (!ruleEnabled)
08364: scroll.setRowHeaderView(null);
08365: }
08366: }
08367: }
08368:
08369: /** Removes the current highlight. */
08370: private void _removeThreadLocationHighlight() {
08371: if (_currentThreadLocationHighlight != null) {
08372: _currentThreadLocationHighlight.remove();
08373: _currentThreadLocationHighlight = null;
08374: }
08375: }
08376:
08377: /** Disable any step timer. */
08378: private void _disableStepTimer() {
08379: synchronized (_debugStepTimer) {
08380: if (_debugStepTimer.isRunning())
08381: _debugStepTimer.stop();
08382: }
08383: }
08384:
08385: /** Checks if debugPanel's status bar displays the DEBUGGER_OUT_OF_SYNC message but the current document is
08386: * in sync. Clears the debugPanel's status bar in this case. Does not assume that frame is in debug mode.
08387: * Must be executed in event thread.
08388: */
08389: private void _updateDebugStatus() {
08390: if (!isDebuggerReady())
08391: return;
08392:
08393: // if the document is untitled, don't show that it is out of sync since it can't be debugged anyway
08394: if (_model.getActiveDocument().isUntitled()
08395: || _model.getActiveDocument().getClassFileInSync()) {
08396: // Hide message
08397: if (_debugPanel.getStatusText()
08398: .equals(DEBUGGER_OUT_OF_SYNC))
08399: _debugPanel.setStatusText("");
08400: } else {
08401: // Show message
08402: if (_debugPanel.getStatusText().equals("")) {
08403: _debugPanel.setStatusText(DEBUGGER_OUT_OF_SYNC);
08404: }
08405: }
08406: _debugPanel.repaint(); // display the updated panel
08407: }
08408:
08409: /** Ensures that the interactions pane is not editable during an interaction. */
08410: protected void _disableInteractionsPane() {
08411: // Only change GUI from event-dispatching thread
08412: Runnable command = new Runnable() {
08413: public void run() {
08414: _interactionsPane.setEditable(false);
08415: _interactionsPane.setCursor(Cursor
08416: .getPredefinedCursor(Cursor.WAIT_CURSOR));
08417:
08418: if (_interactionsScriptController != null)
08419: _interactionsScriptController.setActionsDisabled();
08420: }
08421: };
08422: Utilities.invokeLater(command);
08423: }
08424:
08425: /** Ensures that the interactions pane is editable after an interaction completes. */
08426: protected void _enableInteractionsPane() {
08427: // Only change GUI from event-dispatching thread
08428: Runnable command = new Runnable() {
08429: public void run() {
08430: // if (isDebuggerReady()) {
08431: // _disableStepTimer();
08432: // Debugger manager = _model.getDebugger();
08433: // manager.clearCurrentStepRequest();
08434: // _removeThreadLocationHighlight();
08435: // }
08436:
08437: _interactionsPane.setCursor(Cursor
08438: .getPredefinedCursor(Cursor.TEXT_CURSOR));
08439: _interactionsPane.setEditable(true);
08440: _interactionsController.moveToEnd();
08441: if (_interactionsPane.hasFocus())
08442: _interactionsPane.getCaret().setVisible(true);
08443: if (_interactionsScriptController != null)
08444: _interactionsScriptController.setActionsEnabled();
08445: }
08446: };
08447: Utilities.invokeLater(command);
08448: }
08449:
08450: // Comment out current selection using wing commenting. Non-private for testing purposes only. Only runs in event thread. */
08451: void commentLines() {
08452: // Delegate everything to the DefinitionsDocument.
08453: OpenDefinitionsDocument openDoc = _model.getActiveDocument();
08454: int caretPos = _currentDefPane.getCaretPosition();
08455: openDoc.setCurrentLocation(caretPos);
08456: int start = _currentDefPane.getSelectionStart();
08457: int end = _currentDefPane.getSelectionEnd();
08458: // _currentDefPane.endCompoundEdit();
08459: // _currentDefPane.notifyInactive();
08460: int newEnd = openDoc.commentLines(start, end);
08461: // _currentDefPane.notifyActive();
08462: _currentDefPane.setCaretPosition(start + 2);
08463: if (start != end)
08464: _currentDefPane.moveCaretPosition(newEnd);
08465: }
08466:
08467: // Uncomment out current selection using wing commenting. Public for testing purposes only. Only runs in event thread. */
08468: public void uncommentLines() {
08469: // Delegate everything to the DefinitionsDocument.
08470: OpenDefinitionsDocument openDoc = _model.getActiveDocument();
08471: int caretPos = _currentDefPane.getCaretPosition();
08472: openDoc.setCurrentLocation(caretPos);
08473: int start = _currentDefPane.getSelectionStart();
08474: int end = _currentDefPane.getSelectionEnd();
08475: _currentDefPane.endCompoundEdit();
08476:
08477: //notify inactive to prevent refreshing of the DefPane every time an insertion is made
08478: // _currentDefPane.notifyInactive();
08479: openDoc.setCurrentLocation(start);
08480: Position startPos;
08481: try {
08482: startPos = openDoc.createUnwrappedPosition(start);
08483: } catch (BadLocationException e) {
08484: throw new UnexpectedException(e);
08485: }
08486:
08487: int startOffset = startPos.getOffset();
08488: final int newEnd = openDoc.uncommentLines(start, end);
08489: // _currentDefPane.notifyActive();
08490: if (startOffset != startPos.getOffset())
08491: start -= 2;
08492: final int f_start = start;
08493: final boolean moveSelection = start != end;
08494: Utilities.invokeAndWait(new Runnable() {
08495: public void run() {
08496: _currentDefPane.setCaretPosition(f_start);
08497: if (moveSelection)
08498: _currentDefPane.moveCaretPosition(newEnd);
08499: }
08500: });
08501: }
08502:
08503: /** Blocks access to DrJava while the hourglass cursor is on. */
08504: private static class GlassPane extends JComponent {
08505:
08506: /** Creates a new GlassPane over the DrJava window. */
08507: public GlassPane() {
08508: addKeyListener(new KeyAdapter() {
08509: });
08510: addMouseListener(new MouseAdapter() {
08511: });
08512: super .setCursor(Cursor
08513: .getPredefinedCursor(Cursor.WAIT_CURSOR));
08514: }
08515: }
08516:
08517: /** Called when a specific document and offset should be displayed. Must be executed only in the event thread.
08518: * @param doc Document to display
08519: * @param offset Offset to display
08520: * @param shouldHighlight true iff the line should be highlighted.
08521: */
08522: public void scrollToDocumentAndOffset(
08523: final OpenDefinitionsDocument doc, final int offset,
08524: final boolean shouldHighlight) {
08525: scrollToDocumentAndOffset(doc, offset, shouldHighlight, true);
08526: }
08527:
08528: /** Called when a specific document and offset should be displayed. Must be executed only in the event thread.
08529: * @param doc Document to display
08530: * @param offset Offset to display
08531: * @param shouldHighlight true iff the line should be highlighted.
08532: * @param shouldAddToHistory true if the location before and after the switch should be added to the browser history
08533: */
08534: public void scrollToDocumentAndOffset(
08535: final OpenDefinitionsDocument doc, final int offset,
08536: final boolean shouldHighlight,
08537: final boolean shouldAddToHistory) {
08538: if (shouldAddToHistory)
08539: addToBrowserHistory();
08540:
08541: boolean toSameDoc = _model.getActiveDocument().equals(doc);
08542:
08543: if (!toSameDoc) {
08544: _model.setActiveDocument(doc);
08545: _findReplace.updateFirstDocInSearch();
08546: } else
08547: _model.refreshActiveDocument();
08548:
08549: Runnable command = new Runnable() {
08550: public void run() {
08551: // get the line number after the switch of documents was made
08552: int lineNumber = doc.getLineOfOffset(offset) + 1;
08553:
08554: // this block occurs if the documents is already open and as such has a positive size
08555: if (_currentDefPane.getSize().getWidth() > 0
08556: && _currentDefPane.getSize().getHeight() > 0) {
08557: _currentDefPane.centerViewOnOffset(offset);
08558: _currentDefPane.requestFocusInWindow();
08559: }
08560:
08561: if (shouldHighlight) {
08562: _removeThreadLocationHighlight();
08563: int startOffset = doc.getOffset(lineNumber); // Much faster to directly search back from offset!
08564: if (startOffset > -1) {
08565: int endOffset = doc.getLineEndPos(startOffset);
08566: if (endOffset > -1) {
08567: _currentThreadLocationHighlight = _currentDefPane
08568: .getHighlightManager()
08569: .addHighlight(
08570: startOffset,
08571: endOffset,
08572: DefinitionsPane.THREAD_PAINTER);
08573: }
08574: }
08575: }
08576:
08577: if (_showDebugger) {
08578: // Give the interactions pane focus so we can debug
08579: _interactionsPane.requestFocusInWindow();
08580: // System.err.println("Showing Interactions Tab" );
08581: showTab(_interactionsPane);
08582: _updateDebugStatus();
08583: }
08584:
08585: // if (shouldAddToHistory) { addToBrowserHistory(); }
08586: }
08587: };
08588:
08589: /* Comment by mgricken: If ! toSameDoc, the _currentDefPane hasn't been created yet for a new document.
08590: * Consequently, we need to use EventQueue.invokeLater if ! toSameDoc. */
08591: /* if (toSameDoc) Utilities.invokeLater(command);
08592: else */EventQueue.invokeLater(command);
08593: }
08594:
08595: /** Listens to events from the debugger. */
08596: private class UIDebugListener implements DebugListener {
08597: /* Must be executed in evevt thread.*/
08598: public void debuggerStarted() {
08599: showDebugger();
08600: }
08601:
08602: /* Must be executed in evevt thread.*/
08603: public void debuggerShutdown() {
08604: _disableStepTimer();
08605:
08606: hideDebugger();
08607: _removeThreadLocationHighlight();
08608: }
08609:
08610: /** Called when a step is requested on the current thread. Must be executed in event thread. */
08611: public void stepRequested() {
08612: // Print a message if step takes a long time
08613: synchronized (_debugStepTimer) {
08614: if (!_debugStepTimer.isRunning())
08615: _debugStepTimer.start();
08616: }
08617: }
08618:
08619: public void currThreadSuspended() {
08620: _disableStepTimer();
08621:
08622: // Only change GUI from event-dispatching thread
08623: Runnable command = new Runnable() {
08624: public void run() {
08625: _setThreadDependentDebugMenuItems(true);
08626: }
08627: };
08628: Utilities.invokeLater(command);
08629: }
08630:
08631: /* Must be executed in the event thread. */
08632: public void currThreadResumed() {
08633: _setThreadDependentDebugMenuItems(false);
08634: _removeThreadLocationHighlight();
08635: }
08636:
08637: /** Called when the given line is reached by the current thread in the debugger, to request that the line be
08638: * displayed. Must be executed only in the event thread.
08639: * @param doc Document to display
08640: * @param lineNumber Line to display or highlight
08641: * @param shouldHighlight true iff the line should be highlighted.
08642: */
08643: public void threadLocationUpdated(OpenDefinitionsDocument doc,
08644: int lineNumber, boolean shouldHighlight) {
08645: scrollToDocumentAndOffset(doc, doc.getOffset(lineNumber),
08646: shouldHighlight);
08647: }
08648:
08649: /* Must be executed in event thread. */
08650: public void currThreadDied() {
08651: assert EventQueue.isDispatchThread();
08652: _disableStepTimer();
08653:
08654: if (isDebuggerReady()) {
08655: try {
08656: if (!_model.getDebugger().hasSuspendedThreads()) {
08657: // no more suspended threads, resume default debugger state
08658: // all thread dependent debug menu items are disabled
08659: _setThreadDependentDebugMenuItems(false);
08660: _removeThreadLocationHighlight();
08661: // Make sure we're at the prompt
08662: // (This should really be fixed in InteractionsController, not here.)
08663: _interactionsController.moveToPrompt(); // there are no suspended threads, bring back prompt
08664: }
08665: } catch (DebugException de) {
08666: _showError(de, "Debugger Error",
08667: "Error with a thread in the debugger.");
08668: }
08669: }
08670: }
08671:
08672: public void currThreadSet(DebugThreadData dtd) {
08673: }
08674:
08675: public void regionAdded(final Breakpoint bp, int index) {
08676: }
08677:
08678: public void breakpointReached(Breakpoint bp) {
08679: }
08680:
08681: public void regionChanged(Breakpoint bp, int index) {
08682: }
08683:
08684: public void regionRemoved(final Breakpoint bp) {
08685: }
08686:
08687: public void watchSet(final DebugWatchData w) {
08688: }
08689:
08690: public void watchRemoved(final DebugWatchData w) {
08691: }
08692:
08693: public void threadStarted() {
08694: }
08695:
08696: public void nonCurrThreadDied() {
08697: }
08698: }
08699:
08700: /** @author jlugo */
08701: private class DJAsyncTaskLauncher extends AsyncTaskLauncher {
08702:
08703: protected boolean shouldSetEnabled() {
08704: return true;
08705: }
08706:
08707: protected void setParentContainerEnabled(boolean enabled) {
08708: if (enabled)
08709: hourglassOff();
08710: else
08711: hourglassOn();
08712: }
08713:
08714: protected IAsyncProgress createProgressMonitor(
08715: final String description, final int min, final int max) {
08716: return new IAsyncProgress() {
08717: private ProgressMonitor _monitor = new ProgressMonitor(
08718: MainFrame.this , description, "", min, max);
08719:
08720: public void close() {
08721: _monitor.close();
08722: }
08723:
08724: public int getMaximum() {
08725: return _monitor.getMaximum();
08726: }
08727:
08728: public int getMillisToDecideToPopup() {
08729: return _monitor.getMillisToDecideToPopup();
08730: }
08731:
08732: public int getMillisToPopup() {
08733: return _monitor.getMillisToPopup();
08734: }
08735:
08736: public int getMinimum() {
08737: return _monitor.getMinimum();
08738: }
08739:
08740: public String getNote() {
08741: return _monitor.getNote();
08742: }
08743:
08744: public boolean isCanceled() {
08745: return _monitor.isCanceled();
08746: }
08747:
08748: public void setMaximum(int m) {
08749: _monitor.setMaximum(m);
08750: }
08751:
08752: public void setMinimum(int m) {
08753: _monitor.setMinimum(m);
08754: }
08755:
08756: public void setNote(String note) {
08757: _monitor.setNote(note);
08758: }
08759:
08760: public void setProgress(int nv) {
08761: _monitor.setProgress(nv);
08762: }
08763: };
08764: }
08765: }
08766:
08767: /** Inner class to listen to all events in the model. */
08768: private class ModelListener implements GlobalModelListener {
08769:
08770: public <P, R> void executeAsyncTask(AsyncTask<P, R> task,
08771: P param, boolean showProgress, boolean lockUI) {
08772: new DJAsyncTaskLauncher().executeTask(task, param,
08773: showProgress, lockUI);
08774: }
08775:
08776: public void handleAlreadyOpenDocument(
08777: OpenDefinitionsDocument doc) {
08778: // boolean docChanged = !doc.equals(_model.getActiveDocument());
08779: // if (docChanged) { addToBrowserHistory(); }
08780:
08781: // Always switch to doc
08782: _model.setActiveDocument(doc);
08783:
08784: // // defer executing this code until after active document switch (if any) is complete
08785: // EventQueue.invokeLater(new Runnable() { public void run() { addToBrowserHistory(); } });
08786:
08787: // Prompt to revert if modified
08788: if (doc.isModifiedSinceSave()) {
08789: String title = "Revert to Saved?";
08790: String message = doc.getFileName()
08791: + " is already open and modified.\n"
08792: + "Would you like to revert to the version on disk?\n";
08793: int choice = JOptionPane.showConfirmDialog(
08794: MainFrame.this , message, title,
08795: JOptionPane.YES_NO_OPTION);
08796: if (choice == JOptionPane.YES_OPTION) {
08797: _revert(doc);
08798: }
08799: }
08800: }
08801:
08802: public void newFileCreated(final OpenDefinitionsDocument doc) {
08803: Utilities.invokeLater(new Runnable() {
08804: public void run() {
08805: _createDefScrollPane(doc);
08806: }
08807: });
08808: }
08809:
08810: private volatile int _fnfCount = 0;
08811:
08812: private boolean resetFNFCount() {
08813: return _fnfCount == 0;
08814: }
08815:
08816: private boolean someFilesNotFound() {
08817: return _fnfCount > 0;
08818: }
08819:
08820: public void filesNotFound(File... files) {
08821: if (files.length == 0)
08822: return;
08823: _fnfCount += files.length;
08824:
08825: if (files.length == 1) {
08826: JOptionPane
08827: .showMessageDialog(
08828: MainFrame.this ,
08829: "The following file could not be found and has been removed from the project.\n"
08830: + files[0].getPath(),
08831: "File Not Found",
08832: JOptionPane.ERROR_MESSAGE);
08833: } else {
08834: final Collection<String> filePaths = new ArrayList<String>();
08835: for (File f : files) {
08836: filePaths.add(f.getPath());
08837: }
08838:
08839: ScrollableListDialog dialog = new ScrollableListDialog(
08840: MainFrame.this ,
08841: "Files Not Found",
08842: "The following files could not be found and have been removed from the project.",
08843: filePaths, JOptionPane.ERROR_MESSAGE);
08844:
08845: setPopupLoc(dialog);
08846: dialog.showDialog();
08847: }
08848: }
08849:
08850: public void fileSaved(final OpenDefinitionsDocument doc) {
08851: // new ScrollableDialog(null, "fileSaved called in ModelListener", "", "").show();
08852: Utilities.invokeLater(new Runnable() {
08853: public void run() {
08854: doc.documentSaved(); // used to update the document cache
08855: _saveAction.setEnabled(false);
08856: _renameAction.setEnabled(true);
08857: _revertAction.setEnabled(true);
08858: updateStatusField();
08859: _currentDefPane.requestFocusInWindow();
08860: try {
08861: File f = doc.getFile();
08862: if (!_model.inProject(f))
08863: _recentFileManager.updateOpenFiles(f);
08864: } catch (FileMovedException fme) {
08865: File f = fme.getFile();
08866: // Recover, show it in the list anyway
08867: if (!_model.inProject(f))
08868: _recentFileManager.updateOpenFiles(f);
08869: }
08870: // Check class file sync status, in case file was renamed
08871: _updateDebugStatus();
08872: }
08873: });
08874: }
08875:
08876: public void fileOpened(final OpenDefinitionsDocument doc) {
08877: Utilities.invokeLater(new Runnable() {
08878: public void run() {
08879: _fileOpened(doc);
08880: }
08881: });
08882: }
08883:
08884: private void _fileOpened(final OpenDefinitionsDocument doc) {
08885: try {
08886: File f = doc.getFile();
08887: if (!_model.inProject(f)) {
08888: _recentFileManager.updateOpenFiles(f);
08889:
08890: }
08891: } catch (FileMovedException fme) {
08892: File f = fme.getFile();
08893: // Recover, show it in the list anyway
08894: if (!_model.inProject(f))
08895: _recentFileManager.updateOpenFiles(f);
08896: }
08897: }
08898:
08899: /** NOTE: Makes certain that this action occurs in the event dispatching thread */
08900: public void fileClosed(final OpenDefinitionsDocument doc) {
08901: Utilities.invokeLater(new Runnable() {
08902: public void run() {
08903: _fileClosed(doc);
08904: }
08905: });
08906: }
08907:
08908: /** Does the work of closing a file */
08909: private void _fileClosed(OpenDefinitionsDocument doc) {
08910: _recentDocFrame.closeDocument(doc);
08911: _removeErrorListener(doc);
08912: JScrollPane jsp = _defScrollPanes.get(doc);
08913: if (jsp != null) {
08914: ((DefinitionsPane) jsp.getViewport().getView()).close();
08915: _defScrollPanes.remove(doc);
08916: }
08917: }
08918:
08919: public void fileReverted(OpenDefinitionsDocument doc) {
08920: Utilities.invokeLater(new Runnable() {
08921: public void run() {
08922: updateStatusField();
08923: _saveAction.setEnabled(false);
08924: _currentDefPane.resetUndo();
08925: _currentDefPane.hasWarnedAboutModified(false);
08926: _currentDefPane.setPositionAndScroll(0);
08927: _updateDebugStatus();
08928: }
08929: });
08930: }
08931:
08932: public void undoableEditHappened() {
08933: Utilities.invokeLater(new Runnable() {
08934: public void run() {
08935: _currentDefPane.getUndoAction().updateUndoState();
08936: _currentDefPane.getRedoAction().updateRedoState();
08937: }
08938: });
08939: }
08940:
08941: public void activeDocumentRefreshed(
08942: final OpenDefinitionsDocument active) {
08943: Utilities.invokeLater(new Runnable() {
08944: public void run() {
08945: // System.err.println("activeDocumentRefreshed");
08946: _recentDocFrame.pokeDocument(active);
08947: _refreshDefScrollPane();
08948:
08949: // Update error highlights
08950: int pos = _currentDefPane.getCaretPosition();
08951: _currentDefPane.getErrorCaretListener()
08952: .updateHighlight(pos);
08953: focusOnLastFocusOwner();
08954: }
08955: });
08956: }
08957:
08958: public void activeDocumentChanged(
08959: final OpenDefinitionsDocument active) {
08960: // Utilities.show("MainFrame Listener: ActiveDocument changed to " + active);
08961: // code that accesses the GUI must run in the event-dispatching thread.
08962: Utilities.invokeLater(new Runnable() { // invokeAndWait can create occasional deadlocks.
08963: public void run() {
08964: _recentDocFrame.pokeDocument(active);
08965: _switchDefScrollPane();
08966:
08967: boolean isModified = active
08968: .isModifiedSinceSave();
08969: boolean canCompile = (!isModified && !active
08970: .isUntitled());
08971: boolean hasName = !active.isUntitled();
08972: _saveAction.setEnabled(!canCompile);
08973: _renameAction.setEnabled(hasName);
08974: _revertAction.setEnabled(hasName);
08975:
08976: // Update error highlights
08977: int pos = _currentDefPane
08978: .getCaretPosition();
08979: _currentDefPane.getErrorCaretListener()
08980: .updateHighlight(pos);
08981:
08982: // Update FileChoosers' directory
08983: _setCurrentDirectory(active);
08984:
08985: // Update title and position
08986: updateStatusField();
08987: _posListener.updateLocation();
08988:
08989: // update display (adding "*") in navigatgorPane
08990: if (isModified)
08991: _model.getDocumentNavigator().repaint();
08992:
08993: try {
08994: active.revertIfModifiedOnDisk();
08995: } catch (FileMovedException fme) {
08996: _showFileMovedError(fme);
08997: } catch (IOException e) {
08998: _showIOError(e);
08999: }
09000:
09001: // Change Find/Replace to the new defpane
09002: if (_findReplace.isDisplayed()) {
09003: _findReplace.stopListening();
09004: _findReplace
09005: .beginListeningTo(_currentDefPane);
09006: //uninstallFindReplaceDialog(_findReplace);
09007: //installFindReplaceDialog(_findReplace);
09008: }
09009: // _lastFocusOwner = _currentDefPane;
09010: EventQueue.invokeLater(new Runnable() {
09011: public void run() {
09012: _lastFocusOwner = _currentDefPane;
09013: // System.err.println("Requesting focus on new active document");
09014: _currentDefPane
09015: .requestFocusInWindow();
09016: }
09017: });
09018: }
09019: });
09020: }
09021:
09022: public void focusOnLastFocusOwner() {
09023: // System.err.println("focusOnLastFocusOwner() called; _lastFocusOwner = " + _lastFocusOwner);
09024: _lastFocusOwner.requestFocusInWindow();
09025: }
09026:
09027: /** Moves focus in MainFrame to teh definitions pane. */
09028: public void focusOnDefinitionsPane() {
09029: _currentDefPane.requestFocusInWindow();
09030: }
09031:
09032: public void interactionStarted() {
09033: Utilities.invokeLater(new Runnable() {
09034: public void run() {
09035: _disableInteractionsPane();
09036: _runAction.setEnabled(false);
09037: _runProjectAction.setEnabled(false);
09038: }
09039: });
09040: }
09041:
09042: public void interactionEnded() {
09043: InteractionsModel im = _model.getInteractionsModel();
09044: edu.rice.cs.plt.tuple.Pair<String, String> lastError = im
09045: .getLastError();
09046: if (DrJava
09047: .getConfig()
09048: .getSetting(
09049: edu.rice.cs.drjava.config.OptionConstants.DIALOG_AUTOIMPORT_ENABLED)) {
09050: if (lastError != null) {
09051: // the interaction ended and there was an error
09052: String exceptionClass = lastError.first();
09053: String message = lastError.second();
09054: edu.rice.cs.plt.tuple.Pair<String, String> secondToLastError = im
09055: .getSecondToLastError();
09056: if ((secondToLastError == null) || // either there was no 2nd to last error
09057: (!secondToLastError.first().equals(
09058: exceptionClass)) || // or it is different
09059: (!secondToLastError.second()
09060: .equals(message))) {
09061: // this aborts the auto-importing if the same class comes up twice in a row
09062: if ("koala.dynamicjava.interpreter.error.ExecutionError"
09063: .equals(exceptionClass)
09064: && message != null
09065: && message
09066: .startsWith("Undefined class '")
09067: && message.endsWith("'")) {
09068: // it was an "undefined class" exception
09069: // show auto-import dialog
09070: String undefinedClassName = message
09071: .substring(
09072: message.indexOf('\'') + 1,
09073: message.lastIndexOf('\''));
09074: _showAutoImportDialog(undefinedClassName);
09075: }
09076: }
09077: }
09078: } else {
09079: // reset the last errors, so the dialog works again if it is re-enabled
09080: im.resetLastErrors();
09081: }
09082:
09083: Utilities.invokeLater(new Runnable() {
09084: public void run() {
09085: _enableInteractionsPane();
09086: _runAction.setEnabled(true);
09087: _runProjectAction.setEnabled(_model
09088: .isProjectActive());
09089: }
09090: });
09091: }
09092:
09093: public void interactionErrorOccurred(final int offset,
09094: final int length) {
09095: Utilities.invokeLater(new Runnable() {
09096: public void run() {
09097: _interactionsPane.highlightError(offset, length);
09098: }
09099: });
09100: }
09101:
09102: /** Called when the active interpreter is changed.
09103: * @param inProgress Whether the new interpreter is currently in progress
09104: * with an interaction (ie. whether an interactionEnded event will be fired)
09105: */
09106: public void interpreterChanged(final boolean inProgress) {
09107: Utilities.invokeLater(new Runnable() {
09108: public void run() {
09109: _runAction.setEnabled(!inProgress);
09110: _runProjectAction.setEnabled(!inProgress);
09111: if (inProgress)
09112: _disableInteractionsPane();
09113: else
09114: _enableInteractionsPane();
09115: }
09116: });
09117: }
09118:
09119: public void compileStarted() {
09120: // Only change GUI from event-dispatching thread
09121: Utilities.invokeLater(new Runnable() {
09122: public void run() {
09123: // hourglassOn();
09124: showTab(_compilerErrorPanel);
09125: _compilerErrorPanel.setCompilationInProgress();
09126: _saveAction.setEnabled(false);
09127: }
09128: });
09129: }
09130:
09131: public void compileEnded(File workDir,
09132: final List<? extends File> excludedFiles) {
09133: // Only change GUI from event-dispatching thread
09134: Utilities.invokeLater(new Runnable() {
09135: public void run() {
09136: // try {
09137: _compilerErrorPanel.reset(excludedFiles
09138: .toArray(new File[0]));
09139: if (isDebuggerReady()) {
09140: // _model.getActiveDocument().checkIfClassFileInSync();
09141:
09142: _updateDebugStatus();
09143: }
09144: // }
09145: // finally { hourglassOff(); }
09146: if ((DrJava.getConfig().getSetting(
09147: DIALOG_COMPLETE_SCAN_CLASS_FILES)
09148: .booleanValue())
09149: && (_model.getBuildDirectory() != null)) {
09150: _scanClassFiles();
09151: }
09152: _model.refreshActiveDocument();
09153: }
09154: });
09155: }
09156:
09157: public void runStarted(final OpenDefinitionsDocument doc) {
09158: // Only change GUI from event-dispatching thread
09159: Utilities.invokeLater(new Runnable() {
09160: public void run() {
09161: // Switch to the interactions pane to show results.
09162: showTab(_interactionsPane);
09163: }
09164: });
09165: }
09166:
09167: public void junitStarted() {
09168: /* Note: simpleHourglassOn() is done by various junit commands (other than junitClasses); hourglass must be off
09169: * for actual testing; the balancing simpleHourglassOff() is located here and in nonTestCase */
09170:
09171: // Only change GUI from event-dispatching thread
09172: // new ScrollableDialog(null, "junitStarted(" + docs + ") called in MainFrame", "", "").show();
09173: Utilities.invokeLater(new Runnable() {
09174: public void run() {
09175: // new ScrollableDialog(null, "Ready for hourglassOn in junitStarted", "", "").show();
09176:
09177: try {
09178: showTab(_junitErrorPanel);
09179: _junitErrorPanel.setJUnitInProgress();
09180: // _junitAction.setEnabled(false);
09181: // _junitAllAction.setEnabled(false);
09182: } finally {
09183: hourglassOff();
09184: }
09185: }
09186: });
09187: }
09188:
09189: /** We are junit'ing a specific list of classes given their source files. */
09190: public void junitClassesStarted() {
09191: // Only change GUI from event-dispatching thread
09192: // new ScrollableDialog(null, "junitClassesStarted called in MainFrame", "", "").show();
09193: Utilities.invokeLater(new Runnable() {
09194: public void run() {
09195: // new ScrollableDialog(null, "Ready for hourglassOn in junitClassesStarted", "", "").show();
09196: // hourglassOn();
09197: showTab(_junitErrorPanel);
09198: _junitErrorPanel.setJUnitInProgress();
09199: // _junitAction.setEnabled(false);
09200: // _junitAllAction.setEnabled(false);
09201: } // no hourglassOff here because junitClasses does not perform hourglassOn
09202: });
09203: }
09204:
09205: //public void junitRunning() { }
09206:
09207: public void junitSuiteStarted(final int numTests) {
09208: Utilities.invokeLater(new Runnable() {
09209: public void run() {
09210: _junitErrorPanel.progressReset(numTests);
09211: }
09212: });
09213: }
09214:
09215: public void junitTestStarted(final String name) {
09216: Utilities.invokeLater(new Runnable() {
09217: public void run() {
09218: _junitErrorPanel.getErrorListPane().testStarted(
09219: name); /* this does nothing! */
09220: }
09221: });
09222: }
09223:
09224: public void junitTestEnded(final String name,
09225: final boolean succeeded, final boolean causedError) {
09226: // new ScrollableDialog(null, "junitTestEnded(" + name + ", " + succeeded + ", " + causedError + ")", "", "").show();
09227: // syncUI...?
09228: Utilities.invokeLater(new Runnable() {
09229: public void run() {
09230: _junitErrorPanel.getErrorListPane().testEnded(name,
09231: succeeded, causedError); // this does nothing!
09232: _junitErrorPanel.progressStep(succeeded);
09233: _model.refreshActiveDocument();
09234: }
09235: });
09236: }
09237:
09238: public void junitEnded() {
09239: // Only change GUI from event-dispatching thread
09240: // new ScrollableDialog(null, "MainFrame.junitEnded() called", "", "").show();
09241: Utilities.invokeLater(new Runnable() {
09242: public void run() {
09243: try {
09244: _restoreJUnitActionsEnabled();
09245: _junitErrorPanel.reset();
09246: _model.refreshActiveDocument();
09247: } finally {
09248: // new ScrollableDialog(null, "MainFrame.junitEnded() ready to return", "", "").show();
09249: // hourglassOff();
09250: }
09251: }
09252: });
09253: }
09254:
09255: /** Fire just before javadoc asynchronous thread is started. Only runs in the event thread. */
09256: public void javadocStarted() {
09257:
09258: assert EventQueue.isDispatchThread();
09259:
09260: // // Only change GUI from event-dispatching thread
09261: // Runnable command = new Runnable() {
09262: // public void run() {
09263: // // if we don't lock edits, our error highlighting might break
09264: hourglassOn();
09265:
09266: showTab(_javadocErrorPanel);
09267: _javadocErrorPanel.setJavadocInProgress();
09268: _javadocAllAction.setEnabled(false);
09269: _javadocCurrentAction.setEnabled(false);
09270: // }
09271: // };
09272: // Utilities.invokeLater(command);
09273: }
09274:
09275: public void javadocEnded(final boolean success,
09276: final File destDir, final boolean allDocs) {
09277: // Only change GUI from event-dispatching thread
09278: Runnable command = new Runnable() {
09279: public void run() {
09280: try {
09281: showTab(_javadocErrorPanel);
09282: _javadocAllAction.setEnabled(true);
09283: _javadocCurrentAction.setEnabled(true);
09284: _javadocErrorPanel.reset();
09285: _model.refreshActiveDocument();
09286: } finally {
09287: hourglassOff();
09288: }
09289:
09290: // Display the results.
09291: if (success) {
09292: String className;
09293: try {
09294: className = _model.getActiveDocument()
09295: .getQualifiedClassName();
09296: className = className.replace('.',
09297: File.separatorChar);
09298: } catch (ClassNameNotFoundException cnf) {
09299: // If there is no class name, pass the empty string as a flag.
09300: // We don't want to blow up here.
09301: className = "";
09302: }
09303: try {
09304: String fileName = (allDocs || className
09305: .equals("")) ? "index.html"
09306: : (className + ".html");
09307: File index = new File(destDir, fileName);
09308: URL address = FileOps.toURL(index
09309: .getAbsoluteFile());
09310:
09311: if (!PlatformFactory.ONLY.openURL(address)) {
09312: JavadocFrame _javadocFrame = new JavadocFrame(
09313: destDir, className, allDocs);
09314: _javadocFrame.setVisible(true);
09315: }
09316: } catch (MalformedURLException me) {
09317: throw new UnexpectedException(me);
09318: } catch (IllegalStateException ise) {
09319: // JavadocFrame couldn't find any output files!
09320: // Display a message.
09321: String msg = "Javadoc completed successfully, but did not produce any HTML files.\n"
09322: + "Please ensure that your access level in Preferences is appropriate.";
09323: JOptionPane.showMessageDialog(
09324: MainFrame.this , msg,
09325: "No output to display.",
09326: JOptionPane.INFORMATION_MESSAGE);
09327: }
09328: }
09329: }
09330: };
09331: Utilities.invokeLater(command);
09332: }
09333:
09334: public void interpreterExited(final int status) {
09335: // Only show prompt if option is set and not in TEST_MODE
09336: if (DrJava.getConfig().getSetting(INTERACTIONS_EXIT_PROMPT)
09337: .booleanValue()
09338: && !Utilities.TEST_MODE
09339: && MainFrame.this .isVisible()) {
09340: // Synchronously pop up a dialog box concerning restarting the JVM.
09341: Utilities.invokeAndWait(new Runnable() {
09342: public void run() {
09343: String msg = "The interactions window was terminated by a call "
09344: + "to System.exit("
09345: + status
09346: + ").\n"
09347: + "The interactions window will now be restarted.";
09348:
09349: String title = "Interactions terminated by System.exit("
09350: + status + ")";
09351:
09352: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
09353: MainFrame.this , title, msg,
09354: "Do not show this message again",
09355: JOptionPane.INFORMATION_MESSAGE,
09356: JOptionPane.DEFAULT_OPTION);
09357: if (dialog.show() == JOptionPane.OK_OPTION
09358: && dialog.getCheckBoxValue()) {
09359: DrJava.getConfig().setSetting(
09360: INTERACTIONS_EXIT_PROMPT,
09361: Boolean.FALSE);
09362: }
09363: }
09364: });
09365: }
09366: }
09367:
09368: public void interpreterResetFailed(Throwable t) {
09369: interpreterReady(FileOption.NULL_FILE);
09370: }
09371:
09372: public void interpreterResetting() {
09373: // Only change GUI from event-dispatching thread
09374: Runnable command = new Runnable() {
09375: public void run() {
09376: Debugger dm = _model.getDebugger();
09377: // if (dm.isAvailable() && dm.isReady()) dm.shutdown();
09378: // _resetInteractionsAction.setEnabled(false);
09379: _junitAction.setEnabled(false);
09380: _junitAllAction.setEnabled(false);
09381: _junitProjectAction.setEnabled(false);
09382: _runAction.setEnabled(false);
09383: _runProjectAction.setEnabled(false);
09384: _closeInteractionsScript();
09385: _interactionsPane.setEditable(false);
09386: _interactionsPane.setCursor(Cursor
09387: .getPredefinedCursor(Cursor.WAIT_CURSOR));
09388: if (_showDebugger)
09389: _toggleDebuggerAction.setEnabled(false);
09390: }
09391: };
09392: Utilities.invokeLater(command);
09393: }
09394:
09395: public void interpreterReady(File wd) {
09396: // Only change GUI from event-dispatching thread
09397: Runnable command = new Runnable() {
09398: public void run() {
09399: interactionEnded();
09400: _runAction.setEnabled(true);
09401: _runProjectAction.setEnabled(_model
09402: .isProjectActive());
09403: _junitAction.setEnabled(true);
09404: _junitAllAction.setEnabled(true);
09405: _junitProjectAction.setEnabled(_model
09406: .isProjectActive());
09407: // This action should not be enabled until the slave JVM is used
09408: // _resetInteractionsAction.setEnabled(true);
09409: if (_showDebugger) {
09410: _toggleDebuggerAction.setEnabled(true);
09411: }
09412: // Moved this line here from interpreterResetting since
09413: // it was possible to get an InputBox in InteractionsController
09414: // between interpreterResetting and interpreterReady.
09415: // Fixes bug #917054 "Interactions Reset Bug".
09416: _interactionsController.interruptConsoleInput();
09417: }
09418: };
09419: Utilities.invokeLater(command);
09420: }
09421:
09422: public void slaveJVMUsed() { /* _resetInteractionsAction.setEnabled(true); */
09423: }
09424:
09425: public void consoleReset() {
09426: }
09427:
09428: public void saveBeforeCompile() {
09429: // The following event thread switch supports legacy test code that calls compile methods outside of the
09430: // event thread. The wait is necessary because compilation process cannot proceed until saving is complete.
09431: Utilities.invokeAndWait(new Runnable() {
09432: public void run() {
09433: _saveAllBeforeProceeding(
09434: "To compile, you must first save ALL modified files.\n"
09435: + "Would you like to save and then compile?",
09436: ALWAYS_SAVE_BEFORE_COMPILE,
09437: "Always save before compiling");
09438: }
09439: });
09440: }
09441:
09442: /** Compile all open source files if this option is configured or running as a unit test. Otherwise, pop up a
09443: * dialog to ask if all open source files should be compiled in order to test the program.
09444: */
09445: public void compileBeforeJUnit(
09446: final CompilerListener testAfterCompile) {
09447: // System.err.println("in compileBeforeJUnit, TEST_MODE = " + Utilities.TEST_MODE);
09448: if (DrJava.getConfig().getSetting(
09449: ALWAYS_COMPILE_BEFORE_JUNIT).booleanValue()
09450: || Utilities.TEST_MODE) {
09451: // Compile all open source files
09452: _model.getCompilerModel().addListener(testAfterCompile); // listener removes itself
09453: _compileAll();
09454: } else { // pop up a window to ask if all open files should be compiled before testing
09455: Utilities.invokeLater(new Runnable() {
09456: public void run() {
09457: String title = "Must Compile All Source Files to Run Unit Tests";
09458: String msg = "To unit test all documents, you must first compile all out of sync source files.\n"
09459: + "Would you like to compile all files and run the specified test?";
09460: int rc = JOptionPane.showConfirmDialog(
09461: MainFrame.this , msg, title,
09462: JOptionPane.YES_NO_OPTION);
09463:
09464: switch (rc) {
09465: case JOptionPane.YES_OPTION: // compile all open source files and test
09466: _model.getCompilerModel().addListener(
09467: testAfterCompile); // listener removes itself
09468: _compileAll();
09469: break;
09470: case JOptionPane.CLOSED_OPTION:
09471: case JOptionPane.NO_OPTION: // abort unit testing
09472: _model.getJUnitModel().nonTestCase(true); // cleans up
09473: break;
09474: default:
09475: throw new UnexpectedException(
09476: "Invalid returnCode from showConfirmDialog: "
09477: + rc);
09478: }
09479: }
09480: });
09481: }
09482: }
09483:
09484: public void saveBeforeJavadoc() {
09485: Utilities.invokeLater(new Runnable() {
09486: public void run() {
09487: _saveAllBeforeProceeding(
09488: "To run Javadoc, you must first save ALL modified files.\n"
09489: + "Would you like to save and then run Javadoc?",
09490: ALWAYS_SAVE_BEFORE_JAVADOC,
09491: "Always save before running Javadoc");
09492: }
09493: });
09494: }
09495:
09496: /** Helper method shared by all "saveBeforeX" methods. In JUnit tests, YES option is automatically selected
09497: * @param message a prompt message to be displayed to the user
09498: * @param option the BooleanOption for the prompt dialog checkbox
09499: * @param checkMsg the description of the checkbox ("Always save before X")
09500: */
09501: private void _saveAllBeforeProceeding(String message,
09502: BooleanOption option, String checkMsg) {
09503: // new ScrollableDialog(null, "saveBeforeProceeding called in MainFrame", "", "").show();
09504: if (_model.hasModifiedDocuments()) {
09505: if (!DrJava.getConfig().getSetting(option)
09506: .booleanValue()
09507: && !Utilities.TEST_MODE) {
09508: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
09509: MainFrame.this ,
09510: "Must Save All Files to Continue", message,
09511: checkMsg);
09512: int rc = dialog.show();
09513:
09514: switch (rc) {
09515: case JOptionPane.YES_OPTION:
09516: _saveAll();
09517: // Only remember checkbox if they say yes
09518: if (dialog.getCheckBoxValue())
09519: DrJava.getConfig().setSetting(option,
09520: Boolean.TRUE);
09521: break;
09522: case JOptionPane.NO_OPTION:
09523: case JOptionPane.CANCEL_OPTION:
09524: case JOptionPane.CLOSED_OPTION:
09525: // do nothing
09526: break;
09527: default:
09528: throw new RuntimeException(
09529: "Invalid rc from showConfirmDialog: "
09530: + rc);
09531: }
09532: } else
09533: _saveAll();
09534: }
09535: }
09536:
09537: /** Saves the active document which is untitled. */
09538: public void saveUntitled() {
09539: _saveAs();
09540: }
09541:
09542: public void filePathContainsPound() {
09543: Utilities.invokeLater(new Runnable() {
09544: public void run() {
09545: if (DrJava.getConfig().getSetting(
09546: WARN_PATH_CONTAINS_POUND).booleanValue()) {
09547: String msg = "Files whose paths contain the '#' symbol cannot be used in the\n"
09548: + "Interactions Pane due to a bug in Java's file to URL conversion.\n"
09549: + "It is suggested that you change the name of the directory\n"
09550: + "containing the '#' symbol.";
09551:
09552: String title = "Path Contains Pound Sign";
09553:
09554: ConfirmCheckBoxDialog dialog = new ConfirmCheckBoxDialog(
09555: MainFrame.this , title, msg,
09556: "Do not show this message again",
09557: JOptionPane.WARNING_MESSAGE,
09558: JOptionPane.DEFAULT_OPTION);
09559: if (dialog.show() == JOptionPane.OK_OPTION
09560: && dialog.getCheckBoxValue()) {
09561: DrJava.getConfig().setSetting(
09562: WARN_PATH_CONTAINS_POUND,
09563: Boolean.FALSE);
09564: }
09565: }
09566: }
09567: });
09568: }
09569:
09570: /** Event that is fired with there is nothing to test. JUnit is never started. */
09571: public void nonTestCase(boolean isTestAll) {
09572:
09573: // Utilities.showStackTrace(new UnexpectedException("We should not have called nonTestCase"));
09574:
09575: final String message = isTestAll ? "There are no compiled JUnit TestCases available for execution.\n"
09576: + "Perhaps you have not yet compiled your test files."
09577: : "The current document is not a valid JUnit test case.\n"
09578: + "Please make sure that:\n"
09579: + "- it has been compiled and\n"
09580: + "- it is a subclass of junit.framework.TestCase.\n";
09581:
09582: // Not necessarily invoked from event-handling thread!
09583:
09584: Utilities.invokeLater(new Runnable() {
09585: public void run() {
09586: JOptionPane.showMessageDialog(MainFrame.this ,
09587: message,
09588: "Test Only Executes JUnit test cases",
09589: JOptionPane.ERROR_MESSAGE);
09590: // clean up as in JUnitEnded
09591: try {
09592: showTab(_junitErrorPanel);
09593: _junitAction.setEnabled(true);
09594: _junitAllAction.setEnabled(true);
09595: _junitProjectAction.setEnabled(_model
09596: .isProjectActive());
09597: _junitErrorPanel.reset();
09598: } finally {
09599: hourglassOff();
09600: _restoreJUnitActionsEnabled();
09601: }
09602: }
09603: });
09604: }
09605:
09606: /** Event that is fired when testing encounters an illegal class file. JUnit is never started. */
09607: public void classFileError(ClassFileError e) {
09608:
09609: final String message = "The class file for class "
09610: + e.getClassName()
09611: + " in source file "
09612: + e.getCanonicalPath()
09613: + " cannot be loaded.\n "
09614: + "When DrJava tries to load it, the following error is generated:\n"
09615: + e.getError();
09616:
09617: // Not necessarily invoked from event-handling thread!
09618:
09619: Utilities.invokeLater(new Runnable() {
09620: public void run() {
09621: JOptionPane.showMessageDialog(MainFrame.this ,
09622: message,
09623: "Testing works only on valid class files",
09624: JOptionPane.ERROR_MESSAGE);
09625: // clean up as junitEnded except hourglassOff (should factored into a private method)
09626: showTab(_junitErrorPanel);
09627: _junitAction.setEnabled(true);
09628: _junitAllAction.setEnabled(true);
09629: _junitProjectAction.setEnabled(_model
09630: .isProjectActive());
09631: _junitErrorPanel.reset();
09632: }
09633: });
09634: }
09635:
09636: /** Only callable from within the event-handling thread */
09637: public void currentDirectoryChanged(final File dir) {
09638: _setCurrentDirectory(dir);
09639: }
09640:
09641: /** Check if the specified document has been modified. If it has, ask the user if he would like to save it
09642: * and save the document if yes. Also give the user a "cancel" option to cancel doing the operation
09643: * that got us here in the first place.
09644: *
09645: * @return A boolean indicating whether the user cancelled the save process. False means cancel.
09646: */
09647: public boolean canAbandonFile(OpenDefinitionsDocument doc) {
09648: return _fileSaveHelper(doc,
09649: JOptionPane.YES_NO_CANCEL_OPTION);
09650: }
09651:
09652: private boolean _fileSaveHelper(OpenDefinitionsDocument doc,
09653: int paneOption) {
09654: String text, fname;
09655: OpenDefinitionsDocument lastActive = _model
09656: .getActiveDocument();
09657: if (lastActive != doc) {
09658: _model.setActiveDocument(doc);
09659: }
09660: boolean notFound = false;
09661: try {
09662: File file = doc.getFile();
09663: if (file == null) {
09664: fname = "Untitled file";
09665: text = "Untitled file has been modified. Would you like to save it?";
09666: } else {
09667: fname = file.getName();
09668: text = fname
09669: + " has been modified. Would you like to save it?";
09670: }
09671: } catch (FileMovedException fme) {
09672: // File was deleted, but use the same name anyway
09673: fname = fme.getFile().getName();
09674: text = fname
09675: + " not found on disk. Would you like to save to another file?";
09676: notFound = true;
09677: }
09678:
09679: int rc = JOptionPane.showConfirmDialog(MainFrame.this ,
09680: text, "Save " + fname + "?", paneOption);
09681: switch (rc) {
09682: case JOptionPane.YES_OPTION:
09683: boolean saved = false;
09684: if (notFound)
09685: saved = _saveAs();
09686: else
09687: saved = _save();
09688: if (doc != lastActive) {
09689: _model.setActiveDocument(lastActive); // breaks when "if" clause omitted
09690: }
09691: return saved;
09692: case JOptionPane.NO_OPTION:
09693: if (doc != lastActive) {
09694: _model.setActiveDocument(lastActive); // breaks when "if" clause omitted
09695: }
09696: return true;
09697: case JOptionPane.CLOSED_OPTION:
09698: case JOptionPane.CANCEL_OPTION:
09699: return false;
09700: default: // never executed
09701: throw new RuntimeException("Invalid option: " + rc);
09702: }
09703: }
09704:
09705: /** Check if the current document has been modified. If it has, ask the user if he would like to save it
09706: * and save the document if yes.
09707: * @return true if quitting should continue, false if the user cancelled
09708: */
09709: public boolean quitFile(OpenDefinitionsDocument doc) {
09710: return _fileSaveHelper(doc,
09711: JOptionPane.YES_NO_CANCEL_OPTION);
09712: }
09713:
09714: /** Called to ask the listener if it is OK to revert the current document to a newer version saved on file. */
09715: public boolean shouldRevertFile(OpenDefinitionsDocument doc) {
09716: String fname;
09717: if (!_model.getActiveDocument().equals(doc)) {
09718: _model.setActiveDocument(doc);
09719: }
09720: try {
09721: File file = doc.getFile();
09722: if (file == null)
09723: fname = "Untitled file";
09724: else
09725: fname = file.getName();
09726: } catch (FileMovedException fme) {
09727: fname = fme.getFile().getName();
09728: }
09729: // File was deleted, but use the same name anyway
09730:
09731: String text = fname
09732: + " has changed on disk. Would you like to reload it?\n"
09733: + "This will discard any changes you have made.";
09734: int rc = JOptionPane.showConfirmDialog(MainFrame.this ,
09735: text, fname + " Modified on Disk",
09736: JOptionPane.YES_NO_OPTION);
09737: switch (rc) {
09738: case JOptionPane.YES_OPTION:
09739: return true;
09740: case JOptionPane.NO_OPTION:
09741: return false;
09742: case JOptionPane.CLOSED_OPTION:
09743: case JOptionPane.CANCEL_OPTION:
09744: return false;
09745: default:
09746: throw new RuntimeException("Invalid rc: " + rc);
09747: }
09748: }
09749:
09750: public void interactionIncomplete() {
09751: }
09752:
09753: /* Changes to the state */
09754:
09755: public void projectBuildDirChanged() {
09756: if (_model.getBuildDirectory() != null) {
09757: _cleanAction.setEnabled(true);
09758: } else
09759: _cleanAction.setEnabled(false);
09760: }
09761:
09762: public void projectWorkDirChanged() {
09763: }
09764:
09765: public void projectModified() {
09766: // _saveProjectAction.setEnabled(_model.isProjectChanged());
09767: }
09768:
09769: public void projectClosed() {
09770: Utilities.invokeAndWait(new Runnable() { // Why the wait?
09771: public void run() {
09772: _model.getDocumentNavigator().asContainer()
09773: .addKeyListener(_historyListener);
09774: _model
09775: .getDocumentNavigator()
09776: .asContainer()
09777: .addFocusListener(
09778: _focusListenerForRecentDocs);
09779: _model.getDocumentNavigator().asContainer()
09780: .addMouseListener(
09781: _resetFindReplaceListener);
09782: // new ScrollableDialog(null, "Closing JUnit Error Panel in MainFrame", "", "").show();
09783: removeTab(_junitErrorPanel);
09784: _runButton = _updateToolbarButton(
09785: _runButton, _runAction);
09786: _compileButton = _updateToolbarButton(
09787: _compileButton, _compileAllAction);
09788: _junitButton = _updateToolbarButton(
09789: _junitButton, _junitAllAction);
09790: projectRunnableChanged();
09791: }
09792: });
09793: }
09794:
09795: public void projectOpened(File projectFile,
09796: FileOpenSelector files) {
09797: _setUpContextMenus();
09798: projectRunnableChanged();
09799: _compileButton = _updateToolbarButton(_compileButton,
09800: _compileProjectAction);
09801: _junitButton = _updateToolbarButton(_junitButton,
09802: _junitProjectAction);
09803: _recentProjectManager.updateOpenFiles(projectFile);
09804: open(files);
09805: _openProjectUpdate();
09806: _model.getDocumentNavigator().asContainer().addKeyListener(
09807: _historyListener);
09808: _model.getDocumentNavigator().asContainer()
09809: .addFocusListener(_focusListenerForRecentDocs);
09810: _model.getDocumentNavigator().asContainer()
09811: .addMouseListener(_resetFindReplaceListener);
09812: _model.refreshActiveDocument();
09813: }
09814:
09815: public void projectRunnableChanged() {
09816: if (_model.getMainClass() != null
09817: && _model.getMainClass().exists()) {
09818: _runProjectAction.setEnabled(_model.isProjectActive());
09819: _runButton = _updateToolbarButton(_runButton,
09820: _runProjectAction);
09821: } else {
09822: _runProjectAction.setEnabled(false);
09823: _runButton = _updateToolbarButton(_runButton,
09824: _runAction);
09825: }
09826: }
09827:
09828: public void documentNotFound(OpenDefinitionsDocument d, File f) {
09829:
09830: _model.setProjectChanged(true);
09831:
09832: String text = "File "
09833: + f.getAbsolutePath()
09834: + "\ncould not be found on disk! It was probably moved\n"
09835: + "or deleted. Would you like to try to find it?";
09836: int rc = JOptionPane.showConfirmDialog(MainFrame.this ,
09837: text, "File Moved or Deleted",
09838: JOptionPane.YES_NO_OPTION);
09839: if (rc == JOptionPane.NO_OPTION)
09840: return;
09841: if (rc == JOptionPane.YES_OPTION) {
09842: try {
09843: File[] opened = _openSelector.getFiles();
09844: d.setFile(opened[0]);
09845: } catch (OperationCanceledException oce) {
09846: // Interpret cancelled as "NO"
09847: }
09848: }
09849: // The following line was commented out because it breaks when a user want to close but not save a deleted file
09850: // else throw new DocumentClosedException(d,"Document in " + f + "closed unexpectedly"); // misnamed exception
09851: }
09852: } // End of ModelListener class
09853:
09854: public JViewport getDefViewport() {
09855: OpenDefinitionsDocument doc = _model.getActiveDocument();
09856: // new ScrollableDialog(null, "Active Document is " + doc, "", "").show();
09857: JScrollPane defScroll = _defScrollPanes.get(doc);
09858: return defScroll.getViewport();
09859: }
09860:
09861: public void removeTab(final Component c) {
09862: Utilities.invokeLater(new Runnable() {
09863: public void run() {
09864: if (_tabbedPane.getTabCount() > 1) {
09865: if (_tabbedPane.getSelectedIndex() == _tabbedPane
09866: .getTabCount() - 1)
09867: _tabbedPane.setSelectedIndex(_tabbedPane
09868: .getSelectedIndex() - 1);
09869: else
09870: _tabbedPane.setSelectedIndex(_tabbedPane
09871: .getSelectedIndex() + 1);
09872: _tabbedPane.remove(c);
09873: ((TabbedPanel) c).setDisplayed(false);
09874: }
09875: _currentDefPane.requestFocusInWindow();
09876: }
09877: });
09878: }
09879:
09880: /** Shows the components passed in in the appropriate place in the tabbedPane depending on the position of
09881: * the component in the _tabs list. Only runs in the event thread.
09882: * @param c the component to show in the tabbedPane
09883: */
09884: private void showTab(final Component c) {
09885: // TODO: put all of the _tabbedPane components in _tabs. eliminating special cases for interactions, console (which
09886: // are always displayed)
09887: assert EventQueue.isDispatchThread();
09888: // Utilities.invokeLater(new Runnable() {
09889: // public void run() {
09890: int numVisible = 0;
09891: // System.err.println("showTab called with c = " + c);
09892:
09893: if (c == _interactionsContainer) {
09894: // Utilities.show("InteractionsTab selected");
09895: _tabbedPane.setSelectedIndex(INTERACTIONS_TAB);
09896: c.requestFocusInWindow();
09897: } else if (c == _consoleScroll) {
09898: _tabbedPane.setSelectedIndex(CONSOLE_TAB);
09899: c.requestFocusInWindow();
09900: } else {
09901: for (TabbedPanel tp : _tabs) {
09902: if (tp == c) {
09903: // 2 right now is a magic number for the number of tabs always visible
09904: // interactions & console
09905: if (!tp.isDisplayed()) {
09906: _tabbedPane.insertTab(tp.getName(), null, tp,
09907: null, numVisible + 2);
09908: tp.setVisible(true);
09909: tp.setDisplayed(true);
09910: tp.repaint();
09911: }
09912: _tabbedPane.setSelectedIndex(numVisible + 2);
09913:
09914: c.requestFocusInWindow();
09915: return;
09916: }
09917: if (tp.isDisplayed())
09918: numVisible++;
09919: }
09920: }
09921: // }
09922: // });
09923: }
09924:
09925: /**
09926: * Sets the location of the main divider.
09927: * (not currently used)
09928: private void _setDividerLocation() {
09929: int divLocation = _mainSplit.getHeight() -
09930: _mainSplit.getDividerSize() -
09931: (int)_tabbedPane.getMinimumSize().getHeight();
09932: if (_mainSplit.getDividerLocation() > divLocation)
09933: _mainSplit.setDividerLocation(divLocation);
09934: }*/
09935:
09936: /** Warns the user that the current file is open and query them if they wish to save over the currently open file. */
09937: private boolean _warnFileOpen(File f) {
09938: OpenDefinitionsDocument d = null;
09939: try {
09940: d = _model.getDocumentForFile(f);
09941: } catch (IOException ioe) { /* do nothing */
09942: }
09943: Object[] options = { "Yes", "No" };
09944: if (d == null)
09945: return false;
09946: boolean dMod = d.isModifiedSinceSave();
09947: String msg = "This file is already open in DrJava"
09948: + (dMod ? " and has been modified" : "")
09949: + ". Do you wish to overwrite it?";
09950: int choice = JOptionPane
09951: .showOptionDialog(MainFrame.this , msg,
09952: "File Open Warning", JOptionPane.YES_NO_OPTION,
09953: JOptionPane.QUESTION_MESSAGE, null, options,
09954: options[1]);
09955: if (choice == JOptionPane.YES_OPTION)
09956: return _model.closeFileWithoutPrompt(d);
09957: return false;
09958: }
09959:
09960: /**
09961: * Confirms with the user that the file should be overwritten.
09962: * @return <code>true</code> iff the user accepts overwriting.
09963: */
09964: private boolean _verifyOverwrite() {
09965: Object[] options = { "Yes", "No" };
09966: int n = JOptionPane
09967: .showOptionDialog(
09968: MainFrame.this ,
09969: "This file already exists. Do you wish to overwrite the file?",
09970: "Confirm Overwrite", JOptionPane.YES_NO_OPTION,
09971: JOptionPane.QUESTION_MESSAGE, null, options,
09972: options[1]);
09973: return (n == JOptionPane.YES_OPTION);
09974: }
09975:
09976: /* Pops up a message and cleans up after unit testing has been interrupted. */
09977: private void _junitInterrupted(final UnexpectedException e) {
09978: Utilities.invokeLater(new Runnable() {
09979: public void run() {
09980: _showJUnitInterrupted(e);
09981: removeTab(_junitErrorPanel);
09982: _model.refreshActiveDocument();
09983: // hourglassOff();
09984: }
09985: });
09986: }
09987:
09988: boolean isDebuggerReady() {
09989: return _showDebugger && _model.getDebugger().isReady();
09990: }
09991:
09992: /** Return the find replace dialog. Package protected for use in tests. */
09993: FindReplacePanel getFindReplaceDialog() {
09994: return _findReplace;
09995: }
09996:
09997: /** Builds the Hashtables in KeyBindingManager that are used to keep track of key-bindings and allows for live
09998: * updating, conflict resolution, and intelligent error messages (the ActionToNameMap).
09999: * IMPORTANT: Don't use this way to put actions into the KeyBindingManager if the action is a menu item. It will
10000: * already have been put in. Putting in again will cause bug #803304 "Uncomment lines wont rebind".
10001: */
10002: private void _setUpKeyBindingMaps() {
10003: final ActionMap _actionMap = _currentDefPane.getActionMap();
10004:
10005: KeyBindingManager.Singleton
10006: .put(KEY_BACKWARD, _actionMap
10007: .get(DefaultEditorKit.backwardAction), null,
10008: "Backward");
10009: KeyBindingManager.Singleton.addShiftAction(KEY_BACKWARD,
10010: DefaultEditorKit.selectionBackwardAction);
10011:
10012: KeyBindingManager.Singleton.put(KEY_BEGIN_DOCUMENT, _actionMap
10013: .get(DefaultEditorKit.beginAction), null,
10014: "Begin Document");
10015: KeyBindingManager.Singleton.addShiftAction(KEY_BEGIN_DOCUMENT,
10016: DefaultEditorKit.selectionBeginAction);
10017:
10018: // KeyBindingManager.Singleton.put(KEY_BEGIN_LINE, _actionMap.get(DefaultEditorKit.beginLineAction), null,
10019: // "Begin Line");
10020: KeyBindingManager.Singleton.put(KEY_BEGIN_LINE,
10021: _beginLineAction, null, "Begin Line");
10022: // KeyBindingManager.Singleton.addShiftAction(KEY_BEGIN_LINE,
10023: // DefaultEditorKit.selectionBeginLineAction);
10024: KeyBindingManager.Singleton.addShiftAction(KEY_BEGIN_LINE,
10025: _selectionBeginLineAction);
10026:
10027: KeyBindingManager.Singleton.put(KEY_PREVIOUS_WORD, _actionMap
10028: .get(DefaultEditorKit.previousWordAction), null,
10029: "Previous Word");
10030: KeyBindingManager.Singleton.addShiftAction(KEY_PREVIOUS_WORD,
10031: DefaultEditorKit.selectionPreviousWordAction);
10032:
10033: KeyBindingManager.Singleton.put(KEY_DOWN, _actionMap
10034: .get(DefaultEditorKit.downAction), null, "Down");
10035: KeyBindingManager.Singleton.addShiftAction(KEY_DOWN,
10036: DefaultEditorKit.selectionDownAction);
10037:
10038: KeyBindingManager.Singleton.put(KEY_END_DOCUMENT, _actionMap
10039: .get(DefaultEditorKit.endAction), null, "End Document");
10040: KeyBindingManager.Singleton.addShiftAction(KEY_END_DOCUMENT,
10041: DefaultEditorKit.selectionEndAction);
10042:
10043: KeyBindingManager.Singleton.put(KEY_END_LINE, _actionMap
10044: .get(DefaultEditorKit.endLineAction), null, "End Line");
10045: KeyBindingManager.Singleton.addShiftAction(KEY_END_LINE,
10046: DefaultEditorKit.selectionEndLineAction);
10047:
10048: KeyBindingManager.Singleton.put(KEY_NEXT_WORD, _actionMap
10049: .get(DefaultEditorKit.nextWordAction), null,
10050: "Next Word");
10051: KeyBindingManager.Singleton.addShiftAction(KEY_NEXT_WORD,
10052: DefaultEditorKit.selectionNextWordAction);
10053:
10054: KeyBindingManager.Singleton.put(KEY_FORWARD, _actionMap
10055: .get(DefaultEditorKit.forwardAction), null, "Forward");
10056: KeyBindingManager.Singleton.addShiftAction(KEY_FORWARD,
10057: DefaultEditorKit.selectionForwardAction);
10058:
10059: KeyBindingManager.Singleton.put(KEY_UP, _actionMap
10060: .get(DefaultEditorKit.upAction), null, "Up");
10061: KeyBindingManager.Singleton.addShiftAction(KEY_UP,
10062: DefaultEditorKit.selectionUpAction);
10063:
10064: // These last methods have no default selection methods
10065: KeyBindingManager.Singleton.put(KEY_PAGE_DOWN, _actionMap
10066: .get(DefaultEditorKit.pageDownAction), null,
10067: "Page Down");
10068: KeyBindingManager.Singleton.put(KEY_PAGE_UP, _actionMap
10069: .get(DefaultEditorKit.pageUpAction), null, "Page Up");
10070: KeyBindingManager.Singleton.put(KEY_CUT_LINE, _cutLineAction,
10071: null, "Cut Line");
10072: KeyBindingManager.Singleton.put(KEY_CLEAR_LINE,
10073: _clearLineAction, null, "Clear Line");
10074: KeyBindingManager.Singleton.put(KEY_SHIFT_DELETE_PREVIOUS,
10075: _actionMap.get(DefaultEditorKit.deletePrevCharAction),
10076: null, "Delete Previous");
10077: KeyBindingManager.Singleton.put(KEY_SHIFT_DELETE_NEXT,
10078: _actionMap.get(DefaultEditorKit.deleteNextCharAction),
10079: null, "Delete Next");
10080: }
10081:
10082: /** @param listener The ComponentListener to add to the open documents list
10083: * This method allows for testing of the dancing UI (See MainFrameTest.testDancingUI()).
10084: */
10085: public void addComponentListenerToOpenDocumentsList(
10086: ComponentListener listener) {
10087: _docSplitPane.getLeftComponent().addComponentListener(listener);
10088: }
10089:
10090: /**For test purposes only. Returns the text in the status bar. Is used to test brace matching*/
10091: public String getFileNameField() {
10092: return _statusField.getText();
10093: }
10094:
10095: /**For test purposes only. Returns the edit menu*/
10096: public JMenu getEditMenu() {
10097: return _editMenu;
10098: }
10099:
10100: /** The OptionListener for FONT_MAIN */
10101: private class MainFontOptionListener implements
10102: OptionListener<Font> {
10103: public void optionChanged(OptionEvent<Font> oce) {
10104: _setMainFont();
10105: }
10106: }
10107:
10108: /** The OptionListener for FONT_LINE_NUMBERS */
10109: private class LineNumbersFontOptionListener implements
10110: OptionListener<Font> {
10111: public void optionChanged(OptionEvent<Font> oce) {
10112: _updateLineNums();
10113: }
10114: }
10115:
10116: /** The OptionListener for FONT_DOCLIST */
10117: private class DoclistFontOptionListener implements
10118: OptionListener<Font> {
10119: public void optionChanged(OptionEvent<Font> oce) {
10120: Font doclistFont = DrJava.getConfig().getSetting(
10121: FONT_DOCLIST);
10122: _model.getDocCollectionWidget().setFont(doclistFont);
10123: }
10124: }
10125:
10126: /** The OptionListener for FONT_TOOLBAR */
10127: private class ToolbarFontOptionListener implements
10128: OptionListener<Font> {
10129: public void optionChanged(OptionEvent<Font> oce) {
10130: _updateToolbarButtons();
10131: }
10132: }
10133:
10134: /** The OptionListener for DEFINITIONS_NORMAL_COLOR */
10135: private class NormalColorOptionListener implements
10136: OptionListener<Color> {
10137: public void optionChanged(OptionEvent<Color> oce) {
10138: _updateNormalColor();
10139: }
10140: }
10141:
10142: /** The OptionListener for DEFINITIONS_BACKGROUND_COLOR */
10143: private class BackgroundColorOptionListener implements
10144: OptionListener<Color> {
10145: public void optionChanged(OptionEvent<Color> oce) {
10146: _updateBackgroundColor();
10147: }
10148: }
10149:
10150: /** The OptionListener for TOOLBAR options */
10151: private class ToolbarOptionListener implements
10152: OptionListener<Boolean> {
10153: public void optionChanged(OptionEvent<Boolean> oce) {
10154: _updateToolbarButtons();
10155: }
10156: }
10157:
10158: /** The OptionListener for LINEENUM_ENABLED. */
10159: private class LineEnumOptionListener implements
10160: OptionListener<Boolean> {
10161: public void optionChanged(OptionEvent<Boolean> oce) {
10162: _updateDefScrollRowHeader();
10163: }
10164: }
10165:
10166: /** The OptionListener for QUIT_PROMPT. */
10167: private class QuitPromptOptionListener implements
10168: OptionListener<Boolean> {
10169: public void optionChanged(OptionEvent<Boolean> oce) {
10170: _promptBeforeQuit = oce.value.booleanValue();
10171: }
10172: }
10173:
10174: /** The OptionListener for RECENT_FILES_MAX_SIZE. */
10175: private class RecentFilesOptionListener implements
10176: OptionListener<Integer> {
10177: public void optionChanged(OptionEvent<Integer> oce) {
10178: _recentFileManager.updateMax(oce.value.intValue());
10179: _recentFileManager.numberItems();
10180: _recentProjectManager.updateMax(oce.value.intValue());
10181: _recentProjectManager.numberItems();
10182: }
10183: }
10184:
10185: private class LastFocusListener extends FocusAdapter {
10186: public void focusGained(FocusEvent e) {
10187: _lastFocusOwner = e.getComponent();
10188: // System.err.println("_lastFocusOwner = " + _lastFocusOwner);
10189: }
10190: };
10191:
10192: /** Wrapper for setPopupLoc(Window, Component) that uses the window's owner as the owner to center the popup on.
10193: * @param popup the Popup window
10194: */
10195: public void setPopupLoc(Window popup) {
10196: MainFrame.setPopupLoc(popup, (popup.getOwner() != null) ? popup
10197: .getOwner() : this );
10198: }
10199:
10200: /** Sets the location of the popup in a consistant way. If the popup has an owner, the popup is centered over the
10201: * owner. If the popup has no owner(owner == null), the popup is centered over the first monitor. In either case,
10202: * the popup is moved and scaled if any part of it is not on the screen. This method should be called for all popups
10203: * to maintain consistancy.
10204: * @param popup the popup window
10205: * @param owner the parent component for the popup
10206: */
10207: public static void setPopupLoc(Window popup, Component owner) {
10208: Rectangle frameRect = popup.getBounds();
10209:
10210: Point ownerLoc = null;
10211: Dimension ownerSize = null;
10212: if (owner != null) {
10213: ownerLoc = owner.getLocation();
10214: ownerSize = owner.getSize();
10215: } else {
10216: //for multi-monitor support
10217: //Question: do we want it to popup on the first monitor always?
10218: GraphicsDevice[] dev = GraphicsEnvironment
10219: .getLocalGraphicsEnvironment().getScreenDevices();
10220: Rectangle rec = dev[0].getDefaultConfiguration()
10221: .getBounds();
10222: ownerLoc = rec.getLocation();
10223: ownerSize = rec.getSize();
10224: }
10225:
10226: // center it on owner
10227: Point loc = new Point(ownerLoc.x
10228: + (ownerSize.width - frameRect.width) / 2, ownerLoc.y
10229: + (ownerSize.height - frameRect.height) / 2);
10230: frameRect.setLocation(loc);
10231:
10232: // now find the GraphicsConfiguration the popup is on
10233: GraphicsConfiguration gcBest = null;
10234: int gcBestArea = -1;
10235: GraphicsEnvironment ge = GraphicsEnvironment
10236: .getLocalGraphicsEnvironment();
10237: GraphicsDevice[] gs = ge.getScreenDevices();
10238: for (GraphicsDevice gd : gs) {
10239: GraphicsConfiguration gc = gd.getDefaultConfiguration();
10240: Rectangle isect = frameRect.intersection(gc.getBounds());
10241: int gcArea = isect.width * isect.height;
10242: if (gcArea > gcBestArea) {
10243: gcBest = gc;
10244: gcBestArea = gcArea;
10245: }
10246: }
10247:
10248: // make it fit on the screen
10249: Rectangle screenRect = gcBest.getBounds();
10250: Dimension screenSize = screenRect.getSize();
10251: Dimension frameSize = popup.getSize();
10252:
10253: if (frameSize.height > screenSize.height)
10254: frameSize.height = screenSize.height;
10255: if (frameSize.width > screenSize.width)
10256: frameSize.width = screenSize.width;
10257:
10258: frameRect.setSize(frameSize);
10259:
10260: // center it on owner again
10261: loc = new Point(ownerLoc.x
10262: + (ownerSize.width - frameRect.width) / 2, ownerLoc.y
10263: + (ownerSize.height - frameRect.height) / 2);
10264: frameRect.setLocation(loc);
10265:
10266: // now fit it on the screen
10267: if (frameRect.x < screenRect.x)
10268: frameRect.x = screenRect.x;
10269: if (frameRect.x + frameRect.width > screenRect.x
10270: + screenRect.width)
10271: frameRect.x = screenRect.x + screenRect.width
10272: - frameRect.width;
10273:
10274: if (frameRect.y < screenRect.y)
10275: frameRect.y = screenRect.y;
10276: if (frameRect.y + frameRect.height > screenRect.y
10277: + screenRect.height)
10278: frameRect.y = screenRect.y + screenRect.height
10279: - frameRect.height;
10280:
10281: popup.setSize(frameRect.getSize());
10282: popup.setLocation(frameRect.getLocation());
10283: }
10284:
10285: /** Drag and drop target. */
10286: DropTarget dropTarget = new DropTarget(this , this );
10287:
10288: /** Linux URI drag-and-drop data flavor. */
10289: private static DataFlavor uriListFlavor;
10290: static {
10291: try {
10292: uriListFlavor = new DataFlavor(
10293: "text/uri-list;class=java.lang.String");
10294: } catch (ClassNotFoundException cnfe) {
10295: uriListFlavor = null;
10296: }
10297: }
10298:
10299: /** User dragged something into the component. */
10300: public void dragEnter(DropTargetDragEvent dropTargetDragEvent) {
10301: dropTargetDragEvent
10302: .acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
10303: }
10304:
10305: public void dragExit(DropTargetEvent dropTargetEvent) {
10306: }
10307:
10308: public void dragOver(DropTargetDragEvent dropTargetDragEvent) {
10309: }
10310:
10311: public void dropActionChanged(
10312: DropTargetDragEvent dropTargetDragEvent) {
10313: }
10314:
10315: /** User dropped something on the component. */
10316: public synchronized void drop(
10317: DropTargetDropEvent dropTargetDropEvent) {
10318: try {
10319: Transferable tr = dropTargetDropEvent.getTransferable();
10320: if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
10321: || ((uriListFlavor != null) && (tr
10322: .isDataFlavorSupported(uriListFlavor)))) {
10323: dropTargetDropEvent
10324: .acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
10325: java.util.List<File> fileList;
10326: if (tr
10327: .isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
10328: @SuppressWarnings("unchecked")
10329: java.util.List<File> data = (java.util.List<File>) tr
10330: .getTransferData(DataFlavor.javaFileListFlavor);
10331: fileList = data;
10332: } else {
10333: // work-around for Linux drag-and-drop
10334: // see Java bug 4899516
10335: @SuppressWarnings("unchecked")
10336: String data = (String) tr
10337: .getTransferData(uriListFlavor);
10338: fileList = textURIListToFileList(data);
10339: }
10340: java.util.Iterator<File> iterator = fileList.iterator();
10341: java.util.List<File> filteredFileList = new java.util.ArrayList<File>();
10342: while (iterator.hasNext()) {
10343: File file = (File) iterator.next();
10344: if ((file.isFile())
10345: && ((file.getName().endsWith(".java"))
10346: || (file.getName().endsWith(".dj0"))
10347: || (file.getName().endsWith(".dj1"))
10348: || (file.getName().endsWith(".dj2"))
10349: || (file.getName().endsWith(".dj0")) || (file
10350: .getName().endsWith(".txt")))) {
10351: filteredFileList.add(file);
10352: }
10353: }
10354: final File[] fileArray = filteredFileList
10355: .toArray(new File[filteredFileList.size()]);
10356: FileOpenSelector fs = new FileOpenSelector() {
10357: public File[] getFiles() {
10358: return fileArray;
10359: }
10360: };
10361: open(fs);
10362: dropTargetDropEvent.getDropTargetContext()
10363: .dropComplete(true);
10364: } else {
10365: dropTargetDropEvent.rejectDrop();
10366: }
10367: } catch (IOException ioe) {
10368: ioe.printStackTrace();
10369: dropTargetDropEvent.rejectDrop();
10370: } catch (UnsupportedFlavorException ufe) {
10371: ufe.printStackTrace();
10372: dropTargetDropEvent.rejectDrop();
10373: }
10374: }
10375:
10376: /**
10377: * Convert a string with URIs to a list of files.
10378: * @param data string with URIs
10379: * @return list of files
10380: */
10381: private static java.util.List<File> textURIListToFileList(
10382: String data) {
10383: java.util.List<File> list = new java.util.ArrayList<File>();
10384: java.util.StringTokenizer st = new java.util.StringTokenizer(
10385: data, "\r\n");
10386: while (st.hasMoreTokens()) {
10387: String s = st.nextToken();
10388: if (s.startsWith("#")) {
10389: // the line is a comment (as per the RFC 2483)
10390: continue;
10391: }
10392: try {
10393: java.net.URI uri = new java.net.URI(s);
10394: java.io.File file = new java.io.File(uri);
10395: list.add(file);
10396: } catch (java.net.URISyntaxException e) {
10397: // malformed URI
10398: } catch (IllegalArgumentException e) {
10399: // the URI is not a valid 'file:' URI
10400: }
10401: }
10402: return list;
10403: }
10404:
10405: /** Reset the position of the "Open Javadoc" dialog. */
10406: public void resetAutoImportDialogPosition() {
10407: initAutoImportDialog();
10408: _autoImportDialog.setFrameState("default");
10409: if (DrJava.getConfig().getSetting(
10410: DIALOG_AUTOIMPORT_STORE_POSITION).booleanValue()) {
10411: DrJava.getConfig().setSetting(DIALOG_AUTOIMPORT_STATE,
10412: "default");
10413: }
10414: }
10415:
10416: /** Initialize dialog if necessary. */
10417: void initAutoImportDialog() {
10418: if (_autoImportDialog == null) {
10419: _autoImportPackageCheckbox = new JCheckBox("Import Package");
10420: _autoImportPackageCheckbox
10421: .addActionListener(new ActionListener() {
10422: public void actionPerformed(ActionEvent e) {
10423: _autoImportDialog.resetFocus();
10424: }
10425: });
10426: _autoImportPackageCheckbox.setMnemonic('p');
10427: PredictiveInputFrame.InfoSupplier<JavaAPIListEntry> info = new PredictiveInputFrame.InfoSupplier<JavaAPIListEntry>() {
10428: public String apply(JavaAPIListEntry entry) {
10429: // show full class name as information
10430: return entry.getFullString();
10431: }
10432: };
10433: PredictiveInputFrame.CloseAction<JavaAPIListEntry> okAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() {
10434: public Object apply(
10435: PredictiveInputFrame<JavaAPIListEntry> p) {
10436: String text;
10437: if (p.getItem() != null) {
10438: // if a class was selected...
10439: text = p.getItem().getFullString();
10440: } else {
10441: // otherwise use the text that was entered
10442: text = p.getText();
10443: }
10444: if (_autoImportPackageCheckbox.isSelected()) {
10445: int lastDot = text.lastIndexOf('.');
10446: if (lastDot > 0) {
10447: text = text.substring(0, lastDot + 1) + "*";
10448: }
10449: }
10450: final InteractionsModel im = _model
10451: .getInteractionsModel();
10452: // get the last line (the one that caused the error)
10453: // and remove it from the history
10454: String lastLine = im.removeLastFromHistory();
10455: // import the selected class...
10456: String importLine = "import " + text
10457: + "; // auto-import";
10458: // ...and try to do the last line again
10459: final String code = importLine
10460: + ((lastLine != null) ? ("\n" + lastLine)
10461: : "");
10462: EventQueue.invokeLater(new Runnable() {
10463: public void run() {
10464: // interpret with the added import
10465: im.append(code,
10466: InteractionsDocument.DEFAULT_STYLE);
10467: im.interpretCurrentInteraction();
10468: hourglassOff();
10469: }
10470: });
10471: return null;
10472: }
10473: };
10474: PredictiveInputFrame.CloseAction<JavaAPIListEntry> cancelAction = new PredictiveInputFrame.CloseAction<JavaAPIListEntry>() {
10475: public Object apply(
10476: PredictiveInputFrame<JavaAPIListEntry> p) {
10477: // if no class was selected, do nothing
10478: // just reset the error information so the dialog box works next time
10479: _model.getInteractionsModel().resetLastErrors();
10480: hourglassOff();
10481: return null;
10482: }
10483: };
10484: java.util.ArrayList<PredictiveInputModel.MatchingStrategy<JavaAPIListEntry>> strategies = new java.util.ArrayList<PredictiveInputModel.MatchingStrategy<JavaAPIListEntry>>();
10485: strategies
10486: .add(new PredictiveInputModel.FragmentStrategy<JavaAPIListEntry>());
10487: strategies
10488: .add(new PredictiveInputModel.PrefixStrategy<JavaAPIListEntry>());
10489: strategies
10490: .add(new PredictiveInputModel.RegExStrategy<JavaAPIListEntry>());
10491: _autoImportDialog = new PredictiveInputFrame<JavaAPIListEntry>(
10492: MainFrame.this , "Auto Import Class",
10493: false, // force
10494: true, // ignore case
10495: info, strategies, okAction, cancelAction,
10496: new JavaAPIListEntry("dummy", "dummy", null)) {
10497: public void setOwnerEnabled(boolean b) {
10498: if (b) {
10499: hourglassOff();
10500: } else {
10501: hourglassOn();
10502: }
10503: }
10504:
10505: protected JComponent[] makeOptions() {
10506: return new JComponent[] { _autoImportPackageCheckbox };
10507: }
10508: };
10509: // putting one dummy entry in the list; it will be changed later anyway
10510:
10511: if (DrJava.getConfig().getSetting(
10512: DIALOG_AUTOIMPORT_STORE_POSITION).booleanValue()) {
10513: _autoImportDialog.setFrameState(DrJava.getConfig()
10514: .getSetting(DIALOG_AUTOIMPORT_STATE));
10515: }
10516: generateJavaAPIList();
10517: }
10518: }
10519:
10520: /** The "Auto Import" dialog instance. */
10521: PredictiveInputFrame<JavaAPIListEntry> _autoImportDialog = null;
10522: JCheckBox _autoImportPackageCheckbox;
10523:
10524: /** Imports a class. */
10525: void _showAutoImportDialog(String s) {
10526: generateJavaAPIList();
10527: if (_javaAPIList == null) {
10528: return;
10529: }
10530: List<JavaAPIListEntry> autoImportList = new ArrayList<JavaAPIListEntry>(
10531: _javaAPIList);
10532: if ((DrJava.getConfig().getSetting(
10533: DIALOG_COMPLETE_SCAN_CLASS_FILES).booleanValue())
10534: && (_autoImportClassList.size() > 0)) {
10535: autoImportList.addAll(_autoImportClassList);
10536: } else {
10537: File projectRoot = _model.getProjectRoot();
10538: List<OpenDefinitionsDocument> docs = _model
10539: .getOpenDefinitionsDocuments();
10540: if (docs != null) {
10541: for (OpenDefinitionsDocument d : docs) {
10542: if (d.isUntitled())
10543: continue;
10544: try {
10545: File rel = FileOps.makeRelativeTo(d
10546: .getRawFile(), projectRoot);
10547: String full = rel.toString().replace(
10548: java.io.File.separatorChar, '.');
10549: for (String ext : edu.rice.cs.drjava.model.compiler.CompilerModel.EXTENSIONS) {
10550: if (full.endsWith(ext)) {
10551: full = full.substring(0, full
10552: .lastIndexOf(ext));
10553: break;
10554: }
10555: }
10556: String simple = full;
10557: if (simple.lastIndexOf('.') >= 0) {
10558: simple = simple.substring(simple
10559: .lastIndexOf('.') + 1);
10560: }
10561: JavaAPIListEntry entry = new JavaAPIListEntry(
10562: simple, full, null);
10563: if (!autoImportList.contains(entry)) {
10564: autoImportList.add(entry);
10565: }
10566: } catch (IOException ioe) { /* ignore, just don't add this one */
10567: } catch (SecurityException se) { /* ignore, just don't add this one */
10568: }
10569: }
10570: }
10571: }
10572: PredictiveInputModel<JavaAPIListEntry> pim = new PredictiveInputModel<JavaAPIListEntry>(
10573: true,
10574: new PredictiveInputModel.PrefixStrategy<JavaAPIListEntry>(),
10575: autoImportList);
10576: pim.setMask(s);
10577: initAutoImportDialog();
10578: _autoImportDialog.setModel(true, pim); // ignore case
10579: hourglassOn();
10580: _autoImportPackageCheckbox.setSelected(false);
10581: _autoImportDialog.setVisible(true);
10582: }
10583: }
|