vamsas mouseOvers
[jalview.git] / src / jalview / gui / VamsasApplication.java
1 /**
2  *
3  */
4 package jalview.gui;
5
6 import jalview.bin.Cache;
7 import jalview.datamodel.SequenceI;
8 import jalview.io.VamsasAppDatastore;
9 import jalview.structure.StructureSelectionManager;
10 import jalview.structure.VamsasListener;
11
12 import java.beans.PropertyChangeEvent;
13 import java.beans.PropertyChangeListener;
14 import java.io.File;
15 import java.io.IOException;
16 import java.util.Hashtable;
17 import java.util.IdentityHashMap;
18
19 import javax.swing.JInternalFrame;
20
21 import uk.ac.vamsas.client.ClientHandle;
22 import uk.ac.vamsas.client.IClient;
23 import uk.ac.vamsas.client.IClientDocument;
24 import uk.ac.vamsas.client.NoDefaultSessionException;
25 import uk.ac.vamsas.client.UserHandle;
26 import uk.ac.vamsas.client.VorbaId;
27 import uk.ac.vamsas.client.picking.IMessageHandler;
28 import uk.ac.vamsas.client.picking.IPickManager;
29 import uk.ac.vamsas.client.picking.Message;
30 import uk.ac.vamsas.client.picking.MouseOverMessage;
31 import uk.ac.vamsas.objects.core.Entry;
32 /**
33  * @author jimp
34  *
35  */
36 public class VamsasApplication
37 {
38   IClient vclient=null;
39   ClientHandle app=null;
40   UserHandle user=null;
41   
42   Desktop jdesktop = null; // our jalview desktop reference
43   
44   // Cache.preferences for vamsas client session arena
45   // preferences for check for default session at startup.
46   // user and organisation stuff.
47   public VamsasApplication(Desktop jdesktop,
48                       File sessionPath)
49   {
50     // JBPNote:
51     // we should create a session URI from the sessionPath and pass it to
52     // the clientFactory - but the vamsas api doesn't cope with that yet.
53     this(jdesktop);
54     throw new Error("Sorry - can't start from session file yet."); // make this a warning
55   }
56   private static uk.ac.vamsas.client.IClientFactory getClientFactory() throws IOException {
57     return new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
58   }
59   public VamsasApplication(Desktop jdesktop)
60   {
61     this.jdesktop = jdesktop; 
62     initClientSession(null);
63   }
64   /**
65    * @throws IOException or other if clientfactory instantiation failed.
66    * @return list of current sessions or null if no session exists.
67    */
68   public static String[] getSessionList() throws Exception {
69     return getClientFactory().getCurrentSessions();
70   }
71   /**
72    * initialise, possibly with e valid session url
73    * @param sess
74    * @return
75    */
76   private boolean initClientSession(String sess) {
77     try {
78       // Only need to tell the library what the application is here
79       app = new ClientHandle("jalview.bin.Jalview", jalview.bin.Cache.getProperty("VERSION"));
80       uk.ac.vamsas.client.IClientFactory clientfactory = getClientFactory();
81       if (sess==null)
82       {
83         vclient = clientfactory.getIClient(app);
84       }
85       else
86       {
87         vclient = clientfactory.getIClient(app,sess);
88       }
89       
90       user = vclient.getUserHandle();
91       
92     } catch (NoDefaultSessionException e)
93     {
94       return false;
95     }
96     catch (Exception e)
97     {
98       jalview.bin.Cache.log.error("Couldn't instantiate vamsas client !",e);
99       return false;
100     }
101     return true;
102   }
103   /**
104    * 
105    * @return true if we are registered in a vamsas session
106    */
107   public boolean inSession()
108   {
109     return (vclient!=null);
110   }
111   /**
112    * called to connect to session
113    * inits handlers, does an initial document update.
114    */
115   public void initial_update()
116   {
117     if (!inSession())
118     {
119       throw new Error("Impementation error! Vamsas Operations when client not initialised and connected.");
120     }
121     addDocumentUpdateHandler();
122     startSession();
123     Cache.log.debug("Jalview loading the Vamsas Session for the first time.");
124     dealWithDocumentUpdate(false); // we don't push an update out to the document yet.
125     Cache.log.debug("... finished update for the first time.");
126   }
127   /**
128    * Update all windows after a vamsas datamodel change.
129    * this could go on the desktop object!
130    * 
131    */
132   protected void updateJalviewGui() 
133   {
134     JInternalFrame[] frames = jdesktop.getAllFrames();
135
136     if (frames == null)
137     {
138       return;
139     }
140
141     try
142     {
143       //REVERSE ORDER
144       for (int i = frames.length - 1; i > -1; i--)
145       {
146         if (frames[i] instanceof AlignFrame)
147         {
148           AlignFrame af = (AlignFrame) frames[i];
149           af.alignPanel.alignmentChanged();
150         }
151       }
152     }
153     catch (Exception e)
154     {
155       Cache.log.warn(
156           "Exception whilst refreshing jalview windows after a vamsas document update.",
157           e);
158     }
159   }
160   public void push_update()
161   {
162     Cache.log.info("Jalview updating to the Vamsas Session.");
163     dealWithDocumentUpdate(true);
164     /*
165     IClientDocument cdoc=null;
166     try
167     {
168       cdoc = vclient.getClientDocument();
169     }
170     catch (Exception e)
171     {
172       Cache.log.error("Failed to get client document for update.");
173       // RAISE A WARNING DIALOG
174       disableGui(false);
175       return;
176     }
177     updateVamsasDocument(cdoc);
178     updateJalviewGui();
179     cdoc.setVamsasRoots(cdoc.getVamsasRoots()); // propagate update flags back
180     vclient.updateDocument(cdoc);
181     */
182     Cache.log.info("Jalview finished updating to the Vamsas Session.");
183   }
184
185   public void end_session()
186   {
187     if (!inSession())
188       throw new Error("Jalview not connected to Vamsas session.");
189     Cache.log.info("Jalview disconnecting from the Vamsas Session.");
190     try
191     {
192       if (joinedSession) {
193         vclient.finalizeClient();
194         Cache.log.info("Jalview has left the session.");
195       } else {
196         Cache.log.warn("JV Client leaving a session that's its not joined yet.");
197       }
198       joinedSession=false;
199       vclient = null;
200       app=null; user = null;
201       jv2vobj = null;
202       vobj2jv = null;
203     }
204     catch (Exception e)
205     {
206       Cache.log.error("Vamsas Session finalization threw exceptions!",e);
207     }
208   }
209
210   public void updateJalview(IClientDocument cdoc)
211   {
212     Cache.log.debug("Jalview updating from sesion document ..");
213     ensureJvVamsas();
214     VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj,
215                                               baseProvEntry());
216     vds.updateToJalview();
217     Cache.log.debug(".. finished updating from sesion document.");
218     
219   }
220   private void ensureJvVamsas()
221   {
222     if (jv2vobj == null)
223     {
224       jv2vobj = new IdentityHashMap();
225       vobj2jv = new Hashtable();
226     }
227   }
228
229   /**
230    * jalview object binding to VorbaIds
231    */
232   IdentityHashMap jv2vobj = null;
233   Hashtable vobj2jv = null;
234   public void updateVamsasDocument(IClientDocument doc)
235   {
236     ensureJvVamsas();
237     VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj,
238                                               baseProvEntry());
239     // wander through frames
240     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
241
242     if (frames == null)
243     {
244       return;
245     }
246
247     try
248     {
249       //REVERSE ORDER
250       for (int i = frames.length - 1; i > -1; i--)
251       {
252         if (frames[i] instanceof AlignFrame)
253         {
254           AlignFrame af = (AlignFrame) frames[i];
255
256           // update alignment and root from frame.
257           vds.storeVAMSAS(af.getViewport(), af.getTitle());
258         }
259       }
260     }
261     catch (Exception e)
262     {
263       Cache.log.error("Vamsas Document store exception", e);
264     }
265   }
266
267   private Entry baseProvEntry()
268   {
269     uk.ac.vamsas.objects.core.Entry pentry = new uk.ac.vamsas.objects.core.Entry();
270     pentry.setUser(user.getFullName());
271     pentry.setApp(app.getClientUrn());
272     pentry.setDate(new java.util.Date());
273     pentry.setAction("created");
274     return pentry;
275   }
276   /**
277    * do a vamsas document update or update jalview from the vamsas document
278    * @param fromJalview true to update from jalview to the vamsas document
279    */
280   protected void dealWithDocumentUpdate(boolean fromJalview)
281   {
282     // called by update handler for document update.
283     Cache.log.debug("Updating jalview from changed vamsas document.");
284     disableGui(true);
285     try {
286       long time = System.currentTimeMillis();
287       IClientDocument cdoc = vclient.getClientDocument();
288       if (Cache.log.isDebugEnabled())
289       {
290         Cache.log.debug("Time taken to get ClientDocument = "+(System.currentTimeMillis()-time));
291         time = System.currentTimeMillis();
292       }
293       if (fromJalview)
294       {
295         this.updateVamsasDocument(cdoc);
296         if (Cache.log.isDebugEnabled())
297         {
298           Cache.log.debug("Time taken to update Vamsas Document from jalview\t= "+(System.currentTimeMillis()-time));
299           time = System.currentTimeMillis();
300         }
301         cdoc.setVamsasRoots(cdoc.getVamsasRoots());
302         if (Cache.log.isDebugEnabled())
303         {
304           Cache.log.debug("Time taken to set Document Roots\t\t= "+(System.currentTimeMillis()-time));
305           time = System.currentTimeMillis();
306         }
307       } else
308       {
309         updateJalview(cdoc);
310         if (Cache.log.isDebugEnabled())
311         {
312           Cache.log.debug("Time taken to update Jalview from vamsas document Roots\t= "+(System.currentTimeMillis()-time));
313           time = System.currentTimeMillis();
314         }
315
316       }
317       vclient.updateDocument(cdoc);
318       if (Cache.log.isDebugEnabled())
319       {
320         Cache.log.debug("Time taken to update Session Document\t= "+(System.currentTimeMillis()-time));
321         time = System.currentTimeMillis();
322       }
323       cdoc=null;
324     } catch (Exception ee) {
325       System.err.println("Exception whilst updating :");
326       ee.printStackTrace(System.err);
327     }
328     Cache.log.debug("Finished updating from document change.");
329     disableGui(false);
330   }
331   private void addDocumentUpdateHandler()
332   {
333     final VamsasApplication client = this;
334     vclient.addDocumentUpdateHandler(new PropertyChangeListener() {
335       public void propertyChange(PropertyChangeEvent evt)
336       {
337         Cache.log.debug("Dealing with document update event.");
338         client.dealWithDocumentUpdate(false);
339         Cache.log.debug("finished dealing with event.");
340       }
341     });
342     Cache.log.debug("Added Jalview handler for vamsas document updates.");
343   }
344   public void disableGui(boolean b)
345   {
346     Desktop.instance.setVamsasUpdate(b);
347   }
348   private boolean joinedSession=false;
349   private VamsasListener picker=null;
350   private void startSession()
351   {
352     if (inSession())
353     {
354       try {
355         vclient.joinSession();
356         joinedSession=true;
357       }
358       catch (Exception e)
359       {
360         // Complain to GUI
361         Cache.log.error("Failed to join vamsas session.",e);
362         vclient=null;
363       }
364       try {
365         final IPickManager pm = vclient.getPickManager();
366         final StructureSelectionManager ssm = StructureSelectionManager.getStructureSelectionManager();
367         pm.registerMessageHandler(new IMessageHandler() {
368           String last=null;
369           public void handleMessage(Message message)
370           {
371             if (message instanceof MouseOverMessage && vobj2jv!=null)
372             {
373               MouseOverMessage mm = (MouseOverMessage) message;
374               String mstring = mm.getVorbaID()+" "+mm.getPosition();
375               if (last!=null && mstring.equals(last))
376               {
377                 return;
378               }
379               Object jvobj = vobj2jv.get(mm.getVorbaID());
380               if (jvobj != null && jvobj instanceof SequenceI)
381               {
382                 last = mstring;
383                 // Cache.log.debug("Handling Mouse over "+mm.getVorbaID()+" bound to "+jvobj+" at "+mm.getPosition());
384                 // position is in sequence or in aligned sequence ???????
385                 ssm.mouseOverVamsasSequence((SequenceI) jvobj, mm.getPosition());
386               }
387             }
388           }
389         });
390         picker = new VamsasListener() {
391           SequenceI last=null;
392           int i=-1;
393           public void mouseOver(SequenceI seq, int index)
394           {
395             if (seq!=last || i!=index)
396             {
397               VorbaId v = (VorbaId) jv2vobj.get(seq);
398               if (v!=null)
399               {
400                 // Cache.log.debug("Mouse over "+v.getId()+" bound to "+seq+" at "+index);
401                 last = seq;
402                 i=index;
403                 MouseOverMessage message = new MouseOverMessage(v.getId(), index);
404                 pm.sendMessage(message);
405               }
406             }
407           }
408         };
409         ssm.addStructureViewerListener(picker); // better method here
410       } catch (Exception e)
411       {
412         Cache.log.error("Failed to init Vamsas Picking",e);
413       }
414     }
415   }
416 }