JAL-3073 select columns if dragging sideways in a graph annotation
[jalview.git] / src / jalview / datamodel / features / NCNode.java
index d4c7b0c..b991750 100644 (file)
@@ -1,5 +1,27 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.datamodel.features;
 
+import jalview.datamodel.ContiguousI;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -9,7 +31,7 @@ import java.util.List;
  *
  * @param <V>
  */
-class NCNode<V extends ContiguousI>
+class NCNode<V extends ContiguousI> implements ContiguousI
 {
   /*
    * deep size (number of ranges included)
@@ -18,10 +40,13 @@ class NCNode<V extends ContiguousI>
 
   private V region;
 
+  /*
+   * null, or an object holding contained subregions of this nodes region
+   */
   private NCList<V> subregions;
 
   /**
-   * Constructor
+   * Constructor given a list of ranges
    * 
    * @param ranges
    */
@@ -31,17 +56,24 @@ class NCNode<V extends ContiguousI>
   }
 
   /**
-   * Constructo
+   * Constructor given a single range
    * 
    * @param range
    */
   NCNode(V range)
   {
-    List<V> ranges = new ArrayList<V>();
+    List<V> ranges = new ArrayList<>();
     ranges.add(range);
     build(ranges);
   }
 
+  NCNode(V entry, NCList<V> newNCList)
+  {
+    region = entry;
+    subregions = newNCList;
+    size = 1 + newNCList.size();
+  }
+
   /**
    * @param ranges
    */
@@ -59,16 +91,25 @@ class NCNode<V extends ContiguousI>
     }
   }
 
-  int getStart()
+  @Override
+  public int getBegin()
   {
     return region.getBegin();
   }
 
-  int getEnd()
+  @Override
+  public int getEnd()
   {
     return region.getEnd();
   }
 
+  /**
+   * Formats the node as a bracketed list e.g.
+   * 
+   * <pre>
+   * [1-100 [10-30 [10-20]], 15-30 [20-20]]
+   * </pre>
+   */
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder(10 * size);
@@ -80,6 +121,17 @@ class NCNode<V extends ContiguousI>
     return sb.toString();
   }
 
+  void prettyPrint(StringBuilder sb, int offset, int indent) {
+    for (int i = 0 ; i < offset ; i++) {
+      sb.append(" ");
+    }
+    sb.append(region.getBegin()).append("-").append(region.getEnd());
+    if (subregions != null)
+    {
+      sb.append(System.lineSeparator());
+      subregions.prettyPrint(sb, offset + 2, indent);
+    }
+  }
   /**
    * Add any ranges that overlap the from-to range to the result list
    * 
@@ -87,7 +139,7 @@ class NCNode<V extends ContiguousI>
    * @param to
    * @param result
    */
-  void addOverlaps(long from, long to, List<V> result)
+  void findOverlaps(long from, long to, List<V> result)
   {
     if (region.getBegin() <= to && region.getEnd() >= from)
     {
@@ -104,7 +156,7 @@ class NCNode<V extends ContiguousI>
    * 
    * @param entry
    */
-  public synchronized void add(V entry)
+  synchronized void add(V entry)
   {
     if (entry.getBegin() < region.getBegin() || entry.getEnd() > region.getEnd()) {
       throw new IllegalArgumentException(String.format(
@@ -120,5 +172,104 @@ class NCNode<V extends ContiguousI>
     {
       subregions.add(entry);
     }
+    size++;
+  }
+
+  /**
+   * Answers true if the data held satisfy the rules of construction of an
+   * NCList, else false.
+   * 
+   * @return
+   */
+  boolean isValid()
+  {
+    /*
+     * we don't handle reverse ranges
+     */
+    if (region != null && region.getBegin() > region.getEnd())
+    {
+      return false;
+    }
+    if (subregions == null)
+    {
+      return true;
+    }
+    return subregions.isValid(getBegin(), getEnd());
+  }
+
+  /**
+   * Adds all contained entries to the given list
+   * 
+   * @param entries
+   */
+  void getEntries(List<V> entries)
+  {
+    entries.add(region);
+    if (subregions != null)
+    {
+      subregions.getEntries(entries);
+    }
+  }
+
+  /**
+   * Answers true if this object contains the given entry (by object equals
+   * test), else false
+   * 
+   * @param entry
+   * @return
+   */
+  boolean contains(V entry)
+  {
+    if (entry == null)
+    {
+      return false;
+    }
+    if (entry.equals(region))
+    {
+      return true;
+    }
+    return subregions == null ? false : subregions.contains(entry);
+  }
+
+  /**
+   * Answers the 'root' region modelled by this object
+   * 
+   * @return
+   */
+  V getRegion()
+  {
+    return region;
+  }
+
+  /**
+   * Answers the (possibly null) contained regions within this object
+   * 
+   * @return
+   */
+  NCList<V> getSubRegions()
+  {
+    return subregions;
+  }
+
+  /**
+   * Nulls the subregion reference if it is empty (after a delete entry
+   * operation)
+   */
+  void deleteSubRegionsIfEmpty()
+  {
+    if (subregions != null && subregions.size() == 0)
+    {
+      subregions = null;
+    }
+  }
+
+  /**
+   * Answers the (deep) size of this node i.e. the number of ranges it models
+   * 
+   * @return
+   */
+  int size()
+  {
+    return size;
   }
 }