Merge branch 'develop' into trialMerge
[jalview.git] / src / jalview / gui / AlignFrame.java
index 8cc1dd5..f31a220 100644 (file)
@@ -32,7 +32,6 @@ import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsControllerI;
-import jalview.api.FeatureSettingsModelI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.ScoreModelI;
@@ -54,7 +53,6 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.DBRefSource;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
@@ -77,8 +75,8 @@ import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
+import jalview.io.StructureFile;
 import jalview.io.TCoffeeScoreFile;
-import jalview.io.gff.SequenceOntologyI;
 import jalview.jbgui.GAlignFrame;
 import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.BuriedColourScheme;
@@ -98,12 +96,10 @@ import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.schemes.UserColourScheme;
 import jalview.schemes.ZappoColourScheme;
-import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
-import jalview.ws.SequenceFetcher;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
@@ -117,6 +113,7 @@ import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.StringSelection;
 import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DropTargetDragEvent;
 import java.awt.dnd.DropTargetDropEvent;
 import java.awt.dnd.DropTargetEvent;
@@ -677,6 +674,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           toggleHiddenRegions(toggleSeqs, toggleCols);
           break;
         }
+        case KeyEvent.VK_B:
+        {
+          boolean toggleSel = evt.isControlDown() || evt.isMetaDown();
+          boolean modifyExisting = true; // always modify, don't clear
+                                         // evt.isShiftDown();
+          boolean invertHighlighted = evt.isAltDown();
+          avc.markHighlightedColumns(invertHighlighted, modifyExisting,
+                  toggleSel);
+          break;
+        }
         case KeyEvent.VK_PAGE_UP:
           if (viewport.getWrapAlignment())
           {
@@ -1345,14 +1352,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void htmlMenuItem_actionPerformed(ActionEvent e)
   {
-    new HtmlSvgOutput(null, alignPanel);
+    HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel);
+    htmlSVG.exportHTML(null);
   }
 
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
-    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel, this);
-    bjs.exportJalviewAlignmentAsBioJsHtmlFile();
+    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
+    bjs.exportHTML(null);
   }
 
   public void createImageMap(File file, String image)
@@ -2915,8 +2923,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setFollowHighlight(state);
     if (state)
     {
-      alignPanel.scrollToPosition(
-              alignPanel.getSeqPanel().seqCanvas.searchResults, false);
+      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
     }
   }
 
@@ -2986,9 +2993,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // Hide everything by the current selection - this is a hack - we do the
       // invert and then hide
       // first check that there will be visible columns after the invert.
-      if ((viewport.getColumnSelection() != null
-              && viewport.getColumnSelection().getSelected() != null && viewport
-              .getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns()
               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
                       .getEndRes()))
       {
@@ -3016,8 +3021,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         hideSelSequences_actionPerformed(null);
         hide = true;
       }
-      else if (!(toggleCols && viewport.getColumnSelection().getSelected()
-              .size() > 0))
+      else if (!(toggleCols && viewport.hasSelectedColumns()))
       {
         showAllSeqs_actionPerformed(null);
       }
@@ -3025,7 +3029,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (toggleCols)
     {
-      if (viewport.getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns())
       {
         hideSelColumns_actionPerformed(null);
         if (!toggleSeqs)
@@ -3629,34 +3633,50 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isPopupTrigger())
+            if (evt.isPopupTrigger()) // Mac
             {
-              radioItem.removeActionListener(radioItem.getActionListeners()[0]);
+              offerRemoval(radioItem);
+            }
+          }
 
-              int option = JOptionPane.showInternalConfirmDialog(
-                      jalview.gui.Desktop.desktop,
-                      MessageManager
-                              .getString("label.remove_from_default_list"),
-                      MessageManager
-                              .getString("label.remove_user_defined_colour"),
-                      JOptionPane.YES_NO_OPTION);
-              if (option == JOptionPane.YES_OPTION)
-              {
-                jalview.gui.UserDefinedColours
-                        .removeColourFromDefaults(radioItem.getText());
-                colourMenu.remove(radioItem);
-              }
-              else
+          @Override
+          public void mouseReleased(MouseEvent evt)
+          {
+            if (evt.isPopupTrigger()) // Windows
+            {
+              offerRemoval(radioItem);
+            }
+          }
+
+          /**
+           * @param radioItem
+           */
+          void offerRemoval(final JRadioButtonMenuItem radioItem)
+          {
+            radioItem.removeActionListener(radioItem.getActionListeners()[0]);
+
+            int option = JOptionPane.showInternalConfirmDialog(
+                    jalview.gui.Desktop.desktop, MessageManager
+                            .getString("label.remove_from_default_list"),
+                    MessageManager
+                            .getString("label.remove_user_defined_colour"),
+                    JOptionPane.YES_NO_OPTION);
+            if (option == JOptionPane.YES_OPTION)
+            {
+              jalview.gui.UserDefinedColours
+                      .removeColourFromDefaults(radioItem.getText());
+              colourMenu.remove(radioItem);
+            }
+            else
+            {
+              radioItem.addActionListener(new ActionListener()
               {
-                radioItem.addActionListener(new ActionListener()
+                @Override
+                public void actionPerformed(ActionEvent evt)
                 {
-                  @Override
-                  public void actionPerformed(ActionEvent evt)
-                  {
-                    userDefinedColour_actionPerformed(evt);
-                  }
-                });
-              }
+                  userDefinedColour_actionPerformed(evt);
+                }
+              });
             }
           }
         });
@@ -4630,14 +4650,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
     AlignmentI dataset = viewport.getAlignment().getDataset();
+
+    showProducts.removeAll();
+    final boolean dna = viewport.getAlignment().isNucleotide();
+
+    if (seqs == null || seqs.length == 0)
+    {
+      // nothing to see here.
+      return false;
+    }
+
     boolean showp = false;
     try
     {
-      showProducts.removeAll();
-      final boolean dna = viewport.getAlignment().isNucleotide();
-      List<String> ptypes = (seqs == null || seqs.length == 0) ? null
-              : new CrossRef(seqs, dataset)
-                      .findXrefSourcesForSequences(dna);
+      List<String> ptypes = new CrossRef(seqs, dataset)
+              .findXrefSourcesForSequences(dna);
 
       for (final String source : ptypes)
       {
@@ -4680,236 +4707,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showProductsFor(final SequenceI[] sel,
           final boolean _odna, final String source)
   {
-    Runnable foo = new Runnable()
-    {
-
-      @Override
-      public void run()
-      {
-        final long sttime = System.currentTimeMillis();
-        AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                "status.searching_for_sequences_from",
-                new Object[] { source }), sttime);
-        try
-        {
-          AlignmentI alignment = AlignFrame.this.getViewport()
-                  .getAlignment();
-          AlignmentI dataset = alignment.getDataset() == null ? alignment
-                  : alignment.getDataset();
-          boolean dna = alignment.isNucleotide();
-          if (_odna != dna)
-          {
-            System.err
-                    .println("Conflict: showProducts for alignment originally "
-                            + "thought to be "
-                            + (_odna ? "DNA" : "Protein")
-                            + " now searching for "
-                            + (dna ? "DNA" : "Protein") + " Context.");
-          }
-          AlignmentI xrefs = new CrossRef(sel, dataset).findXrefSequences(
-                  source, dna);
-          if (xrefs == null)
-          {
-            return;
-          }
-          /*
-           * get display scheme (if any) to apply to features
-           */
-          FeatureSettingsModelI featureColourScheme = new SequenceFetcher()
-                  .getFeatureColourScheme(source);
-
-          AlignmentI xrefsAlignment = makeCrossReferencesAlignment(dataset,
-                  xrefs);
-          if (!dna)
-          {
-            xrefsAlignment = AlignmentUtils.makeCdsAlignment(
-                    xrefsAlignment.getSequencesArray(), dataset, sel);
-            xrefsAlignment.alignAs(alignment);
-          }
-
-          /*
-           * If we are opening a splitframe, make a copy of this alignment (sharing the same dataset
-           * sequences). If we are DNA, drop introns and update mappings
-           */
-          AlignmentI copyAlignment = null;
-
-          if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
-          {
-            boolean copyAlignmentIsAligned = false;
-            if (dna)
-            {
-              copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset,
-                      xrefsAlignment.getSequencesArray());
-              if (copyAlignment.getHeight() == 0)
-              {
-                JOptionPane.showMessageDialog(AlignFrame.this,
-                        MessageManager.getString("label.cant_map_cds"),
-                        MessageManager.getString("label.operation_failed"),
-                        JOptionPane.OK_OPTION);
-                System.err.println("Failed to make CDS alignment");
-              }
-
-              /*
-               * pending getting Embl transcripts to 'align', 
-               * we are only doing this for Ensembl
-               */
-              // TODO proper criteria for 'can align as cdna'
-              if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
-                      || AlignmentUtils.looksLikeEnsembl(alignment))
-              {
-                copyAlignment.alignAs(alignment);
-                copyAlignmentIsAligned = true;
-              }
-            }
-            else
-            {
-              copyAlignment = AlignmentUtils.makeCopyAlignment(sel,
-                      xrefs.getSequencesArray(), dataset);
-            }
-            copyAlignment.setGapCharacter(AlignFrame.this.viewport
-                    .getGapCharacter());
-
-            StructureSelectionManager ssm = StructureSelectionManager
-                    .getStructureSelectionManager(Desktop.instance);
-
-            /*
-             * register any new mappings for sequence mouseover etc
-             * (will not duplicate any previously registered mappings)
-             */
-            ssm.registerMappings(dataset.getCodonFrames());
-
-            if (copyAlignment.getHeight() <= 0)
-            {
-              System.err.println("No Sequences generated for xRef type "
-                      + source);
-              return;
-            }
-            /*
-             * align protein to dna
-             */
-            if (dna && copyAlignmentIsAligned)
-            {
-              xrefsAlignment.alignAs(copyAlignment);
-            }
-            else
-            {
-              /*
-               * align cdna to protein - currently only if 
-               * fetching and aligning Ensembl transcripts!
-               */
-              // TODO: generalise for other sources of locus/transcript/cds data
-              if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source))
-              {
-                copyAlignment.alignAs(xrefsAlignment);
-              }
-            }
-          }
-          /*
-           * build AlignFrame(s) according to available alignment data
-           */
-          AlignFrame newFrame = new AlignFrame(xrefsAlignment,
-                  DEFAULT_WIDTH, DEFAULT_HEIGHT);
-          if (Cache.getDefault("HIDE_INTRONS", true))
-          {
-            newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false);
-          }
-          String newtitle = String.format("%s %s %s",
-                  dna ? MessageManager.getString("label.proteins")
-                          : MessageManager.getString("label.nucleotides"),
-                  MessageManager.getString("label.for"), getTitle());
-          newFrame.setTitle(newtitle);
-
-          if (copyAlignment == null)
-          {
-            /*
-             * split frame display is turned off in preferences file
-             */
-            Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH,
-                    DEFAULT_HEIGHT);
-            return; // via finally clause
-          }
-          AlignFrame copyThis = new AlignFrame(copyAlignment,
-                  AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
-          copyThis.setTitle(AlignFrame.this.getTitle());
-
-          boolean showSequenceFeatures = viewport.isShowSequenceFeatures();
-          newFrame.setShowSeqFeatures(showSequenceFeatures);
-          copyThis.setShowSeqFeatures(showSequenceFeatures);
-          FeatureRenderer myFeatureStyling = alignPanel.getSeqPanel().seqCanvas
-                  .getFeatureRenderer();
-
-          /*
-           * copy feature rendering settings to split frame
-           */
-          newFrame.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .transferSettings(myFeatureStyling);
-          copyThis.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .transferSettings(myFeatureStyling);
-
-          /*
-           * apply 'database source' feature configuration
-           * if any was found
-           */
-          // TODO is this the feature colouring for the original
-          // alignment or the fetched xrefs? either could be Ensembl
-          newFrame.getViewport().applyFeaturesStyle(featureColourScheme);
-          copyThis.getViewport().applyFeaturesStyle(featureColourScheme);
-
-          SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame,
-                  dna ? newFrame : copyThis);
-          newFrame.setVisible(true);
-          copyThis.setVisible(true);
-          String linkedTitle = MessageManager
-                  .getString("label.linked_view_title");
-          Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
-          sf.adjustDivider();
-        } catch (OutOfMemoryError e)
-        {
-          new OOMWarning("whilst fetching crossreferences", e);
-        } catch (Throwable e)
-        {
-          Cache.log.error("Error when finding crossreferences", e);
-        } finally
-        {
-          AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                  "status.finished_searching_for_sequences_from",
-                  new Object[] { source }), sttime);
-        }
-      }
-
-      /**
-       * Makes an alignment containing the given sequences, and adds them to the
-       * given dataset, which is also set as the dataset for the new alignment
-       * 
-       * TODO: refactor to DatasetI method
-       * 
-       * @param dataset
-       * @param seqs
-       * @return
-       */
-      protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset,
-              AlignmentI seqs)
-      {
-        SequenceI[] sprods = new SequenceI[seqs.getHeight()];
-        for (int s = 0; s < sprods.length; s++)
-        {
-          sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
-          if (dataset.getSequences() == null
-                  || !dataset.getSequences().contains(
-                          sprods[s].getDatasetSequence()))
-          {
-            dataset.addSequence(sprods[s].getDatasetSequence());
-          }
-          sprods[s].updatePDBIds();
-        }
-        Alignment al = new Alignment(sprods);
-        al.setDataset(dataset);
-        return al;
-      }
-
-    };
-    Thread frunner = new Thread(foo);
-    frunner.start();
+    new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this))
+            .start();
   }
 
   /**
@@ -5031,6 +4830,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void drop(DropTargetDropEvent evt)
   {
+    // JAL-1552 - acceptDrop required before getTransferable call for
+    // Java's Transferable for native dnd
+    evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
     List<String> files = new ArrayList<String>();
     List<DataSourceType> protocols = new ArrayList<DataSourceType>();
@@ -5099,7 +4901,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               }
               if (type != null)
               {
-                if (FileFormat.PDB.equals(type))
+                if (FileFormat.PDB.equals(type) || FileFormat.MMCif.equals(type))
                 {
                   filesmatched.add(new Object[] { file, protocol, mtch });
                   continue;
@@ -5119,14 +4921,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                   this,
                                   MessageManager
                                           .formatMessage(
-                                                  "label.automatically_associate_pdb_files_with_sequences_same_name",
+                                                  "label.automatically_associate_structure_files_with_sequences_same_name",
                                                   new Object[] { Integer
                                                           .valueOf(
                                                                   filesmatched
                                                                           .size())
                                                           .toString() }),
                                   MessageManager
-                                          .getString("label.automatically_associate_pdb_files_by_name"),
+                                          .getString("label.automatically_associate_structure_files_by_name"),
                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
 
           {
@@ -6145,6 +5947,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     return false;
   }
+
+  @Override
+  protected void selectHighlightedColumns_actionPerformed(
+          ActionEvent actionEvent)
+  {
+    // include key modifier check in case user selects from menu
+    avc.markHighlightedColumns(
+            (actionEvent.getModifiers() & ActionEvent.ALT_MASK) != 0,
+            true,
+            (actionEvent.getModifiers() & (ActionEvent.META_MASK | ActionEvent.CTRL_MASK)) != 0);
+  }
 }
 
 class PrintThread extends Thread