Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 443   Methods: 32
NCLOC: 240   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
InteractionsPane.java 56.8% 69.8% 68.8% 66.8%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.ui;
 38   
 39    import javax.swing.*;
 40    import javax.swing.text.*;
 41    import java.awt.*;
 42    import javax.swing.undo.*;
 43    import javax.swing.event.*;
 44    import java.awt.event.*;
 45   
 46    import edu.rice.cs.drjava.model.definitions.*;
 47   
 48    import java.awt.event.KeyEvent;
 49    import java.awt.datatransfer.*;
 50    import java.util.Vector;
 51   
 52    import edu.rice.cs.util.OperationCanceledException;
 53    import edu.rice.cs.util.Log;
 54    import edu.rice.cs.util.swing.*;
 55    import edu.rice.cs.util.swing.Utilities;
 56    import edu.rice.cs.util.UnexpectedException;
 57    import edu.rice.cs.drjava.config.*;
 58    import edu.rice.cs.drjava.*;
 59    import edu.rice.cs.drjava.model.DJDocument;
 60    import edu.rice.cs.drjava.model.definitions.indent.Indenter;
 61    import edu.rice.cs.drjava.model.repl.*;
 62   
 63    /** The view component for repl interaction.
 64    * @version $Id: InteractionsPane.java 5439 2011-08-11 17:13:04Z rcartwright $
 65    */
 66    public abstract class InteractionsPane extends AbstractDJPane implements OptionConstants, ClipboardOwner {
 67   
 68    public static Log LOG = new Log("InteractionsPane.txt", false);
 69   
 70    /** fields for use in undo/redo functionality */
 71    private volatile UndoAction _undoAction;
 72    private volatile RedoAction _redoAction;
 73    public volatile boolean _inCompoundEdit = false;
 74    private volatile int _compoundEditKey;
 75    private volatile boolean deleteCEBool = true;
 76   
 77    /** The custom keymap for the interactions pane. */
 78    protected final Keymap _keymap;
 79   
 80    /** Whether to draw text as antialiased. */
 81    private boolean _antiAliasText = false;
 82   
 83    static StyledEditorKit EDITOR_KIT;
 84   
 85  21 static { EDITOR_KIT = new InteractionsEditorKit(); }
 86   
 87    /** A runnable object that causes the editor to beep. */
 88    protected Runnable _beep = new Runnable() {
 89  0 public void run() { Toolkit.getDefaultToolkit().beep(); }
 90    };
 91   
 92    /** The OptionListener for TEXT_ANTIALIAS. */
 93    private class AntiAliasOptionListener implements OptionListener<Boolean> {
 94  0 public void optionChanged(OptionEvent<Boolean> oce) {
 95  0 _antiAliasText = oce.value.booleanValue();
 96  0 InteractionsPane.this.repaint();
 97    }
 98    }
 99   
 100    /** listens for a left click by mouse and ends a compound edit for the undo/redo funationality
 101    * means that when someone clicks to change position in text, starts typing at the new location,
 102    * the undo will only get rid of the added text
 103    */
 104    private class leftUndoBreak extends MouseAdapter {
 105  0 public void mouseClicked(MouseEvent e){
 106  0 endCompoundEdit();
 107    }
 108    }
 109   
 110    /** Returns a runnable object that beeps to the user. */
 111  203 public Runnable getBeep() { return _beep; }
 112   
 113    private final InteractionsDJDocument _doc;
 114   
 115    // private List<Integer> _listOfPrompt = new Vector<Integer>(); // Vector used because it is synchronized. // NOT USED
 116   
 117    /** Creates an InteractionsPane with the given document.
 118    * Uses default keymap name ("INTERACTIONS_KEYMAP")
 119    * @param doc StyledDocument containing the interactions history.
 120    */
 121  165 public InteractionsPane(InteractionsDJDocument doc) { this("INTERACTIONS_KEYMAP", doc); }
 122   
 123    /** Creates an InteractionsPane with the given document.
 124    * @param keymapName the name of the keymap for this pane
 125    * @param doc StyledDocument containing the interactions history.
 126    */
 127  203 public InteractionsPane(String keymapName, InteractionsDJDocument doc) {
 128  203 super(doc);
 129  203 _doc = doc;
 130    //add actions for enter key, etc.
 131  203 _keymap = addKeymap(keymapName, getKeymap());
 132   
 133  203 setCaretPosition(doc.getLength());
 134   
 135  203 setHighlighter(new ReverseHighlighter());
 136  203 _highlightManager = new HighlightManager(this);
 137   
 138  203 _antiAliasText = DrJava.getConfig().getSetting(TEXT_ANTIALIAS).booleanValue();
 139   
 140    // The superclass AbstractDJPane installs a matchListener for this class
 141   
 142    // Setup color listeners.
 143   
 144  203 new ForegroundColorListener(this);
 145  203 new BackgroundColorListener(this);
 146   
 147  203 OptionListener<Boolean> aaTemp = new AntiAliasOptionListener();
 148  203 DrJava.getConfig().addOptionListener(OptionConstants.TEXT_ANTIALIAS, aaTemp);
 149   
 150  203 _resetUndo(); //gets undoManager ready to go
 151  203 addMouseListener(new leftUndoBreak());
 152    }
 153   
 154    /** We lost ownership of what we put in the clipboard. */
 155  0 public void lostOwnership(Clipboard clipboard, Transferable contents) {
 156    // ignore
 157    }
 158   
 159    /** Widens the visibilitly of the processKeyEvent method; it is protected in the superclass. */
 160  21 public void processKeyEvent(KeyEvent e) {
 161   
 162    //Fixes bug ID:2898576 - Backspace undo/redo issues
 163  21 if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE && deleteCEBool){
 164  0 endCompoundEdit();
 165  0 deleteCEBool=false;
 166    }
 167  21 else if(e.getID()==KeyEvent.KEY_PRESSED && e.getKeyCode() != KeyEvent.VK_BACK_SPACE){
 168  8 deleteCEBool = true;
 169    }
 170   
 171  21 KeyStroke ks = KeyStroke.getKeyStrokeForEvent(e);
 172  21 Action a = KeyBindingManager.ONLY.get(ks);
 173    // Don't perform the action if the keystroke is NULL_KEYSTROKE (generated by some Windows keys)
 174  21 if ((ks != KeyStrokeOption.NULL_KEYSTROKE) && (a != null)) {
 175  1 endCompoundEdit();
 176    }
 177   
 178  2 if ((e.getModifiers() & InputEvent.SHIFT_MASK)!=0 && e.getKeyCode()==KeyEvent.VK_ENTER) endCompoundEdit(); //ends compound edit on line change
 179   
 180  21 super.processKeyEvent(e);
 181    }
 182   
 183    /** Assigns the given keystroke to the given action in this pane.
 184    * @param stroke keystroke that triggers the action
 185    * @param action Action to perform
 186    */
 187  2475 public void addActionForKeyStroke(KeyStroke stroke, Action action) {
 188    // we don't want multiple keys bound to the same action; Why NOT?
 189  2475 KeyStroke[] keys = _keymap.getKeyStrokesForAction(action);
 190  2475 if (keys != null) {
 191  660 for (int i = 0; i < keys.length; i++) _keymap.removeKeyStrokeBinding(keys[i]);
 192    }
 193  2475 _keymap.addActionForKeyStroke(stroke, action);
 194  2475 setKeymap(_keymap);
 195    }
 196   
 197    /** Assigns the given keystroke to the given action in this pane.
 198    * @param stroke keystroke that triggers the action
 199    * @param action Action to perform
 200    */
 201  1624 public void addActionForKeyStroke(Vector<KeyStroke> stroke, Action action) {
 202    // remove previous bindings
 203  1624 KeyStroke[] keys = _keymap.getKeyStrokesForAction(action);
 204  1624 if (keys != null) {
 205  0 for (int i = 0; i < keys.length; i++) _keymap.removeKeyStrokeBinding(keys[i]);
 206    }
 207  1624 for (KeyStroke ks: stroke) {
 208  1624 _keymap.addActionForKeyStroke(ks, action);
 209    }
 210  1624 setKeymap(_keymap);
 211    }
 212   
 213    /** Sets this pane's beep to be a different runnable object. Defaults to Toolkit.getDefaultToolkit().beep().
 214    * @param beep Runnable command to notify the user
 215    */
 216  15 public void setBeep(Runnable beep) { _beep = beep; }
 217   
 218    /** Highlights the given text with error highlight.
 219    * @param offset the offset in the text
 220    * @param length the length of the error to highlight
 221    */
 222  0 public void highlightError(int offset, int length) {
 223  0 _highlightManager.addHighlight(offset, offset+length, ERROR_PAINTER);
 224    }
 225   
 226    /** Overriding this method ensures that all new documents created in this editor pane use our editor kit
 227    * (and thus our model).
 228    */
 229  406 protected EditorKit createDefaultEditorKit() { return EDITOR_KIT; }
 230   
 231    /** Enable anti-aliased text by overriding paintComponent. */
 232  0 protected void paintComponent(Graphics g) {
 233  0 if (g == null) return; // Addresses bug 1651914
 234  0 if (_antiAliasText && g instanceof Graphics2D) {
 235  0 Graphics2D g2d = (Graphics2D)g;
 236  0 g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 237    }
 238  0 super.paintComponent(g);
 239    }
 240   
 241    /** Returns the DJDocument held by the pane. */
 242  428 public DJDocument getDJDocument() { return _doc; }
 243   
 244    /** Updates match highlights. Only runs in the event thread.
 245    * @param offset caret position immediately following some form of brace; hence offset > 0.
 246    * @param opening true if the the preceding brace is "opening"
 247    */
 248  14 protected void matchUpdate(int offset, boolean opening) {
 249  0 if (! _doc.hasPrompt()) return;
 250  14 _doc.setCurrentLocation(offset);
 251  14 _removePreviousHighlight();
 252   
 253  14 int caretPos = getCaretPosition();
 254   
 255  14 if (opening) {
 256    // getCaretPosition() will be the start of the highlight
 257   
 258  0 int to = _doc.balanceForward(); // relative distance to matching bracket
 259   
 260  0 if (to > -1) { // matching closing bracket was found
 261  0 int end = caretPos + to;
 262  0 _addHighlight(caretPos - 1, end);
 263    }
 264    }
 265    else {
 266  14 int from = _doc.balanceBackward();
 267  14 if (from > -1) { // matching open bracket was found
 268  14 int start = caretPos - from;
 269  14 _addHighlight(start, caretPos);
 270    }
 271    }
 272    }
 273   
 274    /** Updates status fields in the main frame (title bar, selected file name) when document is modified. */
 275  412 protected void updateStatusField() { /* do nothing; this is an interactions pane. */ }
 276   
 277    /** Indent the given selection, for the given reason, in the current document. Should only run in the event queuel
 278    * @param selStart - the selection start
 279    * @param selEnd - the selection end
 280    * @param reason - the reason for the indent
 281    * @param pm - the ProgressMonitor used by the indenter
 282    */
 283  0 protected void indentLines(int selStart, int selEnd, Indenter.IndentReason reason, ProgressMonitor pm) {
 284  0 assert EventQueue.isDispatchThread();
 285  0 try {
 286  0 _doc.indentLines(selStart, selEnd, reason, pm);
 287  0 setCaretPos(_doc.getCurrentLocation());
 288    }
 289  0 catch (OperationCanceledException oce) { throw new UnexpectedException(oce); }
 290    }
 291   
 292    /** Returns true if the indent is to be performed. The code in the definitions pane prompts the user, but this
 293    * requires a copy of mainframe, and a reason to do so. The user does not need to be prompted here. The cutoff
 294    * in the definitions pane for the prompt is 10000 characters, which is unlikely to occur in the interactions
 295    * pane very often if at all.
 296    * @param selStart - the selection start
 297    * @param selEnd - the selection end
 298    */
 299  0 protected boolean shouldIndent(int selStart, int selEnd) { return true; }
 300   
 301    /** Gets the current prompt position */
 302    public abstract int getPromptPos();
 303   
 304    /** Listens to any undoable events in the document, and adds them to the undo manager. Must be done in the view
 305    * because the edits are stored along with the caret position at the time of the edit.
 306    */
 307    private final UndoableEditListener _undoListener = new UndoableEditListener() {
 308   
 309    /** The function to handle what happens when an UndoableEditEvent occurs.
 310    * @param e
 311    */
 312  260 public void undoableEditHappened(UndoableEditEvent e) {
 313  260 assert EventQueue.isDispatchThread() || Utilities.TEST_MODE;
 314  260 UndoableEdit undo = e.getEdit();
 315  260 LOG.log("In undoableEditHappened - _inCompoundEdit is "+ _inCompoundEdit);
 316  260 if (! _inCompoundEdit) {
 317  37 CompoundUndoManager undoMan = _doc.getUndoManager();
 318  37 _inCompoundEdit = true;
 319  37 _compoundEditKey = undoMan.startCompoundEdit();
 320  37 getUndoAction().updateUndoState();
 321  37 getRedoAction().updateRedoState();
 322    }
 323  260 _doc.getUndoManager().addEdit(undo);
 324  260 getRedoAction().setEnabled(false);
 325    }
 326    };
 327   
 328   
 329    /** Ends a compound edit.*/
 330  13 public void endCompoundEdit() {
 331  13 if (_inCompoundEdit) {
 332  12 CompoundUndoManager undoMan = _doc.getUndoManager();
 333  12 _inCompoundEdit = false;
 334  12 undoMan.endCompoundEdit(_compoundEditKey);
 335    }
 336    }
 337   
 338    /** @return the undo action. */
 339  188 public UndoAction getUndoAction() { return _undoAction; }
 340   
 341    /** @return the redo action. */
 342  448 public RedoAction getRedoAction() { return _redoAction; }
 343   
 344    /** The undo action. */
 345    public class UndoAction extends AbstractAction {
 346   
 347    /** Constructor. */
 348  203 private UndoAction() {
 349  203 super("Undo");
 350  203 setEnabled(false);
 351    }
 352   
 353    /** What to do when user chooses to undo.
 354    * @param e
 355    */
 356  0 public void actionPerformed(ActionEvent e) {
 357  0 try {
 358    // LOG.log("UndoAction.actionPerformed. _doc = "+_doc+", event = "+e);
 359  0 _doc.getUndoManager().undo();
 360  0 _doc.updateModifiedSinceSave();
 361    }
 362    catch (CannotUndoException ex) {
 363  0 throw new UnexpectedException(ex);
 364    }
 365  0 updateUndoState();
 366  0 _redoAction.updateRedoState();
 367    }
 368   
 369    /** Updates the undo list, i.e., where we are as regards undo and redo. */
 370  250 protected void updateUndoState() {
 371  250 if (_doc.undoManagerCanUndo() && isEditable()) {
 372  37 setEnabled(true);
 373  37 putValue(Action.NAME, _doc.getUndoManager().getUndoPresentationName());
 374    }
 375    else {
 376  213 setEnabled(false);
 377  213 putValue(Action.NAME, "Undo");
 378    }
 379    }
 380    }
 381   
 382   
 383    /** Redo action. */
 384    public class RedoAction extends AbstractAction {
 385   
 386    /** Constructor. */
 387  203 private RedoAction() {
 388  203 super("Redo");
 389  203 setEnabled(false);
 390    }
 391   
 392    /** In the event that the user chooses to redo something, this is what's called.
 393    * @param e
 394    */
 395  0 public void actionPerformed(ActionEvent e) {
 396  0 try {
 397  0 _doc.getUndoManager().redo();
 398  0 _doc.updateModifiedSinceSave();
 399    } catch (CannotRedoException ex) {
 400  0 throw new UnexpectedException(ex);
 401    }
 402  0 updateRedoState();
 403  0 _undoAction.updateUndoState();
 404    }
 405   
 406    /** Updates the redo state, i.e., where we are as regards undo and redo. */
 407  250 protected void updateRedoState() {
 408  250 if (_doc.undoManagerCanRedo() && isEditable()) {
 409  0 setEnabled(true);
 410  0 putValue(Action.NAME, _doc.getUndoManager().getRedoPresentationName());
 411    }
 412    else {
 413  250 setEnabled(false);
 414  250 putValue(Action.NAME, "Redo");
 415    }
 416    }
 417    }
 418   
 419    /** resets undo manager **/
 420  10 private void resetUndo() {
 421  10 _doc.getUndoManager().discardAllEdits();
 422  10 _undoAction.updateUndoState();
 423  10 _redoAction.updateRedoState();
 424    }
 425   
 426    /** discards edits and resets undoManager **/
 427  10 public void discardUndoEdits() {
 428  10 endCompoundEdit();
 429  10 resetUndo();
 430    }
 431   
 432    /** Reset the document Undo list. */
 433  203 public void _resetUndo() {
 434  203 if (_undoAction == null) _undoAction = new UndoAction();
 435  203 if (_redoAction == null) _redoAction = new RedoAction();
 436   
 437  203 _doc.resetUndoManager();
 438   
 439  203 _doc.addUndoableEditListener(_undoListener);
 440  203 _undoAction.updateUndoState();
 441  203 _redoAction.updateRedoState();
 442    }
 443    }