DefinitionsPane.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
edu.rice.cs.drjava.ui |
![]() |
![]() |
DrJava |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
| Metric | Description | |
|---|---|---|
/*BEGIN_COPYRIGHT_BLOCK
*
* Copyright (c) 2001-2008, JavaPLT group at Rice University (drjava@rice.edu)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software is Open Source Initiative approved Open Source Software.
* Open Source Initative Approved is a trademark of the Open Source Initiative.
*
* This file is part of DrJava. Download the current version of this project
* from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
*
* END_COPYRIGHT_BLOCK*/
package edu.rice.cs.drjava.ui;
import javax.swing.*;
import javax.swing.undo.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.LinkedList;
// TODO: Check synchronization.
import edu.rice.cs.plt.tuple.Pair;
import edu.rice.cs.util.UnexpectedException;
import edu.rice.cs.util.OperationCanceledException;
import edu.rice.cs.util.swing.HighlightManager;
import edu.rice.cs.util.swing.RightClickMouseAdapter;
import edu.rice.cs.util.text.SwingDocument;
import edu.rice.cs.drjava.model.*;
import edu.rice.cs.drjava.model.definitions.CompoundUndoManager;
import edu.rice.cs.drjava.model.definitions.DefinitionsEditorKit;
import edu.rice.cs.drjava.model.definitions.NoSuchDocumentException;
import edu.rice.cs.drjava.model.definitions.indent.Indenter;
import edu.rice.cs.drjava.model.definitions.reducedmodel.ReducedModelState;
import edu.rice.cs.drjava.config.*;
import edu.rice.cs.drjava.DrJava;
import edu.rice.cs.drjava.CodeStatus;
import edu.rice.cs.drjava.model.debug.Breakpoint;
import static edu.rice.cs.drjava.model.definitions.reducedmodel.ReducedModelStates.*;
/** The pane in which work on a given OpenDefinitionsDocument occurs. A DefinitionsPane is tied to a single document,
* which cannot be changed.
* @version $Id: DefinitionsPane.java 4629 2008-08-01 22:37:12Z rcartwright $
*/
public class DefinitionsPane extends AbstractDJPane implements Finalizable<DefinitionsPane> {
/** This field NEEDS to be set by setEditorKit() BEFORE any DefinitonsPanes are created. */
private static DefinitionsEditorKit EDITOR_KIT;
/* Minimum number of characters to trigger indent warning prompt */
private static int INDENT_WARNING_THRESHOLD = 200000;
/** Our parent window. */
private final MainFrame _mainFrame;
/** Our corresponding ODD */
private final OpenDefinitionsDocument _doc;
private volatile UndoAction _undoAction;
private volatile RedoAction _redoAction;
private volatile boolean testVariable; //For Tests ONLY
// private Document _defdoc;
/** Flag used to determine if the user has already been warned about debugging when the document within
* this defpane has been modified since its last save.
*/
private volatile boolean _hasWarnedAboutModified = false;
// /** Used by the centering source mechanism to ensure paints */
// private boolean _updatePending = false;
/** Whether to draw text as antialiased. */
private volatile boolean _antiAliasText = false;
/** Our current compiler error matching highlight. */
private volatile HighlightManager.HighlightInfo _errorHighlightTag = null;
/** Highlight painter for bookmarks. */
static volatile ReverseHighlighter.DefaultUnderlineHighlightPainter BOOKMARK_PAINTER =
new ReverseHighlighter.DefaultUnderlineHighlightPainter(DrJava.getConfig().getSetting(BOOKMARK_COLOR), 3);
/** Highlight painter for find results.
* Keep in mind that, while the array is volatile, the elements inside of it are not! */
static volatile LayeredHighlighter.LayerPainter[] FIND_RESULTS_PAINTERS;
static {
FIND_RESULTS_PAINTERS = new LayeredHighlighter.LayerPainter[FIND_RESULTS_COLORS.length+1];
for(int i = 0; i < FIND_RESULTS_COLORS.length; ++i) {
FIND_RESULTS_PAINTERS[i] =
new ReverseHighlighter.DefaultFrameHighlightPainter(DrJava.getConfig().getSetting(FIND_RESULTS_COLORS[i]), 2);
}
FIND_RESULTS_PAINTERS[FIND_RESULTS_COLORS.length] =
new ReverseHighlighter.DefaultUnderlineHighlightPainter(Color.WHITE, 0);
}
/** How many find result panels are using the highlight painters.
* Keep in mind that, while the array is volatile, the elements inside of it are not! */
static volatile int[] FIND_RESULTS_PAINTERS_USAGE = new int[FIND_RESULTS_COLORS.length];
/** Highlight painter for breakpoints. */
static ReverseHighlighter.DrJavaHighlightPainter BREAKPOINT_PAINTER =
new ReverseHighlighter.DrJavaHighlightPainter(DrJava.getConfig().getSetting(DEBUG_BREAKPOINT_COLOR));
/** Highlight painter for disabled breakpoints. */
static volatile ReverseHighlighter.DrJavaHighlightPainter DISABLED_BREAKPOINT_PAINTER =
new ReverseHighlighter.DrJavaHighlightPainter(DrJava.getConfig().getSetting(DEBUG_BREAKPOINT_DISABLED_COLOR));
/** Highlight painter for thread's current location. */
static volatile ReverseHighlighter.DrJavaHighlightPainter THREAD_PAINTER =
new ReverseHighlighter.DrJavaHighlightPainter(DrJava.getConfig().getSetting(DEBUG_THREAD_COLOR));
/** The name of the keymap added to the super class (saved so it can be removed). */
public static final String INDENT_KEYMAP_NAME = "INDENT_KEYMAP";
/** Updates match highlights. Only runs in the event thread except in some unit tests. */
protected void matchUpdate(int offset) {
_doc.setCurrentLocation(offset);
_removePreviousHighlight();
// Update the highlight if there is any. Not necessarily executed in event thread
int to = getCaretPosition();
int from = _doc._balanceBackward();
if (from > -1) {
// Found a matching open brace to this close brace
from = to - from;
_addHighlight(from, to);
// Highlighter.Highlight[] _lites = getHighlighter().getHighlights();
String matchText = _matchText(from);
if (matchText != null) _mainFrame.updateStatusField("Bracket matches: " + matchText);
else updateStatusField();
}
// if this wasn't a close brace, check for an open brace
else {
// (getCaretPosition will be the start of the highlight)
from = to;
to = _doc._balanceForward();
if (to > -1) {
to = to + from;
_addHighlight(from - 1, to);
// Highlighter.Highlight[] _lites = getHighlighter().getHighlights();
}
updateStatusField();
}
}
/** Updates status fields in the main frame (title bar, selected file name) when document is modified. */
protected void updateStatusField() { _mainFrame.updateStatusField(); }
/* Returns the text of the line where a matching open brace exists whenever the cursor is at a closing brace */
private String _matchText(int braceIndex) {
DJDocument doc = _doc;
String docText;
docText = doc.getText();
char ch = docText.charAt(braceIndex);
if ( ch == '{' || ch == '(') { //match everything before if we found a curly brace
Character charBefore = null;
int charBeforeIndex = braceIndex-1;
boolean previousLine = false;
if (charBeforeIndex != -1) charBefore = docText.charAt(charBeforeIndex);
charBeforeIndex--;
while (charBeforeIndex >= 0 && (charBefore == '\n' || charBefore == ' ')) {
charBefore = docText.charAt(charBeforeIndex);
if (!previousLine && charBefore != '\n' && charBefore != ' ') charBeforeIndex = braceIndex-1;
if (charBefore == '\n') previousLine = true;
charBeforeIndex--;
}
final StringBuilder returnText = new StringBuilder(docText.substring(0, charBeforeIndex+2));
if (previousLine) returnText.append("...");
returnText.append(ch);
int lastNewlineIndex = returnText.lastIndexOf("\n");
return returnText.substring(lastNewlineIndex+1);
}
else //not a curly brace
return null;
}
/** The OptionListener for DEFINITIONS_MATCH_COLOR. */
private class MatchColorOptionListener implements OptionListener<Color> {
public void optionChanged(OptionEvent<Color> oce) {
MATCH_PAINTER = new ReverseHighlighter.DrJavaHighlightPainter(oce.value);
if (_matchHighlight != null) {
int start = _matchHighlight.getStartOffset();
int end = _matchHighlight.getEndOffset();
_matchHighlight.remove();
_addHighlight(start, end);
}
}
}
/** The OptionListener for COMPILER_ERROR_COLOR. */
private class ErrorColorOptionListener implements OptionListener<Color> {
public void optionChanged(OptionEvent<Color> oce) {
ERROR_PAINTER = new ReverseHighlighter.DrJavaHighlightPainter(oce.value);
if (_errorHighlightTag != null) {
int start = _errorHighlightTag.getStartOffset();
int end = _errorHighlightTag.getEndOffset();
_errorHighlightTag.remove();
addErrorHighlight(start, end);
}
}
}
/** The OptionListener for BOOKMARK_COLOR. */
private class BookmarkColorOptionListener implements OptionListener<Color> {
public void optionChanged(OptionEvent<Color> oce) {
BOOKMARK_PAINTER = new ReverseHighlighter.DefaultUnderlineHighlightPainter(oce.value, BOOKMARK_PAINTER.getThickness());
_mainFrame.refreshBookmarkHighlightPainter();
}
}
/** The OptionListener for FIND_RESULTS_COLOR. */
private static class FindResultsColorOptionListener implements OptionListener<Color> {
private int _index;
public FindResultsColorOptionListener(int i) { _index = i; }
public void optionChanged(OptionEvent<Color> oce) {
synchronized(FIND_RESULTS_PAINTERS) {
FIND_RESULTS_PAINTERS[_index] = new ReverseHighlighter.DefaultFrameHighlightPainter(oce.value, 2);
}
}
}
/** The OptionListener for DEBUG_BREAKPOINT_COLOR. */
private class BreakpointColorOptionListener implements OptionListener<Color> {
public void optionChanged(OptionEvent<Color> oce) {
BREAKPOINT_PAINTER = new ReverseHighlighter.DrJavaHighlightPainter(oce.value);
_mainFrame.refreshBreakpointHighlightPainter();
}
}
/** The OptionListener for DEBUG_BREAKPOINT_DISABLED_COLOR. */
private class DisabledBreakpointColorOptionListener implements OptionListener<Color> {
public void optionChanged(OptionEvent<Color> oce) {
DISABLED_BREAKPOINT_PAINTER = new ReverseHighlighter.DrJavaHighlightPainter(oce.value);
_mainFrame.refreshBreakpointHighlightPainter();
}
}
/** The OptionListener for DEBUG_THREAD_COLOR. */
private static class ThreadColorOptionListener implements OptionListener<Color> {
public void optionChanged(OptionEvent<Color> oce) {
THREAD_PAINTER = new ReverseHighlighter.DrJavaHighlightPainter(oce.value);
}
}
/** The OptionListener for TEXT_ANTIALIAS. */
private class AntiAliasOptionListener implements OptionListener<Boolean> {
public void optionChanged(OptionEvent<Boolean> oce) {
_antiAliasText = oce.value.booleanValue();
DefinitionsPane.this.repaint();
}
}
/** Listens to any undoable events in the document, and adds them to the undo manager. Must be done in the view
* because the edits are stored along with the caret position at the time of the edit. Correction: document
* cursor position should be used instead of caret position. Perhaps this listener shoud be attached to the
* document.
*/
private final UndoableEditListener _undoListener = new UndoableEditListener() {
/** The function to handle what happens when an UndoableEditEvent occurs.
* @param e
*/
public void undoableEditHappened(UndoableEditEvent e) {
// UndoWithPosition undo = new UndoWithPosition(e.getEdit(), _doc.getCurrentLocation());
UndoableEdit undo = e.getEdit();
if (! _inCompoundEdit) {
CompoundUndoManager undoMan = _doc.getUndoManager();
_inCompoundEdit = true;
_compoundEditKey = undoMan.startCompoundEdit();
getUndoAction().updateUndoState();
getRedoAction().updateRedoState();
}
_doc.getUndoManager().addEdit(undo);
getRedoAction().setEnabled(false);
}
};
/** The menu item for the "Toggle Breakpoint" option. Stored in field so that it may be enabled and
* disabled depending on Debug Mode.
*/
private volatile JMenuItem _toggleBreakpointMenuItem;
// /** The menu item for the "Add Watch" option. Stored in field so that it may be enabled and
// * disabled depending on Debug Mode.
// */
// private JMenuItem _addWatchMenuItem;
/** The contextual popup menu for the Definitions Pane. */
private volatile JPopupMenu _popMenu;
/** The mouse adapter for handling a popup menu. */
private volatile PopupMenuMouseAdapter _popupMenuMA;
/** Listens to caret to highlight errors as appropriate. */
private volatile ErrorCaretListener _errorListener;
private volatile ActionListener _setSizeListener = null;
/** An action to handle indentation spawned by pressing the tab key. */
private class IndentKeyActionTab extends AbstractAction {
/** Handle the key typed event from the text field. */
public void actionPerformed(ActionEvent e) {
// The following commented out code was moved into the indent() method
//int pos = getCaretPosition();
//_doc().setCurrentLocation(pos);
_mainFrame.hourglassOn();
try {
indent();
} finally {
_mainFrame.hourglassOff();
}
}
}
/** Used for indent action spawned by pressing the enter key, '{', or '}'. */
private class IndentKeyAction extends AbstractAction {
/** The key string ("\n"|"{"|"}") for the key pressed that invokes this
* instance. Not used currently, but there for readability and possible
* future use, e.g., debugging add-ons or the rewrite of the indention code.
*/
private final String _key;
/** The default action to take when the specified key is pressed. */
private final Action _defaultAction;
/** Whether to perform the indent if the caret is in a String or comment. */
private final boolean _indentNonCode;
/** Creates an IndentKeyAction which only invokes indent if the caret is in code, and not Strings or
* comments.
*/
IndentKeyAction(String key, Action defaultAction) {
this(key, defaultAction, false);
}
/** Creates a new IndentKeyAction with the specified parameters.
* @param key name of the key, for debugging purposes
* @param defaultAction action to perform in addition to indenting
* @param indentNonCode whether to indent Strings and comments
*/
IndentKeyAction(String key, Action defaultAction, boolean indentNonCode) {
_key = key;
_defaultAction = defaultAction;
_indentNonCode = indentNonCode;
}
/** This method tells what the reason should be for spawning this indent event
* Defaults to Indenter.IndentReason.OTHER
*/
protected Indenter.IndentReason getIndentReason() { return Indenter.IndentReason.OTHER; }
/** Handle the "key typed" event from the text field. Calls the default action to make sure the right things
* happen, then makes a call to indentLine().
*/
public void actionPerformed(ActionEvent e) {
_defaultAction.actionPerformed(e);
// Only indent if in code
_doc.setCurrentLocation(getCaretPosition());
ReducedModelState state = _doc._getStateAtCurrent();
if (state.equals(FREE) || _indentNonCode) indent(getIndentReason());
}
}
/** Special action to take care of case when tab key is pressed. */
private volatile Action _indentKeyActionTab = new IndentKeyActionTab();
/** Because the "default" action for the enter key is special, it must be
* grabbed from the Keymap using getAction(KeyStroke), which returns the
* "default" action for all keys which have behavior extending beyond
* regular text keys.
*/
private final Action _indentKeyActionLine =
new IndentKeyAction("\n", (Action) getActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)),
true /* indent non-code, too */ ) {
/* overriding this method is important so that pressing the enter key causes
* different indentation than pressing other keys, for bug 681203
*/
protected Indenter.IndentReason getIndentReason() { return Indenter.IndentReason.ENTER_KEY_PRESS; }
};
/** Likewise, regular text keys like '{', '}', and ':' do not have special actions that are returned by
* getAction(KeyStroke). To make sure these behave right, we use getDefaultAction() instead.
*/
private final Action _indentKeyActionCurly = new IndentKeyAction("}", getKeymap().getDefaultAction());
private final Action _indentKeyActionOpenCurly = new IndentKeyAction("{", getKeymap().getDefaultAction());
private final Action _indentKeyActionColon = new IndentKeyAction(":", getKeymap().getDefaultAction());
/** Tells us whether we currently are in the middle of a CompoundEdit for regular keystrokes.
* Helps us with granular undo.
*/
public volatile boolean _inCompoundEdit = false;
private volatile int _compoundEditKey;
/** Our keymap containing key bindings. Takes precedence over the default map. */
final Keymap ourMap;
/** Standard Constructor. Sets up all the defaults.
* @param mf the parent window
*/
public DefinitionsPane(MainFrame mf, final OpenDefinitionsDocument doc) {
super(new SwingDocument());
_mainFrame = mf;
addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
_mainFrame.getModel().getDocumentNavigator().requestSelectionUpdate(doc);
}
});
_doc = doc; // NOTE: _doc is final
// read the initial selection/scrolling values from the document
// to be set when the pane is first notified active
_selStart = _doc.getInitialSelectionStart();
_selEnd = _doc.getInitialSelectionEnd();
_savedVScroll = _doc.getInitialVerticalScroll();
_savedHScroll = _doc.getInitialHorizontalScroll();
//super.setDocument(NULL_DOCUMENT);
_resetUndo();
Font mainFont = DrJava.getConfig().getSetting(FONT_MAIN);
setFont(mainFont);
setEditable(true);
// add actions for indent key
ourMap = addKeymap(INDENT_KEYMAP_NAME, getKeymap());
ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), _indentKeyActionLine);
ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), _indentKeyActionTab);
ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke('}'), _indentKeyActionCurly);
ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke('{'), _indentKeyActionOpenCurly);
ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke(':'), _indentKeyActionColon);
setKeymap(ourMap);
// Keymap map = ourMap;
// KeyStroke[] ks;
// ks = ourMap.getBoundKeyStrokes();
// for (KeyStroke k:ks) {
// System.out.println(k);
// }
// ourMap = ourMap.getResolveParent();
// ks = ourMap.getBoundKeyStrokes();
// for (KeyStroke k:ks) {
// System.out.println(k);
// }
// this.setEditorKit(new StyledEditorKit());
_antiAliasText = DrJava.getConfig().getSetting(TEXT_ANTIALIAS).booleanValue();
OptionListener<Color> temp;
Pair<Option<Color>, OptionListener<Color>> pair;
// Setup the color listeners. NOTE: the Foreground/Background listeners add themselves to DrJava.getConfig()
// in their own constructors. Rather than refactor it, we decided to work with that design decision.
temp = new ForegroundColorListener(this);
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEFINITIONS_NORMAL_COLOR, temp);
_colorOptionListeners.add(pair);
temp = new BackgroundColorListener(this);
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEFINITIONS_BACKGROUND_COLOR, temp);
_colorOptionListeners.add(pair);
// These listeners do not register themselves in their own constructors. We do.
temp = new MatchColorOptionListener();
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEFINITIONS_MATCH_COLOR, temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener(OptionConstants.DEFINITIONS_MATCH_COLOR, temp);
temp = new ErrorColorOptionListener();
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.COMPILER_ERROR_COLOR, temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener(OptionConstants.COMPILER_ERROR_COLOR, temp);
temp = new BookmarkColorOptionListener();
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.BOOKMARK_COLOR, temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener(OptionConstants.BOOKMARK_COLOR, temp);
for (int i=0; i<FIND_RESULTS_COLORS.length; ++i) {
temp = new FindResultsColorOptionListener(i);
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.FIND_RESULTS_COLORS[i], temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener(OptionConstants.FIND_RESULTS_COLORS[i], temp);
}
temp = new BreakpointColorOptionListener();
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEBUG_BREAKPOINT_COLOR, temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener(OptionConstants.DEBUG_BREAKPOINT_COLOR, temp);
temp = new DisabledBreakpointColorOptionListener();
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEBUG_BREAKPOINT_DISABLED_COLOR, temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener( OptionConstants.DEBUG_BREAKPOINT_DISABLED_COLOR, temp);
temp = new ThreadColorOptionListener();
pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEBUG_THREAD_COLOR, temp);
_colorOptionListeners.add(pair);
DrJava.getConfig().addOptionListener( OptionConstants.DEBUG_THREAD_COLOR, temp);
OptionListener<Boolean> aaTemp = new AntiAliasOptionListener();
Pair<Option<Boolean>, OptionListener<Boolean>> aaPair = new Pair<Option<Boolean>, OptionListener<Boolean>>(OptionConstants.TEXT_ANTIALIAS, aaTemp);
_booleanOptionListeners.add(aaPair);
DrJava.getConfig().addOptionListener( OptionConstants.TEXT_ANTIALIAS, aaTemp);
createPopupMenu();
//Add listener to components that can bring up popup menus.
_popupMenuMA = new PopupMenuMouseAdapter();
this.addMouseListener(_popupMenuMA);
this.setHighlighter(new ReverseHighlighter());
_highlightManager = new HighlightManager(this);
int rate = this.getCaret().getBlinkRate();
// Change the caret to one that doesn't remove selection highlighting when focus is lost.
// Fixes bug #788295 "No highlight when find/replace switches docs".
this.setCaret(new DefaultCaret() {
public void focusLost(FocusEvent e) { setVisible(false); }
});
this.getCaret().setBlinkRate(rate);
// Utilities.showDebug("DP constructor finished");
}
/** Ends a compound edit.*/
public void endCompoundEdit() {
if (_inCompoundEdit) {
CompoundUndoManager undoMan = _doc.getUndoManager();
_inCompoundEdit = false;
undoMan.endCompoundEdit(_compoundEditKey);
}
}
/** Takes in any keyboard input, checks to see if it is in the keyToActionMap in KeybindingManager, if so
* executes the action, otherwise checks if it contains the current platform's menu shortcut modifier and
* if so, ignores that command (this disallows the execution of the UI's default actions such as
* cut/copy/paste/select all), otherwise does whatever normally would be done.
*/
public void processKeyEvent(KeyEvent e) {
if (_mainFrame.getAllowKeyEvents()) {
KeyStroke ks = KeyStroke.getKeyStrokeForEvent(e);
Action a = KeyBindingManager.ONLY.get(ks);
// Don't perform the action if the keystroke is NULL_KEYSTROKE (generated by some Windows keys)
if ((ks != KeyStrokeOption.NULL_KEYSTROKE) && (a != null)) {
// System.out.println("Keystroke was null");
endCompoundEdit();
// Performs the action a
SwingUtilities.notifyAction(a, ks, e, e.getSource(), e.getModifiers());
// Make sure we don't consume it again
e.consume();
}
else {
// Allows one step undoing of the keystrokes defined on the keymap (e.g. enter, tab, '{', '}', ':').
Keymap km = getKeymap();
if (km.isLocallyDefined(ks) || km.isLocallyDefined(KeyStroke.getKeyStroke(ks.getKeyChar()))) {
// We're breaking up compound edits at the granularity of "enter"'s.
if (e.getKeyCode() == KeyEvent.VK_ENTER) endCompoundEdit();
// CompoundUndoManager undoMan = _doc.getUndoManager();
// int key = undoMan.startCompoundEdit();
// System.out.println("supering 1 " + isAltF4);
super.processKeyEvent(e);
// We call endCompoundEdit() here because one will automatically start when processKeyEvent finishes
// (see the definition of _undoListener).
endCompoundEdit();
// undoMan.endCompoundEdit(key); //commented out because of frenchkeyboard fix
// e.consume();
}
else {
// The following conditional fixes bug #676586 by ignoring typed events when the meta key is down and fixes
// bug #905405 "Undo Alt+Anything Causes Exception" by ignoring typed events when the alt key is down.
// NOTE: no longer need to check for alt since we now only start a new compound edit if an undoable edit
// actually happened.
if ((e.getModifiers() & InputEvent.META_MASK) != 0
// || ((e.getModifiers() & InputEvent.ALT_MASK) != 0)) // omitted for frenchkeyboard support
&& e.getKeyCode() == KeyEvent.VK_UNDEFINED) {
// System.out.println("not supering 1 " + isAltF4);
return;
}
// The following conditional fixes ease of use issue 693253 by checking if a typed event is
// shift-delete or shift-backspace and then performing a delete or backspace operation,
// respectively
if ((e.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
int newModifiers = e.getModifiers() & ~(InputEvent.SHIFT_MASK);
KeyStroke newKs = KeyStroke.getKeyStroke(ks.getKeyCode(), newModifiers, ks.isOnKeyRelease());
String name = KeyBindingManager.ONLY.getName(newKs);
if (name != null && (name.equals("Delete Previous") || name.equals("Delete Next"))) {
endCompoundEdit();
// We are unsure about the third and fourth arguments (e and e.getSource()); we simply
// reuse the original values
SwingUtilities.notifyAction(KeyBindingManager.ONLY.get(newKs), newKs, e, e.getSource(), newModifiers);
e.consume();
// System.out.println("not supering 2 " + isAltF4);
return;
}
}
/* If the KeyEvent is not a pressed event, process it before we do granular undo or _inCompoundEdit may
* get set incorrectly. This code breaks Alt-F4, and may break other system keybindings since the event
* is consumed by us. */
if (e.getID() != KeyEvent.KEY_TYPED) {
super.processKeyEvent(e);
return;
}
}
// This if statement is for tests only
if ((e.getModifiers() & InputEvent.ALT_MASK) != 0) testVariable = true; // ALT_MASK actually pressed
else testVariable = false;
super.processKeyEvent(e);
}
}
}
/** Sets the editor kit that will be used by all DefinitionsPanes.
* @param editorKit The editor kit to use for new DefinitionsPanes.
*/
public static void setEditorKit(DefinitionsEditorKit editorKit) { EDITOR_KIT = editorKit; }
/** Enable anti-aliased text by overriding paintComponent. */
protected void paintComponent(Graphics g) {
if (_antiAliasText && g instanceof Graphics2D) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
super.paintComponent(g);
}
/** Creates the popup menu for the DefinitionsPane. */
private void createPopupMenu() {
// Create the popup menu.
_popMenu = new JPopupMenu();
_popMenu.add(_mainFrame.cutAction);
_popMenu.add(_mainFrame.copyAction);
_popMenu.add(_mainFrame.pasteAction);
_popMenu.addSeparator();
JMenuItem indentItem = new JMenuItem("Indent Line(s)");
indentItem.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
_mainFrame.hourglassOn();
try {
indent();
} finally {
_mainFrame.hourglassOff();
}
}
});
_popMenu.add(indentItem);
JMenuItem commentLinesItem = new JMenuItem("Comment Line(s)");
commentLinesItem.addActionListener(new AbstractAction() {
public void actionPerformed( ActionEvent ae) {
_mainFrame.hourglassOn();
try{
_doc.setCurrentLocation(getCaretPosition());
_commentLines();
}
finally{ _mainFrame.hourglassOff(); }
}
});
_popMenu.add(commentLinesItem);
JMenuItem uncommentLinesItem = new JMenuItem("Uncomment Line(s)");
uncommentLinesItem.addActionListener ( new AbstractAction() {
public void actionPerformed( ActionEvent ae) {
_doc.setCurrentLocation(getCaretPosition());
_uncommentLines();
}
});
_popMenu.add(uncommentLinesItem);
/* Go to this file... */
_popMenu.addSeparator();
JMenuItem gotoFileUnderCursorItem = new JMenuItem("Go to File Under Cursor");
gotoFileUnderCursorItem.addActionListener ( new AbstractAction() {
public void actionPerformed( ActionEvent ae) {
_doc.setCurrentLocation(getCaretPosition());
_mainFrame._gotoFileUnderCursor();
}
});
_popMenu.add(gotoFileUnderCursorItem);
/* Toggle bookmark */
JMenuItem toggleBookmarkItem = new JMenuItem("Toggle Bookmark");
toggleBookmarkItem.addActionListener ( new AbstractAction() {
/** Toggle the selected line as a bookmark. Only runs in event thread. */
public void actionPerformed( ActionEvent ae) {
// Same menu command has the same effect as KEY_BOOKMARKS_TOGGLE
_mainFrame.toggleBookmark();
}
});
_popMenu.add(toggleBookmarkItem);
if (_mainFrame.getModel().getDebugger().isAvailable()) {
_popMenu.addSeparator();
// Breakpoint
JMenuItem breakpointItem = new JMenuItem("Toggle Breakpoint");
breakpointItem.addActionListener( new AbstractAction() {
public void actionPerformed( ActionEvent ae ) {
// Make sure that the breakpoint is set on the *clicked* line, if within a selection block.
setCaretPosition(viewToModel(_popupMenuMA.getLastMouseClick().getPoint()));
_mainFrame.debuggerToggleBreakpoint();
}
});
_toggleBreakpointMenuItem = _popMenu.add(breakpointItem);
}
}
/* The private MouseAdapter for responding to various clicks concerning the popup menu */
private class PopupMenuMouseAdapter extends RightClickMouseAdapter {
private MouseEvent _lastMouseClick = null;
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
_lastMouseClick = e;
endCompoundEdit();
// if not in the selected area,
/*if ((viewToModel(e.getPoint()) < getSelectionStart()) ||
(viewToModel(e.getPoint()) > getSelectionEnd()) ) {
//move caret to clicked position, deselecting previous selection
setCaretPosition(viewToModel(e.getPoint()));
}*/
}
protected void _popupAction(MouseEvent e) {
requestFocusInWindow();
_popMenu.show(e.getComponent(), e.getX(), e.getY());
}
public MouseEvent getLastMouseClick() { return _lastMouseClick; }
}
/** Comments out the lines contained within the given selection. */
private void _commentLines() {
_mainFrame.commentLines();
// _doc.commentLinesInDefinitions(getSelectionStart(), getSelectionEnd());
}
/** Uncomments the lines contained within the given selection. */
private void _uncommentLines() {
_mainFrame.uncommentLines();
// _doc.uncommentLinesInDefinitions(getSelectionStart(), getSelectionEnd());
}
/** @return the undo action. */
public UndoAction getUndoAction() { return _undoAction; }
/** @return the redo action. */
public RedoAction getRedoAction() { return _redoAction; }
/** Get the OpenDefinitionsDocument contained in this DefinitionsPane. */
public OpenDefinitionsDocument getOpenDefDocument() { return _doc; }
/** Get the DJDocument (OpenDefinitionsDocument) contained in this pane.
* Required by the super class AbstractDJPane.
*/
public DJDocument getDJDocument() { return _doc; }
/** Access to the pane's HighlightManager */
public HighlightManager getHighlightManager() { return _highlightManager; }
/** Set the caret position and also scroll to make sure the location is visible. Should only run in the event
* thread.
* @param pos Location to scroll to.
*/
public void setPositionAndScroll(int pos) {
assert EventQueue.isDispatchThread();
try {
setCaretPos(pos);
scrollRectToVisible(modelToView(pos));
}
catch (BadLocationException ble) { throw new UnexpectedException(ble); }
}
/** Override JEditorPane's setDocument to make sure only the Document in our final OpenDefinitionsDocument
* can be used.
*/
public void setDocument(Document d) {
if (_doc != null) { // When can _doc be null?
if ((d == null) || (!d.equals(_doc))) {
throw new IllegalStateException("Cannot set the document of a DefinitionsPane to a different document.");
}
}
super.setDocument(d); // If _doc is null should we do this?
}
public boolean checkAltKey() { // For tests only
return testVariable;
}
/** Add a ErrorCaretListener to this pane, keeping it accessible so its error model can be updated later. */
public void addErrorCaretListener(ErrorCaretListener listener) {
_errorListener = listener;
addCaretListener(listener);
}
/** Gets the ErrorCaretListener for this pane. */
public ErrorCaretListener getErrorCaretListener() { return _errorListener; }
/** Switches the location of the error highlight in the document if there was one. Otherwise adds the
* highlight. The invariant is that there are zero or one error highlights at any time.
*/
public void addErrorHighlight(int from, int to) {
removeErrorHighlight();
_errorHighlightTag = _highlightManager.addHighlight(from, to, ERROR_PAINTER);
}
/** Removes the previous compiler error highlight from the document after the cursor has moved. */
public void removeErrorHighlight() {
if (_errorHighlightTag != null) {
_errorHighlightTag.remove();
_errorHighlightTag = null;
}
}
public boolean hasWarnedAboutModified() { return _hasWarnedAboutModified; }
public void hasWarnedAboutModified( boolean hasWarned) {
_hasWarnedAboutModified = hasWarned;
}
public void addBreakpointHighlight( Breakpoint bp ) { }
public void removeBreakpointHighlight( Breakpoint bp) { }
/** This instance of the scroll pane is here in order to allow for the definitions pane to save the
* horizontal and vertical scroll
*/
private volatile JScrollPane _scrollPane;
public void setScrollPane(JScrollPane s) { _scrollPane = s; }
/** Used to save the caret position, selection, and scroll when setting the definitions pane to be inactive */
private volatile int _savedVScroll;
private volatile int _savedHScroll;
private volatile int _position;
private volatile int _selStart;
private volatile int _selEnd;
/** This function is called when the active document is changed. this function is called on the pane that is
* replaced by the new active pane. It allows the pane to "shutdown" when not in use. Currently, this procedure
* replaces the Definitions Document with a blank dummy document to help conserve memory (so that the pane will
* not be holding onto the last reference of a definitions document not allowing it to be garbage collected)
*/
public void notifyInactive() {
// we catch a NoSuchDocumentException here because during a close/closeAll
// the model closes the definitions document before the MainFrame switches
// out the panes. If this is the case, then the following code does not
// need to be run.
try {
// Sync caret with location before switching
getOpenDefDocument().setCurrentLocation(getCaretPosition());
// Remove any error highlighting in the old def pane
removeErrorHighlight();
_position = _doc.getCurrentLocation();
_selStart = super.getSelectionStart();
_selEnd = super.getSelectionEnd();
_savedVScroll = _scrollPane.getVerticalScrollBar().getValue();
_savedHScroll = _scrollPane.getHorizontalScrollBar().getValue();
super.setDocument(NULL_DOCUMENT);
}
catch(NoSuchDocumentException e) {
// This exception was just thrown because the document was just
// closed and so this pane will soon be garbage collected.
// We don't need to do any more cleanup.
}
}
/** This function is called when switching a pane to be the active document pane. It allows the pane to do whatever
* "startUp" is required. Since setInactive swapped out the document for a dummy document, we need to reload the
* actual document and reset its caret position to the saved location. Only runs in event thread.
*/
public void notifyActive() {
assert ! _mainFrame.isVisible() || EventQueue.isDispatchThread();
super.setDocument(_doc);
if (_doc.getUndoableEditListeners().length == 0) _resetUndo();
int len = _doc.getLength();
if (len < _position || len < _selEnd) {
// the document changed since we're set inactive
//so set selection to be none
_position = len;
_selStart = len;
_selEnd = len;
}
if (_position == _selStart) {
setCaretPosition(_selEnd);
moveCaretPosition(_selStart);
_doc.setCurrentLocation(_selStart);
}
else {
setCaretPosition(_selStart);
moveCaretPosition(_selEnd);
_doc.setCurrentLocation(_selEnd);
}
_scrollPane.getVerticalScrollBar().setValue(_savedVScroll);
_scrollPane.getHorizontalScrollBar().setValue(_savedHScroll);
// Explicitly set scrollbar policies fixing bug #1445898
_scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
_scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
// if the pane is inactive, use the state stored in the fields, otherwise use the super method
public int getSelectionStart() {
if (getDocument() == NULL_DOCUMENT) return _selStart;
else return super.getSelectionStart();
}
public int getSelectionEnd() {
if (getDocument() == NULL_DOCUMENT) return _selEnd;
else return super.getSelectionEnd();
}
public int getVerticalScroll() {
if (getDocument() == NULL_DOCUMENT) return _savedVScroll;
else return _scrollPane.getVerticalScrollBar().getValue();
}
public int getHorizontalScroll() {
if (getDocument() == NULL_DOCUMENT) return _savedHScroll;
else return _scrollPane.getHorizontalScrollBar().getValue();
}
/** Returns the current line of the definitions pane. This is a 1-based number.
* @return current line of the definitions pane, >=1 */
public int getCurrentLine() { return _doc.getLineOfOffset(getCaretPosition())+1; }
// try {
// int pos = getCaretPosition();
// FontMetrics metrics = getFontMetrics(getFont());
// Rectangle startRect = modelToView(pos);
// if (startRect == null) return 1;
// //top left position is (3,3), so font size<=6 will be off
// return (new Double (startRect.getY() / metrics.getHeight()).intValue() + 1);
// } catch (BadLocationException e) {
// // This shouldnt happen b/c we retrieve the caret pos before calling modelToView
// throw new UnexpectedException(e);
// }
// }
/** Determines current line using logic in DefinitionsDocument. Does it differ from getCurrentLine()? */
public int getCurrentLinefromDoc() { return _doc.getCurrentLine(); }
public int getCurrentCol() { return _doc.getCurrentCol(); }
public void setSize(int width, int height) {
super.setSize(width, height);
if (_setSizeListener != null) _setSizeListener.actionPerformed(null);
}
// public void addSetSizeListener(ActionListener listener) { _setSizeListener = listener; }
// public void removeSetSizeListener() { _setSizeListener = null; }
/** Centers the view (pane) on the specified offset. */
public void centerViewOnOffset(int offset) {
assert EventQueue.isDispatchThread();
try {
FontMetrics metrics = getFontMetrics(getFont());
JViewport defViewPort = _mainFrame.getDefViewport();
double viewWidth = defViewPort.getWidth();
double viewHeight = defViewPort.getHeight();
// Scroll to make sure this item is visible
// Centers the selection in the viewport
Rectangle startRect;
startRect = modelToView(offset);
if (startRect != null) {
int startRectX = (int) startRect.getX();
int startRectY = (int) startRect.getY();
startRect.setLocation(startRectX - (int)(viewWidth*.5), startRectY - (int)(viewHeight*.5));
Point endPoint = new Point(startRectX + (int)(viewWidth*.5),
startRectY + (int)(viewHeight*.5) + metrics.getHeight()/2);
// Add the end rect onto the start rect to make a rectangle
// that encompasses the entire selection
startRect.add(endPoint);
scrollRectToVisible(startRect);
}
// removeSetSizeListener(); // Why? None was added
setCaretPos(offset);
}
catch (BadLocationException e) { throw new UnexpectedException(e); }
}
public void centerViewOnLine(int lineNumber) {
FontMetrics metrics = getFontMetrics(getFont());
Point p = new Point(0, metrics.getHeight() * (lineNumber));
int offset = this.viewToModel(p);
this.centerViewOnOffset(offset);
}
/** This method overrides a broken version in JTextComponent. It allows selection to proceed backwards as well as
* forwards. If selection is backwards, then the caret ends up at the start of the selection rather than the end.
*/
public void select(int selectionStart, int selectionEnd) {
setCaretPosition(selectionStart);
moveCaretPosition(selectionEnd); // What about the caret position in the reduced model? It is updated by a listener.
}
/** Reset the document Undo list. */
public void resetUndo() {
_doc.getUndoManager().discardAllEdits();
_undoAction.updateUndoState();
_redoAction.updateRedoState();
}
/** Reset the document Undo list. */
private void _resetUndo() {
if (_undoAction == null) _undoAction = new UndoAction();
if (_redoAction == null) _redoAction = new RedoAction();
_doc.resetUndoManager();
getDocument().addUndoableEditListener(_undoListener);
_undoAction.updateUndoState();
_redoAction.updateRedoState();
}
/** Overriding this method ensures that all new documents created in this editor pane use our editor
* kit (and thus our model).
*/
protected EditorKit createDefaultEditorKit() {
//return _editorKit;
return EDITOR_KIT;
}
/** Prompts the user whether or not they wish to indent, if the selection size is very large.
* @return true if the indent is to be completed
* @param selStart - the selection start
* @param selEnd - the selection end
*/
protected boolean shouldIndent(int selStart, int selEnd) {
if (selEnd > (selStart + INDENT_WARNING_THRESHOLD)) {
Object[] options = {"Yes", "No"};
int n = JOptionPane.showOptionDialog
(_mainFrame,
"Re-indenting this block may take a long time. Are you sure?",
"Confirm Re-indent",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[1]);
switch (n) {
case JOptionPane.CANCEL_OPTION:
case JOptionPane.CLOSED_OPTION:
case JOptionPane.NO_OPTION:
return false;
default:
return true;
}
}
return true;
}
/** Indent the given selection, for the given reason, in the current document.
* @param selStart - the selection start
* @param selEnd - the selection end
* @param reason - the reason for the indent
* @param pm - the ProgressMonitor used by the indenter
*/
protected void indentLines(int selStart, int selEnd, Indenter.IndentReason reason, ProgressMonitor pm) {
//_mainFrame.hourglassOn();
// final int key = _doc.getUndoManager().startCompoundEdit(); //Commented out in regards to French KeyBoard Fix
try {
_doc.indentLines(selStart, selEnd, reason, pm);
endCompoundEdit();
setCaretPosition(_doc.getCurrentLocation()); // redundant?
}
catch(OperationCanceledException oce) {
// if canceled, undo the indent; but first, end compound edit
endCompoundEdit();
_doc.getUndoManager().undo();
// pm = null, so cancel can't be pressed
throw new UnexpectedException(oce);
}
}
/** Saved option listeners kept in this field so they can be removed for garbage collection */
private List<Pair<Option<Color>, OptionListener<Color>>> _colorOptionListeners =
new LinkedList<Pair<Option<Color>, OptionListener<Color>>>();
private List<Pair<Option<Boolean>, OptionListener<Boolean>>> _booleanOptionListeners =
new LinkedList<Pair<Option<Boolean>, OptionListener<Boolean>>>();
/** Called when the definitions pane is released from duty. This frees up any option listeners that are holding
* references to this object so this can be garbage collected.
*/
public void close() {
for (Pair<Option<Color>, OptionListener<Color>> p: _colorOptionListeners) {
DrJava.getConfig().removeOptionListener(p.first(), p.second());
}
for (Pair<Option<Boolean>, OptionListener<Boolean>> p: _booleanOptionListeners) {
DrJava.getConfig().removeOptionListener(p.first(), p.second());
}
_colorOptionListeners.clear();
_booleanOptionListeners.clear();
ourMap.removeBindings();
removeKeymap(ourMap.getName());
_popMenu.removeAll();
}
/** The undo action. */
public class UndoAction extends AbstractAction {
/** Constructor. */
private UndoAction() {
super("Undo");
setEnabled(false);
}
/** What to do when user chooses to undo.
* @param e
*/
public void actionPerformed(ActionEvent e) {
try {
// UndoableEdit edit = _doc.getNextUndo();
// int pos = -1;
// if (edit != null && edit instanceof UndoWithPosition) {
// pos = ((UndoWithPosition)edit).getPosition();
// }
//
// if (pos > -1) {
// //centerViewOnOffset(pos);
// setCaretPosition(pos);
// }
_doc.getUndoManager().undo();
_doc.updateModifiedSinceSave();
_mainFrame.updateStatusField();
}
catch (CannotUndoException ex) {
throw new UnexpectedException(ex);
}
updateUndoState();
_redoAction.updateRedoState();
}
/** Updates the undo list, i.e., where we are as regards undo and redo. */
protected void updateUndoState() {
if (_doc.undoManagerCanUndo()) {
setEnabled(true);
putValue(Action.NAME, _doc.getUndoManager().getUndoPresentationName());
}
else {
setEnabled(false);
putValue(Action.NAME, "Undo");
}
}
}
/** Redo action. */
public class RedoAction extends AbstractAction {
/** Constructor. */
private RedoAction() {
super("Redo");
setEnabled(false);
}
/** In the event that the user chooses to redo something, this is what's called.
* @param e
*/
public void actionPerformed(ActionEvent e) {
try {
// UndoableEdit edit = _doc.getNextRedo();
// int pos = -1;
// if (edit instanceof UndoWithPosition) {
// pos = ((UndoWithPosition)edit).getPosition();
// }
_doc.getUndoManager().redo();
// if (pos > -1) {
// //centerViewOnOffset(pos);
// setCaretPosition(pos);
// }
_doc.updateModifiedSinceSave();
_mainFrame.updateStatusField();
} catch (CannotRedoException ex) {
throw new UnexpectedException(ex);
}
updateRedoState();
_undoAction.updateUndoState();
}
/** Updates the redo state, i.e., where we are as regards undo and redo. */
protected void updateRedoState() {
if (_doc.undoManagerCanRedo()) {
setEnabled(true);
putValue(Action.NAME, _doc.getUndoManager().getRedoPresentationName());
}
else {
setEnabled(false);
putValue(Action.NAME, "Redo");
}
}
}
// /** Wrapper for UndoableEdit that pairs UndoableEdits with their caret positions */
// private class UndoWithPosition implements UndoableEdit {
// private final UndoableEdit _undo;
// private final int _pos;
//
// public UndoWithPosition(UndoableEdit undo, int pos) {
// _undo = undo;
// _pos = pos;
// }
//
// public int getPosition() { return _pos; }
// public boolean addEdit(UndoableEdit ue) { return _undo.addEdit(ue); }
// public boolean canRedo() { return _undo.canRedo(); }
// public boolean canUndo() { return _undo.canUndo(); }
// public void die() { _undo.die(); }
// public String getPresentationName() { return _undo.getPresentationName(); }
// public String getUndoPresentationName() { return _undo.getUndoPresentationName(); }
// public String getRedoPresentationName() { return _undo.getRedoPresentationName(); }
// public boolean isSignificant() { return _undo.isSignificant(); }
//
// public void redo() {
// _undo.redo();
// if (_pos > -1) {
// _doc.setCurrentLocation(_pos); // probably unnecessary
// setCaretPosition(_pos);
// }
// }
//
// public boolean replaceEdit(UndoableEdit ue) { return _undo.replaceEdit(ue); }
//
// public void undo() {
// if (_pos > -1) {
// _doc.setCurrentLocation(_pos);
// setCaretPosition(_pos);
// }
// _undo.undo();
// }
// }
/** This list of listeners to notify when we are finalized */
private List<FinalizationListener<DefinitionsPane>> _finalizationListeners =
new LinkedList<FinalizationListener<DefinitionsPane>>();
/** Registers a finalization listener with the specific instance of the ddoc. NOTE: this should only be used by test
* cases. This policy ensures that we don't spring memory leaks by allowing our unit tests to keep track of
* whether objects are being finalized (garbage collected).
* @param fl the listener to register
*/
public void addFinalizationListener(FinalizationListener<DefinitionsPane> fl) { _finalizationListeners.add(fl); }
public List<FinalizationListener<DefinitionsPane>> getFinalizationListeners() { return _finalizationListeners; }
/** This method is called when this object becomes unreachable. Since this class implements
* edu.rice.cs.drjava.model.Finalizable, it must notify its listeners.
*/
protected void finalize() {
FinalizationEvent<DefinitionsPane> fe = new FinalizationEvent<DefinitionsPane>(this);
for (FinalizationListener<DefinitionsPane> fl: _finalizationListeners) fl.finalized(fe);
}
}
The table below shows all metrics for DefinitionsPane.java.
| Metric | Value | Description | |
|---|---|---|---|



