Clover coverage report - DrJava Test Coverage (drjava-20110828-r5448)
Coverage timestamp: Sun Aug 28 2011 03:13:33 CDT
file stats: LOC: 248   Methods: 22
NCLOC: 133   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
BrowserHistoryManager.java 33.3% 49.4% 59.1% 47.4%
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.model;
 38   
 39    import java.awt.EventQueue;
 40   
 41    import java.util.*;
 42   
 43    import edu.rice.cs.plt.lambda.Lambda;
 44    import edu.rice.cs.util.swing.Utilities;
 45   
 46    /** Browser history manager for the entire model. Follows readers/writers locking protocol of EventNotifier. */
 47    public class BrowserHistoryManager extends EventNotifier<RegionManagerListener<BrowserDocumentRegion>> {
 48    /** Two regions are similar if they are in the same document and not more than DIFF_THRESHOLD lines apart. */
 49    public static final int DIFF_THRESHOLD = 5;
 50   
 51    /** List of regions. In Java 6, ArrayDeque is a better choice than Stack; should be changed once compatibility
 52    * with Java 5 is abandoned. */
 53    private volatile Stack<BrowserDocumentRegion> _pastRegions = new Stack<BrowserDocumentRegion>();
 54    private volatile Stack<BrowserDocumentRegion> _futureRegions = new Stack<BrowserDocumentRegion>();
 55   
 56    private volatile int _maxSize;
 57   
 58    /** Create a new ConcreteRegionManager with the specified maximum size.
 59    * @param size maximum number of regions that can be stored in this manager.
 60    */
 61  159 public BrowserHistoryManager(int size) { _maxSize = size; }
 62   
 63    /** Create a new ConcreteRegionManager without maximum size. */
 64  159 public BrowserHistoryManager() { this(0); }
 65   
 66    /** Add the supplied DocumentRegion r to the manager as current region.
 67    * @param r the DocumentRegion to be inserted into the manager */
 68  27 public void addBrowserRegion(final BrowserDocumentRegion r, final GlobalEventNotifier notifier) {
 69  27 /* */ assert Utilities.TEST_MODE || EventQueue.isDispatchThread();
 70   
 71  27 final BrowserDocumentRegion current = getCurrentRegion();
 72  27 if ((current != null) && (similarRegions(current, r))) {
 73    // the region to be added is similar to the current region
 74    // just update the current region
 75    // edu.rice.cs.drjava.ui.MainFrame.MFLOG.log("Updating instead of adding: " + current + " --> " + r);
 76  7 current.update(r);
 77    }
 78    else {
 79  20 _pastRegions.push(r);
 80  20 r.getDocument().addBrowserRegion(r);
 81   
 82    // Notify listeners of this event
 83  20 Utilities.invokeLater(new Runnable() {
 84  20 public void run() {
 85  20 _lock.startRead();
 86  0 try { for (RegionManagerListener<BrowserDocumentRegion> l: _listeners) { l.regionAdded(r); } }
 87  20 finally { _lock.endRead(); }
 88    }
 89    });
 90   
 91    // remove a region if necessary
 92  20 shrinkManager();
 93    }
 94  27 notifier.browserChanged();
 95    }
 96   
 97    /** Add the supplied DocumentRegion r to the manager before the current region.
 98    * @param r the DocumentRegion to be inserted into the manager */
 99  0 public void addBrowserRegionBefore(final BrowserDocumentRegion r, final GlobalEventNotifier notifier) {
 100  0 /* */ assert Utilities.TEST_MODE || EventQueue.isDispatchThread();
 101   
 102  0 final BrowserDocumentRegion current = getCurrentRegion();
 103  0 if ((current != null) && (similarRegions(current, r))) {
 104    // the region to be added is similar to the current region
 105    // just update the current region
 106    // edu.rice.cs.drjava.ui.MainFrame.MFLOG.log("Updating instead of adding: " + current + " --> " + r);
 107  0 current.update(r);
 108    }
 109    else {
 110  0 if (_pastRegions.size() == 0) {
 111  0 _pastRegions.push(r);
 112    }
 113    else {
 114  0 _futureRegions.push(_pastRegions.pop());
 115  0 _pastRegions.push(r);
 116    }
 117  0 r.getDocument().addBrowserRegion(r);
 118   
 119    // Notify listeners of this event
 120  0 Utilities.invokeLater(new Runnable() {
 121  0 public void run() {
 122  0 _lock.startRead();
 123  0 try { for (RegionManagerListener<BrowserDocumentRegion> l: _listeners) { l.regionAdded(r); } }
 124  0 finally { _lock.endRead(); }
 125    }
 126    });
 127   
 128    // remove a region if necessary
 129  0 shrinkManager();
 130    }
 131  0 notifier.browserChanged();
 132    }
 133   
 134    /** Remove regions if there are more than the maximum number allowed. Typically used to remove one region. */
 135  179 private void shrinkManager() {
 136  179 if (_maxSize > 0) {
 137  179 int size = _pastRegions.size() + _futureRegions.size();
 138  179 int diff = size - _maxSize;
 139  179 for (int i = 0; i < diff; ++i) {
 140    // always remove the element farthest away from the larger stack
 141  0 remove(((_pastRegions.size()>_futureRegions.size())?_pastRegions:_futureRegions).get(0));
 142    }
 143    }
 144    }
 145   
 146    /** Remove the given DocumentRegion from the manager.
 147    * @param r the DocumentRegion to be removed.
 148    */
 149  1 public /* synchronized */ void remove(final BrowserDocumentRegion r) {
 150  1 OpenDefinitionsDocument doc = r.getDocument();
 151  0 if (!_pastRegions.remove(r)) _futureRegions.remove(r);
 152  1 doc.removeBrowserRegion(r);
 153    // Notify listeners of this event
 154  1 Utilities.invokeLater(new Runnable() {
 155  1 public void run() {
 156  1 _lock.startRead();
 157  0 try { for (RegionManagerListener<BrowserDocumentRegion> l: _listeners) { l.regionRemoved(r); } }
 158  1 finally { _lock.endRead(); }
 159    }
 160    });
 161    }
 162   
 163    /** @return a SortedSet<BrowserDocumentRegion> containing the DocumentRegion objects in this mangager. */
 164  3 public SortedSet<BrowserDocumentRegion> getRegions() {
 165  3 TreeSet<BrowserDocumentRegion> ts = new TreeSet<BrowserDocumentRegion>(_pastRegions);
 166  3 ts.addAll(_futureRegions);
 167  3 return ts;
 168    }
 169   
 170    /** Tells the manager to remove all regions. */
 171  0 public /* synchronized */ void clearBrowserRegions() {
 172  0 while(_pastRegions.size()+_futureRegions.size() > 0) {
 173  0 remove(((_pastRegions.size()>_futureRegions.size())?_pastRegions:_futureRegions).get(0));
 174    }
 175    }
 176   
 177    /** @return the current region or null if none selected */
 178  27 public BrowserDocumentRegion getCurrentRegion() {
 179  13 if (_pastRegions.isEmpty()) return null;
 180  14 return _pastRegions.peek();
 181    }
 182   
 183    /** @return true if the current region is the first in the list, i.e. prevCurrentRegion is without effect */
 184  19 public /* synchronized */ boolean isCurrentRegionFirst() { return (_pastRegions.size()<2); }
 185   
 186    /** @return true if the current region is the last in the list, i.e. nextCurrentRegion is without effect */
 187  19 public /* synchronized */ boolean isCurrentRegionLast() { return (_futureRegions.size()<1); }
 188   
 189    /** Make the region that is more recent the current region.
 190    * @return new current region */
 191  0 public /* synchronized */ BrowserDocumentRegion nextCurrentRegion(final GlobalEventNotifier notifier) {
 192  0 if (isCurrentRegionLast()) return null;
 193  0 _pastRegions.push(_futureRegions.pop());
 194  0 notifier.browserChanged();
 195  0 return _pastRegions.peek();
 196    }
 197   
 198    /** Make the region that is less recent the current region.
 199    * @return new current region */
 200  0 public /* synchronized */ BrowserDocumentRegion prevCurrentRegion(final GlobalEventNotifier notifier) {
 201  0 if (isCurrentRegionFirst()) return null;
 202  0 _futureRegions.push(_pastRegions.pop());
 203  0 notifier.browserChanged();
 204  0 return _pastRegions.peek();
 205    }
 206   
 207    /** Set the maximum number of regions that can be stored in this manager.
 208    * @param size maximum number of regions, or 0 if no maximum
 209    */
 210  159 public /* synchronized */ void setMaximumSize(int size) {
 211  159 _maxSize = size;
 212   
 213    // remove regions if necessary
 214  159 shrinkManager();
 215    }
 216   
 217    /** @return the maximum number of regions that can be stored in this manager. */
 218  0 public int getMaximumSize() { return _maxSize; }
 219   
 220    /** Apply the given command to the specified region to change it.
 221    * @param region the region to find and change
 222    * @param cmd command that mutates the region. */
 223  0 public void changeRegion(final BrowserDocumentRegion region, Lambda<BrowserDocumentRegion,Object> cmd) {
 224  0 cmd.value(region);
 225  0 Utilities.invokeLater(new Runnable() { public void run() {
 226    // notify
 227  0 _lock.startRead();
 228  0 try {
 229  0 for (RegionManagerListener<BrowserDocumentRegion> l: _listeners) { l.regionChanged(region); }
 230  0 } finally { _lock.endRead(); }
 231    } });
 232    }
 233   
 234    /** Return true if the two regions are similar. */
 235  14 public static boolean similarRegions(BrowserDocumentRegion r1, BrowserDocumentRegion r2) {
 236  14 OpenDefinitionsDocument d = r1.getDocument();
 237  7 if (d!=r2.getDocument()) return false;
 238  7 int l1 = d.getLineOfOffset(r1.getStartOffset());
 239  7 int l2 = d.getLineOfOffset(r2.getStartOffset());
 240  7 return (Math.abs(l1-l2) <= DIFF_THRESHOLD);
 241    }
 242   
 243  0 public String toString() {
 244  0 ArrayList<BrowserDocumentRegion> future = new ArrayList<BrowserDocumentRegion>(_futureRegions);
 245  0 Collections.reverse(future);
 246  0 return "Past: " + _pastRegions.toString() + ", Future: " + future.toString();
 247    }
 248    }