public ArrayList<FileRegion> getFileRegions() {
   ArrayList<FileRegion> regions = new ArrayList<FileRegion>();
   for (OpenDefinitionsDocument odd : _documents) {
     File f = odd.getRawFile();
     for (R r : _regions.get(odd))
       regions.add(new DummyDocumentRegion(f, r.getStartOffset(), r.getEndOffset()));
   }
   return regions;
 }
  /**
   * Updates _lineStartPos, _lineEndPos of regions in the interval [firstRegion, lastRegion] using
   * total ordering on regions. Removes empty regions. firstRegion and lastRegion are not
   * necessarily regions in this manager.
   */
  public void updateLines(R firstRegion, R lastRegion) {
    assert Utilities.TEST_MODE || EventQueue.isDispatchThread();

    /* Get the tailSet consisting of the ordered set of regions >= firstRegion. */
    SortedSet<R> tail = getTailSet(firstRegion);
    if (tail.size() == 0)
      return; // tail can be empty if firstRegion is a constructed DocumentRegion

    List<R> toBeRemoved = new ArrayList<R>(); // nonsense to avoid concurrent modification exception
    for (R region : tail) {
      if (region.compareTo(lastRegion) > 0) break;
      region.update(); // The bounds of this region must be recomputed.
      if (region.getStartOffset() == region.getEndOffset()) toBeRemoved.add(region);
    }
    removeRegions(toBeRemoved);
  }
  /**
   * Returns the region [start, end) containing offset. Since regions can never overlap, there is at
   * most one such region in the given document. (Degenerate regions can coalesce but they are empty
   * implying that they are never returned by this method.) Only runs in the event thread.
   *
   * @param odd the document
   * @param offset the offset in the document
   * @return the DocumentRegion at the given offset, or null if it does not exist.
   */
  public R getRegionAt(OpenDefinitionsDocument odd, int offset) {
    /* */ assert Utilities.TEST_MODE || EventQueue.isDispatchThread();

    /* Get the tailSet consisting of the ordered set of regions [start, end) such that end > offset. */
    @SuppressWarnings("unchecked")
    SortedSet<R> tail = getTailSet((R) newDocumentRegion(odd, 0, offset + 1));

    /* If tail contains a match, it must be the first region, since all regions in a document are disjoint and no
     * degenerate region in tail can contain offset. (Every degenerate region is disjoint from every other region
     * because it is empty.) tail is sorted by [endOffset, startOffset]; tail may be empty. */

    if (tail.size() == 0) return null;
    R r = tail.first();

    if (r.getStartOffset() <= offset) return r;
    else return null;
  }
  /**
   * Returns the set of regions in the given document that overlap the specified interval
   * [startOffset, endOffset), including degenerate regions [offset, offset) where [offset, offset]
   * is a subset of (startOffset, endOffset). Assumes that all regions in the document are disjoint.
   * Note: degenerate empty regions with form [offset, offset) vacuously satisfy this property. Only
   * executes in the event thread. Note: this method could be implemented more cleanly using a
   * revserseIterator on the headSet containing all regions preceding or equal to the selection. but
   * this functionality was not added to TreeSet until Java 6.0.
   *
   * @param odd the document
   * @param startOffset the left end of the specified interval
   * @param endOffset the right end of the specified interval
   * @return the Collection<DocumentRegion> of regions overlapping the interval.
   */
  public Collection<R> getRegionsOverlapping(
      OpenDefinitionsDocument odd, int startOffset, int endOffset) {

    /* */ assert Utilities.TEST_MODE || EventQueue.isDispatchThread();
    LinkedList<R> result = new LinkedList<R>();
    if (startOffset == endOffset) return result;

    /* Find all regions with an endPoint greater than startOffset. */

    @SuppressWarnings("unchecked")
    SortedSet<R> tail = getTailSet((R) newDocumentRegion(odd, 0, startOffset + 1));

    // tail is sorted by <startOffset, endOffset>; tail may be empty

    for (R r : tail) {
      if (r.getStartOffset() >= endOffset) break;
      else result.add(r);
    }
    return result;
  }