JAL-3981 strategic newlines to help speed up Java's html parser
[jalview.git] / src / jalview / gui / PopupMenu.java
index 8be93a1..6903034 100644 (file)
  */
 package jalview.gui;
 
+import java.util.Locale;
+
+import java.awt.BorderLayout;
+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;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Vector;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+
 import jalview.analysis.AAFrequency;
 import jalview.analysis.AlignmentAnnotationUtils;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.Conservation;
 import jalview.api.AlignViewportI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.ChangeCaseCommand;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
@@ -58,35 +89,6 @@ import jalview.util.StringUtils;
 import jalview.util.UrlLink;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 
-import java.awt.BorderLayout;
-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;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.Vector;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JInternalFrame;
-import javax.swing.JLabel;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.JScrollPane;
-
 /**
  * The popup menu that is displayed on right-click on a sequence id, or in the
  * sequence alignment.
@@ -228,13 +230,13 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         urlLink = new UrlLink(link);
       } catch (Exception foo)
       {
-        Cache.log.error("Exception for URLLink '" + link + "'", foo);
+        Console.error("Exception for URLLink '" + link + "'", foo);
         continue;
       }
 
       if (!urlLink.isValid())
       {
-        Cache.log.error(urlLink.getInvalidMessage());
+        Console.error(urlLink.getInvalidMessage());
         continue;
       }
 
@@ -357,14 +359,15 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   }
 
   /**
-   * Constructor for a PopupMenu for a click in the alignment panel (on a residue)
+   * Constructor for a PopupMenu for a click in the alignment panel (on a
+   * residue)
    * 
    * @param ap
-   *              the panel in which the mouse is clicked
+   *          the panel in which the mouse is clicked
    * @param seq
-   *              the sequence under the mouse
+   *          the sequence under the mouse
    * @throws NullPointerException
-   *                                if seq is null
+   *           if seq is null
    */
   public PopupMenu(final AlignmentPanel ap, SequenceI seq, int column)
   {
@@ -375,13 +378,13 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
    * Constructor for a PopupMenu for a click in the sequence id panel
    * 
    * @param alignPanel
-   *                     the panel in which the mouse is clicked
+   *          the panel in which the mouse is clicked
    * @param seq
-   *                     the sequence under the mouse click
+   *          the sequence under the mouse click
    * @param groupLinks
-   *                     templates for sequence external links
+   *          templates for sequence external links
    * @throws NullPointerException
-   *                                if seq is null
+   *           if seq is null
    */
   public PopupMenu(final AlignmentPanel alignPanel, final SequenceI seq,
           List<String> groupLinks)
@@ -397,11 +400,10 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
    * @param alignPanel
    * @param seq
    * @param column
-   *                      aligned column position (0...)
+   *          aligned column position (0...)
    * @param groupLinks
    */
-  private PopupMenu(boolean fromIdPanel,
-          final AlignmentPanel alignPanel,
+  private PopupMenu(boolean fromIdPanel, final AlignmentPanel alignPanel,
           final SequenceI seq, final int column, List<String> groupLinks)
   {
     Objects.requireNonNull(seq);
@@ -441,9 +443,10 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
     /*
      * And repeat for the current selection group (if there is one):
      */
-    final List<SequenceI> selectedGroup = (alignPanel.av.getSelectionGroup() == null
-            ? Collections.<SequenceI> emptyList()
-            : alignPanel.av.getSelectionGroup().getSequences());
+    final List<SequenceI> selectedGroup = (alignPanel.av
+            .getSelectionGroup() == null
+                    ? Collections.<SequenceI> emptyList()
+                    : alignPanel.av.getSelectionGroup().getSequences());
     buildAnnotationTypesMenus(groupShowAnnotationsMenu,
             groupHideAnnotationsMenu, selectedGroup);
     configureReferenceAnnotationsMenu(groupAddReferenceAnnotations,
@@ -669,7 +672,8 @@ 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<>(), reppdb = new Hashtable<>();
+      Hashtable<String, PDBEntry> pdbe = new Hashtable<>(),
+              reppdb = new Hashtable<>();
 
       SequenceI sqass = null;
       for (SequenceI sq : alignPanel.av.getSequenceSelection())
@@ -706,7 +710,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
     {
       createGroupMenuItem.setVisible(true);
       unGroupMenuItem.setVisible(false);
-      editGroupMenu.setText(MessageManager.getString("action.edit_new_group"));
+      editGroupMenu
+              .setText(MessageManager.getString("action.edit_new_group"));
     }
     else
     {
@@ -733,8 +738,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
    * <li>positional feature links (alignment panel popup menu)</li>
    * <li>feature details links (alignment panel popup menu)</li>
    * </ul>
-   * If this panel is also showed complementary (CDS/protein) features, then links
-   * to their feature details are also added.
+   * If this panel is also showed complementary (CDS/protein) features, then
+   * links to their feature details are also added.
    * 
    * @param seq
    * @param column
@@ -761,14 +766,16 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   }
 
   /**
-   * Add a link to show feature details for each sequence feature
+   * Add a menu item to show feature details for each sequence feature. Any
+   * linked 'virtual' features (CDS/protein) are also optionally found and
+   * included.
    * 
    * @param features
-   * @param column
    * @param seq
+   * @param column
    */
   protected void addFeatureDetails(List<SequenceFeature> features,
-          SequenceI seq, int column)
+          final SequenceI seq, final int column)
   {
     /*
      * add features in CDS/protein complement at the corresponding
@@ -803,39 +810,53 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
     String name = seq.getName();
     for (final SequenceFeature sf : features)
     {
-      addFeatureDetailsMenuItem(details, name, sf);
+      addFeatureDetailsMenuItem(details, name, sf, null);
     }
 
     if (mf != null)
     {
-      name = mf.fromSeq == seq ? mf.mapping.getTo().getName()
-              : mf.fromSeq.getName();
       for (final SequenceFeature sf : mf.features)
       {
-        addFeatureDetailsMenuItem(details, name, sf);
+        addFeatureDetailsMenuItem(details, name, sf, mf);
       }
     }
   }
 
   /**
-   * A helper method to add one menu item whose action is to show details for one
-   * feature. The menu text includes feature description, but this may be
+   * A helper method to add one menu item whose action is to show details for
+   * one feature. The menu text includes feature description, but this may be
    * truncated.
    * 
    * @param details
    * @param seqName
    * @param sf
+   * @param mf
    */
   void addFeatureDetailsMenuItem(JMenu details, final String seqName,
-          final SequenceFeature sf)
+          final SequenceFeature sf, MappedFeatures mf)
   {
     int start = sf.getBegin();
     int end = sf.getEnd();
+    if (mf != null)
+    {
+      /*
+       * show local rather than linked feature coordinates
+       */
+      int[] localRange = mf.getMappedPositions(start, end);
+      if (localRange == null)
+      {
+        // e.g. variant extending to stop codon so not mappable
+        return;
+      }
+      start = localRange[0];
+      end = localRange[localRange.length - 1];
+    }
     StringBuilder desc = new StringBuilder();
     desc.append(sf.getType()).append(" ").append(String.valueOf(start));
     if (start != end)
     {
-      desc.append("-").append(String.valueOf(end));
+      desc.append(sf.isContactFeature() ? ":" : "-");
+      desc.append(String.valueOf(end));
     }
     String description = sf.getDescription();
     if (description != null)
@@ -866,20 +887,21 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        showFeatureDetails(seqName, sf);
+        showFeatureDetails(sf, seqName, mf);
       }
     });
     details.add(item);
   }
 
   /**
-   * Opens a panel showing a text report of feature dteails
-   * 
-   * @param seqName
+   * Opens a panel showing a text report of feature details
    * 
    * @param sf
+   * @param seqName
+   * @param mf
    */
-  protected void showFeatureDetails(String seqName, SequenceFeature sf)
+  protected void showFeatureDetails(SequenceFeature sf, String seqName,
+          MappedFeatures mf)
   {
     JInternalFrame details;
     if (Platform.isJS())
@@ -891,7 +913,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       // TODO JAL-3026 set style of table correctly for feature details
       JLabel reprt = new JLabel(MessageManager
               .formatMessage("label.html_content", new Object[]
-              { sf.getDetailsReport(seqName) }));
+              { sf.getDetailsReport(seqName, mf) }));
       reprt.setBackground(Color.WHITE);
       reprt.setOpaque(true);
       panel.add(reprt, BorderLayout.CENTER);
@@ -906,10 +928,10 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
      */
     {
       CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
-      // it appears Java's CSS does not support border-collaps :-(
+      // it appears Java's CSS does not support border-collapse :-(
       cap.addStylesheetRule("table { border-collapse: collapse;}");
       cap.addStylesheetRule("table, td, th {border: 1px solid black;}");
-      cap.setText(sf.getDetailsReport(seqName));
+      cap.setText(sf.getDetailsReport(seqName, mf));
       details = cap;
     }
     Desktop.addInternalFrame(details,
@@ -1112,7 +1134,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         for (int d = 0; d < nd; d++)
         {
           DBRefEntry e = dbr.get(d);
-          String src = e.getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase();
+          String src = e.getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase(Locale.ROOT);
           Object[] sarray = commonDbrefs.get(src);
           if (sarray == null)
           {
@@ -1125,8 +1147,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
           if (((String[]) sarray[1])[sq] == null)
           {
-            if (!e.hasMap() || (e.getMap()
-                    .locateMappedRange(start, end) != null))
+            if (!e.hasMap()
+                    || (e.getMap().locateMappedRange(start, end) != null))
             {
               ((String[]) sarray[1])[sq] = e.getAccessionId();
               ((int[]) sarray[0])[0]++;
@@ -1146,19 +1168,19 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         urlLink = new GroupUrlLink(link);
       } catch (Exception foo)
       {
-        Cache.log.error("Exception for GroupURLLink '" + link + "'", foo);
+        Console.error("Exception for GroupURLLink '" + link + "'", foo);
         continue;
       }
       if (!urlLink.isValid())
       {
-        Cache.log.error(urlLink.getInvalidMessage());
+        Console.error(urlLink.getInvalidMessage());
         continue;
       }
       final String label = urlLink.getLabel();
       boolean usingNames = false;
       // Now see which parts of the group apply for this URL
       String ltarget = urlLink.getTarget(); // jalview.util.DBRefUtils.getCanonicalName(urlLink.getTarget());
-      Object[] idset = commonDbrefs.get(ltarget.toUpperCase());
+      Object[] idset = commonDbrefs.get(ltarget.toUpperCase(Locale.ROOT));
       String[] seqstr, ids; // input to makeUrl
       if (idset != null)
       {
@@ -1765,7 +1787,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         }
         inserts.and(sq.getInsertionsAsBits());
       }
-      hidden.clearAndHideColumns(inserts, ap.av.getSelectionGroup().getStartRes(),
+      hidden.clearAndHideColumns(inserts,
+              ap.av.getSelectionGroup().getStartRes(),
               ap.av.getSelectionGroup().getEndRes());
     }
 
@@ -1794,8 +1817,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       contents.append("<p><h2>" + MessageManager.formatMessage(
               "label.create_sequence_details_report_annotation_for",
               new Object[]
-              { seq.getDisplayId(true) }) + "</h2></p><p>");
-      new SequenceAnnotationReport(null).createSequenceAnnotationReport(
+              { seq.getDisplayId(true) }) + "</h2></p>\n<p>");
+      new SequenceAnnotationReport(false).createSequenceAnnotationReport(
               contents, seq, true, true, ap.getSeqPanel().seqCanvas.fr);
       contents.append("</p>");
     }
@@ -1995,8 +2018,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
   /**
    * Shows a dialog where the sequence name and description may be edited. If a
-   * name containing spaces is entered, these are converted to underscores, with a
-   * warning message.
+   * name containing spaces is entered, these are converted to underscores, with
+   * a warning message.
    */
   void sequenceName_actionPerformed()
   {
@@ -2004,10 +2027,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
             sequence.getDescription(),
             MessageManager.getString("label.sequence_name"),
             MessageManager.getString("label.sequence_description"));
-    dialog.showDialog(ap.alignFrame,
-            MessageManager.getString(
-                    "label.edit_sequence_name_description"),
-            new Runnable()
+    dialog.showDialog(ap.alignFrame, MessageManager.getString(
+            "label.edit_sequence_name_description"), new Runnable()
             {
               @Override
               public void run()
@@ -2059,8 +2080,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
    */
   protected void outline_actionPerformed()
   {
-    String title = MessageManager
-            .getString("label.select_outline_colour");
+    String title = MessageManager.getString("label.select_outline_colour");
     ColourChooserListener listener = new ColourChooserListener()
     {
       @Override
@@ -2070,8 +2090,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         refresh();
       }
     };
-    JalviewColourChooser.showColourChooser(Desktop.getDesktop(),
-            title, Color.BLUE, listener);
+    JalviewColourChooser.showColourChooser(Desktop.getDesktop(), title,
+            Color.BLUE, listener);
   }
 
   /**