JAL-3089 safer popup menu actions on AnnotationLabels task/JAL-3089annLabelsPopup
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 28 Aug 2018 15:01:52 +0000 (16:01 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 28 Aug 2018 15:01:52 +0000 (16:01 +0100)
src/jalview/gui/AnnotationLabels.java

index 294b8db..aede9e0 100755 (executable)
@@ -70,7 +70,7 @@ import javax.swing.ToolTipManager;
  * height
  */
 public class AnnotationLabels extends JPanel
-        implements MouseListener, MouseMotionListener, ActionListener
+        implements MouseListener, MouseMotionListener
 {
   /**
    * width in pixels within which height adjuster arrows are shown and active
@@ -113,7 +113,7 @@ public class AnnotationLabels extends JPanel
 
   private final boolean debugRedraw = false;
 
-  private AlignmentPanel ap;
+  AlignmentPanel ap;
 
   AlignViewport av;
 
@@ -198,78 +198,19 @@ public class AnnotationLabels extends JPanel
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
+   * Set all annotations visible
    */
-  @Override
-  public void actionPerformed(ActionEvent evt)
+  void showAll()
   {
     AlignmentAnnotation[] aa = ap.av.getAlignment()
             .getAlignmentAnnotation();
-
-    String action = evt.getActionCommand();
-    if (ADDNEW.equals(action))
-    {
-      /*
-       * non-returning dialog
-       */
-      AlignmentAnnotation newAnnotation = new AlignmentAnnotation(null,
-              null, new Annotation[ap.av.getAlignment().getWidth()]);
-      editLabelDescription(newAnnotation, true);
-    }
-    else if (EDITNAME.equals(action))
-    {
-      /*
-       * non-returning dialog
-       */
-      editLabelDescription(aa[selectedRow], false);
-    }
-    else if (HIDE.equals(action))
-    {
-      aa[selectedRow].visible = false;
-    }
-    else if (DELETE.equals(action))
-    {
-      ap.av.getAlignment().deleteAnnotation(aa[selectedRow]);
-      ap.av.getCalcManager().removeWorkerForAnnotation(aa[selectedRow]);
-    }
-    else if (SHOWALL.equals(action))
-    {
-      for (int i = 0; i < aa.length; i++)
-      {
-        if (!aa[i].visible && aa[i].annotations != null)
-        {
-          aa[i].visible = true;
-        }
-      }
-    }
-    else if (OUTPUT_TEXT.equals(action))
-    {
-      new AnnotationExporter(ap).exportAnnotation(aa[selectedRow]);
-    }
-    else if (COPYCONS_SEQ.equals(action))
+    for (int i = 0; i < aa.length; i++)
     {
-      SequenceI cons = null;
-      if (aa[selectedRow].groupRef != null)
-      {
-        cons = aa[selectedRow].groupRef.getConsensusSeq();
-      }
-      else
+      if (!aa[i].visible && aa[i].annotations != null)
       {
-        cons = av.getConsensusSeq();
-      }
-      if (cons != null)
-      {
-        copy_annotseqtoclipboard(cons);
+        aa[i].visible = true;
       }
     }
-    else if (TOGGLE_LABELSCALE.equals(action))
-    {
-      aa[selectedRow].scaleColLabel = !aa[selectedRow].scaleColLabel;
-    }
-
     ap.refresh(true);
   }
 
@@ -321,7 +262,7 @@ public class AnnotationLabels extends JPanel
     oldY = evt.getY();
     if (evt.isPopupTrigger())
     {
-      showPopupMenu(evt);
+      showPopupMenu(evt, selectedRow);
     }
   }
 
@@ -329,41 +270,93 @@ public class AnnotationLabels extends JPanel
    * Build and show the Pop-up menu at the right-click mouse position
    * 
    * @param evt
+   * @param row
    */
-  void showPopupMenu(MouseEvent evt)
+  void showPopupMenu(MouseEvent evt, final int row)
   {
     evt.consume();
     final AlignmentAnnotation[] aa = ap.av.getAlignment()
             .getAlignmentAnnotation();
-
     JPopupMenu pop = new JPopupMenu(
             MessageManager.getString("label.annotations"));
+
+    /*
+     * add new row
+     */
     JMenuItem item = new JMenuItem(ADDNEW);
-    item.addActionListener(this);
+    item.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        AlignmentAnnotation newAnnotation = new AlignmentAnnotation(null,
+                null, new Annotation[ap.av.getAlignment().getWidth()]);
+        editLabelDescription(newAnnotation, true);
+        ap.refresh(true);
+      }});
     pop.add(item);
-    if (selectedRow < 0)
+    
+    /*
+     * if no rows shown, add option to show all 
+     * (if rows are hidden), nothing else to add
+     */
+    if (row < 0)
     {
       if (hasHiddenRows)
-      { // let the user make everything visible again
+      {
         item = new JMenuItem(SHOWALL);
-        item.addActionListener(this);
+        item.addActionListener(new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            showAll();
+          }
+        });
         pop.add(item);
       }
       pop.show(this, evt.getX(), evt.getY());
       return;
     }
+    
+    /*
+     * Edit Name/Description
+     */
     item = new JMenuItem(EDITNAME);
-    item.addActionListener(this);
+    item.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        editLabelDescription(aa[row], false);
+        ap.refresh(false);
+      }
+    });
     pop.add(item);
+
+    /*
+     * hide row
+     */
     item = new JMenuItem(HIDE);
-    item.addActionListener(this);
+    item.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        aa[row].visible = false;
+        ap.refresh(true);
+      }
+    });
     pop.add(item);
-    // JAL-1264 hide all sequence-specific annotations of this type
-    if (selectedRow < aa.length)
+
+    /*
+     * JAL-1264 hide all sequence-specific annotations of this type
+     */
+    if (row < aa.length)
     {
-      if (aa[selectedRow].sequenceRef != null)
+      if (aa[row].sequenceRef != null)
       {
-        final String label = aa[selectedRow].label;
+        final String label = aa[row].label;
         JMenuItem hideType = new JMenuItem();
         String text = MessageManager.getString("label.hide_all") + " "
                 + label;
@@ -376,221 +369,264 @@ public class AnnotationLabels extends JPanel
             AlignmentUtils.showOrHideSequenceAnnotations(
                     ap.av.getAlignment(), Collections.singleton(label),
                     null, false, false);
-            // for (AlignmentAnnotation ann : ap.av.getAlignment()
-            // .getAlignmentAnnotation())
-            // {
-            // if (ann.sequenceRef != null && ann.label != null
-            // && ann.label.equals(label))
-            // {
-            // ann.visible = false;
-            // }
-            // }
             ap.refresh(true);
           }
         });
         pop.add(hideType);
       }
     }
+
+    /*
+     * delete annotation
+     */
     item = new JMenuItem(DELETE);
-    item.addActionListener(this);
+    item.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        ap.av.getAlignment().deleteAnnotation(aa[row]);
+        ap.av.getCalcManager().removeWorkerForAnnotation(aa[row]);
+        ap.refresh(true);
+      }
+    });
     pop.add(item);
+
+    /*
+     * show hidden rows
+     */
     if (hasHiddenRows)
     {
       item = new JMenuItem(SHOWALL);
-      item.addActionListener(this);
+      item.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          showAll();
+        }
+      });
       pop.add(item);
     }
+
+    /*
+     * export annotation
+     */
     item = new JMenuItem(OUTPUT_TEXT);
-    item.addActionListener(this);
+    item.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        new AnnotationExporter(ap).exportAnnotation(aa[row]);
+      }
+    });
     pop.add(item);
+
     // TODO: annotation object should be typed for autocalculated/derived
     // property methods
-    if (selectedRow < aa.length)
+    if (row < aa.length)
     {
-      final String label = aa[selectedRow].label;
-      if (!aa[selectedRow].autoCalculated)
+      final String label = aa[row].label;
+      if (!aa[row].autoCalculated)
       {
-        if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
+        if (aa[row].graph == AlignmentAnnotation.NO_GRAPH)
         {
           // display formatting settings for this row.
           pop.addSeparator();
-          // av and sequencegroup need to implement same interface for
+
+          /*
+           * scale label to column
+           */
           item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
-                  aa[selectedRow].scaleColLabel);
-          item.addActionListener(this);
-          pop.add(item);
-        }
-      }
-      else if (label.indexOf("Consensus") > -1)
-      {
-        pop.addSeparator();
-        // av and sequencegroup need to implement same interface for
-        final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
-                MessageManager.getString("label.ignore_gaps_consensus"),
-                (aa[selectedRow].groupRef != null)
-                        ? aa[selectedRow].groupRef.getIgnoreGapsConsensus()
-                        : ap.av.isIgnoreGapsConsensus());
-        final AlignmentAnnotation aaa = aa[selectedRow];
-        cbmi.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            if (aaa.groupRef != null)
-            {
-              // TODO: pass on reference to ap so the view can be updated.
-              aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
-              ap.getAnnotationPanel()
-                      .paint(ap.getAnnotationPanel().getGraphics());
-            }
-            else
-            {
-              ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
-            }
-            ap.alignmentChanged();
-          }
-        });
-        pop.add(cbmi);
-        // av and sequencegroup need to implement same interface for
-        if (aaa.groupRef != null)
-        {
-          final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_group_histogram"),
-                  aa[selectedRow].groupRef.isShowConsensusHistogram());
-          chist.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              aaa.groupRef.setShowConsensusHistogram(chist.getState());
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(chist);
-          final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_group_logo"),
-                  aa[selectedRow].groupRef.isShowSequenceLogo());
-          cprofl.addActionListener(new ActionListener()
+                  aa[row].scaleColLabel);
+          item.addActionListener(new ActionListener()
           {
             @Override
             public void actionPerformed(ActionEvent e)
             {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              aaa.groupRef.setshowSequenceLogo(cprofl.getState());
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
+              aa[row].scaleColLabel = !aa[row].scaleColLabel;
+              ap.refresh(false);
             }
           });
-          pop.add(cprofl);
-          final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.normalise_group_logo"),
-                  aa[selectedRow].groupRef.isNormaliseSequenceLogo());
-          cproflnorm.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
+          pop.add(item);
+        }
+      }
+      else if (label.indexOf("Consensus") > -1)
+      {
+        addConsensusMenuItems(pop, aa[row]);
+      }
+    }
+    pop.show(this, evt.getX(), evt.getY());
+  }
 
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              aaa.groupRef.setNormaliseSequenceLogo(cproflnorm.getState());
-              // automatically enable logo display if we're clicked
-              aaa.groupRef.setshowSequenceLogo(true);
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cproflnorm);
+  /**
+   * Helper method to add Consensus-specific menu items, for alignment or group
+   * consensus annotation
+   * 
+   * @param menu
+   * @param aa
+   */
+  private void addConsensusMenuItems(JPopupMenu menu,
+          final AlignmentAnnotation aa)
+  {
+    menu.addSeparator();
+
+    /*
+     * ignore gaps in consensus
+     */
+    final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
+            MessageManager.getString("label.ignore_gaps_consensus"),
+            (aa.groupRef != null)
+                    ? aa.groupRef.getIgnoreGapsConsensus()
+                    : ap.av.isIgnoreGapsConsensus());
+    cbmi.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        if (aa.groupRef != null)
+        {
+          aa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
+          // AnnotationLabels.this.repaint();
+          // ap.getAnnotationPanel()
+          // .paint(ap.getAnnotationPanel().getGraphics());
         }
         else
         {
-          final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_histogram"),
-                  av.isShowConsensusHistogram());
-          chist.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              av.setShowConsensusHistogram(chist.getState());
-              ap.alignFrame.setMenusForViewport();
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(chist);
-          final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.show_logo"),
-                  av.isShowSequenceLogo());
-          cprof.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              av.setShowSequenceLogo(cprof.getState());
-              ap.alignFrame.setMenusForViewport();
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cprof);
-          final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem(
-                  MessageManager.getString("label.normalise_logo"),
-                  av.isNormaliseSequenceLogo());
-          cprofnorm.addActionListener(new ActionListener()
-          {
-            @Override
-            public void actionPerformed(ActionEvent e)
-            {
-              // TODO: pass on reference
-              // to ap
-              // so the
-              // view
-              // can be
-              // updated.
-              av.setShowSequenceLogo(true);
-              av.setNormaliseSequenceLogo(cprofnorm.getState());
-              ap.alignFrame.setMenusForViewport();
-              ap.repaint();
-              // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
-            }
-          });
-          pop.add(cprofnorm);
+          ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
         }
-        final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ);
-        consclipbrd.addActionListener(this);
-        pop.add(consclipbrd);
+        ap.alignmentChanged();
       }
+    });
+    menu.add(cbmi);
+
+    if (aa.groupRef != null)
+    {
+      /*
+       * show group histogram
+       */
+      final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_group_histogram"),
+              aa.groupRef.isShowConsensusHistogram());
+      chist.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          aa.groupRef.setShowConsensusHistogram(chist.getState());
+          ap.repaint();
+        }
+      });
+      menu.add(chist);
+
+      /*
+       * show group logo
+       */
+      final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_group_logo"),
+              aa.groupRef.isShowSequenceLogo());
+      cprofl.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          aa.groupRef.setshowSequenceLogo(cprofl.getState());
+          ap.repaint();
+        }
+      });
+      menu.add(cprofl);
+
+      /*
+       * normalise group logo
+       */
+      final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem(
+              MessageManager.getString("label.normalise_group_logo"),
+              aa.groupRef.isNormaliseSequenceLogo());
+      cproflnorm.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          aa.groupRef.setNormaliseSequenceLogo(cproflnorm.getState());
+          // automatically enable logo display if we're clicked
+          aa.groupRef.setshowSequenceLogo(true);
+          ap.repaint();
+        }
+      });
+      menu.add(cproflnorm);
     }
-    pop.show(this, evt.getX(), evt.getY());
+    else
+    {
+      /*
+       * show histogram
+       */
+      final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_histogram"),
+              av.isShowConsensusHistogram());
+      chist.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          av.setShowConsensusHistogram(chist.getState());
+          ap.alignFrame.setMenusForViewport();
+          ap.repaint();
+        }
+      });
+      menu.add(chist);
+
+      /*
+       * show logo
+       */
+      final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_logo"),
+              av.isShowSequenceLogo());
+      cprof.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          av.setShowSequenceLogo(cprof.getState());
+          ap.alignFrame.setMenusForViewport();
+          ap.repaint();
+        }
+      });
+      menu.add(cprof);
+
+      /*
+       * normalise logo
+       */
+      final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem(
+              MessageManager.getString("label.normalise_logo"),
+              av.isNormaliseSequenceLogo());
+      cprofnorm.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          av.setShowSequenceLogo(true);
+          av.setNormaliseSequenceLogo(cprofnorm.getState());
+          ap.alignFrame.setMenusForViewport();
+          ap.repaint();
+        }
+      });
+      menu.add(cprofnorm);
+    }
+
+    /*
+     * copy consensus sequence
+     */
+    final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ);
+    consclipbrd.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        copy_annotseqtoclipboard(aa);
+      }
+    });
+    menu.add(consclipbrd);
   }
 
   /**
@@ -603,7 +639,7 @@ public class AnnotationLabels extends JPanel
   {
     if (evt.isPopupTrigger())
     {
-      showPopupMenu(evt);
+      showPopupMenu(evt, selectedRow);
       return;
     }
 
@@ -915,11 +951,25 @@ public class AnnotationLabels extends JPanel
   /**
    * do a single sequence copy to jalview and the system clipboard
    * 
-   * @param sq
-   *          sequence to be copied to clipboard
+   * @param cons
+   *          Consensus annotation
    */
-  protected void copy_annotseqtoclipboard(SequenceI sq)
+  protected void copy_annotseqtoclipboard(AlignmentAnnotation cons)
   {
+    SequenceI sq = null;
+    if (cons.groupRef != null)
+    {
+      sq = cons.groupRef.getConsensusSeq();
+    }
+    else
+    {
+      sq = av.getConsensusSeq();
+    }
+    if (sq == null)
+    {
+      return;
+    }
+
     SequenceI[] seqs = new SequenceI[] { sq };
     String[] omitHidden = null;
     SequenceI[] dseqs = new SequenceI[] { sq.getDatasetSequence() };