Merge branch 'develop' into update_212_Dec_merge_with_21125_chamges
[jalview.git] / src / jalview / gui / StructureChooser.java
index a8ce659..4fb9e22 100644 (file)
@@ -41,8 +41,10 @@ import javax.swing.JPopupMenu;
 import javax.swing.JTable;
 import javax.swing.SwingUtilities;
 import javax.swing.table.AbstractTableModel;
+
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
@@ -78,8 +80,12 @@ import jalview.ws.sifts.SiftsSettings;
 public class StructureChooser extends GStructureChooser
         implements IProgressIndicator
 {
-  private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
+  protected static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
 
+  /**
+   * warn user if need to fetch more than this many uniprot records at once
+   */
+  private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
   private SequenceI selectedSequence;
 
   private SequenceI[] selectedSequences;
@@ -110,7 +116,7 @@ public class StructureChooser extends GStructureChooser
 
   List<SequenceI> seqsWithoutSourceDBRef = null;
 
-  private static StructureViewer lastTargetedView = null;
+  protected static StructureViewer lastTargetedView = null;
 
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap)
@@ -118,11 +124,13 @@ public class StructureChooser extends GStructureChooser
     // which FTS engine to use
     data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
     initDialog();
+
     this.ap = ap;
     this.selectedSequence = selectedSeq;
     this.selectedSequences = selectedSeqs;
     this.progressIndicator = (ap == null) ? null : ap.alignFrame;
     init();
+
   }
 
   /**
@@ -194,6 +202,7 @@ public class StructureChooser extends GStructureChooser
 
     Executors.defaultThreadFactory().newThread(new Runnable()
     {
+      @Override
       public void run()
       {
         populateSeqsWithoutSourceDBRef();
@@ -212,6 +221,7 @@ public class StructureChooser extends GStructureChooser
 
     // ensure a filter option is in force for search
     populateFilterComboBox(true, cachedPDBExists);
+
     // looks for any existing structures already loaded
     // for the sequences (the cached ones)
     // then queries the StructureChooserQuerySource to
@@ -240,7 +250,9 @@ public class StructureChooser extends GStructureChooser
 
   /**
    * raises dialog for Uniprot fetch followed by 3D beacons search
-   * @param ignoreGui - when true, don't ask, just fetch 
+   * 
+   * @param ignoreGui
+   *          - when true, don't ask, just fetch
    */
   public void promptForTDBFetch(boolean ignoreGui)
   {
@@ -254,24 +266,34 @@ public class StructureChooser extends GStructureChooser
       {
         mainFrame.setEnabled(false);
         cmb_filterOption.setEnabled(false);
-        progressBar.setProgressBar(MessageManager.getString("status.searching_3d_beacons"), progressId);
+        progressBar.setProgressBar(
+                MessageManager.getString("status.searching_3d_beacons"),
+                progressId);
+        btn_queryTDB.setEnabled(false);
         // TODO: warn if no accessions discovered
         populateSeqsWithoutSourceDBRef();
         // redo initial discovery - this time with 3d beacons
         // Executors.
-        previousWantedFields=null;
-        lastSelected=(FilterOption) cmb_filterOption.getSelectedItem();
+        previousWantedFields = null;
+        lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
         cmb_filterOption.setSelectedItem(null);
         cachedPDBExists=false; // reset to initial
         initialStructureDiscovery();
         if (!isStructuresDiscovered())
         {
-          progressBar.setProgressBar(MessageManager.getString("status.no_structures_discovered_from_3d_beacons"), progressId);
-          btn_queryTDB.setToolTipText(MessageManager.getString("status.no_structures_discovered_from_3d_beacons"));
+          progressBar.setProgressBar(MessageManager.getString(
+                  "status.no_structures_discovered_from_3d_beacons"),
+                  progressId);
+          btn_queryTDB.setToolTipText(MessageManager.getString(
+                  "status.no_structures_discovered_from_3d_beacons"));
           btn_queryTDB.setEnabled(false);
-        } else {
+          pnl_queryTDB.setVisible(false);
+        }
+        else
+        {
           cmb_filterOption.setSelectedIndex(0); // select 'best'
           btn_queryTDB.setVisible(false);
+          pnl_queryTDB.setVisible(false);
           progressBar.setProgressBar(null, progressId);
         }
         mainFrame.setEnabled(true);
@@ -299,6 +321,7 @@ public class StructureChooser extends GStructureChooser
       @Override
       public void run()
       {
+        btn_queryTDB.setEnabled(false);
         populateSeqsWithoutSourceDBRef();
 
         final int y = seqsWithoutSourceDBRef.size();
@@ -312,28 +335,38 @@ public class StructureChooser extends GStructureChooser
           dbRefFetcher.addListener(afterDbRefFetch);
           // ideally this would also gracefully run with callbacks
           dbRefFetcher.fetchDBRefs(true);
-        } else {
+        }
+        else
+        {
           // call finished action directly
           afterDbRefFetch.finished();
         }
       }
 
     };
-    final Runnable revertview = new Runnable() {
-      public void run() {
-        if (lastSelected!=null) {
+    final Runnable revertview = new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        if (lastSelected != null)
+        {
           cmb_filterOption.setSelectedItem(lastSelected);
         }
       };
     };
-    if (ignoreGui)
+    int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
+            THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
+    Console.debug("Using Uniprot fetch threshold of " + threshold);
+    if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
     {
       Executors.defaultThreadFactory().newThread(discoverCanonicalDBrefs).start();
       return;
     }
     // need cancel and no to result in the discoverPDB action - mocked is
     // 'cancel' TODO: mock should be OK
-    JvOptionPane.newOptionDialog(this)
+    StructureChooser thisSC = this;
+    JvOptionPane.newOptionDialog(thisSC.getFrame())
             .setResponseHandler(JvOptionPane.OK_OPTION,
                     discoverCanonicalDBrefs)
             .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
@@ -348,7 +381,7 @@ public class StructureChooser extends GStructureChooser
                     null, new Object[]
                     { MessageManager.getString("action.ok"),
                         MessageManager.getString("action.cancel") },
-                    MessageManager.getString("action.ok"));
+                    MessageManager.getString("action.ok"), false);
   }
 
   /**
@@ -431,10 +464,13 @@ public class StructureChooser extends GStructureChooser
 
     discoveredStructuresSet = new LinkedHashSet<>();
     HashSet<String> errors = new HashSet<>();
+
     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
             .getSelectedItem());
+
     for (SequenceI seq : selectedSequences)
     {
+
       FTSRestResponse resultList;
       try
       {
@@ -468,6 +504,7 @@ public class StructureChooser extends GStructureChooser
     {
       getResultTable()
               .setModel(data.getTableModel(discoveredStructuresSet));
+
       noOfStructuresFound = discoveredStructuresSet.size();
       lastDiscoveredStructuresSet = discoveredStructuresSet;
       mainFrame.setTitle(MessageManager.formatMessage(
@@ -525,6 +562,7 @@ public class StructureChooser extends GStructureChooser
   {
     Thread filterThread = new Thread(new Runnable()
     {
+
       @Override
       public void run()
       {
@@ -537,12 +575,14 @@ public class StructureChooser extends GStructureChooser
 
         for (SequenceI seq : selectedSequences)
         {
+
           FTSRestResponse resultList;
           try
           {
             resultList = data.selectFirstRankedQuery(seq,
                     discoveredStructuresSet, wantedFields, fieldToFilterBy,
                     !chk_invertFilter.isSelected());
+
           } catch (Exception e)
           {
             e.printStackTrace();
@@ -613,7 +653,7 @@ public class StructureChooser extends GStructureChooser
     // StructureChooser
     // works
     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new jalview.io.JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.formatMessage("label.select_pdb_file_for",
@@ -626,7 +666,7 @@ public class StructureChooser extends GStructureChooser
     if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
     {
       selectedPdbFileName = chooser.getSelectedFile().getPath();
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
+      Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
       validateSelections();
     }
   }
@@ -648,11 +688,11 @@ public class StructureChooser extends GStructureChooser
   protected void populateFilterComboBox(boolean haveData,
           boolean cachedPDBExist, FilterOption lastSel)
   {
+
     /*
      * temporarily suspend the change listener behaviour
      */
     cmb_filterOption.removeItemListener(this);
-
     int selSet = -1;
     cmb_filterOption.removeAllItems();
     if (haveData)
@@ -672,6 +712,7 @@ public class StructureChooser extends GStructureChooser
         cmb_filterOption.addItem(filter);
       }
     }
+
     cmb_filterOption.addItem(
             new FilterOption(MessageManager.getString("label.enter_pdb_id"),
                     "-", VIEWS_ENTER_ID, false, null));
@@ -681,6 +722,7 @@ public class StructureChooser extends GStructureChooser
     if (canQueryTDB && notQueriedTDBYet)
     {
       btn_queryTDB.setVisible(true);
+      pnl_queryTDB.setVisible(true);
     }
 
     if (cachedPDBExist)
@@ -694,7 +736,6 @@ public class StructureChooser extends GStructureChooser
         cmb_filterOption.setSelectedItem(cachedOption);
       }
     }
-
     if (selSet > -1)
     {
       cmb_filterOption.setSelectedIndex(selSet);
@@ -718,6 +759,7 @@ public class StructureChooser extends GStructureChooser
     // otherwise, record selection
     // and update the layout and dialog accordingly
     lastSelected = selectedFilterOpt;
+
     layout_switchableViews.show(pnl_switchableViews,
             selectedFilterOpt.getView());
     String filterTitle = mainFrame.getTitle();
@@ -814,26 +856,31 @@ public class StructureChooser extends GStructureChooser
     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
             .getSelectedItem());
     String currentView = selectedFilterOpt.getView();
-     
-    if (currentView == VIEWS_FILTER && data instanceof ThreeDBStructureChooserQuerySource)
+    if (currentView == VIEWS_FILTER
+            && data instanceof ThreeDBStructureChooserQuerySource)
     {
-      
-      TDB_FTSData row=((ThreeDBStructureChooserQuerySource)data).getFTSDataFor(getResultTable(), selectedRow, discoveredStructuresSet);
-      String pageUrl = row.getModelViewUrl(); 
+      TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
+              .getFTSDataFor(getResultTable(), selectedRow,
+                      discoveredStructuresSet);
+      String pageUrl = row.getModelViewUrl();
       JPopupMenu popup = new JPopupMenu("3D Beacons");
       JMenuItem viewUrl = new JMenuItem("View model web page");
-      viewUrl.addActionListener(
-              new ActionListener() {
-                @Override
-                public void actionPerformed(ActionEvent e)
-                {
-                  Desktop.showUrl(pageUrl);
-                }
-              }
-              );
+      viewUrl.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          Desktop.showUrl(pageUrl);
+        }
+      });
       popup.add(viewUrl);
-      SwingUtilities.invokeLater(new Runnable()  {
-        public void run() { popup.show(getResultTable(), x, y); }
+      SwingUtilities.invokeLater(new Runnable()
+      {
+        @Override
+        public void run()
+        {
+          popup.show(getResultTable(), x, y);
+        }
       });
       return true;
     }
@@ -911,7 +958,6 @@ public class StructureChooser extends GStructureChooser
   {
     validateSelections();
   }
-
   private FilterOption lastSelected=null;
   /**
    * Handles the state change event for the 'filter' combo-box and 'invert'
@@ -972,6 +1018,7 @@ public class StructureChooser extends GStructureChooser
     }
     return found;
   }
+
   /**
    * Handles the 'New View' action
    */
@@ -1000,7 +1047,8 @@ public class StructureChooser extends GStructureChooser
   {
 
     final StructureSelectionManager ssm = ap.getStructureSelectionManager();
-
+    final StructureViewer theViewer = getTargetedStructureViewer(ssm);
+    boolean superimpose = chk_superpose.isSelected(); 
     final int preferredHeight = pnl_filter.getHeight();
 
     Runnable viewStruc = new Runnable()
@@ -1024,8 +1072,8 @@ public class StructureChooser extends GStructureChooser
 
           SequenceI[] selectedSeqs = selectedSeqsToView
                   .toArray(new SequenceI[selectedSeqsToView.size()]);
-          sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
-                  selectedSeqs);
+          sViewer = StructureViewer.launchStructureViewer(ap, pdbEntriesToView,
+                  selectedSeqs, superimpose, theViewer, progressBar);
         }
         else if (currentView == VIEWS_LOCAL_PDB)
         {
@@ -1041,6 +1089,7 @@ public class StructureChooser extends GStructureChooser
           {
             PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
                     .getModel()).getPDBEntryAt(row).getPdbEntry();
+
             pdbEntriesToView[count++] = pdbEntry;
             SequenceI selectedSeq = (SequenceI) tbl_local_pdb
                     .getValueAt(row, refSeqColIndex);
@@ -1048,8 +1097,8 @@ public class StructureChooser extends GStructureChooser
           }
           SequenceI[] selectedSeqs = selectedSeqsToView
                   .toArray(new SequenceI[selectedSeqsToView.size()]);
-          sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
-                  selectedSeqs);
+          sViewer = StructureViewer.launchStructureViewer(ap, pdbEntriesToView,
+                  selectedSeqs, superimpose, theViewer, progressBar);
         }
         else if (currentView == VIEWS_ENTER_ID)
         {
@@ -1078,9 +1127,10 @@ public class StructureChooser extends GStructureChooser
           }
 
           PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
-          sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
-                  new SequenceI[]
-                  { selectedSequence });
+          sViewer = StructureViewer.launchStructureViewer(ap, pdbEntriesToView,
+                   new SequenceI[]
+                  { selectedSequence }, superimpose, theViewer,
+                  progressBar);
         }
         else if (currentView == VIEWS_FROM_FILE)
         {
@@ -1090,14 +1140,12 @@ public class StructureChooser extends GStructureChooser
           {
             selectedSequence = userSelectedSeq;
           }
-          PDBEntry fileEntry = new AssociatePdbFileWithSeq()
-                  .associatePdbWithSeq(selectedPdbFileName,
-                          DataSourceType.FILE, selectedSequence, true,
-                          Desktop.getInstance());
-
-          sViewer = launchStructureViewer(ssm, new PDBEntry[] { fileEntry },
-                  ap, new SequenceI[]
-                  { selectedSequence });
+          PDBEntry fileEntry =  AssociatePdbFileWithSeq.associatePdbWithSeq(selectedPdbFileName,
+                          DataSourceType.FILE, selectedSequence, true);
+
+          sViewer = StructureViewer.launchStructureViewer(ap,  new PDBEntry[] { fileEntry },
+                 new SequenceI[] { selectedSequence }, superimpose, theViewer,
+                  progressBar);
         }
         SwingUtilities.invokeLater(new Runnable()
         {
@@ -1144,98 +1192,6 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
-   * Adds PDB structures to a new or existing structure viewer
-   * 
-   * @param ssm
-   * @param pdbEntriesToView
-   * @param alignPanel
-   * @param sequences
-   * @return
-   */
-  private StructureViewer launchStructureViewer(
-          StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
-          final AlignmentPanel alignPanel, SequenceI[] sequences)
-  {
-    long progressId = sequences.hashCode();
-    setProgressBar(MessageManager
-            .getString("status.launching_3d_structure_viewer"), progressId);
-    final StructureViewer theViewer = getTargetedStructureViewer(ssm);
-    boolean superimpose = chk_superpose.isSelected();
-    theViewer.setSuperpose(superimpose);
-
-    /*
-     * remember user's choice of superimpose or not
-     */
-    Cache.setProperty(AUTOSUPERIMPOSE,
-            Boolean.valueOf(superimpose).toString());
-
-    setProgressBar(null, progressId);
-    if (SiftsSettings.isMapWithSifts())
-    {
-      List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
-      int p = 0;
-      // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
-      // real PDB ID. For moment, we can also safely do this if there is already
-      // a known mapping between the PDBEntry and the sequence.
-      for (SequenceI seq : sequences)
-      {
-        PDBEntry pdbe = pdbEntriesToView[p++];
-        if (pdbe != null && pdbe.getFile() != null)
-        {
-          StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
-          if (smm != null && smm.length > 0)
-          {
-            for (StructureMapping sm : smm)
-            {
-              if (sm.getSequence() == seq)
-              {
-                continue;
-              }
-            }
-          }
-        }
-        if (seq.getPrimaryDBRefs().isEmpty())
-        {
-          seqsWithoutSourceDBRef.add(seq);
-          continue;
-        }
-      }
-      if (!seqsWithoutSourceDBRef.isEmpty())
-      {
-        int y = seqsWithoutSourceDBRef.size();
-        setProgressBar(MessageManager.formatMessage(
-                "status.fetching_dbrefs_for_sequences_without_valid_refs",
-                y), progressId);
-        SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
-                .toArray(new SequenceI[y]);
-        DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
-        dbRefFetcher.fetchDBRefs(true);
-
-        setProgressBar("Fetch complete.", progressId); // todo i18n
-      }
-    }
-    if (pdbEntriesToView.length > 1)
-    {
-      setProgressBar(
-              MessageManager.getString(
-                      "status.fetching_3d_structures_for_selected_entries"),
-              progressId);
-      theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
-    }
-    else
-    {
-      setProgressBar(MessageManager.formatMessage(
-              "status.fetching_3d_structures_for",
-              pdbEntriesToView[0].getId()), progressId);
-      theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
-    }
-    setProgressBar(null, progressId);
-    // remember the last viewer we used...
-    lastTargetedView = theViewer;
-    return theViewer;
-  }
-
-  /**
    * Populates the combo-box used in associating manually fetched structures to
    * a unique sequence when more than one sequence selection is made.
    */
@@ -1335,6 +1291,7 @@ public class StructureChooser extends GStructureChooser
   {
     if (selectedSequences != null)
     {
+      lbl_loading.setVisible(true);
       Thread refreshThread = new Thread(new Runnable()
       {
         @Override
@@ -1342,9 +1299,11 @@ public class StructureChooser extends GStructureChooser
         {
           fetchStructuresMetaData();
           // populateFilterComboBox(true, cachedPDBExists);
+
           filterResultSet(
                   ((FilterOption) cmb_filterOption.getSelectedItem())
                           .getValue());
+          lbl_loading.setVisible(false);
         }
       });
       refreshThread.start();
@@ -1513,8 +1472,9 @@ public class StructureChooser extends GStructureChooser
    * 
    * @return true if the 3D-Beacons query button will/has been displayed
    */
-  public boolean isCanQueryTDB() {
-         return canQueryTDB;
+  public boolean isCanQueryTDB()
+  {
+    return canQueryTDB;
   }
 
   public boolean isNotQueriedTDBYet()