Merge branch 'develop' into features/JAL-2446NCList
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 22 May 2017 14:16:40 +0000 (15:16 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 22 May 2017 14:16:40 +0000 (15:16 +0100)
Conflicts:
src/jalview/analysis/AlignmentSorter.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/SeqPanel.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
test/jalview/analysis/AlignmentSorterTest.java

27 files changed:
help/html/features/chimera.html
help/html/menus/desktopMenu.html
help/html/releases.html
help/html/whatsNew.html
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/Finder.java
src/jalview/appletgui/SeqPanel.java
src/jalview/datamodel/AlignmentView.java
src/jalview/datamodel/AllColsIterator.java
src/jalview/datamodel/AllRowsIterator.java
src/jalview/datamodel/CigarArray.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/CutAndPasteTransfer.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/Finder.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/SeqPanel.java
src/jalview/jbgui/GDesktop.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
test/jalview/datamodel/AllColsIteratorTest.java
test/jalview/datamodel/AllRowsIteratorTest.java

index 5ae00af..68ac465 100644 (file)
             structure in the alignment. The regions used to calculate
             the superposition will be highlighted using the 'Cartoon'
             rendering style, and the remaining data shown as a chain
-            trace.<br>
+            trace.<br/><br/>
         </em></li>
-      </ul></li>
-    <li><strong>Help<br>
+        <li><strong><a name="experimental">EXPERIMENTAL FEATURES</a></strong><br/>
+          <em>
+            These are only available if the <strong>Tools&#8594;Enable
+            Experimental Features</strong> option is enabled. (Since Jalview 2.10.2)</em>
+          <ul>
+            <li><strong>Write Jalview features</strong><br /> <em>Selecting
+                this option will create new residue attributes for any
+                features currently visible in the associated alignment
+                views, allowing those positions to be selected and
+                analysed with via Chimera's 'Render by Attribute' tool
+                (found in the Tools submenu called Structure Analysis).<br />
+                <br />If you use this option, please remember to select
+                the <em>Refresh Menus</em> option in Chimera's Render by
+                Attribute dialog box in order to see the attributes
+                derived from Jalview sequence features.
+            </em><br />
+            <a href="https://issues.jalview.org/browse/JAL-2295">View
+                this function's issue in Jalview's bug tracker</a></li>
+            <li><strong>Fetch Chimera Attributes</strong><br /> <em>This
+                submenu lists available Chimera residue attributes that
+                can be imported as Jalview features on associated
+                sequences.<br />This is particularly useful for
+                transferring quantitative positional annotation. For
+                example, structure similarity for an alignment can be
+                visualised by transferring the local RMSD attributes
+                generated by Chimera's Match->Align tool onto aligned
+                sequences and displayed with a <a
+                href="featureschemes.html">Graduated feature colour
+                  scheme</a>.
+            </em><a href="https://issues.jalview.org/browse/JAL-2296">View
+                this function's issue in Jalview's bug tracker</a></li>
+          </ul></li>
+        <li><strong>Help<br>
     </strong>
       <ul>
         <li><strong>Chimera Help<br>
index 20e784b..a93ce4b 100755 (executable)
@@ -86,6 +86,7 @@
             the <a href="../features/groovy.html">Groovy Console</a> for
             interactive scripting.
         </em><strong><br></strong></li>
+        <li><strong>Enable Experimental Features</strong> <em>Enable or disable <a href="../whatsNew.html#experimental">features still under development</a> in Jalview's user interface. This setting is remembered in your preferences.</em>
 
       </ul></li>
     <li><strong>Vamsas</strong> <em>For more details, read the
index 2f983fa..1fe2602 100755 (executable)
@@ -79,19 +79,36 @@ li:before {
           <ul>
           <li><!-- JAL-2360,JAL-2371, -->More robust colours and shader model for alignments and groups</li>
           <li><!--  JAL-384 -->Custom shading schemes created via groovy scripts</li>
-          <li><!-- JAL-2314, -->Test suite expanded and debugged (over 940 functional unit tests, only 3 failing due to ongoing work!)
           </ul>
           <em>Application</em>
           <ul>
-          <li><!--  --></li>
+            <li>
+              <!-- JAL-2447 -->
+              Experimental Features Checkbox in Desktop's Tools
+              menu to hide or show untested features in the application.
+            </li>
+            <li><!-- JAL-1476 -->Warning in alignment status bar when there are not enough columns to superimpose structures in Chimera</li>
           <li><!-- JAL-1596 -->Faster Chimera/Jalview communication by file-based command exchange</li>  
           <li><!-- JAL-2316, -->URLs for viewing database cross-references provided by identifiers.org and the EMBL-EBI's MIRIAM DB</li>
           
           </ul>
+          <em>Experimental features</em>
+          <ul>
+            <li>
+              <!-- JAL-2295, JAL-2296 -->New entries in the Chimera menu
+              to transfer Chimera's structure attributes as Jalview
+              features, and vice-versa.
+            </li>
+          </ul>
           <em>Applet</em>
           <ul>
           <li><!--  --></li>
           </ul>
+          <em>Test Suite</em>
+          <li><!--  JAL-2474 -->Added PrivelegedAccessor to test suite</li>
+          <li><!-- JAL-2326 -->Prevent or clear modal dialogs raised during tests</li>
+          <li><!--  -->  
+          </ul>
           </div></td><td><div align="left">
           <em>General</em>
           <ul>
index 0734271..f5fcf18 100755 (executable)
     <strong>What's new in Jalview 2.10.2 ?</strong>
   </p>
   <p>
-    Full details about Jalview 2.10.2 are in the <a href="releases.html#Jalview.2.10.2">
-      Release Notes</a>, but the highlights are below.</p>
+    Full details about Jalview 2.10.2 are in the <a
+      href="releases.html#Jalview.2.10.2"> Release Notes</a>, but the
+    highlights are below.
+  </p>
+  <ul>
+    <li>
+    <li>New preferences for <a href="webServices/urllinks.html">opening
+        web pages for database cross-references</a> via the UK Elixir's
+      EMBL-EBI's MIRIAM database and identifiers.org services.
+    </li>
+  </ul>
+  <p>
+    <strong><a name="experimental">Experimental Features</a></strong>
+  </p>
+  <p>This release of Jalview includes a new option in the Jalview Desktop
+  that allows you to try out features that are still in development. To
+  access the features described below, please first enable the
+  <strong>Tools&#8594;Enable Experimental Features</strong> option, and then restart Jalview.
+  </p>
   <ul>
-  <li>
-  <li>New preferences for <a href="webServices/urllinks.html">opening web pages for database cross-references</a> via the UK Elixir's EMBL-EBI's MIRIAM database and identifiers.org services.</li>
+    <li><em>Annotation transfer between Chimera and Jalview</em><br />Two
+      <a href="features/chimera.html#experimental">new entries in the Chimera viewer's Chimera menu</a> allow positional
+      annotation to be exchanged between Chimera and Jalview.
+      </li>
   </ul>
-
 </body>
 </html>
index 4772d55..8099dff 100644 (file)
@@ -1307,3 +1307,6 @@ label.consensus_descr = PID
 label.complement_consensus_descr = PID for cDNA
 label.strucconsensus_descr = PID for base pairs
 label.occupancy_descr = Number of aligned positions 
+label.show_experimental = Enable experimental features
+label.show_experimental_tip = Enable any new and currently 'experimental' features (see Latest Release Notes for details)
+label.warning_hidden = Warning: {0} {1} is currently hidden
index dd5ba99..7808480 100644 (file)
@@ -1307,3 +1307,4 @@ label.complement_consensus_descr = % Identidad para cDNA
 label.strucconsensus_descr = % Identidad para pares de bases
 label.occupancy_descr = Número de posiciones alineadas
 label.togglehidden = Show hidden regions
+label.warning_hidden = Advertencia: {0} {1} está actualmente oculto
index cd49f63..8fd317a 100644 (file)
@@ -843,7 +843,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
       seqs = rseqs;
 
       if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-              features, true, ap, null))
+              features, true, ap))
       {
         ap.alignFrame.sequenceFeatures.setState(true);
         ap.av.setShowSequenceFeatures(true);
index be027ec..a6d0d99 100644 (file)
@@ -36,7 +36,9 @@ import java.awt.Button;
 import java.awt.Choice;
 import java.awt.Color;
 import java.awt.Dimension;
+import java.awt.FlowLayout;
 import java.awt.Font;
+import java.awt.Frame;
 import java.awt.Graphics;
 import java.awt.GridLayout;
 import java.awt.Label;
@@ -48,6 +50,8 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
 import java.util.Hashtable;
 
 /**
@@ -59,6 +63,13 @@ import java.util.Hashtable;
 public class FeatureRenderer extends
         jalview.renderer.seqfeatures.FeatureRenderer
 {
+  /*
+   * creating a new feature defaults to the type and group as
+   * the last one created
+   */
+  static String lastFeatureAdded = "feature_1";
+
+  static String lastFeatureGroupAdded = "Jalview";
 
   // Holds web links for feature groups and feature types
   // in the form label|link
@@ -75,12 +86,6 @@ public class FeatureRenderer extends
 
   }
 
-  static String lastFeatureAdded;
-
-  static String lastFeatureGroupAdded;
-
-  static String lastDescriptionAdded;
-
   int featureIndex = 0;
 
   boolean deleteFeature = false;
@@ -167,22 +172,23 @@ public class FeatureRenderer extends
 
   /**
    * Shows a dialog allowing the user to create, or amend or delete, sequence
-   * features.
+   * features. If null in the supplied feature(s), feature type and group
+   * default to those for the last feature created (with initial defaults of
+   * "feature_1" and "Jalview").
    * 
    * @param sequences
    * @param features
    * @param create
    * @param ap
-   * @param featureType
    * @return
    */
   boolean amendFeatures(final SequenceI[] sequences,
           final SequenceFeature[] features, boolean create,
-          final AlignmentPanel ap, String featureType)
+          final AlignmentPanel ap)
   {
-    Panel bigPanel = new Panel(new BorderLayout());
+    final Panel bigPanel = new Panel(new BorderLayout());
     final TextField name = new TextField(16);
-    final TextField source = new TextField(16);
+    final TextField group = new TextField(16);
     final TextArea description = new TextArea(3, 35);
     final TextField start = new TextField(8);
     final TextField end = new TextField(8);
@@ -190,6 +196,22 @@ public class FeatureRenderer extends
     Button deleteButton = new Button("Delete");
     deleteFeature = false;
 
+    name.addTextListener(new TextListener()
+    {
+      @Override
+      public void textValueChanged(TextEvent e)
+      {
+        warnIfTypeHidden(ap.alignFrame, name.getText());
+      }
+    });
+    group.addTextListener(new TextListener()
+    {
+      @Override
+      public void textValueChanged(TextEvent e)
+      {
+        warnIfGroupHidden(ap.alignFrame, group.getText());
+      }
+    });
     colourPanel = new FeatureColourPanel();
     colourPanel.setSize(110, 15);
     final FeatureRenderer fr = this;
@@ -233,7 +255,7 @@ public class FeatureRenderer extends
             featureIndex = index;
             name.setText(features[index].getType());
             description.setText(features[index].getDescription());
-            source.setText(features[index].getFeatureGroup());
+            group.setText(features[index].getFeatureGroup());
             start.setText(features[index].getBegin() + "");
             end.setText(features[index].getEnd() + "");
 
@@ -269,7 +291,7 @@ public class FeatureRenderer extends
     tmp = new Panel();
     panel.add(tmp);
     tmp.add(new Label(MessageManager.getString("label.group:"), Label.RIGHT));
-    tmp.add(source);
+    tmp.add(group);
 
     tmp = new Panel();
     panel.add(tmp);
@@ -301,36 +323,16 @@ public class FeatureRenderer extends
       bigPanel.add(panel, BorderLayout.CENTER);
     }
 
-    if (featureType != null)
-    {
-      lastFeatureAdded = featureType;
-    }
-    else
-    {
-      if (lastFeatureAdded == null)
-      {
-        if (features[0].type != null)
-        {
-          lastFeatureAdded = features[0].type;
-        }
-        else
-        {
-          lastFeatureAdded = "feature_1";
-        }
-      }
-    }
-
-    if (lastFeatureGroupAdded == null)
-    {
-      if (features[0].featureGroup != null)
-      {
-        lastFeatureGroupAdded = features[0].featureGroup;
-      }
-      else
-      {
-        lastFeatureAdded = "Jalview";
-      }
-    }
+    /*
+     * use defaults for type and group (and update them on Confirm) only
+     * if feature type has not been supplied by the caller
+     * (e.g. for Amend, or create features from Find) 
+     */
+    boolean useLastDefaults = features[0].getType() == null;
+    String featureType = useLastDefaults ? lastFeatureAdded : features[0]
+            .getType();
+    String featureGroup = useLastDefaults ? lastFeatureGroupAdded
+            : features[0].getFeatureGroup();
 
     String title = create ? MessageManager
             .getString("label.create_new_sequence_features")
@@ -342,12 +344,10 @@ public class FeatureRenderer extends
 
     dialog.setMainPanel(bigPanel);
 
-    if (create)
-    {
-      name.setText(lastFeatureAdded);
-      source.setText(lastFeatureGroupAdded);
-    }
-    else
+    name.setText(featureType);
+    group.setText(featureGroup);
+
+    if (!create)
     {
       dialog.ok.setLabel(MessageManager.getString("label.amend"));
       dialog.buttonPanel.add(deleteButton, 1);
@@ -360,8 +360,6 @@ public class FeatureRenderer extends
           dialog.setVisible(false);
         }
       });
-      name.setText(features[0].getType());
-      source.setText(features[0].getFeatureGroup());
     }
 
     start.setText(features[0].getBegin() + "");
@@ -393,27 +391,27 @@ public class FeatureRenderer extends
 
     FeaturesFile ffile = new FeaturesFile();
 
-    if (dialog.accept)
+    /*
+     * only update default type and group if we used defaults
+     */
+    if (dialog.accept && useLastDefaults)
     {
       lastFeatureAdded = name.getText().trim();
-      lastFeatureGroupAdded = source.getText().trim();
-      lastDescriptionAdded = description.getText().replace('\n', ' ');
-    }
-
-    if (lastFeatureGroupAdded != null && lastFeatureGroupAdded.length() < 1)
-    {
-      lastFeatureGroupAdded = null;
+      lastFeatureGroupAdded = group.getText().trim();
     }
 
     if (!create)
     {
-
       SequenceFeature sf = features[featureIndex];
       if (dialog.accept)
       {
-        sf.type = lastFeatureAdded;
-        sf.featureGroup = lastFeatureGroupAdded;
-        sf.description = lastDescriptionAdded;
+        sf.type = name.getText().trim();
+        sf.featureGroup = group.getText().trim();
+        if (sf.featureGroup != null && sf.featureGroup.length() < 1)
+        {
+          sf.featureGroup = null;
+        }
+        sf.description = description.getText().replace('\n', ' ');
         if (!colourPanel.isGcol)
         {
           // update colour - otherwise its already done.
@@ -425,27 +423,37 @@ public class FeatureRenderer extends
           sf.end = Integer.parseInt(end.getText());
         } catch (NumberFormatException ex)
         {
+          //
         }
+        boolean typeOrGroupChanged = (!featureType.equals(sf.type) || !featureGroup
+                .equals(sf.featureGroup));
 
         ffile.parseDescriptionHTML(sf, false);
-        setVisible(lastFeatureAdded); // if user edited name then make sure new
-                                      // type is visible
+        if (typeOrGroupChanged)
+        {
+          featuresAdded();
+        }
       }
       if (deleteFeature)
       {
         sequences[0].deleteFeature(sf);
+        // ensure Feature Settings reflects removal of feature / group
+        featuresAdded();
       }
-
     }
     else
     {
+      /*
+       * adding feature(s)
+       */
       if (dialog.accept && name.getText().length() > 0)
       {
         for (int i = 0; i < sequences.length; i++)
         {
-          features[i].type = lastFeatureAdded;
-          features[i].featureGroup = lastFeatureGroupAdded;
-          features[i].description = lastDescriptionAdded;
+          features[i].type = name.getText().trim();
+          features[i].featureGroup = group.getText().trim();
+          features[i].description = description.getText()
+                  .replace('\n', ' ');
           sequences[i].addSequenceFeature(features[i]);
           ffile.parseDescriptionHTML(features[i], false);
         }
@@ -453,14 +461,8 @@ public class FeatureRenderer extends
         Color newColour = colourPanel.getBackground();
         // setColour(lastFeatureAdded, fcol);
 
-        if (lastFeatureGroupAdded != null)
-        {
-          setGroupVisibility(lastFeatureGroupAdded, true);
-        }
         setColour(lastFeatureAdded, new FeatureColour(newColour)); // was fcol
-        setVisible(lastFeatureAdded);
-        findAllFeatures(false); // different to original applet behaviour ?
-        // findAllFeatures();
+        featuresAdded();
       }
       else
       {
@@ -479,4 +481,43 @@ public class FeatureRenderer extends
 
     return true;
   }
+
+  protected void warnIfGroupHidden(Frame frame, String group)
+  {
+    if (featureGroups.containsKey(group) && !featureGroups.get(group))
+    {
+      String msg = MessageManager.formatMessage("label.warning_hidden",
+              MessageManager.getString("label.group"), group);
+      showWarning(frame, msg);
+    }
+  }
+
+  protected void warnIfTypeHidden(Frame frame, String type)
+  {
+    if (getRenderOrder().contains(type))
+    {
+      if (!showFeatureOfType(type))
+      {
+        String msg = MessageManager.formatMessage("label.warning_hidden",
+                MessageManager.getString("label.feature_type"), type);
+        showWarning(frame, msg);
+      }
+    }
+  }
+
+  /**
+   * @param frame
+   * @param msg
+   */
+  protected void showWarning(Frame frame, String msg)
+  {
+    JVDialog d = new JVDialog(frame, "", true, 350, 200);
+    Panel mp = new Panel();
+    d.ok.setLabel(MessageManager.getString("action.ok"));
+    d.cancel.setVisible(false);
+    mp.setLayout(new FlowLayout());
+    mp.add(new Label(msg));
+    d.setMainPanel(mp);
+    d.setVisible(true);
+  }
 }
index 68881b2..b0bb372 100755 (executable)
@@ -107,6 +107,7 @@ public class FeatureSettings extends Panel implements ItemListener,
     {
       fr.findAllFeatures(true); // was default - now true to make all visible
     }
+    groupPanel = new Panel();
 
     discoverAllFeatureData();
 
@@ -134,17 +135,15 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     add(lowerPanel, BorderLayout.SOUTH);
 
-    if (groupPanel != null)
-    {
-      groupPanel.setLayout(new GridLayout(
-              (fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote - this was
-                                                        // scaled on number of
-                                                        // visible groups. seems
-                                                        // broken
-      groupPanel.validate();
+    groupPanel.setLayout(new GridLayout(
+            (fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote - this was
+                                                      // scaled on number of
+                                                      // visible groups. seems
+                                                      // broken
+    groupPanel.validate();
+
+    add(groupPanel, BorderLayout.NORTH);
 
-      add(groupPanel, BorderLayout.NORTH);
-    }
     frame = new Frame();
     frame.add(this);
     final FeatureSettings me = this;
@@ -327,44 +326,43 @@ public class FeatureSettings extends Panel implements ItemListener,
     if (fr.getAllFeatureColours() != null
             && fr.getAllFeatureColours().size() > 0)
     {
-      rebuildGroups();
+      // rebuildGroups();
 
     }
     resetTable(false);
   }
 
   /**
-   * rebuilds the group panel
+   * Answers the visibility of the given group, and adds a checkbox for it if
+   * there is not one already
    */
-  public void rebuildGroups()
+  public boolean checkGroupState(String group)
   {
-    boolean rdrw = false;
-    if (groupPanel == null)
-    {
-      groupPanel = new Panel();
-    }
-    else
-    {
-      rdrw = true;
-      groupPanel.removeAll();
-    }
-    // TODO: JAL-964 - smoothly incorporate new group entries if panel already
-    // displayed and new groups present
-    for (String group : fr.getFeatureGroups())
-    {
-      boolean vis = fr.checkGroupVisibility(group, false);
-      Checkbox check = new MyCheckbox(group, vis, false);
-      check.addMouseListener(this);
-      check.setFont(new Font("Serif", Font.BOLD, 12));
-      check.addItemListener(groupItemListener);
-      // note - visibility seems to correlate with displayed. ???wtf ??
-      check.setVisible(vis);
-      groupPanel.add(check);
-    }
-    if (rdrw)
+    boolean visible = fr.checkGroupVisibility(group, true);
+
+    /*
+     * is there already a checkbox for this group?
+     */
+    for (int g = 0; g < groupPanel.getComponentCount(); g++)
     {
-      groupPanel.validate();
+      if (((Checkbox) groupPanel.getComponent(g)).getLabel().equals(group))
+      {
+        ((Checkbox) groupPanel.getComponent(g)).setState(visible);
+        return visible;
+      }
     }
+
+    /*
+     * add a new checkbox
+     */
+    Checkbox check = new MyCheckbox(group, visible, false);
+    check.addMouseListener(this);
+    check.setFont(new Font("Serif", Font.BOLD, 12));
+    check.addItemListener(groupItemListener);
+    groupPanel.add(check);
+
+    groupPanel.validate();
+    return visible;
   }
 
   // This routine adds and removes checkboxes depending on
@@ -372,7 +370,10 @@ public class FeatureSettings extends Panel implements ItemListener,
   void resetTable(boolean groupsChanged)
   {
     List<String> displayableTypes = new ArrayList<String>();
+    Set<String> foundGroups = new HashSet<String>();
+
     AlignmentI alignment = av.getAlignment();
+
     for (int i = 0; i < alignment.getHeight(); i++)
     {
       SequenceI seq = alignment.getSequenceAt(i);
@@ -400,6 +401,11 @@ public class FeatureSettings extends Panel implements ItemListener,
       displayableTypes.addAll(types);
     }
 
+    /*
+     * remove any checkboxes for groups not present
+     */
+    pruneGroups(foundGroups);
+
     Component[] comps;
     int cSize = featurePanel.getComponentCount();
     MyCheckbox check;
@@ -459,6 +465,25 @@ public class FeatureSettings extends Panel implements ItemListener,
   }
 
   /**
+   * Remove from the groups panel any checkboxes for groups that are not in the
+   * foundGroups set. This enables removing a group from the display when the
+   * last feature in that group is deleted.
+   * 
+   * @param foundGroups
+   */
+  protected void pruneGroups(Set<String> foundGroups)
+  {
+    for (int g = 0; g < groupPanel.getComponentCount(); g++)
+    {
+      Checkbox checkbox = (Checkbox) groupPanel.getComponent(g);
+      if (!foundGroups.contains(checkbox.getLabel()))
+      {
+        groupPanel.remove(checkbox);
+      }
+    }
+  }
+
+  /**
    * update the checklist of feature types with the given type
    * 
    * @param groupsChanged
index 2579d91..a342736 100644 (file)
@@ -130,7 +130,7 @@ public class Finder extends Panel implements ActionListener
     }
 
     if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-            features, true, ap, searchString))
+            features, true, ap))
     {
       ap.alignFrame.sequenceFeatures.setState(true);
       av.setShowSequenceFeatures(true);
index 02dc848..c10038f 100644 (file)
@@ -575,8 +575,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         SequenceFeature[] featuresArray = features
                 .toArray(new SequenceFeature[features.size()]);
         seqCanvas.getFeatureRenderer().amendFeatures(
-                new SequenceI[] { sequence }, featuresArray, false, ap,
-                null);
+                new SequenceI[] { sequence }, featuresArray, false, ap);
 
         seqCanvas.highlightSearchResults(null);
       }
index 5058dcf..9ca70f2 100644 (file)
@@ -918,7 +918,7 @@ public class AlignmentView
       }
       if (nvismsa[0] != null)
       {
-        return new Object[] { nvismsa[0], new ColumnSelection() };
+        return new Object[] { nvismsa[0], new HiddenColumns() };
       }
       else
       {
index c7a0bb1..c1296d5 100644 (file)
@@ -48,13 +48,13 @@ public class AllColsIterator implements Iterator<Integer>
   @Override
   public boolean hasNext()
   {
-    return current + 1 <= last;
+    return next <= last;
   }
 
   @Override
   public Integer next()
   {
-    if (current + 1 > last)
+    if (next > last)
     {
       throw new NoSuchElementException();
     }
index aefed60..b6d45f8 100644 (file)
@@ -51,13 +51,13 @@ public class AllRowsIterator implements Iterator<Integer>
   @Override
   public boolean hasNext()
   {
-    return current + 1 <= last;
+    return next <= last;
   }
 
   @Override
   public Integer next()
   {
-    if (current + 1 > last)
+    if (next > last)
     {
       throw new NoSuchElementException();
     }
index aab82a1..837a10b 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.datamodel;
 
-import htsjdk.samtools.Cigar;
-
 import java.util.List;
 
 public class CigarArray extends CigarBase
@@ -220,7 +218,7 @@ public class CigarArray extends CigarBase
   }
 
   /**
-   * @see Cigar.getSequenceAndDeletions
+   * @see CigarBase.getSequenceAndDeletions
    * @param GapChar
    *          char
    * @return Object[][]
index ec9feb7..ab6f6c8 100644 (file)
@@ -100,35 +100,41 @@ public class ChimeraViewFrame extends StructureViewerBase
     savemenu.setVisible(false); // not yet implemented
     viewMenu.add(fitToWindow);
 
-    JMenuItem writeFeatures = new JMenuItem(
-            MessageManager.getString("label.create_chimera_attributes"));
-    writeFeatures.setToolTipText(MessageManager
-            .getString("label.create_chimera_attributes_tip"));
-    writeFeatures.addActionListener(new ActionListener()
+    /*
+     * exchange of Jalview features and Chimera attributes is for now
+     * an optionally enabled experimental feature
+     */
+    if (Desktop.instance.showExperimental())
     {
-      @Override
-      public void actionPerformed(ActionEvent e)
+      JMenuItem writeFeatures = new JMenuItem(
+              MessageManager.getString("label.create_chimera_attributes"));
+      writeFeatures.setToolTipText(MessageManager
+              .getString("label.create_chimera_attributes_tip"));
+      writeFeatures.addActionListener(new ActionListener()
       {
-        sendFeaturesToChimera();
-      }
-    });
-    viewerActionMenu.add(writeFeatures);
-
-    final JMenu fetchAttributes = new JMenu(
-            MessageManager.getString("label.fetch_chimera_attributes"));
-    fetchAttributes.setToolTipText(MessageManager
-            .getString("label.fetch_chimera_attributes_tip"));
-    fetchAttributes.addMouseListener(new MouseAdapter()
-    {
-
-      @Override
-      public void mouseEntered(MouseEvent e)
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          sendFeaturesToChimera();
+        }
+      });
+      viewerActionMenu.add(writeFeatures);
+
+      final JMenu fetchAttributes = new JMenu(
+              MessageManager.getString("label.fetch_chimera_attributes"));
+      fetchAttributes.setToolTipText(MessageManager
+              .getString("label.fetch_chimera_attributes_tip"));
+      fetchAttributes.addMouseListener(new MouseAdapter()
       {
-        buildAttributesMenu(fetchAttributes);
-      }
-    });
-    viewerActionMenu.add(fetchAttributes);
 
+        @Override
+        public void mouseEntered(MouseEvent e)
+        {
+          buildAttributesMenu(fetchAttributes);
+        }
+      });
+      viewerActionMenu.add(fetchAttributes);
+    }
   }
 
   /**
index a5aa9eb..3eced2f 100644 (file)
@@ -298,6 +298,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
                   AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
           af.getViewport().setShowSequenceFeatures(showSeqFeatures);
           af.getViewport().setFeaturesDisplayed(fd);
+          af.setMenusForViewport();
           ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
                   colourSchemeName, al);
           if (cs != null)
index d6c25a8..4877d7f 100644 (file)
@@ -133,6 +133,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   private static int DEFAULT_MIN_HEIGHT = 250;
 
+  private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
+
   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
 
   /**
@@ -330,19 +332,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     instance = this;
     doVamsasClientCheck();
 
-    groovyShell = new JMenuItem();
-    groovyShell.setText(MessageManager.getString("label.groovy_console"));
-    groovyShell.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        groovyShell_actionPerformed();
-      }
-    });
-    toolsMenu.add(groovyShell);
-    groovyShell.setVisible(true);
-
     doConfigureStructurePrefs();
     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@@ -397,6 +386,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     showConsole(showjconsole);
 
     showNews.setVisible(false);
+    
+    experimentalFeatures.setSelected(showExperimental());
 
     getIdentifiersOrgData();
 
@@ -493,6 +484,19 @@ public class Desktop extends jalview.jbgui.GDesktop implements
             });
   }
 
+  /**
+   * Answers true if user preferences to enable experimental features is True
+   * (on), else false
+   * 
+   * @return
+   */
+  public boolean showExperimental()
+  {
+    String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
+            Boolean.FALSE.toString());
+    return Boolean.valueOf(experimental).booleanValue();
+  }
+
   public void doConfigureStructurePrefs()
   {
     // configure services
@@ -2497,8 +2501,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   }
 
-  protected JMenuItem groovyShell;
-
   /**
    * Accessor method to quickly get all the AlignmentFrames loaded.
    * 
@@ -2584,6 +2586,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   /**
    * Add Groovy Support to Jalview
    */
+  @Override
   public void groovyShell_actionPerformed()
   {
     try
@@ -3398,4 +3401,14 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       }
     }
   }
+
+  /**
+   * Sets the Preferences property for experimental features to True or False
+   * depending on the state of the controlling menu item
+   */
+  @Override
+  protected void showExperimental_actionPerformed(boolean selected)
+  {
+    Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
+  }
 }
index b33ada2..0779760 100644 (file)
@@ -55,6 +55,8 @@ import javax.swing.JSpinner;
 import javax.swing.JTextArea;
 import javax.swing.JTextField;
 import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 
 /**
  * DOCUMENT ME!
@@ -65,6 +67,14 @@ import javax.swing.SwingConstants;
 public class FeatureRenderer extends
         jalview.renderer.seqfeatures.FeatureRenderer
 {
+  /*
+   * defaults for creating a new feature are the last created
+   * feature type and group
+   */
+  static String lastFeatureAdded = "feature_1";
+
+  static String lastFeatureGroupAdded = "Jalview";
+
   Color resBoxColour;
 
   AlignmentPanel ap;
@@ -86,16 +96,6 @@ public class FeatureRenderer extends
     }
   }
 
-  // // /////////////
-  // // Feature Editing Dialog
-  // // Will be refactored in next release.
-
-  static String lastFeatureAdded;
-
-  static String lastFeatureGroupAdded;
-
-  static String lastDescriptionAdded;
-
   FeatureColourI oldcol, fcol;
 
   int featureIndex = 0;
@@ -108,32 +108,73 @@ public class FeatureRenderer extends
    * <li>Create sequence feature from pop-up menu on selected region</li>
    * <li>Create features for pattern matches from Find</li>
    * </ul>
+   * If the supplied feature type is null, show (and update on confirm) the type
+   * and group of the last new feature created (with initial defaults of
+   * "feature_1" and "Jalview").
    * 
    * @param sequences
    *          the sequences features are to be created on (if creating
    *          features), or a single sequence (if amending features)
    * @param features
    *          the current features at the position (if amending), or template
-   *          new features with start/end position set (if creating)
+   *          new feature(s) with start/end position set (if creating)
    * @param create
    *          true to create features, false to amend or delete
-   * @param featureType
-   *          the feature type to set on new features; if null, defaults to the
-   *          type of the last new feature created if any, failing that to
-   *          "feature_1"
    * @param alignPanel
    * @return
    */
   protected boolean amendFeatures(final List<SequenceI> sequences,
           final List<SequenceFeature> features, boolean create,
-          final AlignmentPanel alignPanel, String featureType)
+          final AlignmentPanel alignPanel)
   {
-
     featureIndex = 0;
 
     final JPanel mainPanel = new JPanel(new BorderLayout());
+
     final JTextField name = new JTextField(25);
-    final JTextField source = new JTextField(25);
+    name.getDocument().addDocumentListener(new DocumentListener()
+    {
+      @Override
+      public void insertUpdate(DocumentEvent e)
+      {
+        warnIfTypeHidden(mainPanel, name.getText());
+      }
+
+      @Override
+      public void removeUpdate(DocumentEvent e)
+      {
+        warnIfTypeHidden(mainPanel, name.getText());
+      }
+
+      @Override
+      public void changedUpdate(DocumentEvent e)
+      {
+        warnIfTypeHidden(mainPanel, name.getText());
+      }
+    });
+
+    final JTextField group = new JTextField(25);
+    group.getDocument().addDocumentListener(new DocumentListener()
+    {
+      @Override
+      public void insertUpdate(DocumentEvent e)
+      {
+        warnIfGroupHidden(mainPanel, group.getText());
+      }
+
+      @Override
+      public void removeUpdate(DocumentEvent e)
+      {
+        warnIfGroupHidden(mainPanel, group.getText());
+      }
+
+      @Override
+      public void changedUpdate(DocumentEvent e)
+      {
+        warnIfGroupHidden(mainPanel, group.getText());
+      }
+    });
+
     final JTextArea description = new JTextArea(3, 25);
     final JSpinner start = new JSpinner();
     final JSpinner end = new JSpinner();
@@ -223,7 +264,7 @@ public class FeatureRenderer extends
             SequenceFeature sf = features.get(index);
             name.setText(sf.getType());
             description.setText(sf.getDescription());
-            source.setText(sf.getFeatureGroup());
+            group.setText(sf.getFeatureGroup());
             start.setValue(new Integer(sf.getBegin()));
             end.setValue(new Integer(sf.getEnd()));
 
@@ -247,8 +288,6 @@ public class FeatureRenderer extends
 
       gridPanel.add(choosePanel);
     }
-    // ////////
-    // ////////////////////////////////////
 
     JPanel namePanel = new JPanel();
     gridPanel.add(namePanel);
@@ -260,7 +299,7 @@ public class FeatureRenderer extends
     gridPanel.add(groupPanel);
     groupPanel.add(new JLabel(MessageManager.getString("label.group:"),
             JLabel.RIGHT));
-    groupPanel.add(source);
+    groupPanel.add(group);
 
     JPanel colourPanel = new JPanel();
     gridPanel.add(colourPanel);
@@ -302,48 +341,18 @@ public class FeatureRenderer extends
       mainPanel.add(descriptionPanel, BorderLayout.CENTER);
     }
 
+    /*
+     * default feature type and group to that of the first feature supplied,
+     * or to the last feature created if not supplied (null value) 
+     */
     SequenceFeature firstFeature = features.get(0);
-    if (featureType != null)
-    {
-      lastFeatureAdded = featureType;
-    }
-    else
-    {
-      if (lastFeatureAdded == null)
-      {
-        if (firstFeature.type != null)
-        {
-          lastFeatureAdded = firstFeature.type;
-        }
-        else
-        {
-          lastFeatureAdded = "feature_1";
-        }
-      }
-    }
-
-    if (lastFeatureGroupAdded == null)
-    {
-      if (firstFeature.featureGroup != null)
-      {
-        lastFeatureGroupAdded = firstFeature.featureGroup;
-      }
-      else
-      {
-        lastFeatureGroupAdded = "Jalview";
-      }
-    }
-
-    if (create)
-    {
-      name.setText(lastFeatureAdded);
-      source.setText(lastFeatureGroupAdded);
-    }
-    else
-    {
-      name.setText(firstFeature.getType());
-      source.setText(firstFeature.getFeatureGroup());
-    }
+    boolean useLastDefaults = firstFeature.getType() == null;
+    final String featureType = useLastDefaults ? lastFeatureAdded
+            : firstFeature.getType();
+    final String featureGroup = useLastDefaults ? lastFeatureGroupAdded
+            : firstFeature.getFeatureGroup();
+    name.setText(featureType);
+    group.setText(featureGroup);
 
     start.setValue(new Integer(firstFeature.getBegin()));
     end.setValue(new Integer(firstFeature.getEnd()));
@@ -380,13 +389,18 @@ public class FeatureRenderer extends
 
     if (reply == JvOptionPane.OK_OPTION && name.getText().length() > 0)
     {
-      lastFeatureAdded = name.getText().trim();
-      lastFeatureGroupAdded = source.getText().trim();
-      lastDescriptionAdded = description.getText().replaceAll("\n", " ");
-      // TODO: determine if the null feature group is valid
-      if (lastFeatureGroupAdded.length() < 1)
+      /*
+       * update default values only if creating using default values
+       */
+      if (useLastDefaults)
       {
-        lastFeatureGroupAdded = null;
+        lastFeatureAdded = name.getText().trim();
+        lastFeatureGroupAdded = group.getText().trim();
+        // TODO: determine if the null feature group is valid
+        if (lastFeatureGroupAdded.length() < 1)
+        {
+          lastFeatureGroupAdded = null;
+        }
       }
     }
 
@@ -400,19 +414,23 @@ public class FeatureRenderer extends
          * NO_OPTION corresponds to the Delete button
          */
         sequences.get(0).getDatasetSequence().deleteFeature(sf);
+        // update Feature Settings for removal of feature / group
+        featuresAdded();
       }
       else if (reply == JvOptionPane.YES_OPTION)
       {
         /*
          * YES_OPTION corresponds to the Amend button
+         * need to refresh Feature Settings if type, group or colour changed
          */
-        boolean typeChanged = !lastFeatureAdded.equals(sf.type);
-        String newType = lastFeatureAdded;
-        String newFeatureGroup = lastFeatureGroupAdded;
-        String newDescription = lastDescriptionAdded;
-
+        String newType = name.getText().trim();
+        String newFeatureGroup = group.getText().trim();
+        String newDescription = description.getText().replaceAll("\n", " ");
+        boolean refreshSettings = (!featureType.equals(sf.type) || !featureGroup
+                .equals(sf.featureGroup));
+        refreshSettings |= (fcol != oldcol);
         setColour(newType, fcol);
-        getFeaturesDisplayed().setVisible(newType);
+/*?*/        getFeaturesDisplayed().setVisible(newType);
         int newBegin = sf.begin;
         int newEnd = sf.end;
         try
@@ -449,9 +467,9 @@ public class FeatureRenderer extends
         // amend features only gets one sequence to act on
         sequences.get(0).addSequenceFeature(newSf);
 
-        if (typeChanged)
+        if (refreshSettings)
         {
-          findAllFeatures();
+          featuresAdded();
         }
       }
     }
@@ -463,22 +481,17 @@ public class FeatureRenderer extends
         for (int i = 0; i < sequences.size(); i++)
         {
           SequenceFeature sf = features.get(i);
-          sf.type = lastFeatureAdded;
+          sf.type = name.getText().trim();
           // fix for JAL-1538 - always set feature group here
-          sf.featureGroup = lastFeatureGroupAdded;
-          sf.description = lastDescriptionAdded;
+          sf.featureGroup = group.getText().trim();
+          sf.description = description.getText().replaceAll("\n", " ");
           sequences.get(i).addSequenceFeature(sf);
           ffile.parseDescriptionHTML(sf, false);
         }
 
-        if (lastFeatureGroupAdded != null)
-        {
-          setGroupVisibility(lastFeatureGroupAdded, true);
-        }
         setColour(lastFeatureAdded, fcol);
-        setVisible(lastFeatureAdded);
 
-        findAllFeatures(false);
+        featuresAdded();
 
         alignPanel.paintAlignment(true);
 
@@ -496,6 +509,42 @@ public class FeatureRenderer extends
   }
 
   /**
+   * Show a warning message if the entered type is one that is currently hidden
+   * 
+   * @param panel
+   * @param type
+   */
+  protected void warnIfTypeHidden(JPanel panel, String type)
+  {
+    if (getRenderOrder().contains(type))
+    {
+      if (!showFeatureOfType(type))
+      {
+        String msg = MessageManager.formatMessage("label.warning_hidden",
+                MessageManager.getString("label.feature_type"), type);
+        JvOptionPane.showMessageDialog(panel, msg, "",
+                JvOptionPane.OK_OPTION);
+      }
+    }
+  }
+
+  /**
+   * Show a warning message if the entered group is one that is currently hidden
+   * 
+   * @param panel
+   * @param group
+   */
+  protected void warnIfGroupHidden(JPanel panel, String group)
+  {
+    if (featureGroups.containsKey(group) && !featureGroups.get(group))
+    {
+      String msg = MessageManager.formatMessage("label.warning_hidden",
+              MessageManager.getString("label.group"), group);
+      JvOptionPane.showMessageDialog(panel, msg, "", JvOptionPane.OK_OPTION);
+    }
+  }
+
+  /**
    * update the amend feature button dependent on the given style
    * 
    * @param bigPanel
index 419cb34..45b6b0d 100644 (file)
@@ -132,6 +132,11 @@ public class FeatureSettings extends JPanel implements
 
   private static final int MIN_HEIGHT = 400;
 
+  /**
+   * Constructor
+   * 
+   * @param af
+   */
   public FeatureSettings(AlignFrame af)
   {
     this.af = af;
@@ -508,27 +513,15 @@ public class FeatureSettings extends JPanel implements
   {
     boolean visible = fr.checkGroupVisibility(group, true);
 
-    if (groupPanel == null)
-    {
-      groupPanel = new JPanel();
-    }
-
-    boolean alreadyAdded = false;
     for (int g = 0; g < groupPanel.getComponentCount(); g++)
     {
       if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
       {
-        alreadyAdded = true;
         ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
-        break;
+        return visible;
       }
     }
 
-    if (alreadyAdded)
-    {
-
-      return visible;
-    }
     final String grp = group;
     final JCheckBox check = new JCheckBox(group, visible);
     check.setFont(new Font("Serif", Font.BOLD, 12));
@@ -565,6 +558,7 @@ public class FeatureSettings extends JPanel implements
     // rather than float
 
     Set<String> displayableTypes = new HashSet<String>();
+    Set<String> foundGroups = new HashSet<String>();
 
     /*
      * determine which feature types may be visible depending on 
@@ -588,6 +582,7 @@ public class FeatureSettings extends JPanel implements
           visibleGroups.add(group);
         }
       }
+      foundGroups.addAll(groups);
 
       /*
        * get distinct feature types for visible groups
@@ -675,24 +670,105 @@ public class FeatureSettings extends JPanel implements
         System.arraycopy(data[i], 0, originalData[i], 0, 3);
       }
     }
+    else
+    {
+      updateOriginalData(data);
+    }
 
     table.setModel(new FeatureTableModel(data));
     table.getColumnModel().getColumn(0).setPreferredWidth(200);
 
-    if (groupPanel != null)
-    {
-      groupPanel.setLayout(new GridLayout(
-              fr.getFeatureGroupsSize() / 4 + 1, 4));
-
-      groupPanel.validate();
-      bigPanel.add(groupPanel, BorderLayout.NORTH);
-    }
+    groupPanel.setLayout(new GridLayout(fr.getFeatureGroupsSize() / 4 + 1,
+            4));
+    pruneGroups(foundGroups);
+    groupPanel.validate();
 
     updateFeatureRenderer(data, groupChanged != null);
     resettingTable = false;
   }
 
   /**
+   * Updates 'originalData' (used for restore on Cancel) if we detect that
+   * changes have been made outwith this dialog
+   * <ul>
+   * <li>a new feature type added (and made visible)</li>
+   * <li>a feature colour changed (in the Amend Features dialog)</li>
+   * </ul>
+   * 
+   * @param foundData
+   */
+  protected void updateOriginalData(Object[][] foundData)
+  {
+    // todo LinkedHashMap instead of Object[][] would be nice
+
+    Object[][] currentData = ((FeatureTableModel) table.getModel())
+            .getData();
+    for (Object[] row : foundData)
+    {
+      String type = (String) row[0];
+      boolean found = false;
+      for (Object[] current : currentData)
+      {
+        if (type.equals(current[0]))
+        {
+          found = true;
+          /*
+           * currently dependent on object equality here;
+           * really need an equals method on FeatureColour
+           */
+          if (!row[1].equals(current[1]))
+          {
+            /*
+             * feature colour has changed externally - update originalData
+             */
+            for (Object[] original : originalData)
+            {
+              if (type.equals(original[0]))
+              {
+                original[1] = row[1];
+                break;
+              }
+            }
+          }
+          break;
+        }
+      }
+      if (!found)
+      {
+        /*
+         * new feature detected - add to original data (on top)
+         */
+        Object[][] newData = new Object[originalData.length + 1][3];
+        for (int i = 0; i < originalData.length; i++)
+        {
+          System.arraycopy(originalData[i], 0, newData[i + 1], 0, 3);
+        }
+        newData[0] = row;
+        originalData = newData;
+      }
+    }
+  }
+
+  /**
+   * Remove from the groups panel any checkboxes for groups that are not in the
+   * foundGroups set. This enables removing a group from the display when the
+   * last feature in that group is deleted.
+   * 
+   * @param foundGroups
+   */
+  protected void pruneGroups(Set<String> foundGroups)
+  {
+    for (int g = 0; g < groupPanel.getComponentCount(); g++)
+    {
+      JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
+      if (!foundGroups.contains(checkbox.getText()))
+      {
+        groupPanel.remove(checkbox);
+      }
+    }
+  }
+
+  /**
    * reorder data based on the featureRenderers global priority list.
    * 
    * @param data
@@ -1032,6 +1108,10 @@ public class FeatureSettings extends JPanel implements
     settingsPane.setLayout(borderLayout2);
     dasSettingsPane.setLayout(borderLayout3);
     bigPanel.setLayout(borderLayout4);
+
+    groupPanel = new JPanel();
+    bigPanel.add(groupPanel, BorderLayout.NORTH);
+
     invert.setFont(JvSwingUtils.getLabelFont());
     invert.setText(MessageManager.getString("label.invert_selection"));
     invert.addActionListener(new ActionListener()
index 21c6c8a..625fc27 100755 (executable)
@@ -227,7 +227,7 @@ public class Finder extends GFinder
     }
 
     if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-            features, true, ap, searchString))
+            features, true, ap))
     {
       /*
        * ensure feature display is turned on to show the new features,
index 09e3263..3de7c3c 100644 (file)
@@ -1904,13 +1904,12 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       if (start <= end)
       {
         seqs.add(sg.getSequenceAt(i).getDatasetSequence());
-        features.add(new SequenceFeature(null, null, null, start, end,
-                "Jalview"));
+        features.add(new SequenceFeature(null, null, null, start, end, null));
       }
     }
 
     if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-            features, true, ap, null))
+            features, true, ap))
     {
       ap.alignFrame.setShowSeqFeatures(true);
       ap.highlightSearchResults(null);
index a2c2bd9..7dfac5e 100644 (file)
@@ -183,7 +183,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    * @param evt
    * @return
    */
-  int findRes(MouseEvent evt)
+  int findColumn(MouseEvent evt)
   {
     int res = 0;
     int x = evt.getX();
@@ -642,7 +642,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
 
     int seq = findSeq(evt);
-    int res = findRes(evt);
+    int res = findColumn(evt);
 
     if (seq < 0 || res < 0)
     {
@@ -741,25 +741,27 @@ public class SeqPanel extends JPanel implements MouseListener,
       mouseDragged(evt);
     }
 
-    int res = findRes(evt);
+    final int column = findColumn(evt);
     int seq = findSeq(evt);
-    int pos;
-    if (res < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
+    if (column < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
     {
       return;
     }
 
     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
 
-    if (res >= sequence.getLength())
+    if (column >= sequence.getLength())
     {
       return;
     }
 
-    pos = setStatusMessage(sequence, res, seq);
+    /*
+     * set status bar message, returning residue position in sequence
+     */
+    final int pos = setStatusMessage(sequence, column, seq);
     if (ssm != null && pos > -1)
     {
-      mouseOverSequence(sequence, res, pos);
+      mouseOverSequence(sequence, column, pos);
     }
 
     tooltipText.setLength(6); // Cuts the buffer back to <html>
@@ -769,7 +771,8 @@ public class SeqPanel extends JPanel implements MouseListener,
     {
       for (int g = 0; g < groups.length; g++)
       {
-        if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)
+        if (groups[g].getStartRes() <= column
+                && groups[g].getEndRes() >= column)
         {
           if (!groups[g].getName().startsWith("JTreeGroup")
                   && !groups[g].getName().startsWith("JGroup"))
@@ -785,14 +788,11 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
     }
 
-    // use aa to see if the mouse pointer is on a
     if (av.isShowSequenceFeatures())
     {
-      int rpos;
       List<SequenceFeature> features = ap.getFeatureRenderer()
-              .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      rpos = sequence.findPosition(res));
-      seqARep.appendFeatures(tooltipText, rpos, features,
+              .findFeaturesAtRes(sequence.getDatasetSequence(), pos);
+      seqARep.appendFeatures(tooltipText, pos, features,
               this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
     }
     if (tooltipText.length() == 6) // <html>
@@ -859,17 +859,19 @@ public class SeqPanel extends JPanel implements MouseListener,
   // avcontroller or viewModel
 
   /**
-   * Set status message in alignment panel
+   * Sets the status message in alignment panel, showing the sequence number
+   * (index) and id, residue and residue position for the given sequence and
+   * column position. Returns the calculated residue position in the sequence.
    * 
    * @param sequence
    *          aligned sequence object
-   * @param res
+   * @param column
    *          alignment column
    * @param seq
    *          index of sequence in alignment
    * @return position of res in sequence
    */
-  int setStatusMessage(SequenceI sequence, int res, int seq)
+  int setStatusMessage(SequenceI sequence, final int column, int seq)
   {
     StringBuilder text = new StringBuilder(32);
 
@@ -884,7 +886,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     /*
      * Try to translate the display character to residue name (null for gap).
      */
-    final String displayChar = String.valueOf(sequence.getCharAt(res));
+    final String displayChar = String.valueOf(sequence.getCharAt(column));
     if (av.getAlignment().isNucleotide())
     {
       residue = ResidueProperties.nucleotideName.get(displayChar);
@@ -905,9 +907,9 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
 
     int pos = -1;
+    pos = sequence.findPosition(column);
     if (residue != null)
     {
-      pos = sequence.findPosition(res);
       text.append(" (").append(Integer.toString(pos)).append(")");
     }
     ap.alignFrame.statusBar.setText(text.toString());
@@ -1055,7 +1057,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       return;
     }
 
-    int res = findRes(evt);
+    int res = findColumn(evt);
 
     if (res < 0)
     {
@@ -1552,7 +1554,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
       List<SequenceFeature> features = seqCanvas.getFeatureRenderer()
               .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      sequence.findPosition(findRes(evt)));
+                      sequence.findPosition(findColumn(evt)));
 
       if (!features.isEmpty())
       {
@@ -1570,7 +1572,7 @@ public class SeqPanel extends JPanel implements MouseListener,
          */
         List<SequenceI> seqs = Collections.singletonList(sequence);
         seqCanvas.getFeatureRenderer().amendFeatures(seqs, features, false,
-                ap, null);
+                ap);
         seqCanvas.highlightSearchResults(null);
       }
     }
@@ -1614,7 +1616,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   public void doMousePressedDefineMode(MouseEvent evt)
   {
-    final int res = findRes(evt);
+    final int res = findColumn(evt);
     final int seq = findSeq(evt);
     oldSeq = seq;
     needOverviewUpdate = false;
@@ -1673,7 +1675,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (av.cursorMode)
     {
-      seqCanvas.cursorX = findRes(evt);
+      seqCanvas.cursorX = findColumn(evt);
       seqCanvas.cursorY = findSeq(evt);
       seqCanvas.repaint();
       return;
@@ -1729,7 +1731,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   void showPopupMenu(MouseEvent evt)
   {
-    final int res = findRes(evt);
+    final int res = findColumn(evt);
     final int seq = findSeq(evt);
     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
     List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
@@ -1800,7 +1802,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   public void doMouseDraggedDefineMode(MouseEvent evt)
   {
-    int res = findRes(evt);
+    int res = findColumn(evt);
     int y = findSeq(evt);
 
     if (wrappedBlock != startWrapBlock)
index 63ecdaf..3e3691c 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.jbgui;
 import jalview.api.AlignmentViewPanel;
 import jalview.io.FileFormatException;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 import java.awt.FlowLayout;
 import java.awt.Toolkit;
@@ -99,6 +100,10 @@ public class GDesktop extends JFrame
 
   JMenuItem garbageCollect = new JMenuItem();
 
+  protected JMenuItem groovyShell;
+
+  protected JCheckBoxMenuItem experimentalFeatures;
+
   protected JCheckBoxMenuItem showConsole = new JCheckBoxMenuItem();
 
   protected JCheckBoxMenuItem showNews = new JCheckBoxMenuItem();
@@ -119,7 +124,7 @@ public class GDesktop extends JFrame
       e.printStackTrace();
     }
 
-    if (!new jalview.util.Platform().isAMac())
+    if (!Platform.isAMac())
     {
       FileMenu.setMnemonic('F');
       inputLocalFileMenuItem.setMnemonic('L');
@@ -374,6 +379,30 @@ public class GDesktop extends JFrame
         showNews_actionPerformed(e);
       }
     });
+    groovyShell = new JMenuItem();
+    groovyShell.setText(MessageManager.getString("label.groovy_console"));
+    groovyShell.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        groovyShell_actionPerformed();
+      }
+    });
+    experimentalFeatures = new JCheckBoxMenuItem();
+    experimentalFeatures.setText(MessageManager
+            .getString("label.show_experimental"));
+    experimentalFeatures.setToolTipText(MessageManager
+            .getString("label.show_experimental_tip"));
+    experimentalFeatures.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        showExperimental_actionPerformed(experimentalFeatures.isSelected());
+      }
+    });
+
     snapShotWindow.setText(MessageManager.getString("label.take_snapshot"));
     snapShotWindow.addActionListener(new ActionListener()
     {
@@ -410,6 +439,8 @@ public class GDesktop extends JFrame
     toolsMenu.add(showConsole);
     toolsMenu.add(showNews);
     toolsMenu.add(garbageCollect);
+    toolsMenu.add(groovyShell);
+    toolsMenu.add(experimentalFeatures);
     // toolsMenu.add(snapShotWindow);
     inputMenu.add(inputLocalFileMenuItem);
     inputMenu.add(inputURLMenuItem);
@@ -421,6 +452,14 @@ public class GDesktop extends JFrame
     // inputMenu.add(vamsasLoad);
   }
 
+  protected void showExperimental_actionPerformed(boolean selected)
+  {
+  }
+
+  protected void groovyShell_actionPerformed()
+  {
+  }
+
   protected void snapShotWindow_actionPerformed(ActionEvent e)
   {
     // TODO Auto-generated method stub
index 5bbdbec..284ee4f 100644 (file)
@@ -330,7 +330,16 @@ public abstract class FeatureRendererModel implements
         }
       }
     }
-
+    // <<<<<<< HEAD
+    //
+    // =======
+    // if (minmax == null)
+    // {
+    // minmax = new Hashtable<String, float[][]>();
+    // }
+    //
+    // Set<String> oldGroups = new HashSet<String>(featureGroups.keySet());
+    // >>>>>>> refs/heads/develop
     AlignmentI alignment = av.getAlignment();
     List<String> allfeatures = new ArrayList<String>(); // or HashSet?
 
@@ -339,14 +348,30 @@ public abstract class FeatureRendererModel implements
       SequenceI asq = alignment.getSequenceAt(i);
       for (String group : asq.getFeatures().getFeatureGroups(true))
       {
+        // <<<<<<< HEAD
         /*
          * features in null group are always displayed; other groups
          * keep their current visibility; new groups as 'newMadeVisible'
          */
         boolean groupDisplayed = true;
         if (group != null)
+        // =======
+        // continue;
+        // }
+        //
+        // int index = 0;
+        // while (index < features.length)
+        // {
+        // String fgrp = features[index].getFeatureGroup();
+        // oldGroups.remove(fgrp);
+        // if (!featuresDisplayed.isRegistered(features[index].getType()))
+        // >>>>>>> refs/heads/develop
         {
+          // <<<<<<< HEAD
           if (featureGroups.containsKey(group))
+          // =======
+          // if (fgrp != null)
+          // >>>>>>> refs/heads/develop
           {
             groupDisplayed = featureGroups.get(group);
           }
@@ -373,6 +398,7 @@ public abstract class FeatureRendererModel implements
     }
 
     /*
+    //<<<<<<< HEAD
      * mark any new feature types as visible
      */
     Collections.sort(allfeatures, String.CASE_INSENSITIVE_ORDER);
@@ -386,6 +412,14 @@ public abstract class FeatureRendererModel implements
           setOrder(type, 0);
         }
       }
+      // =======
+      // * oldGroups now consists of groups that no longer
+      // * have any feature in them - remove these
+      // */
+      // for (String grp : oldGroups)
+      // {
+      // featureGroups.remove(grp);
+      // >>>>>>> refs/heads/develop
     }
 
     updateRenderOrder(allfeatures);
index fbb20be..3942f0b 100644 (file)
@@ -82,4 +82,21 @@ public class AllColsIteratorTest
     AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
     it.remove();
   }
+
+  /*
+   * Test iterator behaves correctly when there is only one element in the collection
+   */
+  @Test(groups = { "Functional" })
+  public void testOneElement()
+  {
+    HiddenColumns hidden = new HiddenColumns();
+    AllColsIterator it = new AllColsIterator(0, 0, hidden);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 1, "hasNext() is false after 1 iteration");
+  }
 }
index fd1d29d..aeff71d 100644 (file)
@@ -34,7 +34,7 @@ public class AllRowsIteratorTest
 {
   AlignmentI al;
 
-  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+  Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<>();
 
   @BeforeClass
   public void setup()
@@ -110,4 +110,21 @@ public class AllRowsIteratorTest
 
     hiddenRepSequences.put(allseqs[start], theseSeqs);
   }
+
+  /*
+   * Test iterator behaves correctly when there is only one element in the collection
+   */
+  @Test(groups = { "Functional" })
+  public void testOneElement()
+  {
+    AllRowsIterator it = new AllRowsIterator(0, 0, al);
+    int count = 0;
+    while (it.hasNext())
+    {
+      it.next();
+      count++;
+    }
+    assertTrue(count == 1, "hasNext() is false after 1 iteration");
+  }
+
 }