Merge branch 'releases/Release_2_11_3_Branch'
[jalview.git] / src / jalview / gui / AppJmol.java
index 9280caa..0aa4878 100644 (file)
@@ -25,10 +25,13 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.Executors;
 
 import javax.swing.JPanel;
 import javax.swing.JSplitPane;
@@ -37,24 +40,22 @@ import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
 import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentI;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.StructureViewerModel;
 import jalview.datamodel.StructureViewerModel.StructureData;
-import jalview.fts.service.alphafold.AlphafoldRestClient;
 import jalview.gui.ImageExporter.ImageWriterI;
 import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.exceptions.ImageOutputException;
 import jalview.structure.StructureCommand;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.BrowserLauncher;
 import jalview.util.ImageMaker;
+import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
-import jalview.ws.dbsources.EBIAlfaFold;
-import jalview.ws.dbsources.Pdb;
-import jalview.ws.utils.UrlDownloadClient;
+import jalview.util.imagemaker.BitmapImageSizing;
 
 public class AppJmol extends StructureViewerBase
 {
@@ -187,8 +188,7 @@ public class AppJmol extends StructureViewerBase
   }
 
   private void openNewJmol(AlignmentPanel ap, boolean alignAdded,
-          PDBEntry[] pdbentrys,
-          SequenceI[][] seqs)
+          PDBEntry[] pdbentrys, SequenceI[][] seqs)
   {
     setProgressIndicator(ap.alignFrame);
     jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
@@ -237,7 +237,6 @@ public class AppJmol extends StructureViewerBase
     openNewJmol(ap, alignAdded, pe, seqs);
   }
 
-
   void initJmol(String command)
   {
     jmb.setFinishedInit(false);
@@ -265,6 +264,8 @@ public class AppJmol extends StructureViewerBase
     }
     jmb.executeCommand(new StructureCommand(command), false);
     jmb.executeCommand(new StructureCommand("set hoverDelay=0.1"), false);
+    jmb.executeCommand(new StructureCommand("set antialiasdisplay on"),
+            false);
     jmb.setFinishedInit(true);
   }
 
@@ -274,7 +275,7 @@ public class AppJmol extends StructureViewerBase
     _started = true;
     try
     {
-      List<String> files = fetchPdbFiles();
+      List<String> files = jmb.fetchPdbFiles(this);
       if (files.size() > 0)
       {
         showFilesInViewer(files);
@@ -312,10 +313,10 @@ public class AppJmol extends StructureViewerBase
       } catch (OutOfMemoryError oomerror)
       {
         new OOMWarning("When trying to open the Jmol viewer!", oomerror);
-        Cache.log.debug("File locations are " + filesString);
+        Console.debug("File locations are " + filesString);
       } catch (Exception ex)
       {
-        Cache.log.error("Couldn't open Jmol viewer!", ex);
+        Console.error("Couldn't open Jmol viewer!", ex);
         ex.printStackTrace();
         return;
       }
@@ -336,11 +337,11 @@ public class AppJmol extends StructureViewerBase
       {
         new OOMWarning("When trying to add structures to the Jmol viewer!",
                 oomerror);
-        Cache.log.debug("File locations are " + filesString);
+        Console.debug("File locations are " + filesString);
         return;
       } catch (Exception ex)
       {
-        Cache.log.error("Couldn't add files to Jmol viewer!", ex);
+        Console.error("Couldn't add files to Jmol viewer!", ex);
         ex.printStackTrace();
         return;
       }
@@ -356,7 +357,7 @@ public class AppJmol extends StructureViewerBase
     {
       try
       {
-        Cache.log.debug("Waiting around for jmb notify.");
+        Console.debug("Waiting around for jmb notify.");
         waitTotal += waitFor;
 
         // Thread.sleep() throws an exception in JS
@@ -366,9 +367,10 @@ public class AppJmol extends StructureViewerBase
       }
       if (waitTotal > waitMax)
       {
-        System.err.println("Timed out waiting for Jmol to load files after "
-                + waitTotal + "ms");
-        // System.err.println("finished: " + jmb.isFinishedInit()
+        jalview.bin.Console.errPrintln(
+                "Timed out waiting for Jmol to load files after "
+                        + waitTotal + "ms");
+        // jalview.bin.Console.errPrintln("finished: " + jmb.isFinishedInit()
         // + "; loaded: " + Arrays.toString(jmb.getPdbFile())
         // + "; files: " + files.toString());
         jmb.getStructureFiles();
@@ -420,155 +422,115 @@ public class AppJmol extends StructureViewerBase
   }
 
   /**
-   * Retrieves and saves as file any modelled PDB entries for which we do not
-   * already have a file saved. Returns a list of absolute paths to structure
-   * files which were either retrieved, or already stored but not modelled in
-   * the structure viewer (i.e. files to add to the viewer display).
+   * Outputs the Jmol viewer image as an image file, after prompting the user to
+   * choose a file and (for EPS) choice of Text or Lineart character rendering
+   * (unless a preference for this is set)
    * 
-   * @return
+   * @param type
    */
-  List<String> fetchPdbFiles()
+  @Override
+  public void makePDBImage(ImageMaker.TYPE type)
   {
-    // todo - record which pdbids were successfully imported.
-    StringBuilder errormsgs = new StringBuilder();
-
-    List<String> files = new ArrayList<>();
-    String pdbid = "";
     try
     {
-      String[] filesInViewer = jmb.getStructureFiles();
-      // TODO: replace with reference fetching/transfer code (validate PDBentry
-      // as a DBRef?)
-      Pdb pdbclient = new Pdb();
-      EBIAlfaFold afclient = new EBIAlfaFold();
-      
-      for (int pi = 0; pi < jmb.getPdbCount(); pi++)
-      {
-        String file = jmb.getPdbEntry(pi).getFile();
-        if (file == null)
-        {
-          // todo: extract block as method and pull up (also ChimeraViewFrame)
-          // retrieve the pdb and store it locally
-          AlignmentI pdbseq = null;
-          PDBEntry strucEntry = jmb.getPdbEntry(pi);
-          pdbid = strucEntry.getId();
-          long hdl = pdbid.hashCode() - System.currentTimeMillis();
-          setProgressMessage(MessageManager
-                  .formatMessage("status.fetching_pdb", new String[]
-                  { pdbid }), hdl);
-          try
-          {
-            if (afclient.isValidReference(pdbid))
-            {
-              pdbseq = afclient.getSequenceRecords(pdbid);
-            } else {
-              if (strucEntry.hasRetrievalUrl())
-              {
-                File tmpFile = File.createTempFile(pdbid, "cif");
-                String fromUrl = strucEntry.getRetrievalUrl();
-                UrlDownloadClient.download(fromUrl, tmpFile);
-                
-                // may not need this check ?
-                file = tmpFile.getAbsolutePath();
-                if (file != null)
-                {
-                  pdbseq = EBIAlfaFold.importDownloadedStructureFromUrl(fromUrl,tmpFile,pdbid,null,null,null);
-                }
-              } else {
-                pdbseq = pdbclient.getSequenceRecords(pdbid);
-              }
-            }
-          } catch (OutOfMemoryError oomerror)
-          {
-            new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
-          } catch (Exception ex)
-          {
-            ex.printStackTrace();
-            errormsgs.append("'").append(pdbid).append("'");
-          } finally
-          {
-            setProgressMessage(
-                    MessageManager.getString("label.state_completed"), hdl);
-          }
-          if (pdbseq != null)
-          {
-            // just transfer the file name from the first sequence's first
-            // PDBEntry
-            file = new File(pdbseq.getSequenceAt(0).getAllPDBEntries()
-                    .elementAt(0).getFile()).getAbsolutePath();
-            jmb.getPdbEntry(pi).setFile(file);
-            files.add(file);
-          }
-          else
-          {
-            errormsgs.append("'").append(pdbid).append("' ");
-          }
-        }
-        else
-        {
-          if (filesInViewer != null && filesInViewer.length > 0)
-          {
-            addingStructures = true; // already files loaded.
-            for (int c = 0; c < filesInViewer.length; c++)
-            {
-              if (Platform.pathEquals(filesInViewer[c], file))
-              {
-                file = null;
-                break;
-              }
-            }
-          }
-          if (file != null)
-          {
-            files.add(file);
-          }
-        }
-      }
-    } catch (OutOfMemoryError oomerror)
-    {
-      new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
-    } catch (Exception ex)
-    {
-      ex.printStackTrace();
-      errormsgs.append("When retrieving pdbfiles : current was: '")
-              .append(pdbid).append("'");
-    }
-    if (errormsgs.length() > 0)
+      makePDBImage(null, type, null,
+              BitmapImageSizing.defaultBitmapImageSizing());
+    } catch (ImageOutputException ioex)
     {
-      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
-              MessageManager.formatMessage(
-                      "label.pdb_entries_couldnt_be_retrieved", new String[]
-                      { errormsgs.toString() }),
-              MessageManager.getString("label.couldnt_load_file"),
-              JvOptionPane.ERROR_MESSAGE);
+      Console.error("Unexpected error whilst writing " + type.toString(),
+              ioex);
     }
-    return files;
   }
 
-  /**
-   * Outputs the Jmol viewer image as an image file, after prompting the user to
-   * choose a file and (for EPS) choice of Text or Lineart character rendering
-   * (unless a preference for this is set)
-   * 
-   * @param type
-   */
-  @Override
-  public void makePDBImage(ImageMaker.TYPE type)
+  public void makePDBImage(File file, ImageMaker.TYPE type, String renderer,
+          BitmapImageSizing userBis) throws ImageOutputException
   {
     int width = getWidth();
     int height = getHeight();
+
+    BitmapImageSizing bis = ImageMaker.getScaleWidthHeight(width, height,
+            userBis);
+    float usescale = bis.scale();
+    int usewidth = bis.width();
+    int useheight = bis.height();
+
     ImageWriterI writer = new ImageWriterI()
     {
       @Override
       public void exportImage(Graphics g) throws Exception
       {
-        jmb.jmolViewer.renderScreenImage(g, width, height);
+        Graphics2D ig2 = (Graphics2D) g;
+        ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+        if (type == TYPE.PNG && usescale > 0.0f)
+        {
+          // for a scaled image, this scales down a bigger image to give the
+          // right resolution
+          if (usescale > 0.0f)
+          {
+            ig2.scale(1 / usescale, 1 / usescale);
+          }
+        }
+
+        jmb.jmolViewer.requestRepaintAndWait("image export");
+        jmb.jmolViewer.renderScreenImage(ig2, usewidth, useheight);
       }
     };
-    String view = MessageManager.getString("action.view").toLowerCase();
-    ImageExporter exporter = new ImageExporter(writer,
+    String view = MessageManager.getString("action.view")
+            .toLowerCase(Locale.ROOT);
+    final ImageExporter exporter = new ImageExporter(writer,
             getProgressIndicator(), type, getTitle());
-    exporter.doExport(null, this, width, height, view);
+
+    final Throwable[] exceptions = new Throwable[1];
+    exceptions[0] = null;
+    final AppJmol us = this;
+    try
+    {
+      Thread runner = Executors.defaultThreadFactory()
+              .newThread(new Runnable()
+              {
+                @Override
+                public void run()
+                {
+                  try
+                  {
+                    exporter.doExport(file, us, width, height, view,
+                            renderer, userBis);
+                  } catch (Throwable t)
+                  {
+                    exceptions[0] = t;
+                  }
+                }
+              });
+      runner.start();
+      long time = 0;
+      do
+      {
+        Thread.sleep(25);
+      } while (runner.isAlive() && time++ < 4000);
+      if (time >= 4000)
+      {
+        runner.interrupt();
+        throw new ImageOutputException(
+                "Jmol took too long to export. Waited for 100 seconds.");
+      }
+    } catch (Throwable e)
+    {
+      throw new ImageOutputException(
+              "Unexpected error when generating image", e);
+    }
+    if (exceptions[0] != null)
+    {
+      if (exceptions[0] instanceof ImageOutputException)
+      {
+        throw ((ImageOutputException) exceptions[0]);
+      }
+      else
+      {
+        throw new ImageOutputException(
+                "Unexpected error when generating image", exceptions[0]);
+      }
+    }
   }
 
   @Override
@@ -577,10 +539,11 @@ public class AppJmol extends StructureViewerBase
     try
     {
       BrowserLauncher // BH 2018
-              .openURL("http://wiki.jmol.org");//http://jmol.sourceforge.net/docs/JmolUserGuide/");
+              .openURL("http://wiki.jmol.org");// http://jmol.sourceforge.net/docs/JmolUserGuide/");
     } catch (Exception ex)
     {
-      System.err.println("Show Jmol help failed with: " + ex.getMessage());
+      jalview.bin.Console
+              .errPrintln("Show Jmol help failed with: " + ex.getMessage());
     }
   }
 
@@ -652,7 +615,8 @@ public class AppJmol extends StructureViewerBase
           }
         }
       }
-      else if (jmb == null || jmb.jmolViewer == null || !jmb.isFinishedInit())
+      else if (jmb == null || jmb.jmolViewer == null
+              || !jmb.isFinishedInit())
       {
         g.setColor(Color.black);
         g.fillRect(0, 0, currentSize.width, currentSize.height);