JAL-629 Small buglet with getting --seqid
[jalview.git] / src / jalview / bin / Commands.java
index 33bb55e..cdfb67a 100644 (file)
@@ -12,21 +12,13 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import jalview.analysis.AlignmentUtils;
+import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.argparser.Arg;
 import jalview.bin.argparser.ArgParser;
 import jalview.bin.argparser.ArgParser.Position;
 import jalview.bin.argparser.ArgValue;
-import jalview.bin.argparser.ArgValues;
 import jalview.bin.argparser.ArgValuesMap;
 import jalview.bin.argparser.SubVals;
 import jalview.datamodel.AlignmentI;
@@ -34,6 +26,7 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.annotations.AlphaFoldAnnotationRowBuilder;
 import jalview.gui.AlignFrame;
 import jalview.gui.AlignmentPanel;
+import jalview.gui.AppJmol;
 import jalview.gui.Desktop;
 import jalview.gui.Preferences;
 import jalview.gui.StructureChooser;
@@ -51,11 +44,18 @@ import jalview.io.FileLoader;
 import jalview.io.HtmlSvgOutput;
 import jalview.io.IdentifyFile;
 import jalview.io.NewickFile;
+import jalview.io.exceptions.ImageOutputException;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
 import jalview.structure.StructureImportSettings.TFType;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.FileUtils;
 import jalview.util.HttpUtils;
+import jalview.util.ImageMaker;
+import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.imagemaker.BitmapImageSizing;
 
 public class Commands
 {
@@ -71,11 +71,6 @@ public class Commands
 
   private boolean argsWereParsed = false;
 
-  private ThreadPoolExecutor executor = null;
-
-  // have we opened a file?
-  boolean opened = false;
-
   public Commands(ArgParser argparser, boolean headless)
   {
     this(Desktop.instance, argparser, headless);
@@ -86,62 +81,7 @@ public class Commands
     argParser = argparser;
     headless = h;
     desktop = d;
-    afMap = new HashMap<String, AlignFrame>();
-
-    int threads = 3;
-    if (argParser.getBootstrapArgs().contains(Arg.THREADS))
-    {
-      String threadsString = argParser.getBootstrapArgs().get(Arg.THREADS);
-      try
-      {
-        threads = Integer.parseInt(threadsString);
-      } catch (NumberFormatException e)
-      {
-        Console.debug("Could not parse number of threads from '"
-                + Arg.THREADS.argString() + "=" + threadsString
-                + "', fallback to 1.");
-        threads = 1;
-      }
-    }
-
-    BlockingQueue<Runnable> bq = new ArrayBlockingQueue<>(1);
-    if (threads > 0)
-    {
-      // executor = Executors.newFixedThreadPool(threads);
-      executor = new ThreadPoolExecutor(threads, threads, 600,
-              TimeUnit.SECONDS, bq);
-    }
-    else
-    {
-      // executor = Executors.newCachedThreadPool();
-      executor = new ThreadPoolExecutor(threads, Integer.MAX_VALUE, 600,
-              TimeUnit.SECONDS, null);
-    }
-
-    // set a rejectedExecution to block and resubmit.
-    executor.setRejectedExecutionHandler(new RejectedExecutionHandler()
-    {
-      @Override
-      public void rejectedExecution(Runnable r, ThreadPoolExecutor tpe)
-      {
-        try
-        {
-          // block until there's room
-          tpe.getQueue().put(r);
-          // check afterwards and throw if pool shutdown
-          if (tpe.isShutdown())
-          {
-            throw new RejectedExecutionException(
-                    "Task " + r + " rejected from " + tpe);
-          }
-        } catch (InterruptedException e)
-        {
-          Thread.currentThread().interrupt();
-          throw new RejectedExecutionException("Producer interrupted", e);
-        }
-      }
-    });
-
+    afMap = new HashMap<>();
     if (argparser != null)
     {
       processArgs(argparser, headless);
@@ -152,76 +92,55 @@ public class Commands
   {
     argParser = argparser;
     headless = h;
-    AtomicBoolean theseArgsWereParsed = new AtomicBoolean(false);
+    boolean theseArgsWereParsed = false;
 
     if (argParser != null && argParser.getLinkedIds() != null)
     {
-      long progress = -1;
-      boolean progressBarSet = false;
-      opened = false;
-      if (!headless && desktop != null)
-      {
-        desktop.setProgressBar(
-                MessageManager
-                        .getString("status.processing_commandline_args"),
-                progress = System.currentTimeMillis());
-        progressBarSet = true;
-      }
       for (String id : argParser.getLinkedIds())
       {
+        ArgValuesMap avm = argParser.getLinkedArgs(id);
+        theseArgsWereParsed = true;
+        theseArgsWereParsed &= processLinked(id);
+        processGroovyScript(id);
+        boolean processLinkedOkay = theseArgsWereParsed;
 
-        Callable<Void> process = () -> {
-          ArgValuesMap avm = argParser.getLinkedArgs(id);
-          theseArgsWereParsed.set(true);
-          theseArgsWereParsed.compareAndSet(true, processLinked(id)); // &=
-          processGroovyScript(id);
-          boolean processLinkedOkay = theseArgsWereParsed.get();
-          theseArgsWereParsed.compareAndSet(true, processImages(id)); // &=
-          if (processLinkedOkay)
-            theseArgsWereParsed.compareAndSet(true, processOutput(id)); // &=
-
-          // close ap
-          if (avm.getBoolean(Arg.CLOSE))
-          {
-            AlignFrame af = afMap.get(id);
-            if (af != null)
-            {
-              af.closeMenuItem_actionPerformed(true);
-            }
-            afMap.remove(id);
+        // wait around until alignFrame isn't busy
+        AlignFrame af = afMap.get(id);
+        while (af != null && af.getViewport().isCalcInProgress())
+        {
+          try
+          {
+            Thread.sleep(25);
+          } catch (Exception q)
+          {
           }
-          return null;
-        };
+          ;
+        }
 
-        executor.submit(process);
-        Console.debug(
-                "Running " + executor.getActiveCount() + " processes.");
-      }
+        theseArgsWereParsed &= processImages(id);
+        if (processLinkedOkay)
+          theseArgsWereParsed &= processOutput(id);
 
-      if (!opened) // first=true means nothing opened
-      {
-        if (headless)
+        // close ap
+        if (avm.getBoolean(Arg.CLOSE))
         {
-          Jalview.exit("Did not open any files in headless mode", 1);
-        }
-        else
-        {
-          Console.warn("No more files to open");
+          af = afMap.get(id);
+          if (af != null)
+          {
+            af.closeMenuItem_actionPerformed(true);
+          }
         }
-      }
-      if (progressBarSet && desktop != null)
-      {
-        desktop.setProgressBar(null, progress);
+
       }
 
     }
-    if (argParser.getBootstrapArgs().getBoolean(Arg.QUIT))
+    if (argParser.getBoolean(Arg.QUIT))
     {
       Jalview.getInstance().quit();
       return true;
     }
     // carry on with jalview.bin.Jalview
-    argsWereParsed |= theseArgsWereParsed.get();
+    argsWereParsed = theseArgsWereParsed;
     return argsWereParsed;
   }
 
@@ -235,6 +154,11 @@ public class Commands
     return argsWereParsed;
   }
 
+  protected boolean processUnlinked(String id)
+  {
+    return processLinked(id);
+  }
+
   protected boolean processLinked(String id)
   {
     boolean theseArgsWereParsed = false;
@@ -252,6 +176,10 @@ public class Commands
     if (avm.containsArg(Arg.APPEND) || avm.containsArg(Arg.OPEN))
     {
       commandArgsProvided = true;
+      long progress = -1;
+
+      boolean first = true;
+      boolean progressBarSet = false;
       AlignFrame af;
       // Combine the APPEND and OPEN files into one list, along with whether it
       // was APPEND or OPEN
@@ -269,6 +197,18 @@ public class Commands
           continue;
 
         theseArgsWereParsed = true;
+        if (first)
+        {
+          first = false;
+          if (!headless && desktop != null)
+          {
+            desktop.setProgressBar(
+                    MessageManager.getString(
+                            "status.processing_commandline_args"),
+                    progress = System.currentTimeMillis());
+            progressBarSet = true;
+          }
+        }
 
         if (!Platform.isJS())
         /**
@@ -303,8 +243,6 @@ public class Commands
         if (af == null || "true".equals(av.getSubVal("new"))
                 || a == Arg.OPEN || format == FileFormat.Jalview)
         {
-          opened = true;
-
           if (a == Arg.OPEN)
           {
             Jalview.testoutput(argParser, Arg.OPEN, "examples/uniref50.fa",
@@ -328,7 +266,19 @@ public class Commands
                   Arg.COLOUR, sv, null, "DEFAULT_COLOUR_PROT", "");
           if ("" != colour)
           {
-            af.changeColour_actionPerformed(colour);
+            ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
+                    af.getViewport(), af.getViewport().getAlignment(),
+                    colour);
+
+            if (cs == null && !"None".equals(colour))
+            {
+              Console.warn(
+                      "Couldn't parse '" + colour + "' as a colourscheme.");
+            }
+            else
+            {
+              af.changeColour(cs);
+            }
             Jalview.testoutput(argParser, Arg.COLOUR, "zappo", colour);
           }
 
@@ -443,6 +393,19 @@ public class Commands
         Console.debug("Command " + Arg.APPEND + " executed successfully!");
 
       }
+      if (first) // first=true means nothing opened
+      {
+        if (headless)
+        {
+          Jalview.exit("Could not open any files in headless mode", 1);
+        }
+        else
+        {
+          Console.warn("No more files to open");
+        }
+      }
+      if (progressBarSet && desktop != null)
+        desktop.setProgressBar(null, progress);
 
     }
 
@@ -518,14 +481,6 @@ public class Commands
           Console.debug("Using structure file "
                   + structureFile.getAbsolutePath());
 
-          // ##### Does this need to happen? Follow
-          // openStructureFileForSequence() below
-          /*
-          PDBEntry fileEntry = new AssociatePdbFileWithSeq()
-                  .associatePdbWithSeq(structureFile.getAbsolutePath(),
-                          DataSourceType.FILE, seq, true, Desktop.instance);
-                          */
-
           // open structure view
           AlignmentPanel ap = af.alignPanel;
           if (headless)
@@ -567,18 +522,10 @@ public class Commands
                   .getFromSubValArgOrPrefWithSubstitutions(argParser, avm,
                           Arg.TEMPFAC, Position.AFTER, av, subVals, null,
                           null, null);
-          boolean notempfac = ArgParser.getBoolFromSubValOrArg(avm,
-                  Arg.NOTEMPFAC, subVals);
+          boolean notempfac = ArgParser.getFromSubValArgOrPref(avm,
+                  Arg.NOTEMPFAC, subVals, null, "ADD_TEMPFACT_ANN", false,
+                  true);
           TFType tft = notempfac ? null : TFType.DEFAULT;
-          /*
-          String tftString = subVals.get("tempfac");
-          ArgValue tftAv = getArgAssociatedWithStructure(Arg.TEMPFAC, avm,
-                  af, structureFilepath);
-          if (tftString == null && tftAv != null)
-          {
-            tftString = tftAv.getSubVals().getContent();
-          }
-          */
           if (tftString != null && !notempfac)
           {
             // get kind of temperature factor annotation
@@ -624,14 +571,120 @@ public class Commands
             }
           }
 
-          boolean addTempFac = notempfac ? false
-                  : ((tft != null)
-                          || Cache.getDefault("ADD_TEMPFACT_ANN", false));
-
           // TODO use ssFromStructure
-          StructureChooser.openStructureFileForSequence(null, null, ap, seq,
-                  false, structureFilepath, tft, paeFilepath, false,
-                  ssFromStructure, false, viewerType);
+          StructureViewer sv = StructureChooser
+                  .openStructureFileForSequence(null, null, ap, seq, false,
+                          structureFilepath, tft, paeFilepath, false,
+                          ssFromStructure, false, viewerType);
+
+          if (sv == null)
+          {
+            Console.error("Failed to import and open structure view.");
+            continue;
+          }
+          try
+          {
+            long tries = 1000;
+            while (sv.isBusy() && tries > 0)
+            {
+              Thread.sleep(25);
+              if (sv.isBusy())
+              {
+                tries--;
+                Console.debug(
+                        "Waiting for viewer for " + structureFilepath);
+              }
+            }
+            if (tries == 0 && sv.isBusy())
+            {
+              Console.warn(
+                      "Gave up waiting for structure viewer to load. Something may have gone wrong.");
+            }
+          } catch (Exception x)
+          {
+            Console.warn("Exception whilst waiting for structure viewer "
+                    + structureFilepath, x);
+          }
+          Console.debug(
+                  "Successfully opened viewer for " + structureFilepath);
+          String structureImageFilename = ArgParser.getValueFromSubValOrArg(
+                  avm, av, Arg.STRUCTUREIMAGE, subVals);
+          if (sv != null && structureImageFilename != null)
+          {
+            ArgValue siAv = avm.getClosestNextArgValueOfArg(av,
+                    Arg.STRUCTUREIMAGE);
+            SubVals sisv = null;
+            if (structureImageFilename.equals(siAv.getValue()))
+            {
+              sisv = siAv.getSubVals();
+            }
+            File structureImageFile = new File(structureImageFilename);
+            String width = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGEWIDTH, sisv);
+            String height = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGEHEIGHT, sisv);
+            String scale = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGESCALE, sisv);
+            String renderer = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGETEXTRENDERER, sisv);
+            String typeS = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGETYPE, sisv);
+            if (typeS == null || typeS.length() == 0)
+            {
+              typeS = FileUtils.getExtension(structureImageFile);
+            }
+            TYPE imageType;
+            try
+            {
+              imageType = Enum.valueOf(TYPE.class,
+                      typeS.toUpperCase(Locale.ROOT));
+            } catch (IllegalArgumentException e)
+            {
+              Console.warn("Do not know image format '" + typeS
+                      + "', using PNG");
+              imageType = TYPE.PNG;
+            }
+            BitmapImageSizing userBis = ImageMaker
+                    .parseScaleWidthHeightStrings(scale, width, height);
+            // TODO MAKE THIS VIEWER INDEPENDENT!!
+            switch (StructureViewer.getViewerType())
+            {
+            case JMOL:
+              try
+              {
+                Thread.sleep(1000); // WHY ???
+              } catch (InterruptedException e)
+              {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+              }
+              JalviewStructureDisplayI sview = sv
+                      .getJalviewStructureDisplay();
+              if (sview instanceof AppJmol)
+              {
+                AppJmol jmol = (AppJmol) sview;
+                try
+                {
+                  Console.debug("Rendering image to " + structureImageFile);
+                  jmol.makePDBImage(structureImageFile, imageType, renderer,
+                          userBis);
+                  Console.debug("Finished Rendering image to "
+                          + structureImageFile);
+
+                } catch (ImageOutputException ioexc)
+                {
+                  Console.warn("Unexpected error whilst exporting image to "
+                          + structureImageFile, ioexc);
+                }
+
+              }
+              break;
+            default:
+              Console.warn("Cannot export image for structure viewer "
+                      + sv.getViewerType() + " yet");
+              break;
+            }
+          }
         }
       }
     }
@@ -706,48 +759,14 @@ public class Commands
           renderer = "text";
         String type = "png"; // default
 
-        float bitmapscale = 0.0f;
-        int bitmapwidth = 0;
-        int bitmapheight = 0;
         String scale = ArgParser.getValueFromSubValOrArg(avm, av, Arg.SCALE,
                 subVal);
-        if (scale != null)
-        {
-          try
-          {
-            bitmapscale = Float.parseFloat(scale);
-          } catch (NumberFormatException e)
-          {
-            Console.warn("Did not understand scale '" + scale
-                    + "', won't be used.");
-          }
-        }
         String width = ArgParser.getValueFromSubValOrArg(avm, av, Arg.WIDTH,
                 subVal);
-        if (width != null)
-        {
-          try
-          {
-            bitmapwidth = Integer.parseInt(width);
-          } catch (NumberFormatException e)
-          {
-            Console.warn("Did not understand width '" + width
-                    + "', won't be used.");
-          }
-        }
         String height = ArgParser.getValueFromSubValOrArg(avm, av,
                 Arg.HEIGHT, subVal);
-        if (height != null)
-        {
-          try
-          {
-            bitmapheight = Integer.parseInt(height);
-          } catch (NumberFormatException e)
-          {
-            Console.warn("Did not understand height '" + height
-                    + "', won't be used.");
-          }
-        }
+        BitmapImageSizing userBis = ImageMaker
+                .parseScaleWidthHeightStrings(scale, width, height);
 
         type = ArgParser.getValueFromSubValOrArg(avm, av, Arg.TYPE, subVal);
         if (type == null && fileName != null)
@@ -765,54 +784,60 @@ public class Commands
         Cache.setProperty("EXPORT_EMBBED_BIOJSON", "false");
 
         Console.info("Writing " + file);
-
-        switch (type)
+        try
         {
+          switch (type)
+          {
 
-        case "svg":
-          Console.debug("Outputting type '" + type + "' to " + fileName);
-          af.createSVG(file, renderer);
-          break;
+          case "svg":
+            Console.debug("Outputting type '" + type + "' to " + fileName);
+            af.createSVG(file, renderer);
+            break;
 
-        case "png":
-          Console.debug("Outputting type '" + type + "' to " + fileName);
-          af.createPNG(file, null, bitmapscale, bitmapwidth, bitmapheight);
-          break;
+          case "png":
+            Console.debug("Outputting type '" + type + "' to " + fileName);
+            af.createPNG(file, null, userBis);
+            break;
 
-        case "html":
-          Console.debug("Outputting type '" + type + "' to " + fileName);
-          HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
-          htmlSVG.exportHTML(fileName, renderer);
-          break;
+          case "html":
+            Console.debug("Outputting type '" + type + "' to " + fileName);
+            HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
+            htmlSVG.exportHTML(fileName, renderer);
+            break;
 
-        case "biojs":
-          try
-          {
-            BioJsHTMLOutput.refreshVersionInfo(
-                    BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
-          } catch (URISyntaxException e)
-          {
-            e.printStackTrace();
-          }
-          BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
-          bjs.exportHTML(fileName);
-          Console.debug("Creating BioJS MSA Viwer HTML file: " + fileName);
-          break;
-
-        case "eps":
-          af.createEPS(file, name);
-          Console.debug("Creating EPS file: " + fileName);
-          break;
-
-        case "imagemap":
-          af.createImageMap(file, name);
-          Console.debug("Creating ImageMap file: " + fileName);
-          break;
-
-        default:
-          Console.warn(Arg.IMAGE.argString() + " type '" + type
-                  + "' not known. Ignoring");
-          break;
+          case "biojs":
+            Console.debug(
+                    "Outputting BioJS MSA Viwer HTML file: " + fileName);
+            try
+            {
+              BioJsHTMLOutput.refreshVersionInfo(
+                      BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+            } catch (URISyntaxException e)
+            {
+              e.printStackTrace();
+            }
+            BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
+            bjs.exportHTML(fileName);
+            break;
+
+          case "eps":
+            Console.debug("Outputting EPS file: " + fileName);
+            af.createEPS(file, renderer);
+            break;
+
+          case "imagemap":
+            Console.debug("Outputting ImageMap file: " + fileName);
+            af.createImageMap(file, name);
+            break;
+
+          default:
+            Console.warn(Arg.IMAGE.argString() + " type '" + type
+                    + "' not known. Ignoring");
+            break;
+          }
+        } catch (Exception ioex)
+        {
+          Console.warn("Unexpected error during export", ioex);
         }
       }
     }
@@ -943,9 +968,15 @@ public class Commands
     SequenceI seq = null;
     if (subVals == null && idAv == null)
       return null;
+    if (af == null || af.getCurrentView() == null)
+    {
+      return null;
+    }
     AlignmentI al = af.getCurrentView().getAlignment();
     if (al == null)
+    {
       return null;
+    }
     if (subVals != null)
     {
       if (subVals.has(Arg.SEQID.getName()))
@@ -958,60 +989,10 @@ public class Commands
         seq = al.getSequenceAt(subVals.getIndex());
       }
     }
-    else if (idAv != null)
+    if (seq == null && idAv != null)
     {
       seq = al.findName(idAv.getValue());
     }
     return seq;
   }
-
-  // returns the first Arg value intended for the structure structFilename
-  // (in the given AlignFrame from the ArgValuesMap)
-  private ArgValue getArgAssociatedWithStructure(Arg arg, ArgValuesMap avm,
-          AlignFrame af, String structFilename)
-  {
-    if (af != null)
-    {
-      for (ArgValue av : avm.getArgValueList(arg))
-      {
-        SubVals subVals = av.getSubVals();
-        String structid = subVals.get("structid");
-        String structfile = subVals.get("structfile");
-
-        // let's find a structure
-        if (structfile == null && structid == null)
-        {
-          ArgValue likelyStructure = avm.getClosestPreviousArgValueOfArg(av,
-                  Arg.STRUCTURE);
-          if (likelyStructure != null)
-          {
-            SubVals sv = likelyStructure.getSubVals();
-            if (sv != null && sv.has(ArgValues.ID))
-            {
-              structid = sv.get(ArgValues.ID);
-            }
-            else
-            {
-              structfile = likelyStructure.getValue();
-            }
-          }
-        }
-
-        if (structfile == null && structid != null)
-        {
-          StructureSelectionManager ssm = StructureSelectionManager
-                  .getStructureSelectionManager(Desktop.instance);
-          if (ssm != null)
-          {
-            structfile = ssm.findFileForPDBId(structid);
-          }
-        }
-        if (structfile != null && structfile.equals(structFilename))
-        {
-          return av;
-        }
-      }
-    }
-    return null;
-  }
 }