JAL-629 Test and fix --annotation --ssannotation args. Added a viewerType arg/subval...
authorBen Soares <b.soares@dundee.ac.uk>
Sat, 22 Apr 2023 00:26:15 +0000 (01:26 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Sat, 22 Apr 2023 00:26:15 +0000 (01:26 +0100)
20 files changed:
src/jalview/bin/Commands.java
src/jalview/bin/Jalview.java
src/jalview/bin/Launcher.java
src/jalview/bin/argparser/Arg.java
src/jalview/bin/argparser/ArgParser.java
src/jalview/bin/argparser/ArgValuesMap.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewer.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GPreferences.java
test/jalview/bin/CommandsTest2.java [new file with mode: 0644]
test/jalview/bin/commandsTest2.argfile1 [new file with mode: 0644]
test/jalview/bin/commandsTest2.argfile2 [new file with mode: 0644]
test/jalview/bin/commandsTest2.jvprops1 [new file with mode: 0644]
test/jalview/bin/commandsTest2.jvprops2 [new file with mode: 0644]
test/jalview/gui/StructureChooserTest.java
test/jalview/testProps.jvprops
test/jalview/ws/dbsources/EBIAlphaFoldTest.java
utils/eclipse/launcher [new file with mode: 0755]

index 6d514b0..fc2ee1a 100644 (file)
@@ -5,7 +5,7 @@ import java.io.IOException;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -16,11 +16,11 @@ import java.util.Map.Entry;
 import jalview.analysis.AlignmentUtils;
 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.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.annotations.AlphaFoldAnnotationRowBuilder;
@@ -30,6 +30,7 @@ import jalview.gui.Desktop;
 import jalview.gui.Preferences;
 import jalview.gui.StructureChooser;
 import jalview.gui.StructureViewer;
+import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
@@ -38,13 +39,11 @@ import jalview.io.FileFormatI;
 import jalview.io.FileLoader;
 import jalview.io.HtmlSvgOutput;
 import jalview.io.IdentifyFile;
-import jalview.schemes.AnnotationColourGradient;
 import jalview.structure.StructureImportSettings.TFType;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
-import mc_view.PDBChain;
 
 public class Commands
 {
@@ -226,11 +225,11 @@ public class Commands
         {
           /*
            * this approach isn't working yet // get default annotations before opening
-           * AlignFrame if (m.get(Arg.SSANNOTATION) != null) {
-           * Console.debug("##### SSANNOTATION=" + m.get(Arg.SSANNOTATION).getBoolean());
+           * AlignFrame if (m.get(Arg.SSANNOTATIONS) != null) {
+           * Console.debug("##### SSANNOTATIONS=" + m.get(Arg.SSANNOTATIONS).getBoolean());
            * } if (m.get(Arg.NOTEMPFAC) != null) { Console.debug( "##### NOTEMPFAC=" +
            * m.get(Arg.NOTEMPFAC).getBoolean()); } boolean showSecondaryStructure =
-           * (m.get(Arg.SSANNOTATION) != null) ? m.get(Arg.SSANNOTATION).getBoolean() :
+           * (m.get(Arg.SSANNOTATIONS) != null) ? m.get(Arg.SSANNOTATIONS).getBoolean() :
            * false; boolean showTemperatureFactor = (m.get(Arg.NOTEMPFAC) != null) ?
            * !m.get(Arg.NOTEMPFAC).getBoolean() : false; Console.debug("##### tempfac=" +
            * showTemperatureFactor + ", showSS=" + showSecondaryStructure);
@@ -246,6 +245,10 @@ public class Commands
 
           af = fileLoader.LoadFileWaitTillLoaded(openFile, protocol,
                   format);
+          boolean showAnnotations = ArgParser.getFromSubValArgOrPref(avm,
+                  Arg.ANNOTATIONS, av.getSubVals(), null,
+                  "SHOW_ANNOTATIONS", true);
+          af.setAnnotationsVisibility(showAnnotations, false, true);
 
           // wrap alignment?
           if (avm.getBoolean(Arg.WRAP))
@@ -263,15 +266,19 @@ public class Commands
           if (avm.containsArg(Arg.TITLE))
             af.setTitle(avm.getValue(Arg.TITLE));
 
-          /* hacky approach to hiding the annotations */
           // show secondary structure annotations?
-          if (avm.getBoolean(Arg.SSANNOTATION))
+          boolean showSSAnnotations = ArgParser.getFromSubValArgOrPref(avm,
+                  Arg.SSANNOTATIONS, av.getSubVals(), null,
+                  "STRUCT_FROM_PDB", true);
+          if (avm.getBoolean(Arg.SSANNOTATIONS))
           {
-            // do this better (annotation types?)
+            af.setAnnotationsVisibility(showSSAnnotations, true, false);
+            /*
             AlignmentUtils.showOrHideSequenceAnnotations(
                     af.getCurrentView().getAlignment(),
                     Collections.singleton("Secondary Structure"), null,
                     false, false);
+             */
           }
 
           // show temperature factor annotations?
@@ -291,6 +298,7 @@ public class Commands
            * (showTemperatureFactor)
            */
           {
+            /*
             if (avm.containsArg(Arg.TEMPFAC_LABEL))
             {
               AlignmentAnnotation aa = AlignmentUtils
@@ -309,6 +317,7 @@ public class Commands
                                 + label);
               }
             }
+            */
           }
 
           // store the AlignFrame for this id
@@ -463,7 +472,13 @@ public class Commands
             }
           }
 
-          // get TEMPFAC type from subvals or Arg.TEMPFAC
+          // showing annotations from structure file or not
+          boolean ssFromStructure = ArgParser.getFromSubValArgOrPref(avm,
+                  Arg.SSANNOTATIONS, subVals, null, "STRUCT_FROM_PDB",
+                  true);
+
+          // get TEMPFAC type from subvals or Arg.TEMPFAC in case user Adds
+          // reference annotations
           String tftString = subVals.get("tempfac");
           TFType tft = avm.getBoolean(Arg.NOTEMPFAC) ? null
                   : TFType.DEFAULT;
@@ -500,13 +515,36 @@ public class Commands
             }
           }
 
-          // TODO pass PAE label
+          String sViewer = ArgParser.getFromSubValArgOrPref(avm,
+                  Arg.STRUCTUREVIEWER, Position.AFTER, av, subVals,
+                  "viewer", null, "jmol");
+          ViewerType viewerType = null;
+          if (!"none".equals(sViewer))
+          {
+            for (ViewerType v : EnumSet.allOf(ViewerType.class))
+            {
+              String name = v.name().toLowerCase(Locale.ROOT)
+                      .replaceAll(" ", "");
+              if (sViewer.equals(name))
+              {
+                viewerType = v;
+                break;
+              }
+            }
+          }
+
+          boolean addTempFac = tft != null
+                  || Cache.getDefault("ADD_TEMPFACT_ANN", false);
+
+          // TODO use ssFromStructure
           StructureChooser.openStructureFileForSequence(null, null, ap, seq,
-                  false, structureFilepath, tft, paeFilepath, false);
+                  false, structureFilepath, tft, paeFilepath, false,
+                  ssFromStructure, false, viewerType);
         }
       }
     }
 
+    /*
     boolean doShading = avm.getBoolean(Arg.TEMPFAC_SHADING);
     if (doShading)
     {
@@ -521,6 +559,7 @@ public class Commands
         Console.info("Changed colour " + acg.toString());
       }
     }
+    */
 
     return theseArgsWereParsed;
   }
index 5d14f98..d70326e 100755 (executable)
@@ -283,12 +283,14 @@ public class Jalview
    */
   void doMain(String[] args)
   {
-
     if (!Platform.isJS())
     {
       System.setSecurityManager(null);
     }
 
+    if (args == null)
+      args = new String[] {};
+
     // Move any new getdown-launcher-new.jar into place over old
     // getdown-launcher.jar
     String appdirString = System.getProperty("getdownappdir");
index cab2c00..dc42f8c 100644 (file)
@@ -181,6 +181,12 @@ public class Launcher
         // Leaving it in in case it gets fixed
         command.add(
                 "-Xdock:name=" + ChannelProperties.getProperty("app_name"));
+        // this launches WITHOUT an icon in the macOS dock. Could be useful for
+        // getdown?
+        // command.add("-Dapple.awt.UIElement=false");
+        // This also does not work for the dock
+        command.add("-Dcom.apple.mrj.application.apple.menu.about.name="
+                + ChannelProperties.getProperty("app_name"));
       }
     }
 
index e22cfc6..f712010 100644 (file)
@@ -10,11 +10,10 @@ import java.util.stream.Collectors;
 public enum Arg
 {
   HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, ANNOTATIONS,
-  COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, ANNOTATION,
-  ANNOTATION2, DISPLAY, GUI, NEWS, SORTBYTREE, USAGESTATS, OPEN, OPENNEW,
-  PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC, VSESS, OUTPUT, OUTPUTTYPE,
-  SSANNOTATION, NOTEMPFAC, TEMPFAC, TEMPFAC_LABEL, TEMPFAC_DESC,
-  TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP, NOSTRUCTURE, STRUCTURE, IMAGE,
+  COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, DISPLAY, GUI, NEWS,
+  SORTBYTREE, USAGESTATS, OPEN, OPENNEW, PROPS, QUESTIONNAIRE, SETPROP,
+  TREE, VDOC, VSESS, OUTPUT, OUTPUTTYPE, SSANNOTATIONS, NOTEMPFAC, TEMPFAC,
+  TITLE, PAEMATRIX, WRAP, NOSTRUCTURE, STRUCTURE, STRUCTUREVIEWER, IMAGE,
   QUIT, CLOSE, DEBUG("d"), QUIET("q"), ARGFILE, INCREMENT, NPP("n++"),
   SUBSTITUTIONS, INITSUBSTITUTIONS, NIL, SPLASH, SETARGFILE, UNSETARGFILE;
 
@@ -32,7 +31,7 @@ public enum Arg
     MENUBAR.setOptions(true, Opt.BOOLEAN);
     STATUS.setOptions(true, Opt.BOOLEAN);
     SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
-    ANNOTATIONS.setOptions(Opt.STRING, Opt.LINKED);
+    ANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
     COLOUR.setOptions(Opt.STRING, Opt.LINKED);
     FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
             Opt.ALLOWSUBSTITUTIONS);
@@ -41,8 +40,6 @@ public enum Arg
     GROUPS.setOptions(Opt.STRING, Opt.LINKED);
     HEADLESS.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
     JABAWS.setOptions(Opt.STRING);
-    ANNOTATION.setOptions(true, Opt.BOOLEAN, Opt.LINKED);
-    ANNOTATION2.setOptions(true, Opt.BOOLEAN, Opt.LINKED);
     DISPLAY.setOptions(true, Opt.BOOLEAN);
     GUI.setOptions(true, Opt.BOOLEAN);
     NEWS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
@@ -65,18 +62,16 @@ public enum Arg
     OUTPUT.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS);
     OUTPUTTYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
 
-    SSANNOTATION.setOptions(Opt.BOOLEAN, Opt.LINKED);
+    SSANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
     NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
     TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
-    TEMPFAC_LABEL.setOptions(Opt.STRING, Opt.LINKED);
-    TEMPFAC_DESC.setOptions(Opt.STRING, Opt.LINKED);
-    TEMPFAC_SHADING.setOptions(Opt.BOOLEAN, Opt.LINKED);
     TITLE.setOptions(Opt.STRING, Opt.LINKED);
     PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
             Opt.ALLOWSUBSTITUTIONS);
     NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
     STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
             Opt.ALLOWSUBSTITUTIONS);
+    STRUCTUREVIEWER.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
     WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
     IMAGE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS);
     QUIT.setOptions(Opt.UNARY);
index 0ff1845..70ed5d1 100644 (file)
@@ -29,8 +29,10 @@ import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
+import jalview.bin.Cache;
 import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.bin.argparser.Arg.Opt;
@@ -707,4 +709,63 @@ public class ArgParser
     return args;
   }
 
+  public static enum Position
+  {
+    FIRST, BEFORE, AFTER
+  }
+
+  public static String getValueFromSubValOrArg(ArgValuesMap avm, Arg a,
+          SubVals sv)
+  {
+    return getFromSubValArgOrPref(avm, a, sv, null, null, null);
+  }
+
+  public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+          SubVals sv, String key, String pref, String def)
+  {
+    return getFromSubValArgOrPref(avm, a, Position.FIRST, null, sv, key,
+            pref, def);
+  }
+
+  public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+          Position pos, ArgValue av, SubVals sv, String key, String pref,
+          String def)
+  {
+    if (key == null)
+      key = a.getName();
+    if (sv != null && sv.has(key) && sv.get(key) != null)
+      return sv.get(key);
+    if (avm != null && avm.containsArg(a))
+    {
+      String val = null;
+      if (pos == Position.FIRST && avm.getValue(a) != null)
+        return avm.getValue(a);
+      else if (pos == Position.BEFORE
+              && avm.getClosestPreviousArgValueOfArg(av, a) != null)
+        return avm.getClosestPreviousArgValueOfArg(av, a).getValue();
+      else if (pos == Position.AFTER
+              && avm.getClosestNextArgValueOfArg(av, a) != null)
+        return avm.getClosestNextArgValueOfArg(av, a).getValue();
+    }
+    return pref != null ? Cache.getDefault(pref, def) : def;
+  }
+
+  public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a,
+          SubVals sv)
+  {
+    return getFromSubValArgOrPref(avm, a, sv, null, null, false);
+  }
+
+  public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+          SubVals sv, String key, String pref, boolean def)
+  {
+    if (key == null)
+      key = a.getName();
+    if (sv != null && sv.has(key) && sv.get(key) != null)
+      return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
+    if (avm != null && avm.containsArg(a))
+      return avm.getBoolean(a);
+    return pref != null ? Cache.getDefault(pref, def) : def;
+  }
+
 }
\ No newline at end of file
index 2117ee9..176dc7c 100644 (file)
@@ -92,8 +92,7 @@ public class ArgValuesMap
   {
     if (m == null || !m.containsKey(a))
       return false;
-    return a.hasOption(Opt.STRING) ? getArgValue(a) != null
-            : this.getBoolean(a);
+    return a.hasOption(Opt.STRING) ? getArgValue(a) != null : true;
   }
 
   public boolean hasValue(Arg a, String val)
index 2d02e79..5fdaabb 100644 (file)
@@ -3440,8 +3440,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void overviewMenuItem_actionPerformed(ActionEvent e)
   {
-    boolean showHiddenRegions = Cache.getDefault(Preferences.SHOW_OV_HIDDEN_AT_START,
-                false);
+    boolean showHiddenRegions = Cache
+            .getDefault(Preferences.SHOW_OV_HIDDEN_AT_START, false);
     openOverviewPanel(showHiddenRegions);
   }
 
@@ -3452,14 +3452,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       return alignPanel.overviewPanel;
     }
     JInternalFrame frame = new JInternalFrame();
-    final OverviewPanel overview = new OverviewPanel(alignPanel, frame, showHidden);
+    final OverviewPanel overview = new OverviewPanel(alignPanel, frame,
+            showHidden);
     frame.setContentPane(overview);
-    Desktop.addInternalFrame(frame, "", true, frame.getWidth(), frame.getHeight(),
-            true, true);
+    Desktop.addInternalFrame(frame, "", true, frame.getWidth(),
+            frame.getHeight(), true, true);
     frame.setFrameIcon(null);
     frame.pack();
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
-    final AlignmentPanel thePanel = this.alignPanel; 
+    final AlignmentPanel thePanel = this.alignPanel;
     frame.addInternalFrameListener(
             new javax.swing.event.InternalFrameAdapter()
             {
@@ -3478,7 +3479,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     alignPanel.setOverviewPanel(overview);
     alignPanel.setOverviewTitle(this);
-    
+
     return overview;
   }
 
@@ -4133,7 +4134,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return showNewickTree(nf, treeTitle, null, w, h, x, y);
   }
 
-
   /**
    * Add a treeviewer for the tree extracted from a Newick file object to the
    * current alignment view
@@ -4184,13 +4184,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return tp;
   }
 
-
   public void showContactMapTree(AlignmentAnnotation aa,
           PAEContactMatrix cm)
   {
     int x = 4, y = 5;
     int w = 400, h = 500;
-    
+
     try
     {
       NewickFile fin = new NewickFile(
@@ -4198,42 +4197,43 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       String title = "PAE Matrix Tree for "
               + cm.getReferenceSeq().getDisplayId(false);
 
-      showColumnWiseTree(fin, aa, title, w,h, x,y);
+      showColumnWiseTree(fin, aa, title, w, h, x, y);
     } catch (Throwable xx)
     {
       Console.error("Unexpected exception showing tree for contact matrix",
               xx);
     }
   }
-  public TreePanel showColumnWiseTree(NewickFile nf, AlignmentAnnotation aa, String treeTitle,
-           int w, int h, int x, int y)
+
+  public TreePanel showColumnWiseTree(NewickFile nf, AlignmentAnnotation aa,
+          String treeTitle, int w, int h, int x, int y)
   {
-      try
+    try
+    {
+      nf.parse();
+      if (nf.getTree() == null)
       {
-        nf.parse();
-        if (nf.getTree() == null)
-        {
-          return null;
-        }
-        TreePanel tp = new TreePanel(alignPanel, nf, aa, title);
-
-        tp.setSize(w, h);
+        return null;
+      }
+      TreePanel tp = new TreePanel(alignPanel, nf, aa, title);
 
-        if (x > 0 && y > 0)
-        {
-          tp.setLocation(x, y);
-        }
+      tp.setSize(w, h);
 
-        Desktop.addInternalFrame(tp, title, w, h);
-        return tp;
-      } catch (Throwable xx)
+      if (x > 0 && y > 0)
       {
-        Console.error("Unexpected exception showing tree for contact matrix",
-                xx);
+        tp.setLocation(x, y);
       }
-      return null;
+
+      Desktop.addInternalFrame(tp, title, w, h);
+      return tp;
+    } catch (Throwable xx)
+    {
+      Console.error("Unexpected exception showing tree for contact matrix",
+              xx);
+    }
+    return null;
   }
-  
+
   private boolean buildingMenu = false;
 
   /**
@@ -5027,7 +5027,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
        * to add view name "Original" if necessary
        */
       alignPanel.setOverviewTitle(this);
-      
+
       /*
        * switch panels and set Overview title (if there is one
        * because it was opened automatically)
@@ -5698,7 +5698,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          update non-sequence-related annotations
    */
   @Override
-  protected void setAnnotationsVisibility(boolean visible,
+  public void setAnnotationsVisibility(boolean visible,
           boolean forSequences, boolean forAlignment)
   {
     AlignmentAnnotation[] anns = alignPanel.getAlignment()
index 7d2d907..35972b0 100644 (file)
@@ -67,6 +67,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.gui.StructureViewer.ViewerType;
 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
@@ -1344,6 +1345,15 @@ public class StructureChooser extends GStructureChooser
           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);
@@ -1408,7 +1418,8 @@ public class StructureChooser extends GStructureChooser
               MessageManager.getString(
                       "status.fetching_3d_structures_for_selected_entries"),
               progressId);
-      theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
+      theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
+              viewerType);
     }
     else
     {
@@ -1416,7 +1427,8 @@ public class StructureChooser extends GStructureChooser
               "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...
@@ -1721,20 +1733,20 @@ public class StructureChooser extends GStructureChooser
           boolean doXferSettings)
   {
     openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
-            paeFilename, false, true, doXferSettings);
+            paeFilename, false, true, doXferSettings, null);
   }
 
   public static void openStructureFileForSequence(
           StructureSelectionManager ssm, StructureChooser sc,
           AlignmentPanel ap, SequenceI seq, boolean prompt,
           String sFilename, TFType tft, String paeFilename,
-          boolean forceHeadless, boolean showAnnotations,
-          boolean doXferSettings)
+          boolean forceHeadless, boolean showRefAnnotations,
+          boolean doXferSettings, ViewerType viewerType)
   {
     boolean headless = forceHeadless;
     if (sc == null)
     {
-      headless = true;
+      // headless = true;
       prompt = false;
       sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
     }
@@ -1747,14 +1759,15 @@ public class StructureChooser extends GStructureChooser
 
     // 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))
+      sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
+              new SequenceI[]
+              { seq }, viewerType);
 
     if (headless)
       sc.mainFrame.dispose();
 
-    if (showAnnotations)
+    if (showRefAnnotations)
       showReferenceAnnotationsForSequence(ap.alignFrame, seq);
   }
 
index 5effa1a..0c12eb2 100644 (file)
@@ -119,6 +119,12 @@ public class StructureViewer
   public JalviewStructureDisplayI viewStructures(PDBEntry[] pdbs,
           SequenceI[] seqs, AlignmentPanel ap)
   {
+    return viewStructures(pdbs, seqs, ap, null);
+  }
+
+  public JalviewStructureDisplayI viewStructures(PDBEntry[] pdbs,
+          SequenceI[] seqs, AlignmentPanel ap, ViewerType viewerType)
+  {
     JalviewStructureDisplayI viewer = onlyOnePdb(pdbs, seqs, ap);
     if (viewer != null)
     {
@@ -128,7 +134,8 @@ public class StructureViewer
       return viewer;
     }
 
-    ViewerType viewerType = getViewerType();
+    if (viewerType == null)
+      viewerType = getViewerType();
 
     Map<PDBEntry, SequenceI[]> seqsForPdbs = getSequencesForPdbs(pdbs,
             seqs);
@@ -299,6 +306,12 @@ public class StructureViewer
   public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
           SequenceI[] seqsForPdb, AlignmentPanel ap)
   {
+    return viewStructures(pdb, seqsForPdb, ap, null);
+  }
+
+  public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
+          SequenceI[] seqsForPdb, AlignmentPanel ap, ViewerType viewerType)
+  {
     if (sview != null)
     {
       sview.setAlignAddedStructures(superposeAdded);
@@ -311,7 +324,8 @@ public class StructureViewer
       sview.raiseViewer();
       return sview;
     }
-    ViewerType viewerType = getViewerType();
+    if (viewerType == null)
+      viewerType = getViewerType();
     if (viewerType.equals(ViewerType.JMOL))
     {
       sview = new AppJmol(pdb, seqsForPdb, null, ap);
index 8ae97b0..5b886b6 100755 (executable)
@@ -2157,7 +2157,7 @@ public class GAlignFrame extends JInternalFrame
    * @param forAlignment
    *          update non-sequence-related annotations
    */
-  protected void setAnnotationsVisibility(boolean visible,
+  public void setAnnotationsVisibility(boolean visible,
           boolean forSequences, boolean forAlignment)
   {
 
index 69c0f4d..03538ef 100755 (executable)
@@ -39,6 +39,7 @@ import java.awt.event.KeyListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
 
 import javax.swing.AbstractCellEditor;
@@ -1679,10 +1680,16 @@ public class GPreferences extends JPanel
      */
     structViewer.setFont(LABEL_FONT);
     structViewer.setBounds(new Rectangle(190, ypos, 120, height));
+    for (ViewerType v : EnumSet.allOf(ViewerType.class))
+    {
+      structViewer.addItem(v.name());
+    }
+    /*
     structViewer.addItem(ViewerType.JMOL.name());
     structViewer.addItem(ViewerType.CHIMERA.name());
     structViewer.addItem(ViewerType.CHIMERAX.name());
     structViewer.addItem(ViewerType.PYMOL.name());
+    */
     structViewer.addActionListener(new ActionListener()
     {
       @Override
diff --git a/test/jalview/bin/CommandsTest2.java b/test/jalview/bin/CommandsTest2.java
new file mode 100644 (file)
index 0000000..71452e2
--- /dev/null
@@ -0,0 +1,173 @@
+package jalview.bin;
+
+import java.util.Date;
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.gui.StructureViewerBase;
+
+@Test
+public class CommandsTest2
+{
+  @BeforeClass(alwaysRun = true)
+  public static void setUpBeforeClass() throws Exception
+  {
+    Cache.loadProperties("test/jalview/testProps.jvprops");
+    Date oneHourFromNow = new Date(
+            System.currentTimeMillis() + 3600 * 1000);
+    Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", oneHourFromNow);
+    if (Desktop.instance != null)
+      Desktop.instance.closeAll_actionPerformed(null);
+
+  }
+
+  @AfterClass(alwaysRun = true)
+  public static void resetProps()
+  {
+    Cache.loadProperties("test/jalview/testProps.jvprops");
+  }
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  @AfterMethod(alwaysRun = true)
+  public void tearDown()
+  {
+    if (Desktop.instance != null)
+      Desktop.instance.closeAll_actionPerformed(null);
+  }
+
+  @Test(
+    groups =
+    { "Functional" },
+    dataProvider = "structureOpeningArgsParams")
+  public void structureOpeningArgsTest(String cmdLine, int seqNum,
+          int annNum, int viewerNum)
+  {
+    String[] args = cmdLine.split("\\s+");
+
+    Jalview.main(args);
+    AlignFrame[] afs = Desktop.getAlignFrames();
+    Assert.assertNotNull(afs);
+    Assert.assertTrue(afs.length > 0);
+
+    AlignFrame af = afs[0];
+    Assert.assertNotNull(af);
+
+    AlignmentPanel ap = af.alignPanel;
+    Assert.assertNotNull(ap);
+
+    AlignmentI al = ap.getAlignment();
+    Assert.assertNotNull(al);
+
+    List<SequenceI> seqs = al.getSequences();
+    Assert.assertNotNull(seqs);
+
+    Assert.assertEquals(seqs.size(), seqNum, "Wrong number of sequences");
+
+    AlignViewportI av = ap.getAlignViewport();
+    Assert.assertNotNull(av);
+
+    AlignmentAnnotation[] aas = al.getAlignmentAnnotation();
+    int visibleAnn = 0;
+    for (AlignmentAnnotation aa : aas)
+    {
+      if (aa.visible)
+        visibleAnn++;
+    }
+
+    Assert.assertEquals(visibleAnn, annNum,
+            "Wrong number of visible annotations");
+
+    if (viewerNum > -1)
+    {
+      try
+      {
+        Thread.sleep(100);
+      } catch (InterruptedException e)
+      {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+      List<StructureViewerBase> openViewers = Desktop.instance
+              .getStructureViewers(ap, null);
+      Assert.assertNotNull(openViewers);
+      Assert.assertEquals(openViewers.size(), viewerNum,
+              "Wrong number of structure viewers opened");
+    }
+  }
+
+  @DataProvider(name = "structureOpeningArgsParams")
+  public Object[][] structureOpeningArgsParams()
+  {
+    /*
+      String cmdLine,
+      int seqNum,
+      int annNum,
+      int viewerNum,
+      String propsFile
+     */
+    return new Object[][] { { "--nonews --nosplash --debug "
+            + "--open=examples/uniref50.fa " + "--colour=gecos:flower "
+            + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif "
+            + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+            + "--props=test/jalview/bin/commandsTest2.jvprops1 ",
+        15, 7, 1 },
+        { "--nonews --nosplash --debug " + "--open=examples/uniref50.fa "
+                + "--colour=gecos:flower "
+                + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif "
+                + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+                + "--props=test/jalview/bin/commandsTest2.jvprops2 ",
+            15, 4, 1 },
+        { "--nonews --nosplash --debug " + "--open=examples/uniref50.fa "
+                + "--colour=gecos:flower "
+                + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif "
+                + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+                + "--nossannotations "
+                + "--props=test/jalview/bin/commandsTest2.jvprops1 ",
+            15, 4, 1 },
+        { "--nonews --nosplash --debug " + "--open=examples/uniref50.fa "
+                + "--colour=gecos:flower "
+                + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif "
+                + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+                + "--noannotations "
+                + "--props=test/jalview/bin/commandsTest2.jvprops1 ",
+            15, 3, 1 },
+        { "--nonews --nosplash --debug " + "--open=examples/uniref50.fa "
+                + "--colour=gecos:flower "
+                + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif "
+                + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+                + "--noannotations " + "--nossannotations "
+                + "--props=test/jalview/bin/commandsTest2.jvprops1 ",
+            15, 0, 1 },
+        { "--nonews --nosplash --debug " + "--open=examples/uniref50.fa "
+                + "--colour=gecos:flower "
+                + "--structure=[seqid=FER1_SPIOL]examples/AlphaFold/AF-P00221-F1-model_v4.cif "
+                + "--paematrix=examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+                + "--noannotations " + "--nossannotations "
+                + "--props=test/jalview/bin/commandsTest2.jvprops1 ",
+            15, 0, 1 },
+        { "--argfile=test/jalview/bin/commandsTest2.argfile1 ", 16, 19, 3 },
+        { "--argfile=test/jalview/bin/commandsTest2.argfile2 ", 16, 0, 2 },
+        //
+    };
+  }
+}
diff --git a/test/jalview/bin/commandsTest2.argfile1 b/test/jalview/bin/commandsTest2.argfile1
new file mode 100644 (file)
index 0000000..a9c602d
--- /dev/null
@@ -0,0 +1,25 @@
+--debug
+--nonews
+--nosplash
+--substitutions
+--open=examples/test_fab41.result/sample.a2m
+--annotations
+--ssannotations
+--colour=gecos:flower
+--structure=[viewer=jmol;tempfac=plddt;paematrix={dirname}/test_fab41_unrelaxed_rank_1_model_3_scores.json]{dirname}/test_fab41_unrelaxed_rank_1_model_3.pdb
+--structure={dirname}/test_fab41_unrelaxed_rank_2_model_4.pdb
+--structureviewer=jmol
+--paematrix={dirname}/test_fab41_unrelaxed_rank_2_model_4_scores.json
+--tempfac=plddt
+--structure={dirname}/test_fab41_unrelaxed_rank_3_model_2.pdb
+--structureviewer=jmol
+--paematrix={dirname}/test_fab41_unrelaxed_rank_3_model_2_scores.json
+--tempfac=plddt
+--structure=[viewer=none]{dirname}/test_fab41_unrelaxed_rank_4_model_5.pdb
+--paematrix={dirname}/test_fab41_unrelaxed_rank_4_model_5_scores.json
+--tempfac=plddt
+--structure={dirname}/test_fab41_unrelaxed_rank_5_model_1.pdb
+--structureviewer=none
+--tempfac=plddt
+--paematrix={dirname}/test_fab41_unrelaxed_rank_5_model_1_scores.json
+#--headless
diff --git a/test/jalview/bin/commandsTest2.argfile2 b/test/jalview/bin/commandsTest2.argfile2
new file mode 100644 (file)
index 0000000..d057858
--- /dev/null
@@ -0,0 +1,26 @@
+--debug
+--nonews
+--nosplash
+--substitutions
+--open=examples/test_fab41.result/sample.a2m
+--noannotations
+--nossannotations
+--colour=gecos:flower
+--structure=[tempfac=plddt;paematrix={dirname}/test_fab41_unrelaxed_rank_1_model_3_scores.json]{dirname}/test_fab41_unrelaxed_rank_1_model_3.pdb
+--structureviewer=none
+--structure={dirname}/test_fab41_unrelaxed_rank_2_model_4.pdb
+--structureviewer=jmol
+--paematrix={dirname}/test_fab41_unrelaxed_rank_2_model_4_scores.json
+--tempfac=plddt
+--structure={dirname}/test_fab41_unrelaxed_rank_3_model_2.pdb
+--structureviewer=jmol
+--paematrix={dirname}/test_fab41_unrelaxed_rank_3_model_2_scores.json
+--tempfac=plddt
+--structure=[viewer=none]{dirname}/test_fab41_unrelaxed_rank_4_model_5.pdb
+--paematrix={dirname}/test_fab41_unrelaxed_rank_4_model_5_scores.json
+--tempfac=plddt
+--structure={dirname}/test_fab41_unrelaxed_rank_5_model_1.pdb
+--structureviewer=none
+--tempfac=plddt
+--paematrix={dirname}/test_fab41_unrelaxed_rank_5_model_1_scores.json
+#--headless
diff --git a/test/jalview/bin/commandsTest2.jvprops1 b/test/jalview/bin/commandsTest2.jvprops1
new file mode 100644 (file)
index 0000000..bd510e7
--- /dev/null
@@ -0,0 +1,4 @@
+SHOW_STARTUP_FILE=false
+SPLASH=false
+STRUCT_FROM_PDB=true
+ADD_TEMPFACT_ANN=true
diff --git a/test/jalview/bin/commandsTest2.jvprops2 b/test/jalview/bin/commandsTest2.jvprops2
new file mode 100644 (file)
index 0000000..576269a
--- /dev/null
@@ -0,0 +1,4 @@
+SHOW_STARTUP_FILE=false
+SPLASH=false
+STRUCT_FROM_PDB=false
+ADD_TEMPFACT_ANN=true
index b74baf1..b4eaf68 100644 (file)
@@ -24,15 +24,23 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import java.io.File;
 import java.util.Collection;
+import java.util.List;
 import java.util.Vector;
 
 import org.junit.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
@@ -43,8 +51,15 @@ import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.fts.service.pdb.PDBFTSRestClientTest;
 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
 import jalview.fts.threedbeacons.TDBeaconsFTSRestClientTest;
+import jalview.gui.StructureViewer.ViewerType;
 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
+import jalview.io.FileFormatI;
+import jalview.io.FileLoader;
+import jalview.io.IdentifyFile;
 import jalview.jbgui.FilterOption;
+import jalview.structure.StructureImportSettings.TFType;
 import junit.extensions.PA;
 
 @Test(singleThreaded = true)
@@ -259,4 +274,140 @@ public class StructureChooserTest
     assertEquals("abcde12345afg",
             PDBStructureChooserQuerySource.sanitizeSeqName(name));
   }
+
+  @Test(groups = { "Functional" }, dataProvider = "openStructureFileParams")
+  public void openStructureFileForSequenceTest(String alfile, String seqid,
+          String sFilename, TFType tft, String paeFilename,
+          boolean showRefAnnotations, boolean doXferSettings,
+          ViewerType viewerType, int seqNum, int annNum, int viewerNum,
+          String propsFile)
+  {
+    Cache.loadProperties(
+            propsFile == null ? "test/jalview/io/testProps.jvprops"
+                    : propsFile);
+
+    Jalview.main(
+            propsFile == null ? null : new String[]
+            { "--props", propsFile });
+    if (Desktop.instance != null)
+      Desktop.instance.closeAll_actionPerformed(null);
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.OK_OPTION);
+
+    FileLoader fileLoader = new FileLoader(true);
+    FileFormatI format = null;
+    File alFile = new File(alfile);
+    try
+    {
+      format = new IdentifyFile().identify(alFile, DataSourceType.FILE);
+    } catch (FileFormatException e1)
+    {
+      Assert.fail(
+              "Unknown file format for '" + alFile.getAbsolutePath() + "'");
+    }
+
+    AlignFrame af = fileLoader.LoadFileWaitTillLoaded(alFile,
+            DataSourceType.FILE, format);
+    AlignmentPanel ap = af.alignPanel;
+    Assert.assertNotNull("No alignPanel", ap);
+
+    AlignmentI al = ap.getAlignment();
+    Assert.assertNotNull(al);
+
+    SequenceI seq = al.findName(seqid);
+    Assert.assertNotNull("Sequence '" + seqid + "' not found in alignment",
+            seq);
+
+    StructureChooser.openStructureFileForSequence(null, null, ap, seq,
+            false, sFilename, tft, paeFilename, false, showRefAnnotations,
+            doXferSettings, viewerType);
+
+    List<SequenceI> seqs = al.getSequences();
+    Assert.assertNotNull(seqs);
+
+    Assert.assertEquals("Wrong number of sequences", seqNum, seqs.size());
+
+    AlignViewportI av = ap.getAlignViewport();
+    Assert.assertNotNull(av);
+
+    AlignmentAnnotation[] aas = al.getAlignmentAnnotation();
+    int visibleAnn = 0;
+    for (AlignmentAnnotation aa : aas)
+    {
+      if (aa.visible)
+        visibleAnn++;
+    }
+    Assert.assertEquals("Wrong number of viewed annotations", annNum,
+            visibleAnn);
+
+    if (viewerNum > -1)
+    {
+      try
+      {
+        Thread.sleep(100);
+      } catch (InterruptedException e)
+      {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+      List<StructureViewerBase> openViewers = Desktop.instance
+              .getStructureViewers(ap, null);
+      Assert.assertNotNull(openViewers);
+      Assert.assertEquals("Wrong number of structure viewers opened",
+              viewerNum, openViewers.size());
+    }
+
+    if (af != null)
+    {
+      af.setVisible(false);
+      af.dispose();
+    }
+  }
+
+  @DataProvider(name = "openStructureFileParams")
+  public Object[][] openStructureFileParams()
+  {
+    /*
+        String alFile,
+        String seqid,
+        String structureFilename,
+        TFType tft,
+        String paeFilename,
+        boolean showRefAnnotations,
+        boolean doXferSettings, // false for Commands
+        ViewerType viewerType,
+        int seqNum,
+        int annNum,
+        int viewerNum,
+        String propsFile
+     */
+    return new Object[][] {
+        /*
+        */
+        { "examples/uniref50.fa", "FER1_SPIOL",
+            "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.DEFAULT,
+            "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
+            true, false, null, 15, 7, 0, null },
+        { "examples/uniref50.fa", "FER1_SPIOL",
+            "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
+            "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
+            true, false, null, 15, 7, 0, null },
+        { "examples/uniref50.fa", "FER1_SPIOL",
+            "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
+            "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
+            false, false, null, 15, 4, 0, null },
+        { "examples/uniref50.fa", "FER1_SPIOL",
+            "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.DEFAULT,
+            "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
+            true, false, ViewerType.JMOL, 15, 7, 1, null },
+        { "examples/uniref50.fa", "FER1_SPIOL",
+            "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
+            "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
+            true, false, ViewerType.JMOL, 15, 7, 1, null },
+        { "examples/uniref50.fa", "FER1_SPIOL",
+            "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
+            "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
+            false, false, ViewerType.JMOL, 15, 4, 1, null }, };
+  }
+
 }
index 95da22e..fc58822 100644 (file)
@@ -83,3 +83,4 @@ USE_PROXY=false
 WRAP_ALIGNMENT=false
 #DAS_REGISTRY_URL=http\://www.dasregistry.org/das/ # retired 01/05/2015
 DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+SPLASH=false
index e619b8e..076ee7e 100644 (file)
@@ -1,14 +1,22 @@
 package jalview.ws.dbsources;
 
+import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 
+import org.json.simple.parser.ParseException;
 import org.junit.Assert;
+import org.testng.FileAssert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import jalview.datamodel.Sequence;
+import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 
 public class EBIAlphaFoldTest
@@ -40,4 +48,36 @@ public class EBIAlphaFoldTest
                     new FileInputStream(paeFile)));
     Assert.assertNotEquals("No data from " + paeFile, cm.getMax(), 0);
   }
+
+  @Test(groups = { "Functional" }, dataProvider = "getPDBandPAEfiles")
+  public void checkImportPAEToStructure(String pdbFile, String paeFile)
+  {
+    FileInputStream paeInput = null;
+    try
+    {
+      paeInput = new FileInputStream(paeFile);
+    } catch (FileNotFoundException e)
+    {
+      e.printStackTrace();
+      FileAssert.assertFile(new File(paeFile),
+              "Test file '" + paeFile + "' doesn't seem to exist");
+    }
+    StructureSelectionManager ssm = StructureSelectionManager
+            .getStructureSelectionManager(Desktop.instance);
+
+    StructureMapping[] smArray = ssm.getMapping(pdbFile);
+
+    try
+    {
+      boolean done = EBIAlfaFold.importPaeJSONAsContactMatrixToStructure(
+              smArray, paeInput, "label");
+      Assert.assertTrue(
+              "Import of '" + paeFile + "' didn't complete successfully",
+              done);
+    } catch (IOException | ParseException e)
+    {
+      e.printStackTrace();
+    }
+
+  }
 }
diff --git a/utils/eclipse/launcher b/utils/eclipse/launcher
new file mode 100755 (executable)
index 0000000..ccb1d75
--- /dev/null
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+
+java -cp "./bin/main:./j11lib/*:./resources:./help" jalview.bin.Launcher "${@}"