JAL-4310 let the user know when model pages are not available for a 3d-beacons struct...
[jalview.git] / src / jalview / gui / StructureChooser.java
index fc73c27..8135019 100644 (file)
@@ -33,7 +33,6 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 
 import javax.swing.JCheckBox;
 import java.util.concurrent.Executors;
 
 import javax.swing.JCheckBox;
@@ -67,6 +66,7 @@ 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.fts.core.FTSRestResponse;
 import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.fts.service.threedbeacons.TDB_FTSData;
+import jalview.gui.StructureViewer.ViewerType;
 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
@@ -83,6 +83,7 @@ import jalview.util.Platform;
 import jalview.util.StringUtils;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
 import jalview.util.StringUtils;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 import jalview.ws.seqfetcher.DbSourceProxy;
 import jalview.ws.sifts.SiftsSettings;
 
 import jalview.ws.seqfetcher.DbSourceProxy;
 import jalview.ws.sifts.SiftsSettings;
 
@@ -138,6 +139,10 @@ public class StructureChooser extends GStructureChooser
   List<SequenceI> seqsWithoutSourceDBRef = null;
 
   private boolean showChooserGUI = true;
   List<SequenceI> seqsWithoutSourceDBRef = null;
 
   private boolean showChooserGUI = true;
+  /**
+   * when true, queries to external services are supressed (no SIFTs, no PDBe, no 3D-Beacons, etc)
+   */
+  private boolean dontQueryServices = false;
 
   private static StructureViewer lastTargetedView = null;
 
 
   private static StructureViewer lastTargetedView = null;
 
@@ -150,6 +155,13 @@ public class StructureChooser extends GStructureChooser
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap, boolean showGUI)
   {
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap, boolean showGUI)
   {
+    this(selectedSeqs, selectedSeq, ap, showGUI, false);
+  }
+  
+  public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
+          AlignmentPanel ap, boolean showGUI, boolean dontQueryServices)
+  {
+
     // which FTS engine to use
     data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
     initDialog();
     // which FTS engine to use
     data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
     initDialog();
@@ -159,6 +171,7 @@ public class StructureChooser extends GStructureChooser
     this.selectedSequences = selectedSeqs;
     this.progressIndicator = (ap == null) ? null : ap.alignFrame;
     this.showChooserGUI = showGUI;
     this.selectedSequences = selectedSeqs;
     this.progressIndicator = (ap == null) ? null : ap.alignFrame;
     this.showChooserGUI = showGUI;
+    this.dontQueryServices = dontQueryServices;
     init();
 
   }
     init();
 
   }
@@ -230,17 +243,21 @@ public class StructureChooser extends GStructureChooser
       }
     });
 
       }
     });
 
-    Executors.defaultThreadFactory().newThread(new Runnable()
+    if (!dontQueryServices)
     {
     {
-      @Override
-      public void run()
+      Executors.defaultThreadFactory().newThread(new Runnable()
       {
       {
-        populateSeqsWithoutSourceDBRef();
-        initialStructureDiscovery();
-      }
-
-    }).start();
+        @Override
+        public void run()
+        {
+          populateSeqsWithoutSourceDBRef();
+          initialStructureDiscovery();
+        }
 
 
+      }).start();
+    } else {
+      Console.debug("Structure chooser not querying services to discover metadata.");
+    }
   }
 
   // called by init
   }
 
   // called by init
@@ -346,7 +363,7 @@ public class StructureChooser extends GStructureChooser
     };
 
     // fetch db refs if OK pressed
     };
 
     // fetch db refs if OK pressed
-    final Callable discoverCanonicalDBrefs = () -> {
+    final Runnable discoverCanonicalDBrefs = () -> {
       btn_queryTDB.setEnabled(false);
       populateSeqsWithoutSourceDBRef();
 
       btn_queryTDB.setEnabled(false);
       populateSeqsWithoutSourceDBRef();
 
@@ -368,14 +385,12 @@ public class StructureChooser extends GStructureChooser
         // call finished action directly
         afterDbRefFetch.finished();
       }
         // call finished action directly
         afterDbRefFetch.finished();
       }
-      return null;
     };
     };
-    final Callable revertview = () -> {
+    final Runnable revertview = () -> {
       if (lastSelected != null)
       {
         cmb_filterOption.setSelectedItem(lastSelected);
       }
       if (lastSelected != null)
       {
         cmb_filterOption.setSelectedItem(lastSelected);
       }
-      return null;
     };
     int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
             THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
     };
     int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
             THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
@@ -507,7 +522,7 @@ public class StructureChooser extends GStructureChooser
         }
       } catch (Exception e)
       {
         }
       } catch (Exception e)
       {
-        e.printStackTrace();
+        Console.printStackTrace(e);
         errors.add(e.getMessage());
         continue;
       }
         errors.add(e.getMessage());
         continue;
       }
@@ -544,9 +559,18 @@ public class StructureChooser extends GStructureChooser
         {
           errorMsg.append(error).append("\n");
         }
         {
           errorMsg.append(error).append("\n");
         }
-        JvOptionPane.showMessageDialog(this, errorMsg.toString(),
-                MessageManager.getString("label.pdb_web-service_error"),
-                JvOptionPane.ERROR_MESSAGE);
+        if (!Jalview.isHeadlessMode())
+        {
+          JvOptionPane.showMessageDialog(this, errorMsg.toString(),
+                  MessageManager.getString("label.pdb_web-service_error"),
+                  JvOptionPane.ERROR_MESSAGE);
+        }
+        else
+        {
+          Console.error(
+                  MessageManager.getString("label.pdb_web-service_error"));
+          Console.debug(errorMsg.toString());
+        }
       }
     }
   }
       }
     }
   }
@@ -607,7 +631,7 @@ public class StructureChooser extends GStructureChooser
 
           } catch (Exception e)
           {
 
           } catch (Exception e)
           {
-            e.printStackTrace();
+            Console.debugPrintStackTrace(e);
             errors.add(e.getMessage());
             continue;
           }
             errors.add(e.getMessage());
             continue;
           }
@@ -706,7 +730,7 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
   }
 
   /**
-   * Handles action event for btn_pdbFromFile
+   * Handles action event for btn_paeMatrixFile
    */
   @Override
   protected void paeMatrixFile_actionPerformed()
    */
   @Override
   protected void paeMatrixFile_actionPerformed()
@@ -735,10 +759,26 @@ public class StructureChooser extends GStructureChooser
             "label.load_pae_matrix_file_associate_with_structure",
             pdbFile.getName()));
 
             "label.load_pae_matrix_file_associate_with_structure",
             pdbFile.getName()));
 
+    // TODO convert to Callable/Promise
     int value = chooser.showOpenDialog(null);
     if (value == JalviewFileChooser.APPROVE_OPTION)
     {
     int value = chooser.showOpenDialog(null);
     if (value == JalviewFileChooser.APPROVE_OPTION)
     {
-      localPdbPaeMatrixFileName = chooser.getSelectedFile().getPath();
+      String fileName = chooser.getSelectedFile().getPath();
+      try
+      {
+        PAEContactMatrix.validateContactMatrixFile(fileName);
+      } catch (Exception thr)
+      {
+        JvOptionPane.showInternalMessageDialog(this, MessageManager
+                .formatMessage("label.couldnt_load_file", new Object[]
+                { fileName }) + "<br>" + thr.getLocalizedMessage(),
+                MessageManager.getString("label.error_loading_file"),
+                JvOptionPane.WARNING_MESSAGE);
+        Console.error("Couldn't import " + fileName + " as a PAE matrix",
+                thr);
+        return;
+      }
+      localPdbPaeMatrixFileName = fileName;
       Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
     }
     validateAssociationFromFile();
       Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
     }
     validateAssociationFromFile();
@@ -968,8 +1008,13 @@ public class StructureChooser extends GStructureChooser
               .getFTSDataFor(getResultTable(), selectedRow,
                       discoveredStructuresSet);
       String pageUrl = row.getModelViewUrl();
               .getFTSDataFor(getResultTable(), selectedRow,
                       discoveredStructuresSet);
       String pageUrl = row.getModelViewUrl();
+      
       JPopupMenu popup = new JPopupMenu("3D Beacons");
       JMenuItem viewUrl = new JMenuItem("View model web page");
       JPopupMenu popup = new JPopupMenu("3D Beacons");
       JMenuItem viewUrl = new JMenuItem("View model web page");
+      if (pageUrl == null || "".equals(pageUrl.trim())) {
+        viewUrl.setEnabled(false);
+        viewUrl.setText("No model page available.");
+      }
       viewUrl.addActionListener(new ActionListener()
       {
         @Override
       viewUrl.addActionListener(new ActionListener()
       {
         @Override
@@ -1060,11 +1105,13 @@ public class StructureChooser extends GStructureChooser
       {
         pdbFileString = MessageManager.getString("label.none");
         pdbFileTooltip = MessageManager.getString("label.nothing_selected");
       {
         pdbFileString = MessageManager.getString("label.none");
         pdbFileTooltip = MessageManager.getString("label.nothing_selected");
+        setPdbOptionsEnabled(false);
       }
     }
     else
     {
       btn_pdbFromFile.setEnabled(false);
       }
     }
     else
     {
       btn_pdbFromFile.setEnabled(false);
+      setPdbOptionsEnabled(false);
       // lbl_fromFileStatus.setIcon(errorImage);
       pdbFileString = MessageManager.getString("label.none");
       pdbFileTooltip = MessageManager.getString("label.nothing_selected");
       // lbl_fromFileStatus.setIcon(errorImage);
       pdbFileString = MessageManager.getString("label.none");
       pdbFileTooltip = MessageManager.getString("label.nothing_selected");
@@ -1189,7 +1236,14 @@ public class StructureChooser extends GStructureChooser
     final StructureSelectionManager ssm = ap.getStructureSelectionManager();
 
     final int preferredHeight = pnl_filter.getHeight();
     final StructureSelectionManager ssm = ap.getStructureSelectionManager();
 
     final int preferredHeight = pnl_filter.getHeight();
+    btn_add.setEnabled(false);
+    btn_newView.setEnabled(false);
+    btn_cancel.setEnabled(false);
+    actionsPanel.setEnabled(false);
 
 
+    final String progress = MessageManager
+            .getString("label.working_ellipsis");
+    setProgressBar(progress, progress.hashCode());
     Runnable viewStruc = new Runnable()
     {
       @Override
     Runnable viewStruc = new Runnable()
     {
       @Override
@@ -1280,17 +1334,21 @@ public class StructureChooser extends GStructureChooser
                   .getCmb_assSeq().getSelectedItem();
           SequenceI userSelectedSeq = assSeqOpt.getSequence();
           if (userSelectedSeq != null)
                   .getCmb_assSeq().getSelectedItem();
           SequenceI userSelectedSeq = assSeqOpt.getSequence();
           if (userSelectedSeq != null)
+          {
             selectedSequence = userSelectedSeq;
             selectedSequence = userSelectedSeq;
+          }
           String pdbFilename = selectedPdbFileName;
 
           StructureChooser.openStructureFileForSequence(ssm, sc, ap,
           String pdbFilename = selectedPdbFileName;
 
           StructureChooser.openStructureFileForSequence(ssm, sc, ap,
-                  selectedSequence, true, pdbFilename, tft, paeFilename);
+                  selectedSequence, true, pdbFilename, tft, paeFilename,
+                  true);
         }
         SwingUtilities.invokeLater(new Runnable()
         {
           @Override
           public void run()
           {
         }
         SwingUtilities.invokeLater(new Runnable()
         {
           @Override
           public void run()
           {
+            setProgressBar("Complete.", progress.hashCode());
             closeAction(preferredHeight);
             mainFrame.dispose();
           }
             closeAction(preferredHeight);
             mainFrame.dispose();
           }
@@ -1343,6 +1401,15 @@ public class StructureChooser extends GStructureChooser
           StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
           StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
+    return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
+            sequences, null);
+  }
+
+  private StructureViewer launchStructureViewer(
+          StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
+          final AlignmentPanel alignPanel, SequenceI[] sequences,
+          ViewerType viewerType)
+  {
     long progressId = sequences.hashCode();
     setProgressBar(MessageManager
             .getString("status.launching_3d_structure_viewer"), progressId);
     long progressId = sequences.hashCode();
     setProgressBar(MessageManager
             .getString("status.launching_3d_structure_viewer"), progressId);
@@ -1350,6 +1417,12 @@ public class StructureChooser extends GStructureChooser
     boolean superimpose = chk_superpose.isSelected();
     theViewer.setSuperpose(superimpose);
 
     boolean superimpose = chk_superpose.isSelected();
     theViewer.setSuperpose(superimpose);
 
+    // if we're running in --headless mode make this viewer synchronous
+    if (Jalview.isHeadlessMode())
+    {
+      theViewer.setAsync(false);
+    }
+
     /*
      * remember user's choice of superimpose or not
      */
     /*
      * remember user's choice of superimpose or not
      */
@@ -1407,7 +1480,8 @@ public class StructureChooser extends GStructureChooser
               MessageManager.getString(
                       "status.fetching_3d_structures_for_selected_entries"),
               progressId);
               MessageManager.getString(
                       "status.fetching_3d_structures_for_selected_entries"),
               progressId);
-      theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
+      theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
+              viewerType);
     }
     else
     {
     }
     else
     {
@@ -1415,7 +1489,8 @@ public class StructureChooser extends GStructureChooser
               "status.fetching_3d_structures_for",
               pdbEntriesToView[0].getId()), progressId);
       // Can we pass a pre-computeMappinged pdbFile?
               "status.fetching_3d_structures_for",
               pdbEntriesToView[0].getId()), progressId);
       // Can we pass a pre-computeMappinged pdbFile?
-      theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+      theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel,
+              viewerType);
     }
     setProgressBar(null, progressId);
     // remember the last viewer we used...
     }
     setProgressBar(null, progressId);
     // remember the last viewer we used...
@@ -1484,7 +1559,8 @@ public class StructureChooser extends GStructureChooser
             // for moment, it will work fine as is because it is self-contained
             String searchTerm = text.toLowerCase(Locale.ROOT);
             searchTerm = searchTerm.split(":")[0];
             // for moment, it will work fine as is because it is self-contained
             String searchTerm = text.toLowerCase(Locale.ROOT);
             searchTerm = searchTerm.split(":")[0];
-            // System.out.println(">>>>> search term : " + searchTerm);
+            // jalview.bin.Console.outPrintln(">>>>> search term : " +
+            // searchTerm);
             List<FTSDataColumnI> wantedFields = new ArrayList<>();
             FTSRestRequest pdbRequest = new FTSRestRequest();
             pdbRequest.setAllowEmptySeq(false);
             List<FTSDataColumnI> wantedFields = new ArrayList<>();
             FTSRestRequest pdbRequest = new FTSRestRequest();
             pdbRequest.setAllowEmptySeq(false);
@@ -1656,20 +1732,21 @@ public class StructureChooser extends GStructureChooser
   @Override
   public void setProgressBar(String message, long id)
   {
   @Override
   public void setProgressBar(String message, long id)
   {
-    if (!Platform.isHeadless())
+    if (!Platform.isHeadless() && progressBar != null)
       progressBar.setProgressBar(message, id);
   }
 
   @Override
   public void registerHandler(long id, IProgressIndicatorHandler handler)
   {
       progressBar.setProgressBar(message, id);
   }
 
   @Override
   public void registerHandler(long id, IProgressIndicatorHandler handler)
   {
-    progressBar.registerHandler(id, handler);
+    if (progressBar != null)
+      progressBar.registerHandler(id, handler);
   }
 
   @Override
   public boolean operationInProgress()
   {
   }
 
   @Override
   public boolean operationInProgress()
   {
-    return progressBar.operationInProgress();
+    return progressBar == null ? false : progressBar.operationInProgress();
   }
 
   public JalviewStructureDisplayI getOpenedStructureViewer()
   }
 
   public JalviewStructureDisplayI getOpenedStructureViewer()
@@ -1716,43 +1793,55 @@ public class StructureChooser extends GStructureChooser
   public static void openStructureFileForSequence(
           StructureSelectionManager ssm, StructureChooser sc,
           AlignmentPanel ap, SequenceI seq, boolean prompt,
   public static void openStructureFileForSequence(
           StructureSelectionManager ssm, StructureChooser sc,
           AlignmentPanel ap, SequenceI seq, boolean prompt,
-          String sFilename, TFType tft, String paeFilename)
+          String sFilename, TFType tft, String paeFilename,
+          boolean doXferSettings)
   {
     openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
   {
     openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
-            paeFilename, false, true);
+            paeFilename, false, true, doXferSettings, null);
   }
 
   }
 
-  public static void openStructureFileForSequence(
+  public static StructureViewer openStructureFileForSequence(
           StructureSelectionManager ssm, StructureChooser sc,
           AlignmentPanel ap, SequenceI seq, boolean prompt,
           String sFilename, TFType tft, String paeFilename,
           StructureSelectionManager ssm, StructureChooser sc,
           AlignmentPanel ap, SequenceI seq, boolean prompt,
           String sFilename, TFType tft, String paeFilename,
-          boolean forceHeadless, boolean showAnnotations)
+          boolean forceHeadless, boolean showRefAnnotations,
+          boolean doXferSettings, ViewerType viewerType)
   {
   {
+    StructureViewer sv = null;
     boolean headless = forceHeadless;
     if (sc == null)
     {
     boolean headless = forceHeadless;
     if (sc == null)
     {
-      headless = true;
+      // headless = true;
       prompt = false;
       prompt = false;
-      sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
+      // suppress structure viewer's external service queries
+      sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false,true);
     }
     if (ssm == null)
     }
     if (ssm == null)
+    {
       ssm = ap.getStructureSelectionManager();
       ssm = ap.getStructureSelectionManager();
+    }
 
     PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
             sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
 
     PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
             sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
-            tft, paeFilename);
+            tft, paeFilename, doXferSettings);
 
     // if headless, "false" in the sc constructor above will avoid GUI behaviour
     // in sc.launchStructureViewer()
 
     // if headless, "false" in the sc constructor above will avoid GUI behaviour
     // in sc.launchStructureViewer()
-    sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
-            new SequenceI[]
-            { seq });
+    if (!headless && !(viewerType == null))
+    {
+      sv = sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
+              new SequenceI[]
+              { seq }, viewerType);
+    }
 
 
-    if (headless)
-      sc.mainFrame.dispose();
+    sc.mainFrame.dispose();
 
 
-    if (showAnnotations)
+    if (showRefAnnotations)
+    {
       showReferenceAnnotationsForSequence(ap.alignFrame, seq);
       showReferenceAnnotationsForSequence(ap.alignFrame, seq);
+    }
+
+    return sv;
   }
 
   public static void showReferenceAnnotationsForSequence(AlignFrame af,
   }
 
   public static void showReferenceAnnotationsForSequence(AlignFrame af,