refactored for non-interactive import and initiation of sessions. apply gpl developme...
[jalview.git] / src / jalview / gui / VamsasApplication.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import jalview.bin.Cache;
22 import jalview.datamodel.AlignmentI;
23 import jalview.datamodel.ColumnSelection;
24 import jalview.datamodel.SequenceGroup;
25 import jalview.datamodel.SequenceI;
26 import jalview.io.VamsasAppDatastore;
27 import jalview.structure.SelectionListener;
28 import jalview.structure.SelectionSource;
29 import jalview.structure.StructureSelectionManager;
30 import jalview.structure.VamsasListener;
31
32 import java.beans.PropertyChangeEvent;
33 import java.beans.PropertyChangeListener;
34 import java.io.File;
35 import java.io.IOException;
36 import java.util.Enumeration;
37 import java.util.Hashtable;
38 import java.util.IdentityHashMap;
39 import java.util.Iterator;
40
41 import javax.swing.JInternalFrame;
42 import javax.swing.JOptionPane;
43
44 import uk.ac.vamsas.client.ClientHandle;
45 import uk.ac.vamsas.client.IClient;
46 import uk.ac.vamsas.client.IClientDocument;
47 import uk.ac.vamsas.client.InvalidSessionDocumentException;
48 import uk.ac.vamsas.client.NoDefaultSessionException;
49 import uk.ac.vamsas.client.UserHandle;
50 import uk.ac.vamsas.client.VorbaId;
51 import uk.ac.vamsas.client.picking.IMessageHandler;
52 import uk.ac.vamsas.client.picking.IPickManager;
53 import uk.ac.vamsas.client.picking.Message;
54 import uk.ac.vamsas.client.picking.MouseOverMessage;
55 import uk.ac.vamsas.client.picking.SelectionMessage;
56 import uk.ac.vamsas.objects.core.Entry;
57 import uk.ac.vamsas.objects.core.Input;
58 import uk.ac.vamsas.objects.core.Pos;
59 import uk.ac.vamsas.objects.core.Seg;
60
61 /**
62  * @author jimp
63  * 
64  */
65 public class VamsasApplication implements SelectionSource
66 {
67   IClient vclient = null;
68
69   ClientHandle app = null;
70
71   UserHandle user = null;
72
73   Desktop jdesktop = null; // our jalview desktop reference
74
75   // Cache.preferences for vamsas client session arena
76   // preferences for check for default session at startup.
77   // user and organisation stuff.
78   public VamsasApplication(Desktop jdesktop, File sessionPath)
79   {
80     // JBPNote:
81     // we should create a session URI from the sessionPath and pass it to
82     // the clientFactory - but the vamsas api doesn't cope with that yet.
83     this.jdesktop = jdesktop;
84     initClientSession(null, sessionPath);
85   }
86
87   private static uk.ac.vamsas.client.IClientFactory getClientFactory()
88           throws IOException
89   {
90     return new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
91   }
92
93   /**
94    * Start a new vamsas session
95    * 
96    * @param jdesktop
97    */
98   public VamsasApplication(Desktop jdesktop)
99   {
100     this.jdesktop = jdesktop;
101     initClientSession(null, null);
102   }
103
104   /**
105    * init a connection to the session at the given url
106    * 
107    * @param jdesktop
108    * @param sessionUrl
109    */
110   public VamsasApplication(Desktop jdesktop, String sessionUrl)
111   {
112     this.jdesktop = jdesktop;
113     initClientSession(sessionUrl, null);
114   }
115
116   /**
117    * @throws IOException
118    *           or other if clientfactory instantiation failed.
119    * @return list of current sessions or null if no session exists.
120    */
121   public static String[] getSessionList() throws Exception
122   {
123     return getClientFactory().getCurrentSessions();
124   }
125
126   /**
127    * initialise, possibly with either a valid session url or a file for a new
128    * session
129    * 
130    * @param sess
131    *          null or a valid session url
132    * @param vamsasDocument
133    *          null or a valid vamsas document file
134    * @return false if no vamsas connection was made
135    */
136   private boolean initClientSession(String sess, File vamsasDocument)
137   {
138     try
139     {
140       // Only need to tell the library what the application is here
141       app = getJalviewHandle();
142       uk.ac.vamsas.client.IClientFactory clientfactory = getClientFactory();
143       if (vamsasDocument != null)
144       {
145         if (sess != null)
146         {
147           throw new Error(
148                   "Implementation Error - cannot import existing vamsas document into an existing session, Yet!");
149         }
150         try
151         {
152           vclient = clientfactory.openAsNewSessionIClient(app,
153                   vamsasDocument);
154         } catch (InvalidSessionDocumentException e)
155         {
156           JOptionPane
157                   .showInternalMessageDialog(
158                           Desktop.desktop,
159
160                           "VAMSAS Document could not be opened as a new session - please choose another",
161                           "VAMSAS Document Import Failed",
162                           JOptionPane.ERROR_MESSAGE);
163
164         }
165       }
166       else
167       {
168         // join existing or create a new session
169         if (sess == null)
170         {
171           vclient = clientfactory.getNewSessionIClient(app);
172         }
173         else
174         {
175           vclient = clientfactory.getIClient(app, sess);
176         }
177       }
178       // set some properties for our VAMSAS interaction
179       setVclientConfig();
180       user = vclient.getUserHandle();
181
182     } catch (Exception e)
183     {
184       jalview.bin.Cache.log
185               .error("Couldn't instantiate vamsas client !", e);
186       return false;
187     }
188     return true;
189   }
190
191   private void setVclientConfig()
192   {
193     if (vclient == null)
194     {
195       return;
196     }
197     try
198     {
199       if (vclient instanceof uk.ac.vamsas.client.simpleclient.SimpleClient)
200       {
201         uk.ac.vamsas.client.simpleclient.SimpleClientConfig cfg = ((uk.ac.vamsas.client.simpleclient.SimpleClient) vclient)
202                 .getSimpleClientConfig();
203         cfg._validatemergedroots = false;
204         cfg._validateupdatedroots = true; // we may write rubbish otherwise.
205       }
206     } catch (Error e)
207     {
208       Cache.log
209               .warn(
210                       "Probable SERIOUS VAMSAS client incompatibility - carrying on regardless",
211                       e);
212     } catch (Exception e)
213     {
214       Cache.log
215               .warn(
216                       "Probable VAMSAS client incompatibility - carrying on regardless",
217                       e);
218     }
219   }
220
221   /**
222    * make the appHandle for Jalview
223    * 
224    * @return
225    */
226   private ClientHandle getJalviewHandle()
227   {
228     return new ClientHandle("jalview.bin.Jalview", jalview.bin.Cache
229             .getProperty("VERSION"));
230   }
231
232   /**
233    * 
234    * @return true if we are registered in a vamsas session
235    */
236   public boolean inSession()
237   {
238     return (vclient != null);
239   }
240
241   /**
242    * called to connect to session inits handlers, does an initial document
243    * update.
244    */
245   public void initial_update()
246   {
247     if (!inSession())
248     {
249       throw new Error(
250               "Impementation error! Vamsas Operations when client not initialised and connected.");
251     }
252     addDocumentUpdateHandler();
253     addStoreDocumentHandler();
254     startSession();
255     Cache.log
256             .debug("Jalview loading the Vamsas Session for the first time.");
257     dealWithDocumentUpdate(false); // we don't push an update out to the
258     // document yet.
259     Cache.log.debug("... finished update for the first time.");
260   }
261
262   /**
263    * Update all windows after a vamsas datamodel change. this could go on the
264    * desktop object!
265    * 
266    */
267   protected void updateJalviewGui()
268   {
269     JInternalFrame[] frames = jdesktop.getAllFrames();
270
271     if (frames == null)
272     {
273       return;
274     }
275
276     try
277     {
278       // REVERSE ORDER
279       for (int i = frames.length - 1; i > -1; i--)
280       {
281         if (frames[i] instanceof AlignFrame)
282         {
283           AlignFrame af = (AlignFrame) frames[i];
284           af.alignPanel.alignmentChanged();
285         }
286       }
287     } catch (Exception e)
288     {
289       Cache.log
290               .warn(
291                       "Exception whilst refreshing jalview windows after a vamsas document update.",
292                       e);
293     }
294   }
295
296   public void push_update()
297   {
298     Thread udthread = new Thread(new Runnable()
299     {
300
301       public void run()
302       {
303         Cache.log.info("Jalview updating to the Vamsas Session.");
304
305         dealWithDocumentUpdate(true);
306         Cache.log.info("Jalview finished updating to the Vamsas Session.");
307       }
308
309     });
310     udthread.start();
311   }
312
313   /**
314    * leave a session, prompting the user to save if necessary
315    */
316   public void end_session()
317   {
318     end_session(true);
319   }
320
321   private boolean promptUser = true;
322
323   /**
324    * leave a session, optionally prompting the user to save if necessary
325    * 
326    * @param promptUser
327    *          when true enable prompting by this application
328    */
329
330   public void end_session(boolean promptUser)
331   {
332     if (!inSession())
333       throw new Error("Jalview not connected to Vamsas session.");
334     Cache.log.info("Jalview disconnecting from the Vamsas Session.");
335     try
336     {
337       if (joinedSession)
338       {
339         boolean ourprompt = this.promptUser;
340         this.promptUser = promptUser;
341         vclient.finalizeClient();
342         Cache.log.info("Jalview has left the session.");
343         this.promptUser = ourprompt; // restore default value
344       }
345       else
346       {
347         Cache.log
348                 .warn("JV Client leaving a session that's its not joined yet.");
349       }
350       joinedSession = false;
351       vclient = null;
352       app = null;
353       user = null;
354       jv2vobj = null;
355       vobj2jv = null;
356     } catch (Exception e)
357     {
358       Cache.log.error("Vamsas Session finalization threw exceptions!", e);
359     }
360   }
361
362   public void updateJalview(IClientDocument cdoc)
363   {
364     Cache.log.debug("Jalview updating from sesion document ..");
365     ensureJvVamsas();
366     VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj,
367             baseProvEntry(), alRedoState);
368     try
369     {
370       vds.updateToJalview();
371     } catch (Exception e)
372     {
373       Cache.log.error("Failed to update Jalview from vamsas document.", e);
374     }
375     try
376     {
377       if (firstUpdate)
378       {
379         vds.updateJalviewFromAppdata();
380         // Comment this out to repeatedly read in data from JalviewAppData
381         // firstUpdate=false;
382       }
383     } catch (Exception e)
384     {
385       Cache.log.error(
386               "Exception when updating Jalview settings from Appdata.", e);
387     }
388     Cache.log.debug(".. finished updating from sesion document.");
389
390   }
391
392   boolean firstUpdate = false;
393
394   private void ensureJvVamsas()
395   {
396     if (jv2vobj == null)
397     {
398       jv2vobj = new IdentityHashMap();
399       vobj2jv = new Hashtable();
400       alRedoState = new Hashtable();
401       firstUpdate = true;
402     }
403   }
404
405   /**
406    * jalview object binding to VorbaIds
407    */
408   IdentityHashMap jv2vobj = null;
409
410   Hashtable vobj2jv = null;
411
412   Hashtable alRedoState = null;
413
414   boolean errorsDuringUpdate = false;
415
416   boolean errorsDuringAppUpdate = false;
417
418   /**
419    * update the document accessed through doc. A backup of the current object
420    * bindings is made.
421    * 
422    * @param doc
423    */
424   public void updateVamsasDocument(IClientDocument doc)
425   {
426     ensureJvVamsas();
427     errorsDuringUpdate = false;
428     errorsDuringAppUpdate = false;
429     backup_objectMapping();
430     VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj,
431             baseProvEntry(), alRedoState);
432     // wander through frames
433     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
434
435     if (frames == null)
436     {
437       return;
438     }
439     Hashtable skipList = new Hashtable();
440     Hashtable viewset = new Hashtable();
441
442     try
443     {
444       // REVERSE ORDER
445       for (int i = frames.length - 1; i > -1; i--)
446       {
447         if (frames[i] instanceof AlignFrame)
448         {
449           AlignFrame af = (AlignFrame) frames[i];
450           if (!viewset.containsKey(af.getViewport().getSequenceSetId()))
451           {
452             // update alignment and root from frame.
453             boolean stored = false;
454             try
455             {
456               stored = vds.storeVAMSAS(af.getViewport(), af.getTitle());
457             } catch (Exception e)
458             {
459               errorsDuringUpdate = true;
460               Cache.log.error("Exception synchronizing "
461                       + af.getTitle()
462                       + " "
463                       + (af.getViewport().viewName == null ? "" : " view "
464                               + af.getViewport().viewName)
465                       + " to document.", e);
466               stored = false;
467             }
468             if (!stored)
469             { // record skip in skipList
470               skipList.put(af.getViewport().getSequenceSetId(), af);
471             }
472             else
473             {
474               // could try to eliminate sequenceSetId from skiplist ..
475               // (skipList.containsKey(af.getViewport().getSequenceSetId()))
476               // remember sequenceSetId so we can skip all the other views on
477               // same alignment
478               viewset.put(af.getViewport().getSequenceSetId(), af);
479             }
480           }
481         }
482       }
483       // REVERSE ORDER
484       // for (int i = frames.length - 1; i > -1; i--)
485       // {
486       // if (frames[i] instanceof AlignFrame)
487       // {
488       // AlignFrame af = (AlignFrame) frames[i];
489       Iterator aframes = viewset.values().iterator();
490       while (aframes.hasNext())
491       {
492         AlignFrame af = (AlignFrame) aframes.next();
493         // add any AlignedCodonFrame mappings on this alignment to any other.
494         vds.storeSequenceMappings(af.getViewport(), af.getTitle());
495       }
496     } catch (Exception e)
497     {
498       Cache.log.error("Exception synchronizing Views to Document :", e);
499       errorsDuringUpdate = true;
500     }
501
502     try
503     {
504       if (viewset.size() > 0)
505       {
506         // Alignment views were synchronized, so store their state in the
507         // appData, too.
508         // The skipList ensures we don't write out any alignments not actually
509         // in the document.
510         vds.setSkipList(skipList);
511         vds.updateJalviewClientAppdata();
512       }
513     } catch (Exception e)
514     {
515       Cache.log.error("Client Appdata Write exception", e);
516       errorsDuringAppUpdate = true;
517     }
518     vds.clearSkipList();
519   }
520
521   private Entry baseProvEntry()
522   {
523     uk.ac.vamsas.objects.core.Entry pentry = new uk.ac.vamsas.objects.core.Entry();
524     pentry.setUser(user.getFullName());
525     pentry.setApp(app.getClientUrn());
526     pentry.setDate(new java.util.Date());
527     pentry.setAction("created");
528     return pentry;
529   }
530
531   /**
532    * do a vamsas document update or update jalview from the vamsas document
533    * 
534    * @param fromJalview
535    *          true to update from jalview to the vamsas document
536    */
537   protected void dealWithDocumentUpdate(boolean fromJalview)
538   {
539     // called by update handler for document update.
540     Cache.log.debug("Updating jalview from changed vamsas document.");
541     disableGui(true);
542     try
543     {
544       long time = System.currentTimeMillis();
545       IClientDocument cdoc = vclient.getClientDocument();
546       if (Cache.log.isDebugEnabled())
547       {
548         Cache.log.debug("Time taken to get ClientDocument = "
549                 + (System.currentTimeMillis() - time));
550         time = System.currentTimeMillis();
551       }
552       if (fromJalview)
553       {
554         this.updateVamsasDocument(cdoc);
555         if (Cache.log.isDebugEnabled())
556         {
557           Cache.log
558                   .debug("Time taken to update Vamsas Document from jalview\t= "
559                           + (System.currentTimeMillis() - time));
560           time = System.currentTimeMillis();
561         }
562         cdoc.setVamsasRoots(cdoc.getVamsasRoots());
563         if (Cache.log.isDebugEnabled())
564         {
565           Cache.log.debug("Time taken to set Document Roots\t\t= "
566                   + (System.currentTimeMillis() - time));
567           time = System.currentTimeMillis();
568         }
569       }
570       else
571       {
572         updateJalview(cdoc);
573         if (Cache.log.isDebugEnabled())
574         {
575           Cache.log
576                   .debug("Time taken to update Jalview from vamsas document Roots\t= "
577                           + (System.currentTimeMillis() - time));
578           time = System.currentTimeMillis();
579         }
580
581       }
582       vclient.updateDocument(cdoc);
583       if (Cache.log.isDebugEnabled())
584       {
585         Cache.log.debug("Time taken to update Session Document\t= "
586                 + (System.currentTimeMillis() - time));
587         time = System.currentTimeMillis();
588       }
589       cdoc = null;
590     } catch (Exception ee)
591     {
592       System.err.println("Exception whilst updating :");
593       ee.printStackTrace(System.err);
594       // recover object map backup, since its probably corrupted with references
595       // to Vobjects that don't exist anymore.
596       this.recover_objectMappingBackup();
597     }
598     Cache.log.debug("Finished updating from document change.");
599     disableGui(false);
600   }
601
602   private void addDocumentUpdateHandler()
603   {
604     final VamsasApplication client = this;
605     vclient.addDocumentUpdateHandler(new PropertyChangeListener()
606     {
607       public void propertyChange(PropertyChangeEvent evt)
608       {
609         Cache.log.debug("Dealing with document update event.");
610         client.dealWithDocumentUpdate(false);
611         Cache.log.debug("finished dealing with event.");
612       }
613     });
614     Cache.log.debug("Added Jalview handler for vamsas document updates.");
615   }
616
617   private void addStoreDocumentHandler()
618   {
619     final VamsasApplication client = this;
620     vclient.addVorbaEventHandler(
621             uk.ac.vamsas.client.Events.DOCUMENT_REQUESTTOCLOSE,
622             new PropertyChangeListener()
623             {
624               public void propertyChange(PropertyChangeEvent evt)
625               {
626                 if (client.promptUser)
627                 {
628                   Cache.log
629                           .debug("Asking user if the vamsas session should be stored.");
630                   int reply = JOptionPane
631                           .showInternalConfirmDialog(
632                                   Desktop.desktop,
633                                   "The current VAMSAS session has unsaved data - do you want to save it ?",
634                                   "VAMSAS Session Shutdown",
635                                   JOptionPane.YES_NO_OPTION,
636                                   JOptionPane.QUESTION_MESSAGE);
637
638                   if (reply == JOptionPane.YES_OPTION)
639                   {
640                     Cache.log.debug("Prompting for vamsas store filename.");
641                     Desktop.instance.vamsasSave_actionPerformed(null);
642                     Cache.log
643                             .debug("Finished attempt at storing document.");
644                   }
645                   Cache.log
646                           .debug("finished dealing with REQUESTTOCLOSE event.");
647                 }
648                 else
649                 {
650                   Cache.log
651                           .debug("Ignoring store document request (promptUser==false)");
652                 }
653               }
654             });
655     Cache.log.debug("Added Jalview handler for vamsas document updates.");
656   }
657
658   public void disableGui(boolean b)
659   {
660     Desktop.instance.setVamsasUpdate(b);
661   }
662
663   Hashtable _backup_vobj2jv;
664
665   IdentityHashMap _backup_jv2vobj;
666
667   /**
668    * make a backup of the object mappings (vobj2jv and jv2vobj)
669    */
670   public void backup_objectMapping()
671   {
672     _backup_vobj2jv = new Hashtable(vobj2jv);
673     _backup_jv2vobj = new IdentityHashMap(jv2vobj);
674   }
675
676   /**
677    * recover original object mappings from the object mapping backup if document
678    * IO failed
679    * 
680    * @throws Error
681    *           if backup_objectMapping was not called.
682    */
683   public void recover_objectMappingBackup()
684   {
685     if (_backup_vobj2jv == null)
686     {
687       throw new Error(
688               "IMPLEMENTATION ERROR: Cannot recover vamsas object mappings - no backup was made.");
689     }
690     jv2vobj.clear();
691     Iterator el = _backup_jv2vobj.entrySet().iterator();
692     while (el.hasNext())
693     {
694       java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
695       jv2vobj.put(mp.getKey(), mp.getValue());
696     }
697     el = _backup_vobj2jv.entrySet().iterator();
698     while (el.hasNext())
699     {
700       java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
701       vobj2jv.put(mp.getKey(), mp.getValue());
702     }
703   }
704
705   private boolean joinedSession = false;
706
707   private VamsasListener picker = null;
708
709   private SelectionListener selecter;
710
711   private void startSession()
712   {
713     if (inSession())
714     {
715       try
716       {
717         vclient.joinSession();
718         joinedSession = true;
719       } catch (Exception e)
720       {
721         // Complain to GUI
722         Cache.log.error("Failed to join vamsas session.", e);
723         vclient = null;
724       }
725       try
726       {
727         final IPickManager pm = vclient.getPickManager();
728         final StructureSelectionManager ssm = StructureSelectionManager
729                 .getStructureSelectionManager();
730         final SelectionSource me = this;
731         pm.registerMessageHandler(new IMessageHandler()
732         {
733           String last = null;
734
735           public void handleMessage(Message message)
736           {
737             if (vobj2jv == null)
738             {
739               // we are not in a session yet.
740               return;
741             }
742             if (message instanceof MouseOverMessage)
743             {
744               MouseOverMessage mm = (MouseOverMessage) message;
745               String mstring = mm.getVorbaID() + " " + mm.getPosition();
746               if (last != null && mstring.equals(last))
747               {
748                 return;
749               }
750               // if (Cache.log.isDebugEnabled())
751               // {
752               // Cache.log.debug("Received MouseOverMessage "+mm.getVorbaID()+"
753               // "+mm.getPosition());
754               // }
755               Object jvobj = vobj2jv.get(mm.getVorbaID());
756               if (jvobj != null && jvobj instanceof SequenceI)
757               {
758                 last = mstring;
759                 // Cache.log.debug("Handling Mouse over "+mm.getVorbaID()+"
760                 // bound to "+jvobj+" at "+mm.getPosition());
761                 // position is character position in aligned sequence
762                 ssm.mouseOverVamsasSequence((SequenceI) jvobj, mm
763                         .getPosition());
764               }
765             }
766             if (message instanceof uk.ac.vamsas.client.picking.SelectionMessage)
767             {
768               // we only care about AlignmentSequence selections
769               SelectionMessage sm = (SelectionMessage) message;
770               sm.validate();
771               System.err.println("Received\n" + sm.getRawMessage());
772               Object[] jvobjs = sm.getVorbaIDs() == null ? null
773                       : new Object[sm.getVorbaIDs().length];
774               if (jvobjs == null)
775               {
776                 // TODO: rationalise : can only clear a selection over a
777                 // referred to object
778                 ssm.sendSelection(null, null, me);
779                 return;
780               }
781               Class type = null;
782               boolean send = true;
783               for (int o = 0; o < jvobjs.length; o++)
784               {
785                 jvobjs[o] = vobj2jv.get(sm.getVorbaIDs()[o]);
786                 if (jvobjs[o] == null)
787                 {
788                   // can't cope with selections for unmapped objects
789                   // continue;
790                 }
791                 if (type == null)
792                 {
793                   type = jvobjs[o].getClass();
794                 }
795                 ;
796                 if (type != jvobjs[o].getClass())
797                 {
798                   send = false;
799                   // discard - can't cope with selections over mixed objects
800                   // continue;
801                 }
802               }
803               SequenceGroup jselection = null;
804               ColumnSelection colsel = null;
805               if (type == jalview.datamodel.Alignment.class)
806               {
807                 if (jvobjs.length == 1)
808                 {
809                   // TODO if (sm.isNone())// send a message to select the
810                   // specified columns over the
811                   // given
812                   // alignment
813
814                   send = true;
815                 }
816               }
817               if (type == jalview.datamodel.Sequence.class)
818               {
819
820                 SequenceI seq;
821                 boolean aligned = ((jalview.datamodel.Sequence) jvobjs[0])
822                         .getDatasetSequence() != null;
823                 int maxWidth = 0;
824                 if (aligned)
825                 {
826                   jselection = new SequenceGroup();
827                   jselection.addSequence(
828                           seq = (jalview.datamodel.Sequence) jvobjs[0],
829                           false);
830                   maxWidth = seq.getLength();
831                 }
832                 for (int c = 1; aligned && jvobjs.length > 1
833                         && c < jvobjs.length; c++)
834                 {
835                   if (((jalview.datamodel.Sequence) jvobjs[c])
836                           .getDatasetSequence() == null)
837                   {
838                     aligned = false;
839                     continue;
840                   }
841                   else
842                   {
843                     jselection.addSequence(
844                             seq = (jalview.datamodel.Sequence) jvobjs[c],
845                             false);
846                     if (maxWidth < seq.getLength())
847                     {
848                       maxWidth = seq.getLength();
849                     }
850
851                   }
852                 }
853                 if (!aligned)
854                 {
855                   jselection = null;
856                   // if cardinality is greater than one then verify all
857                   // sequences are alignment sequences.
858                   if (jvobjs.length == 1)
859                   {
860                     // find all instances of this dataset sequence in the
861                     // displayed alignments containing the associated range and
862                     // select them.
863                   }
864                 }
865                 else
866                 {
867                   jselection.setStartRes(0);
868                   jselection.setEndRes(maxWidth);
869                   // locate the alignment containing the given sequences and
870                   // select the associated ranges on them.
871                   if (sm.getRanges() != null)
872                   {
873                     int[] prange = uk.ac.vamsas.objects.utils.Range
874                             .getBounds(sm.getRanges());
875                     boolean rangeset = false;
876                     colsel = new ColumnSelection();
877                     prange = uk.ac.vamsas.objects.utils.Range
878                             .getIntervals(sm.getRanges());
879                     for (int p = 0; p < prange.length; p += 2)
880                     {
881                       int d = (prange[p] <= prange[p + 1]) ? 1 : -1;
882                       if (!rangeset)
883                       {
884                         if (jselection != null)
885                         {
886                           // set the bounds of the selected area using the first
887                           // interval.
888                           jselection.setStartRes(prange[p] - 1);
889                           jselection.setEndRes(prange[p + 1] - 1);
890                           rangeset = true;
891                         }
892                       }
893                       else
894                       {
895                         // try to join up adjacent columns to make a larger
896                         // selection
897                         // lower and upper bounds
898                         int l = (d < 0) ? 1 : 0;
899                         int u = (d > 0) ? 1 : 0;
900
901                         if (jselection.getStartRes() > 0
902                                 && prange[p + l] == jselection
903                                         .getStartRes())
904                         {
905                           jselection.setStartRes(prange[p + l] - 1);
906                         }
907                         if (jselection.getEndRes() <= maxWidth
908                                 && prange[p + u] == (jselection.getEndRes() + 2))
909                         {
910                           jselection.setEndRes(prange[p + u] - 1);
911                         }
912                       }
913                       // mark all the columns in the range.
914                       for (int sr = prange[p], er = prange[p + 1], de = er
915                               + d; sr != de; sr += d)
916                       {
917                         colsel.addElement(sr - 1);
918                       }
919                     }
920                   }
921                   send = true;
922                 }
923               }
924               if (send)
925               {
926                 ssm.sendSelection(jselection, colsel, me);
927               }
928               // discard message.
929               for (int c = 0; c < jvobjs.length; c++)
930               {
931                 jvobjs[c] = null;
932               }
933               ;
934               jvobjs = null;
935               return;
936             }
937           }
938         });
939         picker = new VamsasListener()
940         {
941           SequenceI last = null;
942
943           int i = -1;
944
945           public void mouseOver(SequenceI seq, int index)
946           {
947             if (jv2vobj == null)
948               return;
949             if (seq != last || i != index)
950             {
951               VorbaId v = (VorbaId) jv2vobj.get(seq);
952               if (v != null)
953               {
954                 // this should really be a trace message.
955                 // Cache.log.debug("Mouse over " + v.getId() + " bound to "
956                 // + seq + " at " + index);
957                 last = seq;
958                 i = index;
959                 MouseOverMessage message = new MouseOverMessage(v.getId(),
960                         index);
961                 pm.sendMessage(message);
962               }
963             }
964           }
965         };
966         selecter = new SelectionListener()
967         {
968
969           public void selection(SequenceGroup seqsel,
970                   ColumnSelection colsel, SelectionSource source)
971           {
972             if (vobj2jv == null)
973             {
974               Cache.log
975                       .warn("Selection listener still active for dead session.");
976               // not in a session.
977               return;
978             }
979             if (source != me)
980             {
981               AlignmentI visal = null;
982               if (source instanceof AlignViewport)
983               {
984                 visal = ((AlignViewport) source).getAlignment();
985               }
986               SelectionMessage sm = null;
987               if ((seqsel == null || seqsel.getSize() == 0)
988                       && (colsel == null || colsel.getSelected() == null || colsel
989                               .getSelected().size() == 0))
990               {
991                 if (source instanceof AlignViewport)
992                 {
993                   // the empty selection.
994                   sm = new SelectionMessage("jalview", new String[]
995                   { ((AlignViewport) source).getSequenceSetId() }, null,
996                           true);
997                 }
998                 else
999                 {
1000                   // the empty selection.
1001                   sm = new SelectionMessage("jalview", null, null, true);
1002                 }
1003               }
1004               else
1005               {
1006                 String[] vobj = new String[seqsel.getSize()];
1007                 int o = 0;
1008                 Enumeration sels = seqsel.getSequences(null).elements();
1009                 while (sels.hasMoreElements())
1010                 {
1011                   SequenceI sel = (SequenceI) sels.nextElement();
1012                   VorbaId v = (VorbaId) jv2vobj.get(sel);
1013                   if (v != null)
1014                   {
1015                     vobj[o++] = v.toString();
1016                   }
1017                 }
1018                 if (o < vobj.length)
1019                 {
1020                   String t[] = vobj;
1021                   vobj = new String[o];
1022                   System.arraycopy(t, 0, vobj, 0, o);
1023                   t = null;
1024                 }
1025                 Input range = null;
1026                 if (seqsel != null && colsel != null)
1027                 {
1028                   // deparse the colsel into positions on the vamsas alignment
1029                   // sequences
1030                   range = new Input();
1031                   if (colsel.getSelected() != null
1032                           && colsel.getSelected().size() > 0
1033                           && visal != null
1034                           && seqsel.getSize() == visal.getHeight())
1035                   {
1036                     // gather selected columns outwith the sequence positions
1037                     // too
1038                     Enumeration cols = colsel.getSelected().elements();
1039                     while (cols.hasMoreElements())
1040                     {
1041                       int ival = ((Integer) cols.nextElement()).intValue();
1042                       Pos p = new Pos();
1043                       p.setI(ival + 1);
1044                       range.addPos(p);
1045                     }
1046                   }
1047                   else
1048                   {
1049                     int[] intervals = colsel.getVisibleContigs(seqsel
1050                             .getStartRes(), seqsel.getEndRes() + 1);
1051                     for (int iv = 0; iv < intervals.length; iv += 2)
1052                     {
1053                       Seg s = new Seg();
1054                       s.setStart(intervals[iv] + 1); // vamsas indices begin at
1055                                                      // 1, not zero.
1056                       s.setEnd(intervals[iv + 1] + 1);
1057                       s.setInclusive(true);
1058                       range.addSeg(s);
1059                     }
1060                   }
1061                 }
1062                 if (vobj.length > 0)
1063                 {
1064                   sm = new SelectionMessage("jalview", vobj, range);
1065                 }
1066                 else
1067                 {
1068                   sm = null;
1069                 }
1070               }
1071               if (sm != null)
1072               {
1073                 sm.validate(); // debug
1074                 Cache.log.debug("Selection Message\n" + sm.getRawMessage());
1075                 pm.sendMessage(sm);
1076               }
1077             }
1078           }
1079
1080         };
1081         ssm.addStructureViewerListener(picker); // better method here
1082         ssm.addSelectionListener(selecter);
1083       } catch (Exception e)
1084       {
1085         Cache.log.error("Failed to init Vamsas Picking", e);
1086       }
1087     }
1088   }
1089
1090   public String getCurrentSession()
1091   {
1092     if (vclient != null)
1093     {
1094       return (vclient.getSessionUrn());
1095     }
1096     return null;
1097   }
1098 }