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