JAL-2587 Removed annoying double repaint on hide insertions
[jalview.git] / src / jalview / gui / PopupMenu.java
index 310266e..2c4eb7a 100644 (file)
@@ -31,8 +31,8 @@ import jalview.commands.EditCommand.Action;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -43,11 +43,10 @@ import jalview.io.FileFormatI;
 import jalview.io.FileFormats;
 import jalview.io.FormatAdapter;
 import jalview.io.SequenceAnnotationReport;
-import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.Blosum62ColourScheme;
+import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.PIDColourScheme;
-import jalview.schemes.ResidueColourScheme;
 import jalview.util.GroupUrlLink;
 import jalview.util.GroupUrlLink.UrlStringTooLongException;
 import jalview.util.MessageManager;
@@ -56,7 +55,9 @@ import jalview.util.UrlLink;
 import java.awt.Color;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Hashtable;
@@ -413,7 +414,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
         add(menuItem);
       }
-
     }
 
     SequenceGroup sg = ap.av.getSelectionGroup();
@@ -425,7 +425,9 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       groupName.setText(MessageManager
               .getString("label.edit_name_and_description_current_group"));
 
-      ColourMenuHelper.setColourSelected(colourMenu, sg.cs);
+      ColourMenuHelper.setColourSelected(colourMenu, sg.getColourScheme());
+
+      conservationMenuItem.setEnabled(!sg.isNucleotide());
 
       if (sg.cs != null)
       {
@@ -450,7 +452,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         buildGroupURLMenu(sg, groupLinks);
       }
       // Add a 'show all structures' for the current selection
-      Hashtable<String, PDBEntry> pdbe = new Hashtable<String, PDBEntry>(), reppdb = new Hashtable<String, PDBEntry>();
+      Hashtable<String, PDBEntry> pdbe = new Hashtable<>(), reppdb = new Hashtable<>();
       SequenceI sqass = null;
       for (SequenceI sq : ap.av.getSequenceSelection())
       {
@@ -517,7 +519,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   void addFeatureLinks(final SequenceI seq, List<String> links)
   {
     JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
-    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    Map<String, List<String>> linkset = new LinkedHashMap<>();
 
     for (String link : links)
     {
@@ -601,8 +603,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
      * the insertion order, which is the order of the annotations on the
      * alignment.
      */
-    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
-    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
+    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<>();
+    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<>();
     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
             AlignmentAnnotationUtils.asList(annotations), forSequences);
 
@@ -708,7 +710,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
     SequenceI[] seqs = ap.av.getSelectionAsNewSequence();
     String[][] idandseqs = GroupUrlLink.formStrings(seqs);
-    Hashtable<String, Object[]> commonDbrefs = new Hashtable<String, Object[]>();
+    Hashtable<String, Object[]> commonDbrefs = new Hashtable<>();
     for (int sq = 0; sq < seqs.length; sq++)
     {
 
@@ -1177,12 +1179,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         hideInsertions_actionPerformed(e);
       }
     });
-    /*
-     * annotationMenuItem.setText("By Annotation");
-     * annotationMenuItem.addActionListener(new ActionListener() { public void
-     * actionPerformed(ActionEvent actionEvent) {
-     * annotationMenuItem_actionPerformed(actionEvent); } });
-     */
+
     groupMenu.add(sequenceSelDetails);
     add(groupMenu);
     add(sequenceMenu);
@@ -1260,7 +1257,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        abovePIDColour_actionPerformed();
+        abovePIDColour_actionPerformed(abovePIDColour.isSelected());
       }
     });
 
@@ -1282,7 +1279,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        conservationMenuItem_actionPerformed();
+        conservationMenuItem_actionPerformed(conservationMenuItem
+                .isSelected());
       }
     });
 
@@ -1371,8 +1369,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
      * Temporary store to hold distinct calcId / type pairs for the tooltip.
      * Using TreeMap means calcIds are shown in alphabetical order.
      */
-    SortedMap<String, String> tipEntries = new TreeMap<String, String>();
-    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
     AlignmentI al = this.ap.av.getAlignment();
     AlignmentUtils.findAddableReferenceAnnotations(forSequences,
             tipEntries, candidates, al);
@@ -1447,16 +1445,59 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
   protected void hideInsertions_actionPerformed(ActionEvent actionEvent)
   {
-    if (sequence != null)
+
+    HiddenColumns hidden = new HiddenColumns();
+    BitSet inserts = new BitSet(), mask = new BitSet();
+
+    // set mask to preserve existing hidden columns outside selected group
+    if (ap.av.hasHiddenColumns())
     {
-      ColumnSelection cs = ap.av.getColumnSelection();
-      if (cs == null)
+      ap.av.getAlignment().getHiddenColumns().markHiddenRegions(mask);
+    }
+
+    boolean markedPopup = false;
+    // mark inserts in current selection
+    if (ap.av.getSelectionGroup() != null)
+    {
+      // mark just the columns in the selection group to be hidden
+      inserts.set(ap.av.getSelectionGroup().getStartRes(), ap.av
+              .getSelectionGroup().getEndRes() + 1);
+
+      // and clear that part of the mask
+      mask.andNot(inserts);
+
+      // now clear columns without gaps
+      for (SequenceI sq : ap.av.getSelectionGroup().getSequences())
       {
-        cs = new ColumnSelection();
+        if (sq == sequence)
+        {
+          markedPopup = true;
+        }
+        inserts.and(sq.getInsertionsAsBits());
       }
-      cs.hideInsertionsFor(sequence);
-      ap.av.setColumnSelection(cs);
     }
+    else
+    {
+      // initially, mark all columns to be hidden
+      inserts.set(0, ap.av.getAlignment().getWidth());
+
+      // and clear out old hidden regions completely
+      mask.clear();
+    }
+
+    // now mark for sequence under popup if we haven't already done it
+    if (!markedPopup && sequence != null)
+    {
+      inserts.and(sequence.getInsertionsAsBits());
+    }
+
+    // finally, preserve hidden regions outside selection
+    inserts.or(mask);
+
+    // and set hidden columns accordingly
+    hidden.hideMarkedBits(inserts);
+
+    ap.av.getAlignment().setHiddenColumns(hidden);
     refresh();
   }
 
@@ -1515,7 +1556,9 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   void refresh()
   {
     ap.updateAnnotation();
-    ap.paintAlignment(true);
+    // removed paintAlignment(true) here:
+    // updateAnnotation calls paintAlignment already, so don't need to call
+    // again
 
     PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
   }
@@ -1527,10 +1570,12 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   /**
    * DOCUMENT ME!
    * 
+   * @param selected
+   * 
    * @param e
    *          DOCUMENT ME!
    */
-  protected void abovePIDColour_actionPerformed()
+  public void abovePIDColour_actionPerformed(boolean selected)
   {
     SequenceGroup sg = getGroup();
     if (sg.cs == null)
@@ -1538,14 +1583,14 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       return;
     }
 
-    boolean selected = abovePIDColour.isSelected();
     if (selected)
     {
       sg.cs.setConsensus(AAFrequency.calculate(
               sg.getSequences(ap.av.getHiddenRepSequences()),
               sg.getStartRes(), sg.getEndRes() + 1));
 
-      int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
+      int threshold = SliderPanel.setPIDSliderSource(ap,
+              sg.getGroupColourScheme(), getGroup()
               .getName());
 
       sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
@@ -1581,7 +1626,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
    * @param e
    *          DOCUMENT ME!
    */
-  protected void conservationMenuItem_actionPerformed()
+  public void conservationMenuItem_actionPerformed(boolean selected)
   {
     SequenceGroup sg = getGroup();
     if (sg.cs == null)
@@ -1589,7 +1634,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       return;
     }
 
-    boolean selected = conservationMenuItem.isSelected();
     if (selected)
     {
       // JBPNote: Conservation name shouldn't be i18n translated
@@ -1599,10 +1643,10 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
       c.calculate();
       c.verdict(false, ap.av.getConsPercGaps());
-
       sg.cs.setConservation(c);
 
-      SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
+      SliderPanel.setConservationSlider(ap, sg.getGroupColourScheme(),
+              sg.getName());
       SliderPanel.showConservationSlider();
     }
     else
@@ -1616,24 +1660,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
     refresh();
   }
 
-  public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
-  {
-    SequenceGroup sg = getGroup();
-    if (sg == null)
-    {
-      return;
-    }
-
-    AnnotationColourGradient acg = new AnnotationColourGradient(
-            sequence.getAnnotation()[0], null,
-            AnnotationColourGradient.NO_THRESHOLD);
-
-    acg.setPredefinedColours(true);
-    sg.cs = acg;
-
-    refresh();
-  }
-
   /**
    * DOCUMENT ME!
    * 
@@ -1901,33 +1927,36 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       return;
     }
 
-    int rsize = 0, gSize = sg.getSize();
-    SequenceI[] rseqs, seqs = new SequenceI[gSize];
-    SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
+    List<SequenceI> seqs = new ArrayList<>();
+    List<SequenceFeature> features = new ArrayList<>();
 
+    /*
+     * assemble dataset sequences, and template new sequence features,
+     * for the amend features dialog
+     */
+    int gSize = sg.getSize();
     for (int i = 0; i < gSize; i++)
     {
       int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
       int end = sg.findEndRes(sg.getSequenceAt(i));
       if (start <= end)
       {
-        seqs[rsize] = sg.getSequenceAt(i).getDatasetSequence();
-        features[rsize] = new SequenceFeature(null, null, null, start, end,
-                "Jalview");
-        rsize++;
+        seqs.add(sg.getSequenceAt(i).getDatasetSequence());
+        features.add(new SequenceFeature(null, null, null, start, end, null));
       }
     }
-    rseqs = new SequenceI[rsize];
-    tfeatures = new SequenceFeature[rsize];
-    System.arraycopy(seqs, 0, rseqs, 0, rsize);
-    System.arraycopy(features, 0, tfeatures, 0, rsize);
-    features = tfeatures;
-    seqs = rseqs;
-    if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-            features, true, ap))
-    {
-      ap.alignFrame.setShowSeqFeatures(true);
-      ap.highlightSearchResults(null);
+
+    /*
+     * an entirely gapped region will generate empty lists of sequence / features
+     */
+    if (!seqs.isEmpty())
+    {
+      if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(
+              seqs, features, true, ap))
+      {
+        ap.alignFrame.setShowSeqFeatures(true);
+        ap.highlightSearchResults(null);
+      }
     }
   }
 
@@ -1997,32 +2026,26 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   /**
    * Action on user selecting an item from the colour menu (that does not have
    * its bespoke action handler)
+   * 
+   * @return
    */
   @Override
   public void changeColour_actionPerformed(String colourSchemeName)
   {
     SequenceGroup sg = getGroup();
-    if (ResidueColourScheme.USER_DEFINED.equals(colourSchemeName))
-    {
-      /*
-       * open a panel to load or configure a user-defined colour scheme
-       */
-      new UserDefinedColours(ap, sg);
-    }
-    else
+    /*
+     * switch to the chosen colour scheme (or null for None)
+     */
+    ColourSchemeI colourScheme = ColourSchemes.getInstance()
+            .getColourScheme(colourSchemeName, sg,
+                    ap.av.getHiddenRepSequences());
+    sg.setColourScheme(colourScheme);
+    if (colourScheme instanceof Blosum62ColourScheme
+            || colourScheme instanceof PIDColourScheme)
     {
-      /*
-       * switch to the chosen colour scheme (or null for None)
-       */
-      sg.cs = ColourSchemes.getInstance().getColourScheme(colourSchemeName,
-              sg, ap.av.getHiddenRepSequences());
-      if (sg.cs instanceof Blosum62ColourScheme
-              || sg.cs instanceof PIDColourScheme)
-      {
-        sg.cs.setConsensus(AAFrequency.calculate(
-                sg.getSequences(ap.av.getHiddenRepSequences()),
-                sg.getStartRes(), sg.getEndRes() + 1));
-      }
+      sg.cs.setConsensus(AAFrequency.calculate(
+              sg.getSequences(ap.av.getHiddenRepSequences()),
+              sg.getStartRes(), sg.getEndRes() + 1));
     }
 
     refresh();