KickJava   Java API By Example, From Geeks To Geeks.

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


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

33
34 package edu.rice.cs.drjava.ui;
35
36 import javax.swing.*;
37 import javax.swing.undo.*;
38 import javax.swing.event.*;
39 import javax.swing.text.*;
40 import java.awt.*;
41 import java.awt.event.*;
42 import java.util.List JavaDoc;
43 import java.util.LinkedList JavaDoc;
44
45 // TODO: Check synchronization.
46
import edu.rice.cs.plt.tuple.Pair;
47 import edu.rice.cs.util.UnexpectedException;
48 import edu.rice.cs.util.OperationCanceledException;
49 import edu.rice.cs.util.swing.HighlightManager;
50 import edu.rice.cs.util.swing.RightClickMouseAdapter;
51 import edu.rice.cs.util.text.SwingDocument;
52 import edu.rice.cs.drjava.model.*;
53 import edu.rice.cs.drjava.model.definitions.CompoundUndoManager;
54 import edu.rice.cs.drjava.model.definitions.DefinitionsEditorKit;
55 import edu.rice.cs.drjava.model.definitions.NoSuchDocumentException;
56 import edu.rice.cs.drjava.model.definitions.indent.Indenter;
57 import edu.rice.cs.drjava.model.definitions.reducedmodel.ReducedModelState;
58 import edu.rice.cs.drjava.config.*;
59 import edu.rice.cs.drjava.DrJava;
60 import edu.rice.cs.drjava.CodeStatus;
61 import edu.rice.cs.drjava.model.debug.Breakpoint;
62
63 /** The pane in which work on a given OpenDefinitionsDocument occurs. A DefinitionsPane is tied to a single document,
64  * which cannot be changed.
65  * @version $Id: DefinitionsPane.java 4057 2007-01-16 00:06:10Z dlsmith $
66  */

67 public class DefinitionsPane extends AbstractDJPane implements Finalizable<DefinitionsPane> {
68
69   /** This field NEEDS to be set by setEditorKit() BEFORE any DefinitonsPanes are created. */
70   private static DefinitionsEditorKit EDITOR_KIT;
71   
72   /* Minimum number of characters to trigger indent warning prompt */
73   private static int INDENT_WARNING_THRESHOLD = 20000;
74     
75   /** Our parent window. */
76   private final MainFrame _mainFrame;
77   /** Our corresponding ODD */
78   private final OpenDefinitionsDocument _doc;
79   
80   private volatile UndoAction _undoAction;
81   private volatile RedoAction _redoAction;
82   private volatile boolean testVariable; //For Tests ONLY
83
// private Document _defdoc;
84

85   /** Flag used to determine if the user has already been warned about debugging when the document within
86    * this defpane has been modified since its last save.
87    */

88   private volatile boolean _hasWarnedAboutModified = false;
89
90 // /** Used by the centering source mechanism to ensure paints */
91
// private boolean _updatePending = false;
92

93   /** Whether to draw text as antialiased. */
94   private volatile boolean _antiAliasText = false;
95
96   /** Our current compiler error matching highlight. */
97   private volatile HighlightManager.HighlightInfo _errorHighlightTag = null;
98
99   /** Highlight painter for bookmarks. */
100   static volatile ReverseHighlighter.DefaultUnderlineHighlightPainter BOOKMARK_PAINTER =
101     new ReverseHighlighter.DefaultUnderlineHighlightPainter(DrJava.getConfig().getSetting(BOOKMARK_COLOR), 3);
102
103   /** Highlight painter for find results. */
104   static volatile ReverseHighlighter.DefaultUnderlineHighlightPainter[] FIND_RESULTS_PAINTERS;
105   
106   static {
107     FIND_RESULTS_PAINTERS = new ReverseHighlighter.DefaultUnderlineHighlightPainter[FIND_RESULTS_COLORS.length+1];
108     for(int i = 0; i < FIND_RESULTS_COLORS.length; ++i) {
109       FIND_RESULTS_PAINTERS[i] =
110         new ReverseHighlighter.DefaultUnderlineHighlightPainter(DrJava.getConfig().getSetting(FIND_RESULTS_COLORS[i]), 3);
111     }
112     FIND_RESULTS_PAINTERS[FIND_RESULTS_COLORS.length] =
113         new ReverseHighlighter.DefaultUnderlineHighlightPainter(Color.WHITE, 0);
114   }
115   
116   /** How many find result panels are using the highlight painters. */
117   static volatile int[] FIND_RESULTS_PAINTERS_USAGE = new int[FIND_RESULTS_COLORS.length];
118
119   /** Highlight painter for breakpoints. */
120   static ReverseHighlighter.DefaultHighlightPainter BREAKPOINT_PAINTER =
121     new ReverseHighlighter.DefaultHighlightPainter(DrJava.getConfig().getSetting(DEBUG_BREAKPOINT_COLOR));
122
123   /** Highlight painter for disabled breakpoints. */
124   static volatile ReverseHighlighter.DefaultHighlightPainter DISABLED_BREAKPOINT_PAINTER =
125     new ReverseHighlighter.DefaultHighlightPainter(DrJava.getConfig().getSetting(DEBUG_BREAKPOINT_DISABLED_COLOR));
126
127   /** Highlight painter for thread's current location. */
128   static volatile ReverseHighlighter.DefaultHighlightPainter THREAD_PAINTER =
129     new ReverseHighlighter.DefaultHighlightPainter(DrJava.getConfig().getSetting(DEBUG_THREAD_COLOR));
130
131   /** The name of the keymap added to the super class (saved so it can be removed). */
132   public static final String JavaDoc INDENT_KEYMAP_NAME = "INDENT_KEYMAP";
133
134   /** Updates the highlight if there is any. Not necessarily executed in event thread. */
135   protected void _updateMatchHighlight() {
136     int to = getCaretPosition();
137     int from = _doc.balanceBackward(); //_doc()._reduced.balanceBackward();
138
if (from > -1) {
139       // Found a matching open brace to this close brace
140
from = to - from;
141       _addHighlight(from, to);
142       // Highlighter.Highlight[] _lites = getHighlighter().getHighlights();
143

144       String JavaDoc matchText = _matchText(from);
145       
146       if (matchText != null) _mainFrame.updateFileTitle("Matches: " + matchText);
147       else _mainFrame.updateFileTitle();
148     }
149     
150     // if this wasn't a close brace, check for an open brace
151
else {
152       // (getCaretPosition will be the start of the highlight)
153
from = to;
154
155       to = _doc.balanceForward();
156       if (to > -1) {
157         to = to + from;
158         _addHighlight(from - 1, to);
159 // Highlighter.Highlight[] _lites = getHighlighter().getHighlights();
160
}
161       _mainFrame.updateFileTitle();
162     }
163   }
164   
165   /* Returns the text of the line where a matching open brace exists whenever the cursor is at a closing brace */
166   private String JavaDoc _matchText(int braceIndex) {
167     DJDocument doc = _doc;
168     String JavaDoc docText;
169     docText = doc.getText();
170    
171     if (docText.charAt(braceIndex) == '{') {//match everything before if we found a curly brace
172
Character JavaDoc charBefore = null;
173       int charBeforeIndex = braceIndex-1;
174       boolean previousLine = false;
175       
176       if (charBeforeIndex != -1) charBefore = docText.charAt(charBeforeIndex);
177       
178       charBeforeIndex--;
179       
180       while (charBeforeIndex >= 0 && (charBefore == '\n' || charBefore == ' ')) {
181         charBefore = docText.charAt(charBeforeIndex);
182         if (!previousLine && charBefore != '\n' && charBefore != ' ') charBeforeIndex = braceIndex-1;
183         if (charBefore == '\n') previousLine = true;
184         charBeforeIndex--;
185       }
186       
187       final StringBuilder JavaDoc returnText = new StringBuilder JavaDoc(docText.substring(0, charBeforeIndex+2));
188       if (previousLine) returnText.append("...");
189       returnText.append("{");
190       
191       int lastNewLineIndex = returnText.lastIndexOf("\n");
192       return returnText.substring(lastNewLineIndex+1);
193     }
194     else //not a curly brace
195
return null;
196   }
197     
198   /** The OptionListener for DEFINITIONS_MATCH_COLOR. */
199   private class MatchColorOptionListener implements OptionListener<Color> {
200     public void optionChanged(OptionEvent<Color> oce) {
201       MATCH_PAINTER = new ReverseHighlighter.DefaultHighlightPainter(oce.value);
202       if (_matchHighlight != null) {
203         int start = _matchHighlight.getStartOffset();
204         int end = _matchHighlight.getEndOffset();
205         _matchHighlight.remove();
206         _addHighlight(start, end);
207       }
208     }
209   }
210
211   /** The OptionListener for COMPILER_ERROR_COLOR. */
212   private class ErrorColorOptionListener implements OptionListener<Color> {
213     public void optionChanged(OptionEvent<Color> oce) {
214       ERROR_PAINTER = new ReverseHighlighter.DefaultHighlightPainter(oce.value);
215       if (_errorHighlightTag != null) {
216         int start = _errorHighlightTag.getStartOffset();
217         int end = _errorHighlightTag.getEndOffset();
218         _errorHighlightTag.remove();
219         addErrorHighlight(start, end);
220       }
221     }
222   }
223
224   /** The OptionListener for BOOKMARK_COLOR. */
225   private class BookmarkColorOptionListener implements OptionListener<Color> {
226     public void optionChanged(OptionEvent<Color> oce) {
227       BOOKMARK_PAINTER = new ReverseHighlighter.DefaultUnderlineHighlightPainter(oce.value, BOOKMARK_PAINTER.getThickness());
228       _mainFrame.refreshBookmarkHighlightPainter();
229     }
230   }
231
232   /** The OptionListener for FIND_RESULTS_COLOR. */
233   private class FindResultsColorOptionListener implements OptionListener<Color> {
234     private int _index;
235     public FindResultsColorOptionListener(int i) { _index = i; }
236     public void optionChanged(OptionEvent<Color> oce) {
237       FIND_RESULTS_PAINTERS[_index] =
238         new ReverseHighlighter.DefaultUnderlineHighlightPainter(oce.value, FIND_RESULTS_PAINTERS[_index].getThickness());
239     }
240   }
241
242   /** The OptionListener for DEBUG_BREAKPOINT_COLOR. */
243   private class BreakpointColorOptionListener implements OptionListener<Color> {
244     public void optionChanged(OptionEvent<Color> oce) {
245       BREAKPOINT_PAINTER = new ReverseHighlighter.DefaultHighlightPainter(oce.value);
246       _mainFrame.refreshBreakpointHighlightPainter();
247     }
248   }
249
250   /** The OptionListener for DEBUG_BREAKPOINT_DISABLED_COLOR. */
251   private class DisabledBreakpointColorOptionListener implements OptionListener<Color> {
252     public void optionChanged(OptionEvent<Color> oce) {
253       DISABLED_BREAKPOINT_PAINTER = new ReverseHighlighter.DefaultHighlightPainter(oce.value);
254       _mainFrame.refreshBreakpointHighlightPainter();
255     }
256   }
257
258   /** The OptionListener for DEBUG_THREAD_COLOR. */
259   private static class ThreadColorOptionListener implements OptionListener<Color> {
260     public void optionChanged(OptionEvent<Color> oce) {
261       THREAD_PAINTER = new ReverseHighlighter.DefaultHighlightPainter(oce.value);
262     }
263   }
264
265   /** The OptionListener for TEXT_ANTIALIAS. */
266   private class AntiAliasOptionListener implements OptionListener<Boolean JavaDoc> {
267     public void optionChanged(OptionEvent<Boolean JavaDoc> oce) {
268       _antiAliasText = oce.value.booleanValue();
269       DefinitionsPane.this.repaint();
270     }
271   }
272
273   /** Listens to any undoable events in the document, and adds them to the undo manager. Must be done in the view
274     * because the edits are stored along with the caret position at the time of the edit.
275     */

276   private final UndoableEditListener _undoListener = new UndoableEditListener() {
277     
278     /** The function to handle what happens when an UndoableEditEvent occurs.
279      * @param e
280      */

281     public void undoableEditHappened(UndoableEditEvent e) {
282       UndoWithPosition undo = new UndoWithPosition(e.getEdit(), getCaretPosition());
283       if (!_inCompoundEdit) {
284         CompoundUndoManager undoMan = _doc.getUndoManager();
285         _inCompoundEdit = true;
286         _compoundEditKey = undoMan.startCompoundEdit();
287         getUndoAction().updateUndoState();
288         getRedoAction().updateRedoState();
289       }
290       _doc.getUndoManager().addEdit(undo);
291       getRedoAction().setEnabled(false);
292     }
293   };
294
295   /** The menu item for the "Toggle Breakpoint" option. Stored in field so that it may be enabled and
296    * disabled depending on Debug Mode.
297    */

298   private volatile JMenuItem _toggleBreakpointMenuItem;
299
300 // /** The menu item for the "Add Watch" option. Stored in field so that it may be enabled and
301
// * disabled depending on Debug Mode.
302
// */
303
// private JMenuItem _addWatchMenuItem;
304

305   /** The contextual popup menu for the Definitions Pane. */
306   private volatile JPopupMenu _popMenu;
307
308   /** The mouse adapter for handling a popup menu. */
309   private volatile PopupMenuMouseAdapter _popupMenuMA;
310
311   /** Listens to caret to highlight errors as appropriate. */
312   private volatile ErrorCaretListener _errorListener;
313
314   private volatile ActionListener _setSizeListener = null;
315
316   /** An action to handle indentation spawned by pressing the tab key. */
317   private class IndentKeyActionTab extends AbstractAction {
318     
319     /** Handle the key typed event from the text field. */
320     public void actionPerformed(ActionEvent e) {
321       // The following commented out code was moved into the indent() method
322
//int pos = getCaretPosition();
323
//_doc().setCurrentLocation(pos);
324
indent();
325     }
326   }
327
328   /** Used for indent action spawned by pressing the enter key, '{', or '}'. */
329   private class IndentKeyAction extends AbstractAction {
330     
331     /** The key string ("\n"|"{"|"}") for the key pressed that invokes this
332      * instance. Not used currently, but there for readability and possible
333      * future use, e.g., debugging add-ons or the rewrite of the indention code.
334      */

335     private final String JavaDoc _key;
336
337     /** The default action to take when the specified key is pressed. */
338     private final Action _defaultAction;
339
340     /** Whether to perform the indent if the caret is in a String or comment. */
341     private final boolean _indentNonCode;
342
343     /** Creates an IndentKeyAction which only invokes indent if the caret is in code, and not Strings or
344      * comments.
345      */

346     IndentKeyAction(String JavaDoc key, Action defaultAction) {
347       this(key, defaultAction, false);
348     }
349
350     /** Creates a new IndentKeyAction with the specified parameters.
351      * @param key name of the key, for debugging purposes
352      * @param defaultAction action to perform in addition to indenting
353      * @param indentNonCode whether to indent Strings and comments
354      */

355     IndentKeyAction(String JavaDoc key, Action defaultAction, boolean indentNonCode) {
356       _key = key;
357       _defaultAction = defaultAction;
358       _indentNonCode = indentNonCode;
359     }
360
361     /** This method tells what the reason should be for spawning this indent event
362      * Defaults to Indenter.OTHER
363      */

364     protected int getIndentReason() { return Indenter.OTHER; }
365
366     /** Handle the "key typed" event from the text field. Calls the default action to make sure the right things
367      * happen, then makes a call to indentLine().
368      */

369     public void actionPerformed(ActionEvent e) {
370       _defaultAction.actionPerformed(e);
371       
372       // Only indent if in code
373

374       _doc.setCurrentLocation(getCaretPosition());
375       ReducedModelState state = _doc.getStateAtCurrent();
376       if (state.equals(ReducedModelState.FREE) || _indentNonCode) indent(getIndentReason());
377     }
378   }
379
380   /** Special action to take care of case when tab key is pressed. */
381   private volatile Action _indentKeyActionTab = new IndentKeyActionTab();
382
383   /** Because the "default" action for the enter key is special, it must be
384    * grabbed from the Keymap using getAction(KeyStroke), which returns the
385    * "default" action for all keys which have behavior extending beyond
386    * regular text keys.
387    */

388   private final Action _indentKeyActionLine =
389     new IndentKeyAction("\n", (Action) getActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)),
390                         true /* indent non-code, too */ ) {
391     /* overriding this method is important so that pressing the enter key causes
392      * different indentation than pressing other keys, for bug 681203
393      */

394     protected int getIndentReason() { return Indenter.ENTER_KEY_PRESS; }
395   };
396
397   /** Likewise, regular text keys like '{', '}', and ':' do not have special actions that are returned by
398    * getAction(KeyStroke). To make sure these behave right, we use getDefaultAction() instead.
399    */

400   private final Action _indentKeyActionSquiggly = new IndentKeyAction("}", getKeymap().getDefaultAction());
401   private final Action _indentKeyActionOpenSquiggly = new IndentKeyAction("{", getKeymap().getDefaultAction());
402   private final Action _indentKeyActionColon = new IndentKeyAction(":", getKeymap().getDefaultAction());
403
404   /** Tells us whether we currently are in the middle of a CompoundEdit for regular keystrokes.
405    * Helps us with granular undo.
406    */

407   private volatile boolean _inCompoundEdit = false;
408   private volatile int _compoundEditKey;
409
410   /** Our keymap containing key bindings. Takes precedence over the default map. */
411   final Keymap ourMap;
412   
413   /** Standard Constructor. Sets up all the defaults.
414    * @param mf the parent window
415    */

416   public DefinitionsPane(MainFrame mf, final OpenDefinitionsDocument doc) {
417     super(new SwingDocument());
418     
419     _mainFrame = mf;
420     
421     addFocusListener(new FocusListener() {
422       public void focusGained(FocusEvent e) {
423         _mainFrame.getModel().getDocumentNavigator().requestSelectionUpdate(doc);
424       }
425       public void focusLost(FocusEvent e) { }
426     });
427     
428     _doc = doc; // NOTE: _doc is final
429

430     // read the initial selection/scrolling values from the document
431
// to be set when the pane is first notified active
432
_selStart = _doc.getInitialSelectionStart();
433     _selEnd = _doc.getInitialSelectionEnd();
434     _savedVScroll = _doc.getInitialVerticalScroll();
435     _savedHScroll = _doc.getInitialHorizontalScroll();
436     
437     //super.setDocument(NULL_DOCUMENT);
438
_resetUndo();
439     
440     Font mainFont = DrJava.getConfig().getSetting(FONT_MAIN);
441     setFont(mainFont);
442     
443     setEditable(true);
444     
445     // add actions for indent key
446
ourMap = addKeymap(INDENT_KEYMAP_NAME, getKeymap());
447     ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), _indentKeyActionLine);
448     ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), _indentKeyActionTab);
449     ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke('}'), _indentKeyActionSquiggly);
450     ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke('{'), _indentKeyActionOpenSquiggly);
451     ourMap.addActionForKeyStroke(KeyStroke.getKeyStroke(':'), _indentKeyActionColon);
452     setKeymap(ourMap);
453
454 // Keymap map = ourMap;
455
// KeyStroke[] ks;
456
// ks = ourMap.getBoundKeyStrokes();
457
// for (KeyStroke k:ks) {
458
// System.out.println(k);
459
// }
460
// ourMap = ourMap.getResolveParent();
461
// ks = ourMap.getBoundKeyStrokes();
462
// for (KeyStroke k:ks) {
463
// System.out.println(k);
464
// }
465

466 // this.setEditorKit(new StyledEditorKit());
467

468     if (CodeStatus.DEVELOPMENT) _antiAliasText = DrJava.getConfig().getSetting(TEXT_ANTIALIAS).booleanValue();
469
470     OptionListener<Color> temp;
471     Pair<Option<Color>, OptionListener<Color>> pair;
472       
473     // Setup the color listeners. NOTE: the Foreground/Background listeners add themselves to DrJava.getConfig()
474
// in their own constructors. Rather than refactor it, we decided to work with that design decision.
475
temp = new ForegroundColorListener(this);
476     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEFINITIONS_NORMAL_COLOR, temp);
477     _colorOptionListeners.add(pair);
478     
479     temp = new BackgroundColorListener(this);
480     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEFINITIONS_BACKGROUND_COLOR, temp);
481     _colorOptionListeners.add(pair);
482
483     // These listeners do not register themselves in their own constructors. We do.
484
temp = new MatchColorOptionListener();
485     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEFINITIONS_MATCH_COLOR, temp);
486     _colorOptionListeners.add(pair);
487     DrJava.getConfig().addOptionListener(OptionConstants.DEFINITIONS_MATCH_COLOR, temp);
488     
489     temp = new ErrorColorOptionListener();
490     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.COMPILER_ERROR_COLOR, temp);
491     _colorOptionListeners.add(pair);
492     DrJava.getConfig().addOptionListener(OptionConstants.COMPILER_ERROR_COLOR, temp);
493
494     temp = new BookmarkColorOptionListener();
495     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.BOOKMARK_COLOR, temp);
496     _colorOptionListeners.add(pair);
497     DrJava.getConfig().addOptionListener(OptionConstants.BOOKMARK_COLOR, temp);
498
499     for (int i=0; i<FIND_RESULTS_COLORS.length; ++i) {
500       temp = new FindResultsColorOptionListener(i);
501       pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.FIND_RESULTS_COLORS[i], temp);
502       _colorOptionListeners.add(pair);
503       DrJava.getConfig().addOptionListener(OptionConstants.FIND_RESULTS_COLORS[i], temp);
504     }
505     
506     temp = new BreakpointColorOptionListener();
507     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEBUG_BREAKPOINT_COLOR, temp);
508     _colorOptionListeners.add(pair);
509     DrJava.getConfig().addOptionListener(OptionConstants.DEBUG_BREAKPOINT_COLOR, temp);
510     
511     temp = new DisabledBreakpointColorOptionListener();
512     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEBUG_BREAKPOINT_DISABLED_COLOR, temp);
513     _colorOptionListeners.add(pair);
514     DrJava.getConfig().addOptionListener( OptionConstants.DEBUG_BREAKPOINT_DISABLED_COLOR, temp);
515     
516     temp = new ThreadColorOptionListener();
517     pair = new Pair<Option<Color>, OptionListener<Color>>(OptionConstants.DEBUG_THREAD_COLOR, temp);
518     _colorOptionListeners.add(pair);
519     DrJava.getConfig().addOptionListener( OptionConstants.DEBUG_THREAD_COLOR, temp);
520
521     if (CodeStatus.DEVELOPMENT) {
522       OptionListener<Boolean JavaDoc> aaTemp = new AntiAliasOptionListener();
523       Pair<Option<Boolean JavaDoc>, OptionListener<Boolean JavaDoc>> aaPair = new Pair<Option<Boolean JavaDoc>, OptionListener<Boolean JavaDoc>>(OptionConstants.TEXT_ANTIALIAS, aaTemp);
524       _booleanOptionListeners.add(aaPair);
525       DrJava.getConfig().addOptionListener( OptionConstants.TEXT_ANTIALIAS, aaTemp);
526     }
527
528     createPopupMenu();
529
530     //Add listener to components that can bring up popup menus.
531
_popupMenuMA = new PopupMenuMouseAdapter();
532     this.addMouseListener(_popupMenuMA);
533     this.setHighlighter(new ReverseHighlighter());
534     _highlightManager = new HighlightManager(this);
535
536     int rate = this.getCaret().getBlinkRate();
537     // Change the caret to one that doesn't remove selection highlighting when focus is lost.
538
// Fixes bug #788295 "No highlight when find/replace switches docs".
539
this.setCaret(new DefaultCaret() {
540       public void focusLost(FocusEvent e) { setVisible(false); }
541     });
542     this.getCaret().setBlinkRate(rate);
543 // Utilities.showDebug("DP constructor finished");
544
}
545   
546   /** Ends a compound edit.*/
547   public void endCompoundEdit() {
548     if (_inCompoundEdit) {
549       CompoundUndoManager undoMan = _doc.getUndoManager();
550       _inCompoundEdit = false;
551       undoMan.endCompoundEdit(_compoundEditKey);
552     }
553   }
554
555   /** Takes in any keyboard input, checks to see if it is in the keyToActionMap in KeybindingManager, if so
556    * executes the action, otherwise checks if it contains the current platform's menu shortcut modifier and
557    * if so, ignores that command (this disallows the execution of the UI's default actions such as
558    * cut/copy/paste/select all), otherwise does whatever normally would be done.
559    */

560   public void processKeyEvent(KeyEvent e) {
561     if (_mainFrame.getAllowKeyEvents()) {
562       KeyStroke ks = KeyStroke.getKeyStrokeForEvent(e);
563       Action a = KeyBindingManager.Singleton.get(ks);
564       // Don't perform the action if the keystroke is NULL_KEYSTROKE (generated by some Windows keys)
565
if ((ks != KeyStrokeOption.NULL_KEYSTROKE) && (a != null)) {
566 // System.out.println("Keystroke was null");
567
endCompoundEdit();
568         // Performs the action a
569
SwingUtilities.notifyAction(a, ks, e, e.getSource(), e.getModifiers());
570         
571         // Make sure we don't consume it again
572
e.consume();
573       }
574       else {
575         // Allows one step undoing of the keystrokes defined on the keymap (e.g. enter, tab, '{', '}', ':').
576
Keymap km = getKeymap();
577         
578         if (km.isLocallyDefined(ks) || km.isLocallyDefined(KeyStroke.getKeyStroke(ks.getKeyChar()))) {
579           // We're breaking up compound edits at the granularity of "enter"'s.
580
if (e.getKeyCode() == KeyEvent.VK_ENTER) endCompoundEdit();
581           
582           CompoundUndoManager undoMan = _doc.getUndoManager();
583 // int key = undoMan.startCompoundEdit();
584
// System.out.println("supering 1 " + isAltF4);
585

586           super.processKeyEvent(e);
587           // We call endCompoundEdit() here because one will automatically start when processKeyEvent finishes
588
// (see the definition of _undoListener).
589
endCompoundEdit();
590 // undoMan.endCompoundEdit(key); //commented out because of frenchkeyboard fix
591
// e.consume();
592
}
593         else {
594           
595           // The following conditional fixes bug #676586 by ignoring typed events when the meta key is down and fixes
596
// bug #905405 "Undo Alt+Anything Causes Exception" by ignoring typed events when the alt key is down.
597
// NOTE: no longer need to check for alt since we now only start a new compound edit if an undoable edit
598
// actually happened.
599
if ((e.getModifiers() & InputEvent.META_MASK) != 0
600                 // || ((e.getModifiers() & InputEvent.ALT_MASK) != 0)) // omitted for frenchkeyboard support
601
&& e.getKeyCode() == KeyEvent.VK_UNDEFINED) {
602             
603 // System.out.println("not supering 1 " + isAltF4);
604
return;
605           }
606           
607           // The following conditional fixes ease of use issue 693253 by checking if a typed event is
608
// shift-delete or shift-backspace and then performing a delete or backspace operation,
609
// respectively
610
if ((e.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
611             int newModifiers = e.getModifiers() & ~(InputEvent.SHIFT_MASK);
612             
613             KeyStroke newKs = KeyStroke.getKeyStroke(ks.getKeyCode(), newModifiers, ks.isOnKeyRelease());
614             String JavaDoc name = KeyBindingManager.Singleton.getName(newKs);
615             
616             if (name != null && (name.equals("Delete Previous") || name.equals("Delete Next"))) {
617               endCompoundEdit();
618               // We are unsure about the third and fourth arguments (e and e.getSource()); we simply
619
// reuse the original values
620
SwingUtilities.notifyAction(KeyBindingManager.Singleton.get(newKs), newKs, e, e.getSource(), newModifiers);
621               e.consume();
622               // System.out.println("not supering 2 " + isAltF4);
623
return;
624             }
625           }
626           
627           /* If the KeyEvent is not a pressed event, process it before we do granular undo or _inCompoundEdit may
628            * get set incorrectly. This code breaks Alt-F4, and may break other system keybindings since the event
629            * is consumed by us. */

630           if (e.getID() != KeyEvent.KEY_TYPED) {
631             super.processKeyEvent(e);
632             return;
633           }
634         }
635         // This if statement is for tests only
636
if ((e.getModifiers() & InputEvent.ALT_MASK) != 0) testVariable = true; // ALT_MASK actually pressed
637
else testVariable = false;
638         
639         super.processKeyEvent(e);
640       }
641     }
642   }
643
644   /** Sets the editor kit that will be used by all DefinitionsPanes.
645    * @param editorKit The editor kit to use for new DefinitionsPanes.
646    */

647   public static void setEditorKit(DefinitionsEditorKit editorKit) { EDITOR_KIT = editorKit; }
648
649   /** Enable anti-aliased text by overriding paintComponent. */
650   protected void paintComponent(Graphics g) {
651     if (CodeStatus.DEVELOPMENT) {
652       if (_antiAliasText && g instanceof Graphics2D) {
653         Graphics2D g2d = (Graphics2D)g;
654         g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
655       }
656     }
657     super.paintComponent(g);
658   }
659
660   /** Creates the popup menu for the DefinitionsPane. */
661   private void createPopupMenu() {
662     // Create the popup menu.
663
_popMenu = new JPopupMenu();
664
665     _popMenu.add(_mainFrame.cutAction);
666     _popMenu.add(_mainFrame.copyAction);
667     _popMenu.add(_mainFrame.pasteAction);
668     _popMenu.addSeparator();
669
670     JMenuItem indentItem = new JMenuItem("Indent Line(s)");
671     indentItem.addActionListener(new AbstractAction() {
672       public void actionPerformed(ActionEvent ae) { indent(); }
673     });
674     _popMenu.add(indentItem);
675
676     JMenuItem commentLinesItem = new JMenuItem("Comment Line(s)");
677     commentLinesItem.addActionListener(new AbstractAction() {
678       public void actionPerformed( ActionEvent ae) {
679         _mainFrame.hourglassOn();
680         try{
681           _doc.setCurrentLocation(getCaretPosition());
682           _commentLines();
683         }
684         finally{ _mainFrame.hourglassOff(); }
685       }
686     });
687     _popMenu.add(commentLinesItem);
688
689     JMenuItem uncommentLinesItem = new JMenuItem("Uncomment Line(s)");
690     uncommentLinesItem.addActionListener ( new AbstractAction() {
691       public void actionPerformed( ActionEvent ae) {
692         _doc.setCurrentLocation(getCaretPosition());
693         _uncommentLines();
694       }
695     });
696     _popMenu.add(uncommentLinesItem);
697
698     /* Go to this file... */
699     _popMenu.addSeparator();
700     JMenuItem gotoFileUnderCursorItem = new JMenuItem("Go to File Under Cursor");
701     gotoFileUnderCursorItem.addActionListener ( new AbstractAction() {
702       public void actionPerformed( ActionEvent ae) {
703         _doc.setCurrentLocation(getCaretPosition());
704         _mainFrame._gotoFileUnderCursor();
705       }
706     });
707     _popMenu.add(gotoFileUnderCursorItem);
708
709     /* Toggle bookmark */
710     JMenuItem toggleBookmarkItem = new JMenuItem("Toggle Bookmark");
711     toggleBookmarkItem.addActionListener ( new AbstractAction() {
712       public void actionPerformed( ActionEvent ae) {
713         if (getSelectionStart()==getSelectionEnd()) { // nothing selected
714
// Make sure that the breakpoint is set on the *clicked* line, if within a selection block.
715
setCaretPosition(viewToModel(_popupMenuMA.getLastMouseClick().getPoint()));
716         }
717         _mainFrame.toggleBookmark();
718       }
719     });
720     _popMenu.add(toggleBookmarkItem);
721       
722     if (_mainFrame.getModel().getDebugger().isAvailable()) {
723       _popMenu.addSeparator();
724
725       // Breakpoint
726
JMenuItem breakpointItem = new JMenuItem("Toggle Breakpoint");
727       breakpointItem.addActionListener( new AbstractAction() {
728         public void actionPerformed( ActionEvent ae ) {
729           // Make sure that the breakpoint is set on the *clicked* line, if within a selection block.
730
setCaretPosition(viewToModel(_popupMenuMA.getLastMouseClick().getPoint()));
731           _mainFrame.debuggerToggleBreakpoint();
732         }
733       });
734       _toggleBreakpointMenuItem = _popMenu.add(breakpointItem);
735     }
736   }
737
738   /* The private MouseAdapter for responding to various clicks concerning the popup menu */
739   private class PopupMenuMouseAdapter extends RightClickMouseAdapter {
740
741     private MouseEvent _lastMouseClick = null;
742
743     public void mousePressed(MouseEvent e) {
744       super.mousePressed(e);
745
746       _lastMouseClick = e;
747       endCompoundEdit();
748
749       // if not in the selected area,
750
if ((viewToModel(e.getPoint()) < getSelectionStart()) ||
751           (viewToModel(e.getPoint()) > getSelectionEnd()) ) {
752         //move caret to clicked position, deselecting previous selection
753
setCaretPosition(viewToModel(e.getPoint()));
754       }
755     }
756
757     protected void _popupAction(MouseEvent e) {
758       requestFocusInWindow();
759       _popMenu.show(e.getComponent(), e.getX(), e.getY());
760     }
761
762     public MouseEvent getLastMouseClick() { return _lastMouseClick; }
763   }
764
765   /** Comments out the lines contained within the given selection. */
766   private void _commentLines() {
767       _mainFrame.commentLines();
768 // _doc.commentLinesInDefinitions(getSelectionStart(), getSelectionEnd());
769
}
770
771   /** Uncomments the lines contained within the given selection. */
772   private void _uncommentLines() {
773     _mainFrame.uncommentLines();
774 // _doc.uncommentLinesInDefinitions(getSelectionStart(), getSelectionEnd());
775
}
776
777   /** @return the undo action. */
778   public UndoAction getUndoAction() { return _undoAction; }
779
780   /** @return the redo action. */
781   public RedoAction getRedoAction() { return _redoAction; }
782
783   /** Get the OpenDefinitionsDocument contained in this DefinitionsPane. */
784   public OpenDefinitionsDocument getOpenDefDocument() { return _doc; }
785   
786   /** Get the DJDocument (OpenDefinitionsDocument) contained in this pane.
787    * Required by the super class AbstractDJPane.
788    */

789   public DJDocument getDJDocument() { return _doc; }
790
791   /** Access to the pane's HighlightManager */
792   public HighlightManager getHighlightManager() { return _highlightManager; }
793
794   /** Set the caret position and also scroll to make sure the location is visible.
795    * @param pos Location to scroll to.
796    */

797   public void setPositionAndScroll(int pos) {
798     try {
799       setCaretPosition(pos);
800       scrollRectToVisible(modelToView(pos));
801     }
802     catch (BadLocationException ble) { throw new UnexpectedException(ble); }
803   }
804
805   /** Override JEditorPane's setDocument to make sure only the Document in our final OpenDefinitionsDocument
806    * can be used.
807    */

808   public void setDocument(Document d) {
809     if (_doc != null) { // When can _doc be null?
810
if ((d == null) || (!d.equals(_doc))) {
811         throw new IllegalStateException JavaDoc("Cannot set the document of a DefinitionsPane to a different document.");
812       }
813     }
814     super.setDocument(d); // If _doc is null should we do this?
815
}
816
817   public boolean checkAltKey() { // For tests only
818
return testVariable;
819   }
820   
821   /** Add a ErrorCaretListener to this pane, keeping it accessible so its error model can be updated later. */
822   public void addErrorCaretListener(ErrorCaretListener listener) {
823     _errorListener = listener;
824     addCaretListener(listener);
825   }
826
827   /** Gets the ErrorCaretListener for this pane. */
828   public ErrorCaretListener getErrorCaretListener() { return _errorListener; }
829
830   /** Switches the location of the error highlight in the document if there was one. Otherwise adds the
831    * highlight. The invariant is that there are zero or one error highlights at any time.
832    */

833   public void addErrorHighlight(int from, int to) {
834     removeErrorHighlight();
835     _errorHighlightTag = _highlightManager.addHighlight(from, to, ERROR_PAINTER);
836   }
837
838   /** Removes the previous compiler error highlight from the document after the cursor has moved. */
839   public void removeErrorHighlight() {
840     if (_errorHighlightTag != null) {
841       _errorHighlightTag.remove();
842       _errorHighlightTag = null;
843     }
844   }
845
846   public boolean hasWarnedAboutModified() { return _hasWarnedAboutModified; }
847
848   public void hasWarnedAboutModified( boolean hasWarned) {
849     _hasWarnedAboutModified = hasWarned;
850   }
851
852   public void addBreakpointHighlight( Breakpoint bp ) { }
853
854   public void removeBreakpointHighlight( Breakpoint bp) { }
855
856   /** This instance of the scroll pane is here in order to allow for the definitions pane to save the
857    * horizontal and vertical scroll
858    */

859   private volatile JScrollPane _scrollPane;
860   
861   public void setScrollPane(JScrollPane s) { _scrollPane = s; }
862   
863   /** Used to save the caret position, selection, and scroll when setting the definitions pane to be inactive */
864   private volatile int _savedVScroll;
865   private volatile int _savedHScroll;
866   private volatile int _position;
867   private volatile int _selStart;
868   private volatile int _selEnd;
869   
870   /** This function is called when the active document is changed. this function is called on the pane that is
871    * replaced by the new active pane. It allows the pane to "shutdown" when not in use. Currently, this procedure
872    * replaces the Definitions Document with a blank dummy document to help conserve memory (so that the pane will
873    * not be holding onto the last reference of a definitions document not allowing it to be garbage collected)
874    */

875   public void notifyInactive() {
876     // we catch a NoSuchDocumentException here because during a close/closeAll
877
// the model closes the definitions document before the MainFrame switches
878
// out the panes. If this is the case, then the following code does not
879
// need to be run.
880
try {
881       // Sync caret with location before switching
882
getOpenDefDocument().setCurrentLocation(getCaretPosition());
883       
884       // Remove any error highlighting in the old def pane
885
removeErrorHighlight();
886       
887       _position = _doc.getCurrentLocation();
888       _selStart = getSelectionStart();
889       _selEnd = getSelectionEnd();
890
891       _savedVScroll = _scrollPane.getVerticalScrollBar().getValue();
892       _savedHScroll = _scrollPane.getHorizontalScrollBar().getValue();
893
894       super.setDocument(NULL_DOCUMENT);
895     }
896     catch(NoSuchDocumentException e) {
897       // This exception was just thrown because the document was just
898
// closed and so this pane will soon be garbage collected.
899
// We don't need to do any more cleanup.
900
}
901   }
902     
903   /** This function is called when switching a pane to be the active document pane. It allows the pane to do whatever
904    * "startUp" is required. Since setInactive swapped out the document for a dummy document, we need to reload the
905    * actual document and reset its caret position to the saved location. Only runs in event thread.
906    */

907   public void notifyActive() {
908     assert ! _mainFrame.isVisible() || EventQueue.isDispatchThread();
909     super.setDocument(_doc);
910     if (_doc.getUndoableEditListeners().length == 0) _resetUndo();
911     
912     _doc.acquireWriteLock();
913     int len = _doc.getLength();
914     if (len < _position || len < _selEnd) {
915       // the document changed since we're set inactive
916
//so set selection to be none
917
_position = len;
918       _selStart = len;
919       _selEnd = len;
920     }
921     try {
922       if (_position == _selStart) {
923         setCaretPosition(_selEnd);
924         moveCaretPosition(_selStart);
925         _doc.setCurrentLocation(_selStart);
926       }
927       else {
928         setCaretPosition(_selStart);
929         moveCaretPosition(_selEnd);
930         _doc.setCurrentLocation(_selEnd);
931       }
932     }
933     finally { _doc.releaseWriteLock(); }
934     _scrollPane.getVerticalScrollBar().setValue(_savedVScroll);
935     _scrollPane.getHorizontalScrollBar().setValue(_savedHScroll);
936     // Explicitly set scrollbar policies fixing bug #1445898
937
_scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
938     _scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
939   }
940   
941   public int getVerticalScroll() {
942     if (getDocument() == NULL_DOCUMENT) return _savedVScroll;
943     else return _scrollPane.getVerticalScrollBar().getValue();
944   }
945   
946   public int getHorizontalScroll() {
947     if (getDocument() == NULL_DOCUMENT) return _savedHScroll;
948     else return _scrollPane.getHorizontalScrollBar().getValue();
949   }
950   
951   public int getCurrentLine() {
952     try {
953       int pos = getCaretPosition();
954       FontMetrics metrics = getFontMetrics(getFont());
955       Rectangle startRect = modelToView(pos);
956       if (startRect == null) return 1;
957       //top left position is (3,3), so font size<=6 will be off
958
return (new Double JavaDoc (startRect.getY() / metrics.getHeight()).intValue() + 1);
959     } catch (BadLocationException e) {
960       // This shouldnt happen b/c we retrieve the caret pos before calling modelToView
961
throw new UnexpectedException(e);
962     }
963   }
964
965   /** Determines current line using logic in DefinitionsDocument. Does it differ from getCurrentLine()? */
966   public int getCurrentLinefromDoc() { return _doc.getCurrentLine(); }
967   
968   public int getCurrentCol() { return _doc.getCurrentCol(); }
969   
970   public void setSize(int width, int height) {
971     super.setSize(width, height);
972     if (_setSizeListener != null) _setSizeListener.actionPerformed(null);
973   }
974
975 // public void addSetSizeListener(ActionListener listener) { _setSizeListener = listener; }
976
// public void removeSetSizeListener() { _setSizeListener = null; }
977

978   public void centerViewOnOffset(int offset) {
979     assert EventQueue.isDispatchThread();
980     try {
981       FontMetrics metrics = getFontMetrics(getFont());
982       JViewport defViewPort = _mainFrame.getDefViewport();
983       double viewWidth = defViewPort.getWidth();
984       double viewHeight = defViewPort.getHeight();
985       // Scroll to make sure this item is visible
986
// Centers the selection in the viewport
987
Rectangle startRect;
988       startRect = modelToView(offset);
989
990       if (startRect != null) {
991         int startRectX = (int) startRect.getX();
992         int startRectY = (int) startRect.getY();
993         startRect.setLocation(startRectX - (int)(viewWidth/2), startRectY - (int)(viewHeight/2));
994         Point endPoint = new Point(startRectX+(int)(viewWidth/2),
995                                    startRectY+(int)(viewHeight/2 + metrics.getHeight()/2));
996
997         // Add the end rect onto the start rect to make a rectangle
998
// that encompasses the entire selection
999
startRect.add(endPoint);
1000
1001        scrollRectToVisible(startRect);
1002      }
1003// removeSetSizeListener(); // Why? None was added
1004

1005      setCaretPosition(offset);
1006    }
1007    catch (BadLocationException e) { throw new UnexpectedException(e); }
1008  }
1009
1010  public void centerViewOnLine(int lineNumber) {
1011    FontMetrics metrics = getFontMetrics(getFont());
1012    Point p = new Point(0, metrics.getHeight() * (lineNumber));
1013    int offset = this.viewToModel(p);
1014    this.centerViewOnOffset(offset);
1015  }
1016
1017  /** This method overrides a broken version in JTextComponent. It allows
1018   * selection to proceed backwards as well as forwards. If selection is backwards,
1019   * then the caret will end up at the start of the selection rather than the end.
1020   */

1021  public void select(int selectionStart, int selectionEnd) {
1022    if (selectionStart < 0) selectionStart = 0;
1023    if (selectionEnd < 0) selectionEnd = 0;
1024    setCaretPosition(selectionStart);
1025    moveCaretPosition(selectionEnd); // What about the caret position in the reduced model? It is now inconsistent!
1026
}
1027
1028  /** Reset the document Undo list. */
1029  public void resetUndo() {
1030    _doc.getUndoManager().discardAllEdits();
1031
1032    _undoAction.updateUndoState();
1033    _redoAction.updateRedoState();
1034  }
1035
1036  /** Reset the document Undo list. */
1037  private void _resetUndo() {
1038    if (_undoAction == null) _undoAction = new UndoAction();
1039    if (_redoAction == null) _redoAction = new RedoAction();
1040
1041    _doc.resetUndoManager();
1042    
1043    getDocument().addUndoableEditListener(_undoListener);
1044    _undoAction.updateUndoState();
1045    _redoAction.updateRedoState();
1046  }
1047
1048
1049  /** Overriding this method ensures that all new documents created in this editor pane use our editor
1050   * kit (and thus our model).
1051   */

1052  protected EditorKit createDefaultEditorKit() {
1053    //return _editorKit;
1054
return EDITOR_KIT;
1055  }
1056  
1057  /** Prompt the user whether or not they wish to indent, if the selection size is very large.
1058   * Return true if the indent is to be completed
1059   * @param selStart - the selection start
1060   * @param selEnd - the selection end
1061   */

1062  protected boolean shouldIndent(int selStart, int selEnd) {
1063    if (selEnd > (selStart + INDENT_WARNING_THRESHOLD)) {
1064      Object JavaDoc[] options = {"Yes", "No"};
1065      int n = JOptionPane.showOptionDialog
1066        (_mainFrame,
1067         "Re-indenting this block may take a very long time. Are you sure?",
1068         "Confirm Re-indent",
1069         JOptionPane.YES_NO_OPTION,
1070         JOptionPane.QUESTION_MESSAGE,
1071         null,
1072         options,
1073         options[1]);
1074      switch (n) {
1075        case JOptionPane.CANCEL_OPTION:
1076        case JOptionPane.CLOSED_OPTION:
1077        case JOptionPane.NO_OPTION:
1078          return false;
1079        default:
1080          return true;
1081      }
1082    }
1083    return true;
1084  }
1085  
1086  
1087  /** Indent the given selection, for the given reason, in the current document.
1088   * @param selStart - the selection start
1089   * @param selEnd - the selection end
1090   * @param reason - the reason for the indent
1091   * @param pm - the ProgressMonitor used by the indenter
1092   */

1093  protected void indentLines(int selStart, int selEnd, int reason, ProgressMonitor pm) {
1094    //_mainFrame.hourglassOn();
1095
// final int key = _doc.getUndoManager().startCompoundEdit(); //Commented out in regards to French KeyBoard Fix
1096
try {
1097      _doc.indentLines(selStart, selEnd, reason, pm);
1098      endCompoundEdit();
1099    }
1100    catch (OperationCanceledException oce) {
1101      // if canceled, undo the indent; but first, end compound edit
1102
endCompoundEdit();
1103      _doc.getUndoManager().undo();
1104      // pm = null, so cancel can't be pressed
1105
throw new UnexpectedException(oce);
1106    }
1107    catch (RuntimeException JavaDoc e) {
1108      /* Catches the exception to turn off the the hourglass and close the compound edit before throwing out to the
1109       * main frame. */

1110      endCompoundEdit();
1111      throw e;
1112    }
1113    
1114    //_doc.setCurrentLocation(caretPos);
1115
setCaretPosition(_doc.getCurrentLocation());
1116  }
1117    
1118  /** Saved option listeners kept in this field so they can be removed for garbage collection */
1119  private List JavaDoc<Pair<Option<Color>, OptionListener<Color>>> _colorOptionListeners =
1120    new LinkedList JavaDoc<Pair<Option<Color>, OptionListener<Color>>>();
1121    
1122  private List JavaDoc<Pair<Option<Boolean JavaDoc>, OptionListener<Boolean JavaDoc>>> _booleanOptionListeners =
1123    new LinkedList JavaDoc<Pair<Option<Boolean JavaDoc>, OptionListener<Boolean JavaDoc>>>();
1124  
1125  /** Called when the definitions pane is released from duty. This frees up any option listeners that are holding
1126   * references to this object so this can be garbage collected.
1127   */

1128  public void close() {
1129    for (Pair<Option<Color>, OptionListener<Color>> p: _colorOptionListeners) {
1130      DrJava.getConfig().removeOptionListener(p.first(), p.second());
1131    }
1132    for (Pair<Option<Boolean JavaDoc>, OptionListener<Boolean JavaDoc>> p: _booleanOptionListeners) {
1133      DrJava.getConfig().removeOptionListener(p.first(), p.second());
1134    }
1135    _colorOptionListeners.clear();
1136    _booleanOptionListeners.clear();
1137    
1138    ourMap.removeBindings();
1139    removeKeymap(ourMap.getName());
1140    
1141    _popMenu.removeAll();
1142  }
1143
1144  /** The undo action. */
1145  public class UndoAction extends AbstractAction {
1146    
1147    /** Constructor. */
1148    private UndoAction() {
1149      super("Undo");
1150      setEnabled(false);
1151    }
1152
1153    /** What to do when user chooses to undo.
1154     * @param e
1155     */

1156    public void actionPerformed(ActionEvent e) {
1157      try {
1158        // UndoableEdit edit = _doc.getNextUndo();
1159
// int pos = -1;
1160
// if (edit != null && edit instanceof UndoWithPosition) {
1161
// pos = ((UndoWithPosition)edit).getPosition();
1162
// }
1163
//
1164
// if (pos > -1) {
1165
// //centerViewOnOffset(pos);
1166
// setCaretPosition(pos);
1167
// }
1168
_doc.getUndoManager().undo();
1169        _doc.updateModifiedSinceSave();
1170        _mainFrame.updateFileTitle();
1171      }
1172      catch (CannotUndoException ex) {
1173        throw new UnexpectedException(ex);
1174      }
1175      updateUndoState();
1176      _redoAction.updateRedoState();
1177    }
1178
1179    /** Updates the undo list, i.e., where we are as regards undo and redo. */
1180    protected void updateUndoState() {
1181      if (_doc.undoManagerCanUndo()) {
1182        setEnabled(true);
1183        putValue(Action.NAME, _doc.getUndoManager().getUndoPresentationName());
1184      }
1185      else {
1186        setEnabled(false);
1187        putValue(Action.NAME, "Undo");
1188      }
1189    }
1190  }
1191
1192  /** Redo action. */
1193  public class RedoAction extends AbstractAction {
1194
1195    /** Constructor. */
1196    private RedoAction() {
1197      super("Redo");
1198      setEnabled(false);
1199    }
1200
1201    /** In the event that the user chooses to redo something, this is what's called.
1202     * @param e
1203     */

1204    public void actionPerformed(ActionEvent e) {
1205      try {
1206        // UndoableEdit edit = _doc.getNextRedo();
1207
// int pos = -1;
1208
// if (edit instanceof UndoWithPosition) {
1209
// pos = ((UndoWithPosition)edit).getPosition();
1210
// }
1211
_doc.getUndoManager().redo();
1212
1213        // if (pos > -1) {
1214
// //centerViewOnOffset(pos);
1215
// setCaretPosition(pos);
1216
// }
1217
_doc.updateModifiedSinceSave();
1218        _mainFrame.updateFileTitle();
1219      } catch (CannotRedoException ex) {
1220        throw new UnexpectedException(ex);
1221      }
1222      updateRedoState();
1223      _undoAction.updateUndoState();
1224    }
1225
1226    /** Updates the redo state, i.e., where we are as regards undo and redo. */
1227    protected void updateRedoState() {
1228      if (_doc.undoManagerCanRedo()) {
1229        setEnabled(true);
1230        putValue(Action.NAME, _doc.getUndoManager().getRedoPresentationName());
1231      }
1232      else {
1233        setEnabled(false);
1234        putValue(Action.NAME, "Redo");
1235      }
1236    }
1237  }
1238
1239  /** Wrapper for UndoableEdit that pairs UndoableEdits with their caret positions */
1240  private class UndoWithPosition implements UndoableEdit {
1241    private final UndoableEdit _undo;
1242    private final int _pos;
1243
1244    public UndoWithPosition(UndoableEdit undo, int pos) {
1245      _undo = undo;
1246      _pos = pos;
1247    }
1248
1249    public int getPosition() { return _pos; }
1250    public boolean addEdit(UndoableEdit ue) { return _undo.addEdit(ue); }
1251    public boolean canRedo() { return _undo.canRedo(); }
1252    public boolean canUndo() { return _undo.canUndo(); }
1253    public void die() { _undo.die(); }
1254    public String JavaDoc getPresentationName() { return _undo.getPresentationName(); }
1255    public String JavaDoc getUndoPresentationName() { return _undo.getUndoPresentationName(); }
1256    public String JavaDoc getRedoPresentationName() { return _undo.getRedoPresentationName(); }
1257    public boolean isSignificant() { return _undo.isSignificant(); }
1258
1259    public void redo() {
1260      _undo.redo();
1261      if (_pos > -1) setCaretPosition(_pos);
1262    }
1263
1264    public boolean replaceEdit(UndoableEdit ue) { return _undo.replaceEdit(ue); }
1265
1266    public void undo() {
1267      if (_pos > -1) setCaretPosition(_pos);
1268      _undo.undo();
1269    }
1270  }
1271  
1272  /** This list of listeners to notify when we are finalized */
1273  private List JavaDoc<FinalizationListener<DefinitionsPane>> _finalizationListeners =
1274    new LinkedList JavaDoc<FinalizationListener<DefinitionsPane>>();
1275  
1276  /** Registers a finalization listener with the specific instance of the ddoc. NOTE: this should only be used by test
1277   * cases. This policy ensures that we don't spring memory leaks by allowing our unit tests to keep track of
1278   * whether objects are being finalized (garbage collected).
1279   * @param fl the listener to register
1280   */

1281  public void addFinalizationListener(FinalizationListener<DefinitionsPane> fl) { _finalizationListeners.add(fl); }
1282
1283  public List JavaDoc<FinalizationListener<DefinitionsPane>> getFinalizationListeners() { return _finalizationListeners; }
1284
1285  /** This method is called when this object becomes unreachable. Since this class implements
1286   * edu.rice.cs.drjava.model.Finalizable, it must notify its listeners.
1287   */

1288  protected void finalize() {
1289    FinalizationEvent<DefinitionsPane> fe = new FinalizationEvent<DefinitionsPane>(this);
1290    for (FinalizationListener<DefinitionsPane> fl: _finalizationListeners) fl.finalized(fe);
1291  }
1292}
1293
Popular Tags