JAL-1645 Version-Rel Version 2.9 Year-Rel 2015 Licensing glob
[jalview.git] / src / jalview / gui / VamsasApplication.java
index 5988bb8..4630fd1 100644 (file)
@@ -1,28 +1,38 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
- * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
+ * Copyright (C) 2015 The Jalview Authors
  * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * This file is part of Jalview.
  * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.gui;
 
 import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.io.VamsasAppDatastore;
+import jalview.structure.SelectionListener;
+import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasListener;
+import jalview.structure.VamsasSource;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
@@ -30,6 +40,7 @@ import java.io.File;
 import java.io.IOException;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
 
 import javax.swing.JInternalFrame;
 import javax.swing.JOptionPane;
@@ -38,20 +49,23 @@ import uk.ac.vamsas.client.ClientHandle;
 import uk.ac.vamsas.client.IClient;
 import uk.ac.vamsas.client.IClientDocument;
 import uk.ac.vamsas.client.InvalidSessionDocumentException;
-import uk.ac.vamsas.client.NoDefaultSessionException;
 import uk.ac.vamsas.client.UserHandle;
 import uk.ac.vamsas.client.VorbaId;
 import uk.ac.vamsas.client.picking.IMessageHandler;
 import uk.ac.vamsas.client.picking.IPickManager;
 import uk.ac.vamsas.client.picking.Message;
 import uk.ac.vamsas.client.picking.MouseOverMessage;
+import uk.ac.vamsas.client.picking.SelectionMessage;
 import uk.ac.vamsas.objects.core.Entry;
+import uk.ac.vamsas.objects.core.Input;
+import uk.ac.vamsas.objects.core.Pos;
+import uk.ac.vamsas.objects.core.Seg;
 
 /**
  * @author jimp
  * 
  */
-public class VamsasApplication
+public class VamsasApplication implements SelectionSource, VamsasSource
 {
   IClient vclient = null;
 
@@ -61,16 +75,19 @@ public class VamsasApplication
 
   Desktop jdesktop = null; // our jalview desktop reference
 
+  private boolean inInitialUpdate = true;
+
   // Cache.preferences for vamsas client session arena
   // preferences for check for default session at startup.
   // user and organisation stuff.
-  public VamsasApplication(Desktop jdesktop, File sessionPath)
+  public VamsasApplication(Desktop jdesktop, File sessionPath,
+          String sessionName)
   {
     // JBPNote:
     // we should create a session URI from the sessionPath and pass it to
     // the clientFactory - but the vamsas api doesn't cope with that yet.
     this.jdesktop = jdesktop;
-    initClientSession(null, sessionPath);
+    initClientSession(null, sessionPath, sessionName);
   }
 
   private static uk.ac.vamsas.client.IClientFactory getClientFactory()
@@ -104,7 +121,7 @@ public class VamsasApplication
 
   /**
    * @throws IOException
-   *                 or other if clientfactory instantiation failed.
+   *           or other if clientfactory instantiation failed.
    * @return list of current sessions or null if no session exists.
    */
   public static String[] getSessionList() throws Exception
@@ -117,12 +134,18 @@ public class VamsasApplication
    * session
    * 
    * @param sess
-   *                null or a valid session url
+   *          null or a valid session url
    * @param vamsasDocument
-   *                null or a valid vamsas document file
+   *          null or a valid vamsas document file
    * @return false if no vamsas connection was made
    */
-  private boolean initClientSession(String sess, File vamsasDocument)
+  private void initClientSession(String sess, File vamsasDocument)
+  {
+    initClientSession(sess, vamsasDocument, null);
+  }
+
+  private boolean initClientSession(String sess, File vamsasDocument,
+          String newDocSessionName)
   {
     try
     {
@@ -134,20 +157,31 @@ public class VamsasApplication
         if (sess != null)
         {
           throw new Error(
-                  "Implementation Error - cannot import existing vamsas document into an existing session, Yet!");
+                  MessageManager
+                          .getString("error.implementation_error_cannot_import_vamsas_doc"));
         }
         try
         {
-          vclient = clientfactory.openAsNewSessionIClient(app,
-                  vamsasDocument);
+          if (newDocSessionName != null)
+          {
+            vclient = clientfactory.openAsNewSessionIClient(app,
+                    vamsasDocument, newDocSessionName);
+          }
+          else
+          {
+            vclient = clientfactory.openAsNewSessionIClient(app,
+                    vamsasDocument);
+          }
         } catch (InvalidSessionDocumentException e)
         {
           JOptionPane
                   .showInternalMessageDialog(
                           Desktop.desktop,
 
-                          "VAMSAS Document could not be opened as a new session - please choose another",
-                          "VAMSAS Document Import Failed",
+                          MessageManager
+                                  .getString("label.vamsas_doc_couldnt_be_opened_as_new_session"),
+                          MessageManager
+                                  .getString("label.vamsas_document_import_failed"),
                           JOptionPane.ERROR_MESSAGE);
 
         }
@@ -195,14 +229,12 @@ public class VamsasApplication
     } catch (Error e)
     {
       Cache.log
-              .warn(
-                      "Probable SERIOUS VAMSAS client incompatibility - carrying on regardless",
+              .warn("Probable SERIOUS VAMSAS client incompatibility - carrying on regardless",
                       e);
     } catch (Exception e)
     {
       Cache.log
-              .warn(
-                      "Probable VAMSAS client incompatibility - carrying on regardless",
+              .warn("Probable VAMSAS client incompatibility - carrying on regardless",
                       e);
     }
   }
@@ -214,8 +246,8 @@ public class VamsasApplication
    */
   private ClientHandle getJalviewHandle()
   {
-    return new ClientHandle("jalview.bin.Jalview", jalview.bin.Cache
-            .getProperty("VERSION"));
+    return new ClientHandle("jalview.bin.Jalview",
+            jalview.bin.Cache.getProperty("VERSION"));
   }
 
   /**
@@ -236,14 +268,17 @@ public class VamsasApplication
     if (!inSession())
     {
       throw new Error(
-              "Impementation error! Vamsas Operations when client not initialised and connected.");
+              MessageManager
+                      .getString("error.implementation_error_vamsas_operation_not_init"));
     }
     addDocumentUpdateHandler();
     addStoreDocumentHandler();
     startSession();
+    inInitialUpdate = true;
     Cache.log
             .debug("Jalview loading the Vamsas Session for the first time.");
     dealWithDocumentUpdate(false); // we don't push an update out to the
+    inInitialUpdate = false;
     // document yet.
     Cache.log.debug("... finished update for the first time.");
   }
@@ -276,8 +311,7 @@ public class VamsasApplication
     } catch (Exception e)
     {
       Cache.log
-              .warn(
-                      "Exception whilst refreshing jalview windows after a vamsas document update.",
+              .warn("Exception whilst refreshing jalview windows after a vamsas document update.",
                       e);
     }
   }
@@ -292,33 +326,48 @@ public class VamsasApplication
         Cache.log.info("Jalview updating to the Vamsas Session.");
 
         dealWithDocumentUpdate(true);
-        /*
-         * IClientDocument cdoc=null; try { cdoc = vclient.getClientDocument(); }
-         * catch (Exception e) { Cache.log.error("Failed to get client document
-         * for update."); // RAISE A WARNING DIALOG disableGui(false); return; }
-         * updateVamsasDocument(cdoc); updateJalviewGui();
-         * cdoc.setVamsasRoots(cdoc.getVamsasRoots()); // propagate update flags
-         * back vclient.updateDocument(cdoc);
-         */
         Cache.log.info("Jalview finished updating to the Vamsas Session.");
-        // TODO Auto-generated method stub
       }
 
     });
     udthread.start();
   }
 
+  /**
+   * leave a session, prompting the user to save if necessary
+   */
   public void end_session()
   {
+    end_session(true);
+  }
+
+  private boolean promptUser = true;
+
+  /**
+   * leave a session, optionally prompting the user to save if necessary
+   * 
+   * @param promptUser
+   *          when true enable prompting by this application
+   */
+
+  public void end_session(boolean promptUser)
+  {
     if (!inSession())
-      throw new Error("Jalview not connected to Vamsas session.");
+    {
+      throw new Error(
+              MessageManager
+                      .getString("error.jalview_no_connected_vamsas_session"));
+    }
     Cache.log.info("Jalview disconnecting from the Vamsas Session.");
     try
     {
       if (joinedSession)
       {
+        boolean ourprompt = this.promptUser;
+        this.promptUser = promptUser;
         vclient.finalizeClient();
         Cache.log.info("Jalview has left the session.");
+        this.promptUser = ourprompt; // restore default value
       }
       else
       {
@@ -343,11 +392,32 @@ public class VamsasApplication
     ensureJvVamsas();
     VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj,
             baseProvEntry(), alRedoState);
-    vds.updateToJalview();
+    try
+    {
+      vds.updateToJalview();
+    } catch (Exception e)
+    {
+      Cache.log.error("Failed to update Jalview from vamsas document.", e);
+    }
+    try
+    {
+      if (firstUpdate)
+      {
+        vds.updateJalviewFromAppdata();
+        // Comment this out to repeatedly read in data from JalviewAppData
+        // firstUpdate=false;
+      }
+    } catch (Exception e)
+    {
+      Cache.log.error(
+              "Exception when updating Jalview settings from Appdata.", e);
+    }
     Cache.log.debug(".. finished updating from sesion document.");
 
   }
 
+  boolean firstUpdate = false;
+
   private void ensureJvVamsas()
   {
     if (jv2vobj == null)
@@ -355,6 +425,7 @@ public class VamsasApplication
       jv2vobj = new IdentityHashMap();
       vobj2jv = new Hashtable();
       alRedoState = new Hashtable();
+      firstUpdate = true;
     }
   }
 
@@ -367,9 +438,24 @@ public class VamsasApplication
 
   Hashtable alRedoState = null;
 
-  public void updateVamsasDocument(IClientDocument doc)
+  boolean errorsDuringUpdate = false;
+
+  boolean errorsDuringAppUpdate = false;
+
+  /**
+   * update the document accessed through doc. A backup of the current object
+   * bindings is made.
+   * 
+   * @param doc
+   * @return number of views stored in document (updated and new views)
+   */
+  public int updateVamsasDocument(IClientDocument doc)
   {
+    int storedviews = 0;
     ensureJvVamsas();
+    errorsDuringUpdate = false;
+    errorsDuringAppUpdate = false;
+    backup_objectMapping();
     VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj,
             baseProvEntry(), alRedoState);
     // wander through frames
@@ -377,8 +463,10 @@ public class VamsasApplication
 
     if (frames == null)
     {
-      return;
+      return 0;
     }
+    Hashtable skipList = new Hashtable();
+    Hashtable viewset = new Hashtable();
 
     try
     {
@@ -388,26 +476,77 @@ public class VamsasApplication
         if (frames[i] instanceof AlignFrame)
         {
           AlignFrame af = (AlignFrame) frames[i];
-
-          // update alignment and root from frame.
-          vds.storeVAMSAS(af.getViewport(), af.getTitle());
+          if (!viewset.containsKey(af.getViewport().getSequenceSetId()))
+          {
+            // update alignment and root from frame.
+            boolean stored = false;
+            try
+            {
+              stored = vds.storeVAMSAS(af.getViewport(), af.getTitle());
+            } catch (Exception e)
+            {
+              errorsDuringUpdate = true;
+              Cache.log.error("Exception synchronizing "
+                      + af.getTitle()
+                      + " "
+                      + (af.getViewport().viewName == null ? "" : " view "
+                              + af.getViewport().viewName)
+                      + " to document.", e);
+              stored = false;
+            }
+            if (!stored)
+            { // record skip in skipList
+              skipList.put(af.getViewport().getSequenceSetId(), af);
+            }
+            else
+            {
+              storedviews++;
+              // could try to eliminate sequenceSetId from skiplist ..
+              // (skipList.containsKey(af.getViewport().getSequenceSetId()))
+              // remember sequenceSetId so we can skip all the other views on
+              // same alignment
+              viewset.put(af.getViewport().getSequenceSetId(), af);
+            }
+          }
         }
       }
       // REVERSE ORDER
-      for (int i = frames.length - 1; i > -1; i--)
+      // for (int i = frames.length - 1; i > -1; i--)
+      // {
+      // if (frames[i] instanceof AlignFrame)
+      // {
+      // AlignFrame af = (AlignFrame) frames[i];
+      Iterator aframes = viewset.values().iterator();
+      while (aframes.hasNext())
       {
-        if (frames[i] instanceof AlignFrame)
-        {
-          AlignFrame af = (AlignFrame) frames[i];
+        AlignFrame af = (AlignFrame) aframes.next();
+        // add any AlignedCodonFrame mappings on this alignment to any other.
+        vds.storeSequenceMappings(af.getViewport(), af.getTitle());
+      }
+    } catch (Exception e)
+    {
+      Cache.log.error("Exception synchronizing Views to Document :", e);
+      errorsDuringUpdate = true;
+    }
 
-          // add any AlignedCodonFrame mappings on this alignment to any other.
-          vds.storeSequenceMappings(af.getViewport(), af.getTitle());
-        }
+    try
+    {
+      if (viewset.size() > 0)
+      {
+        // Alignment views were synchronized, so store their state in the
+        // appData, too.
+        // The skipList ensures we don't write out any alignments not actually
+        // in the document.
+        vds.setSkipList(skipList);
+        vds.updateJalviewClientAppdata();
       }
     } catch (Exception e)
     {
-      Cache.log.error("Vamsas Document store exception", e);
+      Cache.log.error("Client Appdata Write exception", e);
+      errorsDuringAppUpdate = true;
     }
+    vds.clearSkipList();
+    return storedviews;
   }
 
   private Entry baseProvEntry()
@@ -424,10 +563,12 @@ public class VamsasApplication
    * do a vamsas document update or update jalview from the vamsas document
    * 
    * @param fromJalview
-   *                true to update from jalview to the vamsas document
+   *          true to update from jalview to the vamsas document
+   * @return total number of stored alignments in the document after the update
    */
-  protected void dealWithDocumentUpdate(boolean fromJalview)
+  protected int dealWithDocumentUpdate(boolean fromJalview)
   {
+    int storedviews = 0;
     // called by update handler for document update.
     Cache.log.debug("Updating jalview from changed vamsas document.");
     disableGui(true);
@@ -443,7 +584,7 @@ public class VamsasApplication
       }
       if (fromJalview)
       {
-        this.updateVamsasDocument(cdoc);
+        storedviews += updateVamsasDocument(cdoc);
         if (Cache.log.isDebugEnabled())
         {
           Cache.log
@@ -483,9 +624,14 @@ public class VamsasApplication
     {
       System.err.println("Exception whilst updating :");
       ee.printStackTrace(System.err);
+      // recover object map backup, since its probably corrupted with references
+      // to Vobjects that don't exist anymore.
+      recover_objectMappingBackup();
+      storedviews = 0;
     }
     Cache.log.debug("Finished updating from document change.");
     disableGui(false);
+    return storedviews;
   }
 
   private void addDocumentUpdateHandler()
@@ -512,24 +658,33 @@ public class VamsasApplication
             {
               public void propertyChange(PropertyChangeEvent evt)
               {
-                Cache.log
-                        .debug("Asking user if the vamsas session should be stored.");
-                int reply = JOptionPane
-                        .showInternalConfirmDialog(
-                                Desktop.desktop,
-                                "The current VAMSAS session has unsaved data - do you want to save it ?",
-                                "VAMSAS Session Shutdown",
-                                JOptionPane.YES_NO_OPTION,
-                                JOptionPane.QUESTION_MESSAGE);
-
-                if (reply == JOptionPane.YES_OPTION)
+                if (client.promptUser)
+                {
+                  Cache.log
+                          .debug("Asking user if the vamsas session should be stored.");
+                  int reply = JOptionPane
+                          .showInternalConfirmDialog(
+                                  Desktop.desktop,
+                                  "The current VAMSAS session has unsaved data - do you want to save it ?",
+                                  "VAMSAS Session Shutdown",
+                                  JOptionPane.YES_NO_OPTION,
+                                  JOptionPane.QUESTION_MESSAGE);
+
+                  if (reply == JOptionPane.YES_OPTION)
+                  {
+                    Cache.log.debug("Prompting for vamsas store filename.");
+                    Desktop.instance.vamsasSave_actionPerformed(null);
+                    Cache.log
+                            .debug("Finished attempt at storing document.");
+                  }
+                  Cache.log
+                          .debug("finished dealing with REQUESTTOCLOSE event.");
+                }
+                else
                 {
-                  Cache.log.debug("Prompting for vamsas store filename.");
-                  Desktop.instance.vamsasSave_actionPerformed(null);
-                  Cache.log.debug("Finished attempt at storing document.");
+                  Cache.log
+                          .debug("Ignoring store document request (promptUser==false)");
                 }
-                Cache.log
-                        .debug("finished dealing with REQUESTTOCLOSE event.");
               }
             });
     Cache.log.debug("Added Jalview handler for vamsas document updates.");
@@ -540,10 +695,61 @@ public class VamsasApplication
     Desktop.instance.setVamsasUpdate(b);
   }
 
+  Hashtable _backup_vobj2jv;
+
+  IdentityHashMap _backup_jv2vobj;
+
+  /**
+   * make a backup of the object mappings (vobj2jv and jv2vobj)
+   */
+  public void backup_objectMapping()
+  {
+    _backup_vobj2jv = new Hashtable(vobj2jv);
+    _backup_jv2vobj = new IdentityHashMap(jv2vobj);
+  }
+
+  /**
+   * recover original object mappings from the object mapping backup if document
+   * IO failed
+   * 
+   * @throws Error
+   *           if backup_objectMapping was not called.
+   */
+  public void recover_objectMappingBackup()
+  {
+    if (_backup_vobj2jv == null)
+    {
+      if (inInitialUpdate)
+      {
+        // nothing to recover so just
+        return;
+      }
+
+      throw new Error(
+              MessageManager
+                      .getString("error.implementation_error_cannot_recover_vamsas_object_mappings"));
+    }
+    jv2vobj.clear();
+    Iterator el = _backup_jv2vobj.entrySet().iterator();
+    while (el.hasNext())
+    {
+      java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
+      jv2vobj.put(mp.getKey(), mp.getValue());
+    }
+    el = _backup_vobj2jv.entrySet().iterator();
+    while (el.hasNext())
+    {
+      java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
+      vobj2jv.put(mp.getKey(), mp.getValue());
+    }
+  }
+
   private boolean joinedSession = false;
 
   private VamsasListener picker = null;
 
+  private SelectionListener selecter;
+
   private void startSession()
   {
     if (inSession())
@@ -562,14 +768,20 @@ public class VamsasApplication
       {
         final IPickManager pm = vclient.getPickManager();
         final StructureSelectionManager ssm = StructureSelectionManager
-                .getStructureSelectionManager();
+                .getStructureSelectionManager(Desktop.instance);
+        final VamsasApplication me = this;
         pm.registerMessageHandler(new IMessageHandler()
         {
           String last = null;
 
           public void handleMessage(Message message)
           {
-            if (message instanceof MouseOverMessage && vobj2jv != null)
+            if (vobj2jv == null)
+            {
+              // we are not in a session yet.
+              return;
+            }
+            if (message instanceof MouseOverMessage)
             {
               MouseOverMessage mm = (MouseOverMessage) message;
               String mstring = mm.getVorbaID() + " " + mm.getPosition();
@@ -589,9 +801,166 @@ public class VamsasApplication
                 // Cache.log.debug("Handling Mouse over "+mm.getVorbaID()+"
                 // bound to "+jvobj+" at "+mm.getPosition());
                 // position is character position in aligned sequence
-                ssm.mouseOverVamsasSequence((SequenceI) jvobj, mm
-                        .getPosition());
+                ssm.mouseOverVamsasSequence((SequenceI) jvobj,
+                        mm.getPosition(), me);
+              }
+            }
+            if (message instanceof uk.ac.vamsas.client.picking.SelectionMessage)
+            {
+              // we only care about AlignmentSequence selections
+              SelectionMessage sm = (SelectionMessage) message;
+              sm.validate();
+              System.err.println("Received\n" + sm.getRawMessage());
+              Object[] jvobjs = sm.getVorbaIDs() == null ? null
+                      : new Object[sm.getVorbaIDs().length];
+              if (jvobjs == null)
+              {
+                // TODO: rationalise : can only clear a selection over a
+                // referred to object
+                ssm.sendSelection(null, null, me);
+                return;
+              }
+              Class type = null;
+              boolean send = true;
+              for (int o = 0; o < jvobjs.length; o++)
+              {
+                jvobjs[o] = vobj2jv.get(sm.getVorbaIDs()[o]);
+                if (jvobjs[o] == null)
+                {
+                  // can't cope with selections for unmapped objects
+                  continue;
+                }
+                if (type == null)
+                {
+                  type = jvobjs[o].getClass();
+                }
+                ;
+                if (type != jvobjs[o].getClass())
+                {
+                  send = false;
+                  // discard - can't cope with selections over mixed objects
+                  // continue;
+                }
+              }
+              SequenceGroup jselection = null;
+              ColumnSelection colsel = null;
+              if (type == jalview.datamodel.Alignment.class)
+              {
+                if (jvobjs.length == 1)
+                {
+                  // TODO if (sm.isNone())// send a message to select the
+                  // specified columns over the
+                  // given
+                  // alignment
+
+                  send = true;
+                }
+              }
+              if (type == jalview.datamodel.Sequence.class)
+              {
+
+                SequenceI seq;
+                boolean aligned = ((jalview.datamodel.Sequence) jvobjs[0])
+                        .getDatasetSequence() != null;
+                int maxWidth = 0;
+                if (aligned)
+                {
+                  jselection = new SequenceGroup();
+                  jselection.addSequence(
+                          seq = (jalview.datamodel.Sequence) jvobjs[0],
+                          false);
+                  maxWidth = seq.getLength();
+                }
+                for (int c = 1; aligned && jvobjs.length > 1
+                        && c < jvobjs.length; c++)
+                {
+                  if (((jalview.datamodel.Sequence) jvobjs[c])
+                          .getDatasetSequence() == null)
+                  {
+                    aligned = false;
+                    continue;
+                  }
+                  else
+                  {
+                    jselection.addSequence(
+                            seq = (jalview.datamodel.Sequence) jvobjs[c],
+                            false);
+                    if (maxWidth < seq.getLength())
+                    {
+                      maxWidth = seq.getLength();
+                    }
+
+                  }
+                }
+                if (!aligned)
+                {
+                  jselection = null;
+                  // if cardinality is greater than one then verify all
+                  // sequences are alignment sequences.
+                  if (jvobjs.length == 1)
+                  {
+                    // find all instances of this dataset sequence in the
+                    // displayed alignments containing the associated range and
+                    // select them.
+                  }
+                }
+                else
+                {
+                  jselection.setStartRes(0);
+                  jselection.setEndRes(maxWidth);
+                  // locate the alignment containing the given sequences and
+                  // select the associated ranges on them.
+                  if (sm.getRanges() != null)
+                  {
+                    int[] prange = uk.ac.vamsas.objects.utils.Range
+                            .getBounds(sm.getRanges());
+                    jselection.setStartRes(prange[0] - 1);
+                    jselection.setEndRes(prange[1] - 1);
+                    prange = uk.ac.vamsas.objects.utils.Range
+                            .getIntervals(sm.getRanges());
+                    colsel = new ColumnSelection();
+                    for (int p = 0; p < prange.length; p += 2)
+                    {
+                      int d = (prange[p] <= prange[p + 1]) ? 1 : -1;
+                      // try to join up adjacent columns to make a larger
+                      // selection
+                      // lower and upper bounds
+                      int l = (d < 0) ? 1 : 0;
+                      int u = (d > 0) ? 1 : 0;
+
+                      if (jselection.getStartRes() > 0
+                              && prange[p + l] == jselection.getStartRes())
+                      {
+                        jselection.setStartRes(prange[p + l] - 1);
+                      }
+                      if (jselection.getEndRes() <= maxWidth
+                              && prange[p + u] == (jselection.getEndRes() + 2))
+                      {
+                        jselection.setEndRes(prange[p + u] - 1);
+                      }
+                      // mark all the columns in the range.
+                      for (int sr = prange[p], er = prange[p + 1], de = er
+                              + d; sr != de; sr += d)
+                      {
+                        colsel.addElement(sr - 1);
+                      }
+                    }
+                  }
+                  send = true;
+                }
+              }
+              if (send)
+              {
+                ssm.sendSelection(jselection, colsel, me);
+              }
+              // discard message.
+              for (int c = 0; c < jvobjs.length; c++)
+              {
+                jvobjs[c] = null;
               }
+              ;
+              jvobjs = null;
+              return;
             }
           }
         });
@@ -601,17 +970,22 @@ public class VamsasApplication
 
           int i = -1;
 
-          public void mouseOver(SequenceI seq, int index)
+          @Override
+          public void mouseOverSequence(SequenceI seq, int index,
+                  VamsasSource source)
           {
             if (jv2vobj == null)
+            {
               return;
+            }
             if (seq != last || i != index)
             {
               VorbaId v = (VorbaId) jv2vobj.get(seq);
               if (v != null)
               {
-                Cache.log.debug("Mouse over " + v.getId() + " bound to "
-                        + seq + " at " + index);
+                // this should really be a trace message.
+                // Cache.log.debug("Mouse over " + v.getId() + " bound to "
+                // + seq + " at " + index);
                 last = seq;
                 i = index;
                 MouseOverMessage message = new MouseOverMessage(v.getId(),
@@ -621,11 +995,133 @@ public class VamsasApplication
             }
           }
         };
+        selecter = new SelectionListener()
+        {
+
+          public void selection(SequenceGroup seqsel,
+                  ColumnSelection colsel, SelectionSource source)
+          {
+            if (vobj2jv == null)
+            {
+              Cache.log
+                      .warn("Selection listener still active for dead session.");
+              // not in a session.
+              return;
+            }
+            if (source != me)
+            {
+              AlignmentI visal = null;
+              if (source instanceof AlignViewport)
+              {
+                visal = ((AlignmentViewport) source).getAlignment();
+              }
+              SelectionMessage sm = null;
+              if ((seqsel == null || seqsel.getSize() == 0)
+                      && (colsel == null || colsel.getSelected() == null || colsel
+                              .getSelected().size() == 0))
+              {
+                if (source instanceof AlignViewport)
+                {
+                  // the empty selection.
+                  sm = new SelectionMessage("jalview",
+                          new String[] { ((AlignmentViewport) source)
+                                  .getSequenceSetId() }, null, true);
+                }
+                else
+                {
+                  // the empty selection.
+                  sm = new SelectionMessage("jalview", null, null, true);
+                }
+              }
+              else
+              {
+                String[] vobj = new String[seqsel.getSize()];
+                int o = 0;
+                for (SequenceI sel : seqsel.getSequences(null))
+                {
+                  VorbaId v = (VorbaId) jv2vobj.get(sel);
+                  if (v != null)
+                  {
+                    vobj[o++] = v.toString();
+                  }
+                }
+                if (o < vobj.length)
+                {
+                  String t[] = vobj;
+                  vobj = new String[o];
+                  System.arraycopy(t, 0, vobj, 0, o);
+                  t = null;
+                }
+                Input range = null;
+                if (seqsel != null && colsel != null)
+                {
+                  // deparse the colsel into positions on the vamsas alignment
+                  // sequences
+                  range = new Input();
+                  if (colsel.getSelected() != null
+                          && colsel.getSelected().size() > 0
+                          && visal != null
+                          && seqsel.getSize() == visal.getHeight())
+                  {
+                    // gather selected columns outwith the sequence positions
+                    // too
+                    for (Object obj : colsel.getSelected())
+                    {
+                      int ival = ((Integer) obj).intValue();
+                      Pos p = new Pos();
+                      p.setI(ival + 1);
+                      range.addPos(p);
+                    }
+                  }
+                  else
+                  {
+                    int[] intervals = colsel.getVisibleContigs(
+                            seqsel.getStartRes(), seqsel.getEndRes() + 1);
+                    for (int iv = 0; iv < intervals.length; iv += 2)
+                    {
+                      Seg s = new Seg();
+                      s.setStart(intervals[iv] + 1); // vamsas indices begin at
+                      // 1, not zero.
+                      s.setEnd(intervals[iv + 1] + 1);
+                      s.setInclusive(true);
+                      range.addSeg(s);
+                    }
+                  }
+                }
+                if (vobj.length > 0)
+                {
+                  sm = new SelectionMessage("jalview", vobj, range);
+                }
+                else
+                {
+                  sm = null;
+                }
+              }
+              if (sm != null)
+              {
+                sm.validate(); // debug
+                Cache.log.debug("Selection Message\n" + sm.getRawMessage());
+                pm.sendMessage(sm);
+              }
+            }
+          }
+
+        };
         ssm.addStructureViewerListener(picker); // better method here
+        ssm.addSelectionListener(selecter);
       } catch (Exception e)
       {
         Cache.log.error("Failed to init Vamsas Picking", e);
       }
     }
   }
+
+  public String getCurrentSession()
+  {
+    if (vclient != null)
+    {
+      return (vclient.getSessionUrn());
+    }
+    return null;
+  }
 }