Merge commit 'alpha/update_2_12_for_2_11_2_series_merge^2' into HEAD
[jalview.git] / src / jalview / gui / StructureChooser.java
index 9f9de6e..a8ce659 100644 (file)
 
 package jalview.gui;
 
-import java.util.Locale;
-
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.concurrent.Executors;
 
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+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.Jalview;
@@ -50,6 +53,7 @@ import jalview.fts.core.FTSDataColumnPreferences;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.fts.service.threedbeacons.TDB_FTSData;
 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
@@ -76,11 +80,6 @@ public class StructureChooser extends GStructureChooser
 {
   private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
 
-  /**
-   * transient combo box choice for initiating 3db fetch
-   */
-  private static final String VIEWS_QUERYING_TDB = "QUERY_3DB";
-
   private SequenceI selectedSequence;
 
   private SequenceI[] selectedSequences;
@@ -119,13 +118,11 @@ 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();
-
   }
 
   /**
@@ -168,7 +165,8 @@ public class StructureChooser extends GStructureChooser
       canQueryTDB = true;
       if (needCanonical)
       {
-        notQueriedTDBYet = false;
+        // triggers display of the 'Query TDB' button
+        notQueriedTDBYet = true;
       }
     }
   };
@@ -184,6 +182,15 @@ public class StructureChooser extends GStructureChooser
     }
 
     chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
+    btn_queryTDB.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        promptForTDBFetch(false);
+      }
+    });
 
     Executors.defaultThreadFactory().newThread(new Runnable()
     {
@@ -205,7 +212,6 @@ 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
@@ -232,7 +238,11 @@ public class StructureChooser extends GStructureChooser
     updateCurrentView();
   }
 
-  private void promptForTDBFetch()
+  /**
+   * raises dialog for Uniprot fetch followed by 3D beacons search
+   * @param ignoreGui - when true, don't ask, just fetch 
+   */
+  public void promptForTDBFetch(boolean ignoreGui)
   {
     final long progressId = System.currentTimeMillis();
 
@@ -242,13 +252,30 @@ public class StructureChooser extends GStructureChooser
       @Override
       public void run()
       {
+        mainFrame.setEnabled(false);
+        cmb_filterOption.setEnabled(false);
+        progressBar.setProgressBar(MessageManager.getString("status.searching_3d_beacons"), progressId);
         // TODO: warn if no accessions discovered
         populateSeqsWithoutSourceDBRef();
         // redo initial discovery - this time with 3d beacons
         // Executors.
         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"));
+          btn_queryTDB.setEnabled(false);
+        } else {
+          cmb_filterOption.setSelectedIndex(0); // select 'best'
+          btn_queryTDB.setVisible(false);
+          progressBar.setProgressBar(null, progressId);
+        }
+        mainFrame.setEnabled(true);
+        cmb_filterOption.setEnabled(true);
       }
     };
 
@@ -299,8 +326,13 @@ public class StructureChooser extends GStructureChooser
         }
       };
     };
+    if (ignoreGui)
+    {
+      Executors.defaultThreadFactory().newThread(discoverCanonicalDBrefs).start();
+      return;
+    }
     // need cancel and no to result in the discoverPDB action - mocked is
-    // 'cancel'
+    // 'cancel' TODO: mock should be OK
     JvOptionPane.newOptionDialog(this)
             .setResponseHandler(JvOptionPane.OK_OPTION,
                     discoverCanonicalDBrefs)
@@ -326,7 +358,7 @@ public class StructureChooser extends GStructureChooser
    */
   private void discoverStructureViews()
   {
-    if (Desktop.instance != null)
+    if (Desktop.getInstance() != null)
     {
       targetView.removeAllItems();
       if (lastTargetedView != null && !lastTargetedView.isVisible())
@@ -334,7 +366,7 @@ public class StructureChooser extends GStructureChooser
         lastTargetedView = null;
       }
       int linkedViewsAt = 0;
-      for (StructureViewerBase view : Desktop.instance
+      for (StructureViewerBase view : Desktop.getInstance()
               .getStructureViewers(null, null))
       {
         StructureViewer viewHandler = (lastTargetedView != null
@@ -399,13 +431,10 @@ 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
       {
@@ -439,7 +468,6 @@ public class StructureChooser extends GStructureChooser
     {
       getResultTable()
               .setModel(data.getTableModel(discoveredStructuresSet));
-
       noOfStructuresFound = discoveredStructuresSet.size();
       lastDiscoveredStructuresSet = discoveredStructuresSet;
       mainFrame.setTitle(MessageManager.formatMessage(
@@ -497,7 +525,6 @@ public class StructureChooser extends GStructureChooser
   {
     Thread filterThread = new Thread(new Runnable()
     {
-
       @Override
       public void run()
       {
@@ -510,14 +537,12 @@ 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();
@@ -623,11 +648,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)
@@ -647,7 +672,6 @@ 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));
@@ -656,10 +680,7 @@ public class StructureChooser extends GStructureChooser
                     "-", VIEWS_FROM_FILE, false, null));
     if (canQueryTDB && notQueriedTDBYet)
     {
-      FilterOption queryTDBOption = new FilterOption(
-              MessageManager.getString("label.search_3dbeacons"), "-",
-              VIEWS_QUERYING_TDB, false, null);
-      cmb_filterOption.addItem(queryTDBOption);
+      btn_queryTDB.setVisible(true);
     }
 
     if (cachedPDBExist)
@@ -673,6 +694,7 @@ public class StructureChooser extends GStructureChooser
         cmb_filterOption.setSelectedItem(cachedOption);
       }
     }
+
     if (selSet > -1)
     {
       cmb_filterOption.setSelectedIndex(selSet);
@@ -688,12 +710,6 @@ public class StructureChooser extends GStructureChooser
     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
             .getSelectedItem());
     
-    // first check if we need to rebuild dialog
-    if (selectedFilterOpt.getView() == VIEWS_QUERYING_TDB)
-    {
-      promptForTDBFetch();
-      return;
-    }
     if (lastSelected == selectedFilterOpt)
     {
       // don't need to do anything, probably
@@ -702,7 +718,6 @@ 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();
@@ -793,6 +808,38 @@ public class StructureChooser extends GStructureChooser
             .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
   }
 
+  @Override
+  protected boolean showPopupFor(int selectedRow, int x, int y)
+  {
+    FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+            .getSelectedItem());
+    String currentView = selectedFilterOpt.getView();
+     
+    if (currentView == VIEWS_FILTER && data instanceof ThreeDBStructureChooserQuerySource)
+    {
+      
+      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);
+                }
+              }
+              );
+      popup.add(viewUrl);
+      SwingUtilities.invokeLater(new Runnable()  {
+        public void run() { popup.show(getResultTable(), x, y); }
+      });
+      return true;
+    }
+    // event not handled by us
+    return false;
+  }
   /**
    * Validates inputs from the Manual PDB entry panel
    */
@@ -864,6 +911,7 @@ public class StructureChooser extends GStructureChooser
   {
     validateSelections();
   }
+
   private FilterOption lastSelected=null;
   /**
    * Handles the state change event for the 'filter' combo-box and 'invert'
@@ -924,7 +972,6 @@ public class StructureChooser extends GStructureChooser
     }
     return found;
   }
-
   /**
    * Handles the 'New View' action
    */
@@ -994,7 +1041,6 @@ 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);
@@ -1047,7 +1093,7 @@ public class StructureChooser extends GStructureChooser
           PDBEntry fileEntry = new AssociatePdbFileWithSeq()
                   .associatePdbWithSeq(selectedPdbFileName,
                           DataSourceType.FILE, selectedSequence, true,
-                          Desktop.instance);
+                          Desktop.getInstance());
 
           sViewer = launchStructureViewer(ssm, new PDBEntry[] { fileEntry },
                   ap, new SequenceI[]
@@ -1296,7 +1342,6 @@ public class StructureChooser extends GStructureChooser
         {
           fetchStructuresMetaData();
           // populateFilterComboBox(true, cachedPDBExists);
-
           filterResultSet(
                   ((FilterOption) cmb_filterOption.getSelectedItem())
                           .getValue());
@@ -1422,6 +1467,12 @@ public class StructureChooser extends GStructureChooser
   {
     progressBar.setProgressBar(message, id);
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    progressBar.removeProgressBar(id);
+  }
 
   @Override
   public void registerHandler(long id, IProgressIndicatorHandler handler)
@@ -1458,4 +1509,16 @@ public class StructureChooser extends GStructureChooser
             && mainFrame.isVisible()
             && cmb_filterOption.getSelectedItem() != null;
   }
+  /**
+   * 
+   * @return true if the 3D-Beacons query button will/has been displayed
+   */
+  public boolean isCanQueryTDB() {
+         return canQueryTDB;
+  }
+
+  public boolean isNotQueriedTDBYet()
+  {
+    return notQueriedTDBYet;
+  }
 }