JAL-3446 JavaScript interface
[jalview.git] / src / jalview / api / JalviewJSApp.java
index 2975317..5641295 100644 (file)
@@ -5,7 +5,6 @@ import java.awt.EventQueue;
 import java.io.IOException;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.StringTokenizer;
 import java.util.Vector;
@@ -24,7 +23,6 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.AlignViewport;
-import jalview.gui.AlignmentPanel;
 import jalview.gui.CalculationChooser;
 import jalview.gui.Desktop;
 import jalview.gui.StructureViewer;
@@ -39,7 +37,6 @@ import jalview.io.IdentifyFile;
 import jalview.io.JPredFile;
 import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
-import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.structure.SelectionListener;
 import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
@@ -68,9 +65,17 @@ public class JalviewJSApp implements JalviewJSApi
                                        // be '|', but many sequence IDS include
                                        // pipes.
 
+  /**
+   * We maintain a pointer to the jalview instance here, because only with that do we have a direct 
+   * connection from the JavaScript "applet" object to the proper instance of Jalview in case there
+   * are multiple applets on a page.
+   */
+  private Jalview jalview;
+
 
-  public JalviewJSApp(ArgsParser aparser)
+  public JalviewJSApp(Jalview jalview, ArgsParser aparser)
   {
+    this.jalview = jalview;
     this.aparser = aparser;
     Platform.setAppClass(this);
   }
@@ -113,10 +118,7 @@ public class JalviewJSApp implements JalviewJSApi
 
   // private boolean alignPDBStructures; // From JalviewLite; not implemented
   //
-  private Hashtable<String, Hashtable<String, String[]>> jsmessages;
-
-  private Hashtable<String, int[]> jshashes;
-
+  
   @Override
   public String getParameter(String name)
   {
@@ -170,31 +172,6 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   @Override
-  public Hashtable<String, int[]> getJSHashes()
-  {
-    return (jshashes == null ? (jshashes = new Hashtable<>()) : jshashes);
-  }
-
-  @Override
-  public Hashtable<String, Hashtable<String, String[]>> getJSMessages()
-  {
-    return (jsmessages == null ? (jsmessages = new Hashtable<>())
-            : jsmessages);
-  }
-
-  @Override
-  public Object getJSObject()
-  {
-    return Jalview.getInstance();
-  }
-
-  @Override
-  public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp)
-  {
-    return new jalview.gui.FeatureRenderer((AlignmentPanel) vp);
-  }
-
-  @Override
   public Object[] getSelectionForListener(SequenceGroup seqsel,
           ColumnSelection colsel, HiddenColumns hidden,
           SelectionSource source, Object alignFrame)
@@ -251,6 +228,47 @@ public class JalviewJSApp implements JalviewJSApi
     
   }
 
+  /**
+   * @j2sAlias showStructure
+   */
+  @Override
+  public void showStructure(AlignFrame af, String pdbID, String fileType) {
+    if (af == null)
+      af = Jalview.getCurrentAlignFrame();
+    PDBEntry pe = null;
+    SequenceI[] seqs = null;
+    if (pdbID == null) {
+      seqs = af.getViewport().getSequenceSelection();
+      if (seqs.length == 0)
+        seqs = af.getViewport().getAlignment().getSequencesArray();
+      for (int i = 0; i < seqs.length; i++) {
+        Vector<PDBEntry> list = seqs[i].getAllPDBEntries();
+        if (list.size() > 0) {
+          pe = list.get(0);
+          break;
+        }
+      }
+    }
+    if (pe == null) {
+      if (pdbID == null)
+        return;
+      pe = new PDBEntry(pdbID, null, fileType);
+      List<SequenceI> list = af.getViewport().getAlignment().getSequences();
+      List<SequenceI> tmp = new ArrayList<SequenceI>();
+      for (int i = 0; i < list.size(); i++) {
+        SequenceI seq = list.get(i);
+        if (seq.getPDBEntry(pdbID) != null) {
+          tmp.add(seq);
+        }
+      }
+      seqs = tmp.toArray(new SequenceI[tmp.size()]);
+      af.alignPanel.selectSequences(tmp);
+    }
+    StructureViewer.launchStructureViewer(
+            af.alignPanel,
+            pe, seqs);
+  }
+  
   public void newStructureView(AlignFrame af, PDBEntry pdb,
           SequenceI[] seqs, String[] chains, DataSourceType protocol)
   {
@@ -271,20 +289,19 @@ public class JalviewJSApp implements JalviewJSApi
     return parseFeaturesFile(null, filename, protocol);
   }
   
+  /**
+   * @j2sAlias parseFeatureFile
+   * 
+   * @param af
+   * @param filename
+   * @param protocol
+   * @return
+   */
   public boolean parseFeaturesFile(AlignFrame af, String filename, DataSourceType protocol)
   {
-    return af.parseFeaturesFile(filename, protocol);
-  }
-
-  @Override
-  public void setFeatureGroupState(String[] groups, boolean state)
-  {
-    setFeatureGroupState(null, groups, state);
+    return (af == null ? Jalview.getCurrentAlignFrame() : af).parseFeaturesFile(filename, protocol);
   }
 
-  public void setFeatureGroupState(AlignFrame af, String[] groups, boolean state) {
-    (af == null ? Jalview.getCurrentAlignFrame() : af).setFeatureGroupState(groups, state);
-  }
   /**
    * annotations, jpredfile, jnetfile
    * 
@@ -302,55 +319,42 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   @Override
-  public boolean addPdbFile(AlignFrame alf, String sequenceId,
-          String pdbEntryString, String pdbFile)
+  public boolean addPdbFile(AlignFrame alf, String sequenceId, String pdbId,
+          String pdbFile)
   {
     if (alf == null)
     {
       alf = Jalview.getCurrentAlignFrame();
     }
-    SequenceI toaddpdb = alf.getViewport().getAlignment()
-            .findName(sequenceId);
-    boolean needtoadd = false;
-    if (toaddpdb != null)
+    SequenceI seq = alf.getViewport().getAlignment().findName(sequenceId);
+    if (seq != null)
     {
-      Vector<PDBEntry> pdbe = toaddpdb.getAllPDBEntries();
+      Vector<PDBEntry> pdbe = seq.getAllPDBEntries();
       PDBEntry pdbentry = null;
       if (pdbe != null && pdbe.size() > 0)
       {
         for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++)
         {
           pdbentry = pdbe.elementAt(pe);
-          if (!pdbentry.getId().equals(pdbEntryString)
-                  && !pdbentry.getFile().equals(pdbFile))
+          if (!pdbentry.getId().equals(pdbId)
+                  || pdbFile != null && !pdbentry.getFile().equals(pdbFile))
           {
             pdbentry = null;
           }
-          else
-          {
-            continue;
-          }
         }
       }
       if (pdbentry == null)
       {
-        pdbentry = new PDBEntry();
-        pdbentry.setId(pdbEntryString);
-        pdbentry.setFile(pdbFile);
-        needtoadd = true; // add this new entry to sequence.
-      }
-      // resolve data source
-      // TODO: this code should be a refactored to an io package
-      DataSourceType protocol = AppletFormatAdapter.resolveProtocol(pdbFile,
-              FileFormat.PDB);
-      if (protocol == null)
-      {
-        return false;
-      }
-      if (needtoadd)
-      {
-        pdbentry.setProperty("protocol", protocol);
-        toaddpdb.addPDBId(pdbentry);
+        pdbentry = new PDBEntry(pdbId, null, pdbFile);
+        if (pdbFile != null)
+        {
+          DataSourceType protocol = AppletFormatAdapter
+                  .resolveProtocol(pdbFile, FileFormat.PDB);
+          if (protocol == null)
+            return false;
+          pdbentry.setProperty("protocol", protocol);
+        }
+        seq.addPDBId(pdbentry);
         alf.alignPanel.getStructureSelectionManager()
                 .registerPDBEntry(pdbentry);
       }
@@ -358,51 +362,51 @@ public class JalviewJSApp implements JalviewJSApi
     return true;
   }
 
-  @Override
-  public String arrayToSeparatorList(String[] array)
-  {
-    return arrayToSeparatorList(array, separator);
-  }
-
-  /**
-   * concatenate the list with separator
-   * 
-   * @param list
-   * @param separator
-   * @return concatenated string
-   */
-  public static String arrayToSeparatorList(String[] list, String separator)
-  {
-    // TODO use StringUtils version
-    StringBuffer v = new StringBuffer();
-    if (list != null && list.length > 0)
-    {
-      for (int i = 0, iSize = list.length; i < iSize; i++)
-      {
-        if (list[i] != null)
-        {
-          if (i > 0)
-          {
-            v.append(separator);
-          }
-          v.append(list[i]);
-        }
-      }
-      // if (debug)
-      // {
-      // System.err
-      // .println("Returning '" + separator + "' separated List:\n");
-      // System.err.println(v);
-      // }
-      return v.toString();
-    }
-    // if (debug)
-    // {
-    // System.err.println(
-    // "Returning empty '" + separator + "' separated List\n");
-    // }
-    return "" + separator;
-  }
+//  @Override
+//  public String arrayToSeparatorList(String[] array)
+//  {
+//    return arrayToSeparatorList(array, separator);
+//  }
+
+//  /**
+//   * concatenate the list with separator
+//   * 
+//   * @param list
+//   * @param separator
+//   * @return concatenated string
+//   */
+//  public static String arrayToSeparatorList(String[] list, String separator)
+//  {
+//    // TODO use StringUtils version
+//    StringBuffer v = new StringBuffer();
+//    if (list != null && list.length > 0)
+//    {
+//      for (int i = 0, iSize = list.length; i < iSize; i++)
+//      {
+//        if (list[i] != null)
+//        {
+//          if (i > 0)
+//          {
+//            v.append(separator);
+//          }
+//          v.append(list[i]);
+//        }
+//      }
+//      // if (debug)
+//      // {
+//      // System.err
+//      // .println("Returning '" + separator + "' separated List:\n");
+//      // System.err.println(v);
+//      // }
+//      return v.toString();
+//    }
+//    // if (debug)
+//    // {
+//    // System.err.println(
+//    // "Returning empty '" + separator + "' separated List\n");
+//    // }
+//    return "" + separator;
+//  }
 
   @Override
   public String getAlignment(String format)
@@ -410,6 +414,11 @@ public class JalviewJSApp implements JalviewJSApi
     return getAlignmentFrom(null, format, null);
   }
 
+  /**
+   * suffix string "true"/"false" (default true)
+   *          passed to AlnFile class controls whether /START-END is added to
+   *          sequence names
+   */
   @Override
   public String getAlignment(String format, String suffix)
   {
@@ -454,13 +463,7 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   @Override
-  public String getAlignmentOrderFrom(AlignFrame alf)
-  {
-    return getAlignmentFrom(alf, null);
-  }
-
-  @Override
-  public String getAlignmentOrderFrom(AlignFrame alf, String sep)
+  public String[] getAlignmentOrderFrom(AlignFrame alf)
   {
     if (alf == null)
     {
@@ -472,7 +475,7 @@ public class JalviewJSApp implements JalviewJSApi
     {
       order[i] = alorder.getSequenceAt(i).getName();
     }
-    return arrayToSeparatorList(order, sep);
+    return order;//  arrayToSeparatorList(order, sep);
   }
 
   @Override
@@ -494,35 +497,35 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   @Override
-  public String getFeatureGroups()
+  public String[] getFeatureGroups()
   {
     return getFeatureGroupsOn(null);
   }
 
   @Override
-  public String getFeatureGroupsOfState(boolean visible)
+  public String[] getFeatureGroupsOfState(boolean visible)
   {
     return getFeatureGroupsOfStateOn(null, visible);
   }
 
   @Override
-  public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible)
+  public String[] getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible)
   {
     if (alf == null)
     {
       alf = Jalview.getCurrentAlignFrame();
     }
-    return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible));
+    return alf.getFeatureGroupsOfState(visible);
   }
 
   @Override
-  public String getFeatureGroupsOn(AlignFrame alf)
+  public String[] getFeatureGroupsOn(AlignFrame alf)
   {
     if (alf == null)
     {
       alf = Jalview.getCurrentAlignFrame();
     }
-    return arrayToSeparatorList(alf.getFeatureGroups());
+    return alf.getFeatureGroups();
   }
 
   @Override
@@ -575,14 +578,7 @@ public class JalviewJSApp implements JalviewJSApi
     return features;
 
   }
-
-  @Override
-  public String getJsMessage(String messageclass, String viewId)
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
+  
   /**
    * read sequence1...sequenceN as a raw alignment
    * 
@@ -612,7 +608,7 @@ public class JalviewJSApp implements JalviewJSApi
    * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequences()
    */
   @Override
-  public String getSelectedSequences()
+  public SequenceI[] getSelectedSequences()
   {
     return getSelectedSequencesFrom(Jalview.getCurrentAlignFrame());
   }
@@ -622,7 +618,7 @@ public class JalviewJSApp implements JalviewJSApi
    * @see jalview.appletgui.js.JalviewLiteJsApi#getSelectedSequences(java.lang.String)
    */
   @Override
-  public String getSelectedSequences(String sep)
+  public SequenceI[] getSelectedSequences(String sep)
   {
     return getSelectedSequencesFrom(Jalview.getCurrentAlignFrame(), sep);
   }
@@ -673,37 +669,26 @@ public class JalviewJSApp implements JalviewJSApi
    *      .AlignFrame)
    */
   @Override
-  public String getSelectedSequencesFrom(AlignFrame alf)
+  public SequenceI[] getSelectedSequencesFrom(AlignFrame alf)
   {
     return getSelectedSequencesFrom(alf, null);
   }
 
   @Override
-  public String getSelectedSequencesFrom(AlignFrame alf, String sep)
+  public SequenceI[] getSelectedSequencesFrom(AlignFrame alf, String sep)
   {
     if (alf == null)
     {
       alf = Jalview.getCurrentAlignFrame();
     }
-    StringBuffer result = new StringBuffer("");
-    if (sep == null || sep.length() == 0)
-    {
-      sep = separator; // "+0x00AC;
-    }
     AlignViewport v = alf.getViewport();
     if (v.getSelectionGroup() != null)
     {
-      SequenceI[] seqs = v.getSelectionGroup()
+      return v.getSelectionGroup()
               .getSequencesInOrder(v.getAlignment());
-
-      for (int i = 0; i < seqs.length; i++)
-      {
-        result.append(seqs[i].getName());
-        result.append(sep);
-      }
     }
 
-    return result.toString();
+    return null;
   }
 
   public Object[] getSelectionForListener(AlignFrame alf,
@@ -768,14 +753,7 @@ public class JalviewJSApp implements JalviewJSApi
         cols[0] = "" + (1 + strt) + "-" + (1 + end);
       }
     }
-    return new Object[] { src, setid, arrayToSeparatorList(seqs),
-        arrayToSeparatorList(cols) };
-  }
-
-  @Override
-  public String getSeparator()
-  {
-    return separator;
+    return new Object[] { src, setid, seqs, cols };
   }
 
   /**
@@ -1311,6 +1289,8 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   /**
+   * @j2sAlias openPcaPanel
+   * 
    * public static method for JalviewJS API to open a PCAPanel without
    * necessarily using a dialog.
    * 
@@ -1330,6 +1310,8 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   /**
+   * @j2sAlias openTreePanel
+   * 
    * Open a new Tree panel on the desktop statically. Params are standard (not
    * set by Groovy). No dialog is opened.
    * 
@@ -1350,22 +1332,22 @@ public class JalviewJSApp implements JalviewJSApi
     return CalculationChooser.openTreePanel(af, treeType, modelName, null);
   }
 
+
   @Override
-  public String orderAlignmentBy(AlignFrame alf, String order,
-          String undoName, String sep)
+  public String orderBy(String[] ids, String undoName)
   {
-    if (sep == null || sep.length() == 0)
-    {
-      sep = separator;
-    }
-    String[] ids = separatorListToArray(order, sep);
+    return orderAlignmentBy(null, ids, undoName);
+  }
+
+  @Override
+  public String orderAlignmentBy(AlignFrame alf, String[] ids,
+          String undoName)
+  {
+    if (alf == null)
+      alf = Jalview.getCurrentAlignFrame();
     SequenceI[] sqs = null;
     if (ids != null && ids.length > 0)
     {
-      if (alf == null)
-      {
-        alf = Jalview.getCurrentAlignFrame();
-      }
       jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
               alf.getViewport().getAlignment().getSequencesArray());
       int s = 0;
@@ -1410,19 +1392,6 @@ public class JalviewJSApp implements JalviewJSApi
     return alf.sortBy(aorder, _undoName) ? "true" : "";
   }
 
-  @Override
-  public String orderBy(String order, String undoName)
-  {
-    return orderBy(order, undoName, null);
-  }
-
-  @Override
-  public String orderBy(String order, String undoName, String sep)
-  {
-    return orderAlignmentBy(Jalview.getCurrentAlignFrame(), order, undoName,
-            sep);
-  }
-
   /**
    * Allow an outside entity to initiate the second half of argument parsing
    * (only).
@@ -1436,7 +1405,7 @@ public class JalviewJSApp implements JalviewJSApi
 
     try
     {
-      Jalview.getInstance().parseArguments(new ArgsParser(args), false);
+      jalview.parseArguments(new ArgsParser(args), false);
       return null;
     } catch (Throwable t)
     {
@@ -1805,15 +1774,10 @@ public class JalviewJSApp implements JalviewJSApi
     }
   }
 
-  // public AlignFrame newViewFrom(AlignFrame alf, String name)
-  // {
-  // return (AlignFrame) alf.newView(name, true);
-  // }
-  //
   @Override
-  public String[] separatorListToArray(String list)
+  public void setFeatureGroupState(String[] groups, boolean state)
   {
-    return separatorListToArray(list, separator);
+    setFeatureGroupState(null, groups, state);
   }
 
   @Override
@@ -1826,19 +1790,24 @@ public class JalviewJSApp implements JalviewJSApi
   public void setFeatureGroupStateOn(final AlignFrame alf,
           final String groups, boolean state)
   {
+    setFeatureGroupState(alf, separatorListToArray(groups, separator), state);
+//    java.awt.EventQueue.invokeLater(new Runnable()
+//    {
+//      @Override
+//      public void run()
+//      {
+//        (alf == null ? Jalview.getCurrentAlignFrame() : alf)
+//                .setFeatureGroupState(
+//                        separatorListToArray(groups, separator), state);
+//      }
+//    });
+  }
 
-    java.awt.EventQueue.invokeLater(new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        (alf == null ? Jalview.getCurrentAlignFrame() : alf)
-                .setFeatureGroupState(
-                        separatorListToArray(groups, separator), state);
-      }
-    });
+  public void setFeatureGroupState(AlignFrame af, String[] groups, boolean state) {
+    (af == null ? Jalview.getCurrentAlignFrame() : af).setFeatureGroupState(groups, state);
   }
 
+
   @Override
   public void setSelectionListener(AlignFrame af, String listener)
   {
@@ -1854,12 +1823,6 @@ public class JalviewJSApp implements JalviewJSApi
   }
 
   @Override
-  public void setSeparator(String separator)
-  {
-    this.separator = separator;
-  }
-
-  @Override
   public void showOverview()
   {
     Jalview.getCurrentAlignFrame().overviewMenuItem_actionPerformed(null);
@@ -1897,7 +1860,7 @@ public class JalviewJSApp implements JalviewJSApi
    */
   public String doSendCallback(Object callback, Object[] data)
   {
-    Jalview me = Jalview.getInstance();
+    Jalview me = jalview;
 
     if (me != null && callback != null)
     {
@@ -2178,7 +2141,7 @@ public class JalviewJSApp implements JalviewJSApi
         if (seqsel != null && seqsel.getSize() > 0)
         {
           // send a valid range, otherwise we send the empty selection
-          cols = new String[2];
+          cols = new String[1];
           cols[0] = "" + (1 + strt) + "-" + (1 + end);
         }
         ;
@@ -2187,8 +2150,7 @@ public class JalviewJSApp implements JalviewJSApi
 
       doSendCallback(_listener,
               new Object[]
-              { src, setid, arrayToSeparatorList(seqs),
-                  arrayToSeparatorList(cols) });
+              { src, setid, seqs, cols });
     }
 
     public boolean isFor(AlignFrame af, String listener)