remove unnecessary import
[jalview.git] / src / jalview / io / VamsasDatastore.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.io;\r
21 \r
22 import org.vamsas.client.Vobject;\r
23 import org.vamsas.client.VorbaId;\r
24 import org.vamsas.objects.core.*;\r
25 import org.vamsas.objects.utils.DocumentStuff;\r
26 import org.vamsas.test.simpleclient.ClientDoc;\r
27 \r
28 import jalview.bin.Cache;\r
29 import jalview.datamodel.AlignmentAnnotation;\r
30 import jalview.datamodel.AlignmentI;\r
31 import jalview.datamodel.AlignmentView;\r
32 import jalview.datamodel.DBRefEntry;\r
33 import jalview.datamodel.SequenceFeature;\r
34 import jalview.datamodel.SequenceI;\r
35 import jalview.gui.*;\r
36 \r
37 import java.util.HashMap;\r
38 import java.util.HashSet;\r
39 import java.util.Hashtable;\r
40 import java.util.IdentityHashMap;\r
41 import java.util.Vector;\r
42 import java.util.jar.*;\r
43 import org.exolab.castor.xml.*;\r
44 import org.exolab.castor.mapping.Mapping;\r
45 \r
46 /*\r
47  *\r
48  * static {\r
49  * org.exolab.castor.util.LocalConfiguration.getInstance().getProperties().setProperty(\r
50  * "org.exolab.castor.serializer", "org.apache.xml.serialize.XMLSerilazizer"); }\r
51  *\r
52  */\r
53 \r
54 public class VamsasDatastore {\r
55   Entry provEntry = null;\r
56 \r
57   // AlignViewport av;\r
58 \r
59   org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(\r
60       new java.util.Date());\r
61 \r
62   ClientDoc cdoc;\r
63 \r
64   Hashtable vobj2jv;\r
65 \r
66   IdentityHashMap jv2vobj;\r
67 \r
68   public VamsasDatastore(ClientDoc cdoc, Hashtable vobj2jv,\r
69       IdentityHashMap jv2vobj, Entry provEntry) {\r
70       this.cdoc = cdoc;\r
71     this.vobj2jv = vobj2jv;\r
72     this.jv2vobj = jv2vobj;\r
73     this.provEntry = provEntry;\r
74   }\r
75 \r
76   /*\r
77    * public void storeJalview(String file, AlignFrame af) { try { // 1. Load the\r
78    * mapping information from the file Mapping map = new\r
79    * Mapping(getClass().getClassLoader()); java.net.URL url =\r
80    * getClass().getResource("/jalview_mapping.xml"); map.loadMapping(url); // 2.\r
81    * Unmarshal the data // Unmarshaller unmar = new Unmarshaller();\r
82    * //unmar.setIgnoreExtraElements(true); //unmar.setMapping(map); // uni =\r
83    * (UniprotFile) unmar.unmarshal(new FileReader(file)); // 3. marshal the data\r
84    * with the total price back and print the XML in the console Marshaller\r
85    * marshaller = new Marshaller( new FileWriter(file) );\r
86    *\r
87    * marshaller.setMapping(map); marshaller.marshal(af); } catch (Exception e) {\r
88    * e.printStackTrace(); } }\r
89    *\r
90    *\r
91    */\r
92   /**\r
93    * @return the Vobject bound to Jalview datamodel object\r
94    */\r
95   protected Vobject getjv2vObj(Object jvobj) {\r
96     if (jv2vobj.containsKey(jvobj))\r
97       return cdoc.getObject((VorbaId) jv2vobj.get(jvobj));\r
98     return null;\r
99   }\r
100 \r
101   /**\r
102    *\r
103    * @param vobj\r
104    * @return Jalview datamodel object bound to the vamsas document object\r
105    */\r
106   protected Object getvObj2jv(org.vamsas.client.Vobject vobj) {\r
107     VorbaId id = vobj.getVorbaId();\r
108     if (id == null)\r
109     {\r
110       id = cdoc.registerObject(vobj);\r
111       Cache.log\r
112       .debug("Registering new object and returning null for getvObj2jv");\r
113       return null;\r
114     }\r
115     if (vobj2jv.containsKey(vobj.getVorbaId()))\r
116       return vobj2jv.get(vobj.getVorbaId());\r
117     return null;\r
118   }\r
119 \r
120   protected void bindjvvobj(Object jvobj, org.vamsas.client.Vobject vobj) {\r
121     VorbaId id = vobj.getVorbaId();\r
122     if (id == null)\r
123     {\r
124       id = cdoc.registerObject(vobj);\r
125       if (id==null || vobj.getVorbaId()==null)\r
126         Cache.log.error("Failed to get id for "+(vobj.isRegisterable() ? "registerable" : "unregisterable") +" object "+vobj);\r
127     }\r
128 \r
129     if (vobj2jv.containsKey(vobj.getVorbaId()) && !((VorbaId)vobj2jv.get(vobj.getVorbaId())).equals(jvobj)) {\r
130       Cache.log.debug("Warning? Overwriting existing vamsas id binding for "+vobj.getVorbaId(), new Exception("Overwriting vamsas id binding."));\r
131     }\r
132     else if (jv2vobj.containsKey(jvobj) && !((VorbaId)jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))\r
133     {\r
134       Cache.log.debug("Warning? Overwriting existing jalview object binding for "+jvobj, new Exception("Overwriting jalview object binding."));\r
135     }\r
136     /* Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id " +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+" already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to bindjvvobj"));\r
137     }*/\r
138     // we just update the hash's regardless!\r
139     vobj2jv.put(vobj.getVorbaId(), jvobj);\r
140     // JBPNote - better implementing a hybrid invertible hash.\r
141     jv2vobj.put(jvobj, vobj.getVorbaId());\r
142   }\r
143 \r
144   /**\r
145    * put the alignment viewed by AlignViewport into cdoc.\r
146    *\r
147    * @param av alignViewport to be stored\r
148    * @param aFtitle title for alignment\r
149    */\r
150   public void storeVAMSAS(AlignViewport av, String aFtitle) {\r
151     try\r
152     {\r
153       jalview.datamodel.AlignmentI jal = av.getAlignment();\r
154       boolean nw = false;\r
155       VAMSAS root = null; // will be resolved based on Dataset Parent.\r
156       // /////////////////////////////////////////\r
157       // SAVE THE DATASET\r
158       if (jal.getDataset() == null)\r
159       {\r
160         Cache.log.warn("Creating new dataset for an alignment.");\r
161         jal.setDataset(null);\r
162       }\r
163       DataSet dataset = (DataSet) getjv2vObj(jal.getDataset());\r
164       if (dataset == null)\r
165       {\r
166         root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying.\r
167         dataset = new DataSet();\r
168         root.addDataSet(dataset);\r
169         bindjvvobj(jal.getDataset(), dataset);\r
170         dataset.setProvenance(dummyProvenance());\r
171         dataset.getProvenance().addEntry(provEntry);\r
172         nw = true;\r
173       }\r
174       else\r
175       {\r
176         root = (VAMSAS) dataset.getV_parent();\r
177       }\r
178       // update dataset\r
179       Sequence sequence;\r
180       DbRef dbref;\r
181       // set new dataset and alignment sequences based on alignment Nucleotide\r
182       // flag.\r
183       // this *will* break when alignment contains both nucleotide and amino\r
184       // acid sequences.\r
185       String dict = jal.isNucleotide() ? org.vamsas.objects.utils.SymbolDictionary.STANDARD_NA\r
186           : org.vamsas.objects.utils.SymbolDictionary.STANDARD_AA;\r
187       for (int i = 0; i < jal.getHeight(); i++)\r
188       {\r
189         SequenceI sq = jal.getSequenceAt(i).getDatasetSequence(); // only insert\r
190         // referenced\r
191         // sequences\r
192         // to dataset.\r
193         sequence = (Sequence) getjv2vObj(sq);\r
194         if (sequence == null)\r
195         {\r
196           sequence = new Sequence();\r
197           bindjvvobj(sq, sequence);\r
198           sq.setVamsasId(sequence.getVorbaId().getId());\r
199           sequence.setSequence(sq.getSequenceAsString());\r
200           sequence.setDictionary(dict);\r
201           sequence.setName(jal.getDataset().getSequenceAt(i).getName());\r
202           sequence.setStart(jal.getDataset().getSequenceAt(i).getStart());\r
203           sequence.setEnd(jal.getDataset().getSequenceAt(i).getEnd());\r
204           dataset.addSequence(sequence);\r
205         }\r
206         else\r
207         {\r
208           // verify principal attributes. and update any new\r
209           // features/references.\r
210           System.out.println("update dataset sequence object.");\r
211         }\r
212         if (sq.getSequenceFeatures() != null)\r
213         {\r
214           int sfSize = sq.getSequenceFeatures().length;\r
215 \r
216           for (int sf = 0; sf < sfSize; sf++)\r
217           {\r
218             jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) sq\r
219             .getSequenceFeatures()[sf];\r
220 \r
221             DataSetAnnotations dsa = (DataSetAnnotations) getjv2vObj(feature);\r
222             if (dsa == null)\r
223             {\r
224               dsa = (DataSetAnnotations) getDSAnnotationFromJalview(\r
225                   new DataSetAnnotations(), feature);\r
226               if (dsa.getProvenance() == null)\r
227               {\r
228                 dsa.setProvenance(new Provenance());\r
229               }\r
230               addProvenance(dsa.getProvenance(), "created"); // JBPNote - need\r
231               // to update\r
232               dsa.setSeqRef(sequence);\r
233               bindjvvobj(feature, dsa);\r
234               dataset.addDataSetAnnotations(dsa);\r
235             }\r
236             else\r
237             {\r
238               // todo: verify and update dataset annotations for sequence\r
239               System.out.println("update dataset sequence annotations.");\r
240             }\r
241           }\r
242         }\r
243 \r
244         if (sq.getDBRef() != null)\r
245         {\r
246           DBRefEntry[] entries = sq.getDBRef();\r
247           jalview.datamodel.DBRefEntry dbentry;\r
248           for (int db = 0; db < entries.length; db++)\r
249           {\r
250             dbentry = entries[db];\r
251             dbref = (DbRef) getjv2vObj(dbentry);\r
252             if (dbref == null)\r
253             {\r
254               dbref = new DbRef();\r
255               bindjvvobj(dbentry, dbref);\r
256               dbref.setAccessionId(dbentry.getAccessionId());\r
257               dbref.setSource(dbentry.getSource());\r
258               dbref.setVersion(dbentry.getVersion());\r
259               /*\r
260                * TODO: Maps are not yet supported by Jalview. Map vMap = new\r
261                * Map(); vMap.set dbref.addMap(vMap);\r
262                */\r
263               sequence.addDbRef(dbref);\r
264             }\r
265             else\r
266             {\r
267               // TODO: verify and update dbrefs in vamsas document\r
268               // there will be trouble when a dataset sequence is modified to\r
269               // contain more residues than were originally referenced - we must\r
270               // then make a number of dataset sequence entries\r
271               System.out\r
272               .println("update dataset sequence database references.");\r
273             }\r
274           }\r
275 \r
276         }\r
277       }\r
278       // dataset.setProvenance(getVamsasProvenance(jal.getDataset().getProvenance()));\r
279       // ////////////////////////////////////////////\r
280 \r
281       // ////////////////////////////////////////////\r
282       // Save the Alignments\r
283 \r
284       Alignment alignment = (Alignment) getjv2vObj(av); // this is so we can get the alignviewport back\r
285       if (alignment == null)\r
286       {\r
287         alignment = new Alignment();\r
288         bindjvvobj(av, alignment);\r
289         if (alignment.getProvenance() == null)\r
290           alignment.setProvenance(new Provenance());\r
291         addProvenance(alignment.getProvenance(), "added"); // TODO: insert some\r
292         // sensible source\r
293         // here\r
294         dataset.addAlignment(alignment);\r
295         {\r
296           Property title = new Property();\r
297           title.setName("jalview:AlTitle");\r
298           title.setType("string");\r
299           title.setContent(aFtitle);\r
300           alignment.addProperty(title);\r
301         }\r
302         alignment.setGapChar(String.valueOf(av.getGapCharacter()));\r
303         AlignmentSequence alseq = null;\r
304         for (int i = 0; i < jal.getHeight(); i++)\r
305         {\r
306           alseq = new AlignmentSequence();\r
307           // TODO: VAMSAS: translate lowercase symbols to annotation ?\r
308           alseq.setSequence(jal.getSequenceAt(i).getSequenceAsString());\r
309           alseq.setName(jal.getSequenceAt(i).getName());\r
310           alseq.setStart(jal.getSequenceAt(i).getStart());\r
311           alseq.setEnd(jal.getSequenceAt(i).getEnd());\r
312           alseq.setRefid(getjv2vObj(jal.getSequenceAt(i).getDatasetSequence()));\r
313           alignment.addAlignmentSequence(alseq);\r
314           bindjvvobj(jal.getSequenceAt(i), alseq);\r
315         }\r
316       }\r
317       else\r
318       {\r
319         // todo: verify and update mutable alignment props.\r
320         if (alignment.getModifiable())\r
321         {\r
322           System.out.println("update alignment in document.");\r
323         }\r
324         else\r
325         {\r
326           System.out\r
327           .println("update edited alignment to new alignment in document.");\r
328         }\r
329       }\r
330       // ////////////////////////////////////////////\r
331       // SAVE Alignment Sequence Features\r
332       for (int i = 0, iSize = alignment.getAlignmentSequenceCount(); i < iSize; i++)\r
333       {\r
334         AlignmentSequence valseq;\r
335         SequenceI alseq = (SequenceI) getvObj2jv(valseq = alignment\r
336             .getAlignmentSequence(i));\r
337         if (alseq != null && alseq.getSequenceFeatures() != null)\r
338         {\r
339           jalview.datamodel.SequenceFeature[] features = alseq\r
340           .getSequenceFeatures();\r
341           for (int f = 0; f < features.length; f++)\r
342           {\r
343             if (features[f] != null)\r
344             {\r
345               AlignmentSequenceAnnotation valseqf = (AlignmentSequenceAnnotation) getjv2vObj(features[i]);\r
346               if (valseqf == null)\r
347               {\r
348 \r
349                 valseqf = (AlignmentSequenceAnnotation) getDSAnnotationFromJalview(\r
350                     new AlignmentSequenceAnnotation(), features[i]);\r
351                 if (valseqf.getProvenance() == null)\r
352                 {\r
353                   valseqf.setProvenance(new Provenance());\r
354                 }\r
355                 addProvenance(valseqf.getProvenance(), "created"); // JBPNote -\r
356                 // need to\r
357                 // update\r
358                 bindjvvobj(features[i], valseqf);\r
359                 valseq.addAlignmentSequenceAnnotation(valseqf);\r
360               }\r
361             }\r
362 \r
363           }\r
364         }\r
365       }\r
366 \r
367       // ////////////////////////////////////////////\r
368       // SAVE ANNOTATIONS\r
369       if (jal.getAlignmentAnnotation() != null)\r
370       {\r
371         jalview.datamodel.AlignmentAnnotation[] aa = jal\r
372         .getAlignmentAnnotation();\r
373         java.util.HashMap AlSeqMaps = new HashMap(); // stores int maps from\r
374         // alignment columns to\r
375         // sequence positions.\r
376         for (int i = 0; i < aa.length; i++)\r
377         {\r
378           if (aa[i] == null || isJalviewOnly(aa[i]))\r
379           {\r
380             continue;\r
381           }\r
382           if (aa[i].sequenceRef != null)\r
383           {\r
384             org.vamsas.objects.core.AlignmentSequence alsref = (org.vamsas.objects.core.AlignmentSequence) getjv2vObj(aa[i].sequenceRef);\r
385             org.vamsas.objects.core.AlignmentSequenceAnnotation an = (org.vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(aa[i]);\r
386             int[] gapMap = null;\r
387             if (AlSeqMaps.containsKey(aa[i].sequenceRef))\r
388             {\r
389               gapMap = (int[]) AlSeqMaps.get(aa[i].sequenceRef);\r
390             }\r
391             else\r
392             {\r
393               gapMap = new int[aa[i].sequenceRef.getLength()];\r
394               // map from alignment position to sequence position.\r
395               int[] sgapMap = aa[i].sequenceRef.gapMap();\r
396               for (int a = 0; a < sgapMap.length; a++)\r
397                 gapMap[sgapMap[a]] = a;\r
398             }\r
399             if (an == null)\r
400             {\r
401               an = new org.vamsas.objects.core.AlignmentSequenceAnnotation();\r
402               Seg vSeg = new Seg();\r
403               vSeg.setStart(1);\r
404               vSeg.setInclusive(true);\r
405               vSeg.setEnd(gapMap.length);\r
406               an.addSeg(vSeg);\r
407               an.setType("jalview:SecondaryStructurePrediction");// TODO: better fix this rough guess ;)\r
408               alsref.addAlignmentSequenceAnnotation(an);\r
409               bindjvvobj(aa[i],an);\r
410               // LATER: much of this is verbatim from the alignmentAnnotation\r
411               // method below. suggests refactoring to make rangeAnnotation the\r
412               // base class\r
413               an.setDescription(aa[i].description);\r
414               if (aa[i].graph > 0)\r
415                 an.setGraph(true); // aa[i].graph);\r
416               else\r
417                 an.setGraph(false);\r
418               an.setLabel(aa[i].label);\r
419               an.setProvenance(dummyProvenance()); // get provenance as user\r
420               // created, or jnet, or\r
421               // something else.\r
422               an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -\r
423               // originally we\r
424               // were going to\r
425               // store\r
426               // graphGroup in\r
427               // the Jalview\r
428               // specific\r
429               // bits.\r
430               AnnotationElement ae;\r
431               for (int a = 0; a < aa[i].annotations.length; a++)\r
432               {\r
433                 if (aa[i].annotations[a] == null)\r
434                 {\r
435                   continue;\r
436                 }\r
437 \r
438                 ae = new AnnotationElement();\r
439                 ae.setDescription(aa[i].annotations[a].description);\r
440                 ae.addGlyph(new Glyph());\r
441                 ae.getGlyph(0)\r
442                 .setContent(aa[i].annotations[a].displayCharacter); // assume\r
443                 // jax-b\r
444                 // takes\r
445                 // care\r
446                 // of\r
447                 // utf8\r
448                 // translation\r
449                 if (aa[i].graph!=jalview.datamodel.AlignmentAnnotation.NO_GRAPH)\r
450                   ae.addValue(aa[i].annotations[a].value);\r
451                 ae.setPosition(gapMap[a]+1); // position w.r.t. AlignmentSequence\r
452                 // symbols\r
453                 if (aa[i].annotations[a].secondaryStructure != ' ')\r
454                 {\r
455                   // we only write an annotation where it really exists.\r
456                   Glyph ss = new Glyph();\r
457                   ss\r
458                   .setDict(org.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);\r
459                   ss.setContent(String\r
460                       .valueOf(aa[i].annotations[a].secondaryStructure));\r
461                   ae.addGlyph(ss);\r
462                 }\r
463                 an.addAnnotationElement(ae);\r
464               }\r
465             }\r
466             else\r
467             {\r
468               // update reference sequence Annotation\r
469               if (an.getModifiable())\r
470               {\r
471                 // verify existing alignment sequence annotation is up to date\r
472                 System.out.println("update alignment sequence annotation.");\r
473               }\r
474               else\r
475               {\r
476                 // verify existing alignment sequence annotation is up to date\r
477                 System.out\r
478                 .println("make new alignment sequence annotation if modification has happened.");\r
479               }\r
480             }\r
481           }\r
482           else\r
483           {\r
484             // add Alignment Annotation\r
485             org.vamsas.objects.core.AlignmentAnnotation an = (org.vamsas.objects.core.AlignmentAnnotation) getjv2vObj(aa[i]);\r
486             if (an == null)\r
487             {\r
488               an = new org.vamsas.objects.core.AlignmentAnnotation();\r
489               an.setType("jalview:AnnotationRow");\r
490               an.setDescription(aa[i].description);\r
491               alignment.addAlignmentAnnotation(an);\r
492               Seg vSeg = new Seg();\r
493               vSeg.setStart(1);\r
494               vSeg.setInclusive(true);\r
495               vSeg.setEnd(jal.getWidth());\r
496               an.addSeg(vSeg);\r
497               if (aa[i].graph > 0)\r
498                 an.setGraph(true); // aa[i].graph);\r
499               an.setLabel(aa[i].label);\r
500               an.setProvenance(dummyProvenance());\r
501               if (aa[i].graph!=aa[i].NO_GRAPH) {\r
502                 an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -\r
503                 // originally we\r
504               // were going to\r
505               // store\r
506               // graphGroup in\r
507               // the Jalview\r
508               // specific\r
509               // bits.\r
510                 an.setGraph(true);\r
511               } else {\r
512                 an.setGraph(false);\r
513               }\r
514               AnnotationElement ae;\r
515 \r
516               for (int a = 0; a < aa[i].annotations.length; a++)\r
517               {\r
518                 if ((aa[i] == null) || (aa[i].annotations[a] == null))\r
519                 {\r
520                   continue;\r
521                 }\r
522 \r
523                 ae = new AnnotationElement();\r
524                 ae.setDescription(aa[i].annotations[a].description);\r
525                 ae.addGlyph(new Glyph());\r
526                 ae.getGlyph(0)\r
527                 .setContent(aa[i].annotations[a].displayCharacter); // assume\r
528                 // jax-b\r
529                 // takes\r
530                 // care\r
531                 // of\r
532                 // utf8\r
533                 // translation\r
534                 ae.addValue(aa[i].annotations[a].value);\r
535                 ae.setPosition(a+1);\r
536                 if (aa[i].annotations[a].secondaryStructure != ' ')\r
537                 {\r
538                   Glyph ss = new Glyph();\r
539                   ss\r
540                   .setDict(org.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE);\r
541                   ss.setContent(String\r
542                       .valueOf(aa[i].annotations[a].secondaryStructure));\r
543                   ae.addGlyph(ss);\r
544                 }\r
545                 an.addAnnotationElement(ae);\r
546               }\r
547               if (aa[i].editable) {\r
548                 //an.addProperty(newProperty("jalview:editable", null, "true"));\r
549                 an.setModifiable(true);\r
550               }\r
551               if (aa[i].graph!=jalview.datamodel.AlignmentAnnotation.NO_GRAPH) {\r
552                 an.setGraph(true);\r
553                 an.setGroup(Integer.toString(aa[i].graphGroup));\r
554                 an.addProperty(newProperty("jalview:graphType",null,\r
555                     ((aa[i].graph==jalview.datamodel.AlignmentAnnotation.BAR_GRAPH) ? "BAR_GRAPH" : "LINE_GRAPH")));\r
556 \r
557                 /** and on and on..\r
558                  vProperty=new Property();\r
559                   vProperty.setName("jalview:graphThreshhold");\r
560                   vProperty.setContent(aa[i].threshold);\r
561                  */\r
562 \r
563               }\r
564             }\r
565             else\r
566             {\r
567               if (an.getModifiable())\r
568               {\r
569                 // verify annotation - update (perhaps)\r
570                 Cache.log.info("update alignment sequence annotation. not yet implemented.");\r
571               }\r
572               else\r
573               {\r
574                 // verify annotation - update (perhaps)\r
575                 Cache.log.info("updated alignment sequence annotation added.");\r
576               }\r
577             }\r
578           }\r
579         }\r
580       }\r
581       // /////////////////////////////////////////////////////\r
582 \r
583       // //////////////////////////////////////////////\r
584       // /SAVE THE TREES\r
585       // /////////////////////////////////\r
586       // FIND ANY ASSOCIATED TREES\r
587       if (Desktop.desktop != null)\r
588       {\r
589         javax.swing.JInternalFrame[] frames = Desktop.desktop.getAllFrames();\r
590 \r
591         for (int t = 0; t < frames.length; t++)\r
592         {\r
593           if (frames[t] instanceof TreePanel)\r
594           {\r
595             TreePanel tp = (TreePanel) frames[t];\r
596 \r
597             if (tp.getAlignment() == jal)\r
598             {\r
599               Tree tree = (Tree) getjv2vObj(tp);\r
600               if (tree == null)\r
601               {\r
602                 tree = new Tree();\r
603                 bindjvvobj(tp, tree);\r
604                 tree.setTitle(tp.getTitle());\r
605                 Newick newick = new Newick();\r
606                 // TODO: translate sequenceI to leaf mappings to vamsas\r
607                 // references - see tree specification in schema.\r
608                 newick.setContent(tp.getTree().toString());\r
609                 newick.setTitle(tp.getTitle());\r
610                 tree.addNewick(newick);\r
611                 tree.setProvenance(makeTreeProvenance(jal, tp));\r
612                 alignment.addTree(tree);\r
613               }\r
614               else\r
615               {\r
616                 if (tree.getModifiable())\r
617                 {\r
618                   // verify any changes.\r
619                   System.out.println("Update tree in document.");\r
620                 }\r
621                 else\r
622                 {\r
623                   System.out\r
624                   .println("Add modified tree as new tree in document.");\r
625                 }\r
626               }\r
627             }\r
628           }\r
629         }\r
630       }\r
631       // Store Jalview specific stuff in the Jalview appData\r
632       // not implemented in the SimpleDoc interface.\r
633     }\r
634 \r
635     catch (Exception ex)\r
636     {\r
637       ex.printStackTrace();\r
638     }\r
639 \r
640   }\r
641 \r
642   private Property newProperty(String name, String type, String content) {\r
643     Property vProperty=new Property();\r
644     vProperty.setName(name);\r
645     if (type!=null)\r
646       vProperty.setType(type);\r
647     else\r
648       vProperty.setType("String");\r
649     vProperty.setContent(content);\r
650     return vProperty;\r
651   }\r
652 \r
653   /**\r
654    * correctly create a RangeAnnotation from a jalview sequence feature\r
655    *\r
656    * @param dsa\r
657    *          (typically DataSetAnnotations or AlignmentSequenceAnnotation)\r
658    * @param feature\r
659    *          (the feature to be mapped from)\r
660    * @return\r
661    */\r
662   private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa,\r
663       SequenceFeature feature) {\r
664     dsa.setType(feature.getType());\r
665     Seg vSeg = new Seg();\r
666     vSeg.setStart(feature.getBegin());\r
667     vSeg.setEnd(feature.getEnd());\r
668     vSeg.setInclusive(true);\r
669     dsa.addSeg(vSeg);\r
670     dsa.setDescription(feature.getDescription());\r
671     dsa.setStatus(feature.getStatus());\r
672     if (feature.links != null && feature.links.size() > 0)\r
673     {\r
674       for (int i = 0, iSize = feature.links.size(); i < iSize; i++)\r
675       {\r
676         String link = (String) feature.links.elementAt(i);\r
677         int sep = link.indexOf('|');\r
678         if (sep > -1)\r
679         {\r
680           Link vLink = new Link();\r
681           if (sep > 0)\r
682             vLink.setContent(link.substring(0, sep - 1));\r
683           else\r
684             vLink.setContent("");\r
685           vLink.setHref(link.substring(sep + 1)); // TODO: validate href.\r
686           dsa.addLink(vLink);\r
687         }\r
688       }\r
689     }\r
690     dsa.setGroup(feature.getFeatureGroup());\r
691     return dsa;\r
692   }\r
693 \r
694   /**\r
695    * correctly creates provenance for trees calculated on an alignment by\r
696    * jalview.\r
697    *\r
698    * @param jal\r
699    * @param tp\r
700    * @return\r
701    */\r
702   private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp) {\r
703     Provenance prov = new Provenance();\r
704     prov.addEntry(new Entry());\r
705     prov.getEntry(0).setAction("imported "+tp.getTitle());\r
706     prov.getEntry(0).setUser(provEntry.getUser());\r
707     prov.getEntry(0).setApp(provEntry.getApp());\r
708     prov.getEntry(0).setDate(provEntry.getDate());\r
709     if (tp.getTree().hasOriginalSequenceData())\r
710     {\r
711       Input vInput = new Input();\r
712       // LATER: check to see if tree input data is contained in this alignment -\r
713       // or just correctly resolve the tree's seqData to the correct alignment in\r
714       // the document.\r
715       // vInput.setObjRef(getjv2vObj(jal));\r
716       vInput.setObjRef(getjv2vObj(tp.getViewPort()));\r
717       prov.getEntry(0).setAction("created "+tp.getTitle());\r
718       prov.getEntry(0).addInput(vInput);\r
719       vInput.setName("jalview:seqdist");\r
720       prov.getEntry(0).addParam(new Param());\r
721       prov.getEntry(0).getParam(0).setName("treeType");\r
722       prov.getEntry(0).getParam(0).setType("utf8");\r
723       prov.getEntry(0).getParam(0).setContent("NJ");\r
724 \r
725       int ranges[] = tp.getTree().seqData.getVisibleContigs();\r
726       // VisibleContigs are with respect to alignment coordinates. Still need offsets\r
727       int start= tp.getTree().seqData.getAlignmentOrigin();\r
728       for (int r = 0; r < ranges.length; r += 2)\r
729       {\r
730         Seg visSeg = new Seg();\r
731         visSeg.setStart(1+start+ranges[r]);\r
732         visSeg.setEnd(start+ranges[r + 1]);\r
733         visSeg.setInclusive(true);\r
734         vInput.addSeg(visSeg);\r
735       }\r
736     }\r
737     return prov;\r
738   }\r
739 \r
740   /**\r
741    *\r
742    * @param tp\r
743    * @return Object[] { AlignmentView, AlignmentI - reference alignment for\r
744    *         input }\r
745    */\r
746   private Object[] recoverInputData(Provenance tp) {\r
747     for (int pe = 0; pe < tp.getEntryCount(); pe++)\r
748     {\r
749       if (tp.getEntry(pe).getInputCount() > 0)\r
750       {\r
751         if (tp.getEntry(pe).getInputCount() > 1)\r
752           Cache.log.warn("Ignoring additional input spec in provenance entry "\r
753               + tp.getEntry(pe).toString());\r
754         // LATER: deal sensibly with multiple inputs.\r
755         Input vInput = tp.getEntry(pe).getInput(0);\r
756         if (vInput.getObjRef() instanceof org.vamsas.objects.core.Alignment)\r
757         {\r
758           // recover an AlignmentView for the input data\r
759           AlignViewport javport = (AlignViewport) getvObj2jv((org.vamsas.client.Vobject) vInput\r
760               .getObjRef());\r
761           jalview.datamodel.AlignmentI jal = javport.getAlignment();\r
762           jalview.datamodel.CigarArray view = javport.getAlignment().getCompactAlignment();\r
763           int from = 1, to = jal.getWidth();\r
764           int offset=0; // deleteRange modifies its frame of reference\r
765           for (int r = 0, s = vInput.getSegCount(); r < s; r++)\r
766           {\r
767             Seg visSeg = vInput.getSeg(r);\r
768             int se[] = getSegRange(visSeg,true); // jalview doesn't do bidirection alignments yet.\r
769             if (to < se[1])\r
770               Cache.log.warn("Ignoring invalid segment in InputData spec.");\r
771             else\r
772             {\r
773               if (se[0] > from)\r
774               {\r
775                 view.deleteRange(offset+from-1, offset+se[0] - 2);\r
776                 offset-=se[0]-from;\r
777               }\r
778               from = se[1] + 1;\r
779             }\r
780           }\r
781           if (from < to)\r
782           {\r
783             view.deleteRange(offset+from-1, offset+to-1); // final deletion - TODO: check off by\r
784             // one for to\r
785           }\r
786           return new Object[] { new AlignmentView(view), jal };\r
787         }\r
788       }\r
789     }\r
790     Cache.log.debug("Returning null for input data recovery from provenance.");\r
791     return null;\r
792   }\r
793 \r
794   /**\r
795    * get start<end range of segment, adjusting for inclusivity flag and\r
796    * polarity.\r
797    *\r
798    * @param visSeg\r
799    * @param ensureDirection when true - always ensure start is less than end.\r
800    * @return int[] { start, end, direction} where direction==1 for range running from end to start.\r
801    */\r
802   private int[] getSegRange(Seg visSeg, boolean ensureDirection) {\r
803     boolean incl = visSeg.getInclusive();\r
804     // adjust for inclusive flag.\r
805     int pol = (visSeg.getStart() <= visSeg.getEnd()) ? 1 : -1; // polarity of\r
806     // region.\r
807     int start = visSeg.getStart() + (incl ? 0 : pol);\r
808     int end = visSeg.getEnd() + (incl ? 0 : -pol);\r
809     if (ensureDirection && pol==-1)\r
810     {\r
811       // jalview doesn't deal with inverted ranges, yet.\r
812       int t = end;\r
813       end = start;\r
814       start = t;\r
815     }\r
816     return new int[] { start, end, pol<0 ? 1 : 0 };\r
817   }\r
818 \r
819   /**\r
820    *\r
821    * @param annotation\r
822    * @return true if annotation is not to be stored in document\r
823    */\r
824   private boolean isJalviewOnly(AlignmentAnnotation annotation) {\r
825     return annotation.label.equals("Quality")\r
826     || annotation.label.equals("Conservation")\r
827     || annotation.label.equals("Consensus");\r
828   }\r
829   /**\r
830    * This will return the first AlignFrame viewing AlignViewport av.\r
831    * It will break if there are more than one AlignFrames viewing a particular av.\r
832    * This also shouldn't be in the io package.\r
833    * @param av\r
834    * @return alignFrame for av\r
835    */\r
836   public AlignFrame getAlignFrameFor(AlignViewport av) {\r
837     if (Desktop.desktop != null)\r
838     {\r
839       javax.swing.JInternalFrame[] frames = Desktop.desktop.getAllFrames();\r
840 \r
841       for (int t = 0; t < frames.length; t++)\r
842       {\r
843         if (frames[t] instanceof AlignFrame) {\r
844           if (((AlignFrame) frames[t]).getViewport()==av)\r
845             return (AlignFrame) frames[t];\r
846         }\r
847       }\r
848     }\r
849     return null;\r
850   }\r
851   public void updateToJalview() {\r
852     VAMSAS _roots[] = cdoc.getVamsasRoots();\r
853 \r
854     for (int _root = 0; _root<_roots.length; _root++) {\r
855       VAMSAS root = _roots[_root];\r
856       boolean newds=false;\r
857       for (int _ds=0,_nds=root.getDataSetCount(); _ds<_nds; _ds++) {\r
858         // ///////////////////////////////////\r
859         // ///LOAD DATASET\r
860         DataSet dataset = root.getDataSet(_ds);\r
861         int i, iSize = dataset.getSequenceCount();\r
862         Vector dsseqs;\r
863         jalview.datamodel.Alignment jdataset = (jalview.datamodel.Alignment) getvObj2jv(dataset);\r
864         int jremain=0;\r
865         if (jdataset==null) {\r
866           Cache.log.debug("Initialising new jalview dataset fields");\r
867           newds=true;\r
868           dsseqs=new Vector();\r
869         } else {\r
870           Cache.log.debug("Update jalview dataset from vamsas.");\r
871           jremain=jdataset.getHeight();\r
872           dsseqs=jdataset.getSequences();\r
873         }\r
874 \r
875         // TODO: test sequence merging - we preserve existing non vamsas\r
876         // sequences but add in any new vamsas ones, and don't yet update any\r
877         // sequence attributes\r
878         for (i = 0; i < iSize ; i++)\r
879         {\r
880           Sequence vdseq = dataset.getSequence(i);\r
881           jalview.datamodel.SequenceI dsseq = (SequenceI) getvObj2jv(vdseq);\r
882           if (dsseq!=null) {\r
883             if (!dsseq.getSequence().equals(vdseq.getSequence()))\r
884               throw new Error("Broken! - mismatch of dataset sequence and jalview internal dataset sequence.");\r
885             jremain--;\r
886           } else {\r
887             dsseq = new jalview.datamodel.Sequence(\r
888                 dataset.getSequence(i).getName(),\r
889                 dataset.getSequence(i).getSequence(),\r
890                 dataset.getSequence(i).getStart(),\r
891                 dataset.getSequence(i).getEnd()  );\r
892             bindjvvobj(dsseq, dataset.getSequence(i));\r
893             dsseq.setVamsasId(dataset.getSequence(i).getVorbaId().getId());\r
894             dsseqs.add(dsseq);\r
895           }\r
896           if (vdseq.getDbRefCount()>0) {\r
897             DbRef [] dbref = vdseq.getDbRef();\r
898             for(int db=0; db<dbref.length; db++)\r
899             {\r
900               jalview.datamodel.DBRefEntry dbr=(jalview.datamodel.DBRefEntry) getvObj2jv(dbref[db]);\r
901               if (dbr==null) {\r
902                 // add new dbref\r
903                 dsseq.addDBRef(dbr= new jalview.datamodel.DBRefEntry\r
904                     (\r
905                         dbref[db].getSource().toString(),\r
906                         dbref[db].getVersion().toString(),\r
907                         dbref[db].getAccessionId().toString()));\r
908                 bindjvvobj(dbr, dbref[db]);\r
909               }\r
910             }\r
911           }\r
912         }\r
913 \r
914         if (newds) {\r
915           SequenceI[] seqs = new SequenceI[dsseqs.size()];\r
916           for (i=0,iSize=dsseqs.size(); i<iSize; i++) {\r
917             seqs[i]=(SequenceI) dsseqs.elementAt(i);\r
918             dsseqs.setElementAt(null, i);\r
919           }\r
920           jdataset = new jalview.datamodel.Alignment(seqs);\r
921           Cache.log.debug("New vamsas dataset imported into jalview.");\r
922           bindjvvobj(jdataset, dataset);\r
923         }\r
924         // ////////\r
925         // add any new dataset sequence feature annotations\r
926         if (dataset.getDataSetAnnotations() != null) {\r
927           for (int dsa = 0; dsa < dataset.getDataSetAnnotationsCount(); dsa++) {\r
928             DataSetAnnotations dseta=dataset.getDataSetAnnotations(dsa);\r
929             SequenceI dsSeq=(SequenceI) getvObj2jv((Vobject) dseta.getSeqRef());\r
930             if (dsSeq==null) {\r
931               jalview.bin.Cache.log.warn("Couldn't resolve jalview sequenceI for dataset object reference "+((Vobject)dataset.getDataSetAnnotations(dsa).getSeqRef()).getVorbaId().getId());\r
932             } else {\r
933               if (dseta.getAnnotationElementCount()==0) {\r
934                 jalview.datamodel.SequenceFeature sf=(jalview.datamodel.SequenceFeature) getvObj2jv(dseta);\r
935                 if (sf==null) {\r
936                   dsSeq.addSequenceFeature(sf=getJalviewSeqFeature(dseta));\r
937                   bindjvvobj(sf, dseta);\r
938                 }\r
939               } else {\r
940                 // TODO: deal with alignmentAnnotation style annotation\r
941                 // appearing on dataset sequences.\r
942                 // JBPNote: we could just add them to all alignments but\r
943                 // that may complicate cross references in the jalview\r
944                 // datamodel\r
945                 Cache.log.warn("Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");\r
946               }\r
947             }\r
948           }\r
949         }\r
950 \r
951         if (dataset.getAlignmentCount()>0) {\r
952           // LOAD ALIGNMENTS from DATASET\r
953 \r
954           for (int al=0,nal=dataset.getAlignmentCount(); al<nal; al++) {\r
955             org.vamsas.objects.core.Alignment alignment = dataset.getAlignment(al);\r
956             AlignViewport av = (AlignViewport) getvObj2jv(alignment);\r
957             jalview.datamodel.AlignmentI jal=null;\r
958             if (av!=null)\r
959               jal = av.getAlignment();\r
960             iSize = alignment.getAlignmentSequenceCount();\r
961             boolean newal=(jal==null) ? true : false;\r
962             Vector newasAnnots=new Vector();\r
963             char gapChar=' '; // default for new alignments read in from the document\r
964             if (jal!=null) {\r
965               dsseqs=jal.getSequences(); // for merge/update\r
966               gapChar=jal.getGapCharacter();\r
967             } else {\r
968               dsseqs=new Vector();\r
969             }\r
970             char valGapchar=alignment.getGapChar().charAt(0);\r
971             for (i = 0; i < iSize; i++)\r
972             {\r
973               AlignmentSequence valseq = alignment.getAlignmentSequence(i);\r
974               jalview.datamodel.SequenceI alseq = (SequenceI) getvObj2jv(valseq);\r
975               if (alseq!=null) {\r
976                 //TODO: upperCase/LowerCase situation here ? do we allow it ?\r
977                 //if (!alseq.getSequence().equals(valseq.getSequence())) {\r
978                 // throw new Error("Broken! - mismatch of dataset sequence and jalview internal dataset sequence.");\r
979                 if (Cache.log.isDebugEnabled())\r
980                   Cache.log.debug("Updating apparently edited sequence "+alseq.getName());\r
981                 // this might go *horribly* wrong\r
982                 alseq.setSequence(new String(valseq.getSequence()).replace(valGapchar, gapChar));\r
983                 jremain--;\r
984               } else {\r
985                 alseq = new jalview.datamodel.Sequence(\r
986                     valseq.getName(),\r
987                     valseq.getSequence().replace(valGapchar, gapChar),\r
988                     valseq.getStart(),\r
989                     valseq.getEnd()  );\r
990 \r
991                 Vobject datsetseq = (Vobject)valseq.getRefid();\r
992                 if (datsetseq!=null) {\r
993                   alseq.setDatasetSequence((SequenceI)getvObj2jv(datsetseq)); // exceptions if AlignemntSequence reference isn't a simple SequenceI\r
994                 } else {\r
995                   Cache.log.error("Invalid dataset sequence id (null) for alignment sequence "+valseq.getVorbaId());\r
996                 }\r
997                 bindjvvobj(alseq, valseq);\r
998                 alseq.setVamsasId(valseq.getVorbaId().getId());\r
999                 dsseqs.add(alseq);\r
1000               }\r
1001               if (valseq.getAlignmentSequenceAnnotationCount()>0) {\r
1002                 AlignmentSequenceAnnotation[] vasannot=valseq.getAlignmentSequenceAnnotation();\r
1003                 for (int a=0; a<vasannot.length; a++) {\r
1004                   jalview.datamodel.AlignmentAnnotation asa = (jalview.datamodel.AlignmentAnnotation) getvObj2jv(vasannot[a]); // TODO: 1:many jalview alignment sequence annotations\r
1005                   if (asa==null) {\r
1006                     int se[] = getBounds(vasannot[a]);\r
1007                     asa = getjAlignmentAnnotation(jal, vasannot[a]);\r
1008                     asa.sequenceRef=alseq;\r
1009                     asa.createSequenceMapping(alseq, alseq.getStart()+se[0], false); // TODO: verify that positions in alseqAnnotation correspond to ungapped residue positions.\r
1010                     bindjvvobj(asa, vasannot[a]);\r
1011                     newasAnnots.add(asa);\r
1012                   } else {\r
1013                     // update existing annotation - can do this in place\r
1014                     if (vasannot[a].getModifiable()) {\r
1015                       Cache.log.info("UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");\r
1016                       // TODO: should at least replace with new one - otherwise things will break\r
1017                       // basically do this:\r
1018                       // int se[] = getBounds(vasannot[a]);\r
1019                       // asa.update(getjAlignmentAnnotation(jal, vasannot[a])); //  update from another annotation object in place.\r
1020                       // asa.createSequenceMapping(alseq, se[0], false);\r
1021 \r
1022                     }\r
1023                   }\r
1024                 }\r
1025               }\r
1026             }\r
1027             if (jal==null) {\r
1028               SequenceI[] seqs = new SequenceI[dsseqs.size()];\r
1029               for (i=0,iSize=dsseqs.size(); i<iSize; i++) {\r
1030                 seqs[i]=(SequenceI) dsseqs.elementAt(i);\r
1031                 dsseqs.setElementAt(null, i);\r
1032               }\r
1033               jal = new jalview.datamodel.Alignment(seqs);\r
1034               Cache.log.debug("New vamsas alignment imported into jalview "+alignment.getVorbaId().getId());\r
1035               jal.setDataset(jdataset);\r
1036             }\r
1037             if (newasAnnots!=null && newasAnnots.size()>0) {\r
1038               // Add the new sequence annotations in to the alignment.\r
1039               for (int an=0,anSize=newasAnnots.size(); an<anSize; an++) {\r
1040                 jal.addAnnotation((AlignmentAnnotation) newasAnnots.elementAt(an));\r
1041                 // TODO: check if anything has to be done - like calling adjustForAlignment or something.\r
1042                 newasAnnots.setElementAt(null, an);\r
1043               }\r
1044               newasAnnots=null;\r
1045             }\r
1046             // //////////////////////////////////////////\r
1047             // //LOAD ANNOTATIONS FOR THE ALIGNMENT\r
1048             // ////////////////////////////////////\r
1049             if (alignment.getAlignmentAnnotationCount()>0)\r
1050             {\r
1051               org.vamsas.objects.core.AlignmentAnnotation[] an = alignment.getAlignmentAnnotation();\r
1052 \r
1053               for (int j = 0; j < an.length; j++)\r
1054               {\r
1055                 jalview.datamodel.AlignmentAnnotation jan=(jalview.datamodel.AlignmentAnnotation) getvObj2jv(an[j]);\r
1056                 if (jan!=null) {\r
1057                   // update or stay the same.\r
1058                   // TODO: should at least replace with a new one - otherwise things will break\r
1059                   // basically do this:\r
1060                   // jan.update(getjAlignmentAnnotation(jal, an[a])); //  update from another annotation object in place.\r
1061 \r
1062                   Cache.log.debug("update from vamsas alignment annotation to existing jalview alignment annotation.");\r
1063                   if (an[j].getModifiable()) {\r
1064                     // TODO: user defined annotation is totally mutable... - so load it up or throw away if locally edited.\r
1065                     Cache.log.info("NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");\r
1066                   }\r
1067                   // TODO: compare annotation element rows\r
1068                   // TODO: compare props.\r
1069                 } else {\r
1070                   jan = getjAlignmentAnnotation(jal, an[j]);\r
1071                   jal.addAnnotation(jan);\r
1072                   bindjvvobj(jan, an[j]);\r
1073                 }\r
1074               }\r
1075             }\r
1076             AlignFrame alignFrame;\r
1077             if (av==null) {\r
1078               Cache.log.debug("New alignframe for alignment "+alignment.getVorbaId());\r
1079               // ///////////////////////////////\r
1080               // construct alignment view\r
1081               alignFrame = new AlignFrame(jal, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);\r
1082               av=alignFrame.getViewport();\r
1083               String title = alignment.getProvenance().getEntry(alignment.getProvenance().getEntryCount()-1).getAction();\r
1084               if (alignment.getPropertyCount()>0) {\r
1085                 for (int p=0,pe=alignment.getPropertyCount(); p<pe; p++) {\r
1086                   if (alignment.getProperty(p).getName().equals("jalview:AlTitle")) {\r
1087                     title = alignment.getProperty(p).getContent();\r
1088                   }\r
1089                 }\r
1090               }\r
1091               // TODO: automatically create meaningful title for a vamsas alignment using its provenance.\r
1092               jalview.gui.Desktop.addInternalFrame(alignFrame, title + "("+alignment.getVorbaId()+")",\r
1093                   AlignFrame.DEFAULT_WIDTH,\r
1094                   AlignFrame.DEFAULT_HEIGHT);\r
1095               bindjvvobj(av, alignment);\r
1096             } else {\r
1097               // find the alignFrame for jal.\r
1098               // TODO: fix this so we retrieve the alignFrame handing av *directly*\r
1099               alignFrame=getAlignFrameFor(av);\r
1100             }\r
1101             // LOAD TREES\r
1102             // /////////////////////////////////////\r
1103             if (alignment.getTreeCount() > 0)\r
1104             {\r
1105 \r
1106               for (int t = 0; t < alignment.getTreeCount(); t++)\r
1107               {\r
1108                 Tree tree = alignment.getTree(t);\r
1109                 TreePanel tp=(TreePanel) getvObj2jv(tree);\r
1110                 if (tp!=null) {\r
1111                   Cache.log.info("Update from vamsas document to alignment associated tree not implemented yet.");\r
1112                 } else {\r
1113                   // make a new tree\r
1114                   Object[] idata = this.recoverInputData(tree.getProvenance());\r
1115                   try {\r
1116                     AlignmentView inputData=null;\r
1117                     if (idata!=null && idata[0]!=null)\r
1118                       inputData = (AlignmentView) idata[0];\r
1119                     tp = alignFrame.ShowNewickTree(\r
1120                         new jalview.io.NewickFile(tree.getNewick(0).getContent()),\r
1121                         tree.getNewick(0).getTitle()+" ("+tree.getVorbaId()+")",inputData,\r
1122                         600, 500,\r
1123                         t * 20 + 50, t * 20 + 50);\r
1124                     bindjvvobj(tp, tree);\r
1125                   } catch (Exception e) {\r
1126                     Cache.log.warn("Problems parsing treefile '"+tree.getNewick(0).getContent()+"'",e);\r
1127                   }\r
1128                 }\r
1129               }\r
1130             }\r
1131 \r
1132           }\r
1133         }\r
1134       }\r
1135     }\r
1136   }\r
1137   // bitfields - should be a template in j1.5\r
1138   private static int HASSECSTR=0;\r
1139   private static int HASVALS=1;\r
1140   private static int HASHPHOB=2;\r
1141   private static int HASDC=3;\r
1142   private static int HASDESCSTR=4;\r
1143   private static int HASTWOSTATE=5; // not used yet.\r
1144   /**\r
1145    * parses the AnnotationElements - if they exist - into jalview.datamodel.Annotation[] rows\r
1146    * Two annotation rows are made if there are distinct annotation for both at 'pos' and 'after pos' at any particular site.\r
1147    * @param annotation\r
1148    * @return { boolean[static int constants ], int[ae.length] - map to annotated object frame, jalview.datamodel.Annotation[], jalview.datamodel.Annotation[] (after)}\r
1149    */\r
1150   private Object[] parseRangeAnnotation(org.vamsas.objects.core.RangeAnnotation annotation) {\r
1151     // set these attributes by looking in the annotation to decide what kind of alignment annotation rows will be made\r
1152     // TODO: potentially we might make several annotation rows from one vamsas alignment annotation. the jv2Vobj binding mechanism\r
1153     // may not quite cope with this (without binding an array of annotations to a vamsas alignment annotation)\r
1154     // summary flags saying what we found over the set of annotation rows.\r
1155     boolean[] AeContent = new boolean[] { false, false, false, false, false};\r
1156     int[] rangeMap = getMapping(annotation);\r
1157     jalview.datamodel.Annotation[][] anot=new jalview.datamodel.Annotation[][] {\r
1158         new jalview.datamodel.Annotation[rangeMap.length],\r
1159         new jalview.datamodel.Annotation[rangeMap.length]\r
1160     };\r
1161     boolean mergeable=true; //false  if 'after positions cant be placed on same annotation row as positions.\r
1162 \r
1163     if (annotation.getAnnotationElementCount()>0) {\r
1164       AnnotationElement ae[] = annotation.getAnnotationElement();\r
1165       for (int aa = 0; aa < ae.length; aa++)\r
1166       {\r
1167         int pos = ae[aa].getPosition()-1;// pos counts from 1 to (|seg.start-seg.end|+1)\r
1168         if (pos>=0 && pos<rangeMap.length) {\r
1169           int row=ae[aa].getAfter()?1:0;\r
1170           if (anot[row][pos]!=null) {\r
1171             // only time this should happen is if the After flag is set.\r
1172             Cache.log.debug("Ignoring duplicate annotation site at "+pos);\r
1173             continue;\r
1174           }\r
1175           if (anot[1-row][pos]!=null)\r
1176             mergeable=false;\r
1177           String desc = "";\r
1178           if (ae[aa].getDescription()!=null) {\r
1179             desc = ae[aa].getDescription();\r
1180             if (desc.length()>0) {\r
1181               // have imported valid description string\r
1182               AeContent[HASDESCSTR]=true;\r
1183             }\r
1184           }\r
1185           String dc = null;//ae[aa].getDisplayCharacter()==null ? "dc" : ae[aa].getDisplayCharacter();\r
1186           String ss = null;//ae[aa].getSecondaryStructure()==null ? "ss" : ae[aa].getSecondaryStructure();\r
1187           java.awt.Color colour = null;\r
1188           if (ae[aa].getGlyphCount()>0) {\r
1189             Glyph[] glyphs = ae[aa].getGlyph();\r
1190             for (int g=0; g<glyphs.length; g++) {\r
1191               if (glyphs[g].getDict().equals(org.vamsas.objects.utils.GlyphDictionary.PROTEIN_SS_3STATE)) {\r
1192                 ss=glyphs[g].getContent();\r
1193                 AeContent[HASSECSTR]=true;\r
1194               } else if (glyphs[g].getDict().equals(org.vamsas.objects.utils.GlyphDictionary.PROTEIN_HD_HYDRO)) {\r
1195                 Cache.log.debug("ignoring hydrophobicity glyph marker.");\r
1196                 AeContent[HASHPHOB]=true;\r
1197                 char c=(dc=glyphs[g].getContent()).charAt(0);\r
1198                 // dc may get overwritten - but we still set the colour.\r
1199                 colour = new java.awt.Color(c=='+'?255:0,c=='.'?255:0,c=='-'?255:0);\r
1200 \r
1201               } else if (glyphs[g].getDict().equals(org.vamsas.objects.utils.GlyphDictionary.DEFAULT)) {\r
1202                 dc = glyphs[g].getContent();\r
1203                 AeContent[HASDC]=true;\r
1204               } else {\r
1205                 Cache.log.debug("Ignoring unknown glyph type "+glyphs[g].getDict());\r
1206               }\r
1207             }\r
1208           }\r
1209           float val=0;\r
1210           if (ae[aa].getValueCount()>0) {\r
1211             AeContent[HASVALS]=true;\r
1212             if (ae[aa].getValueCount()>1) {\r
1213               Cache.log.warn("ignoring additional "+(ae[aa].getValueCount()-1)+"values in annotation element.");\r
1214             }\r
1215             val = ae[aa].getValue(0);\r
1216           }\r
1217           if (colour==null) {\r
1218             anot[row][pos]=new jalview.datamodel.Annotation((dc!=null) ? dc : "", desc, (ss!=null)?ss.charAt(0):' ', val);\r
1219           } else {\r
1220             anot[row][pos]=new jalview.datamodel.Annotation((dc!=null) ? dc : "", desc, (ss!=null)?ss.charAt(0):' ', val, colour);\r
1221           }\r
1222         } else {\r
1223           Cache.log.warn("Ignoring out of bound annotation element "+aa+" in "+annotation.getVorbaId().getId());\r
1224         }\r
1225       }\r
1226       // decide on how many annotation rows are needed.\r
1227       if (mergeable) {\r
1228         for (int i=0; i<anot[0].length;i++) {\r
1229           if (anot[1][i]!=null) {\r
1230             anot[0][i] = anot[1][i];\r
1231             anot[0][i].description = anot[0][i].description+" (after)";\r
1232             AeContent[HASDESCSTR]=true; // we have valid description string data\r
1233             anot[1][i] = null;\r
1234           }\r
1235         }\r
1236         anot[1] = null;\r
1237       } else {\r
1238         for (int i=0; i<anot[0].length;i++) {\r
1239           anot[1][i].description = anot[1][i].description+" (after)";\r
1240         }\r
1241       }\r
1242       return new Object[] { AeContent, rangeMap, anot[0], anot[1] };\r
1243     } else {\r
1244       // no annotations to parse. Just return an empty annotationElement[] array.\r
1245       return new Object[] { AeContent, rangeMap, anot[0], anot[1] };\r
1246     }\r
1247     // return null;\r
1248   }\r
1249   /**\r
1250    * @param jal the jalview alignment to which the annotation will be attached (ideally - freshly updated from corresponding vamsas alignment)\r
1251    * @param annotation\r
1252    * @return unbound jalview alignment annotation object.\r
1253    */\r
1254   private jalview.datamodel.AlignmentAnnotation getjAlignmentAnnotation(jalview.datamodel.AlignmentI jal, org.vamsas.objects.core.RangeAnnotation annotation) {\r
1255     jalview.datamodel.AlignmentAnnotation jan =null;\r
1256     if (annotation==null)\r
1257       return null;\r
1258     // boolean hasSequenceRef=annotation.getClass().equals(org.vamsas.objects.core.AlignmentSequenceAnnotation.class);\r
1259     //boolean hasProvenance=hasSequenceRef || (annotation.getClass().equals(org.vamsas.objects.core.AlignmentAnnotation.class));\r
1260     /*int se[] = getBounds(annotation);\r
1261     if (se==null)\r
1262       se=new int[] {0,jal.getWidth()-1};\r
1263      */\r
1264     Object[] parsedRangeAnnotation = parseRangeAnnotation(annotation);\r
1265     String a_label=annotation.getLabel();\r
1266     String a_descr=annotation.getDescription();\r
1267     if (a_label==null || a_label.length()==0) {\r
1268       a_label = annotation.getType();\r
1269       if (a_label.length()==0)\r
1270         a_label = "Unamed annotation";\r
1271     }\r
1272     if (a_descr==null || a_descr.length()==0) {\r
1273       a_descr = "Annotation of type '"+annotation.getType()+"'";\r
1274     }\r
1275     if (parsedRangeAnnotation==null) {\r
1276       Cache.log.debug("Inserting empty annotation row elements for a whole-alignment annotation.");\r
1277 \r
1278 \r
1279     } else {\r
1280       if (parsedRangeAnnotation[3]!=null) {\r
1281         Cache.log.warn("Ignoring 'After' annotation row in "+annotation.getVorbaId());\r
1282       }\r
1283       jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[]) parsedRangeAnnotation[2];\r
1284       boolean[] has=(boolean[])parsedRangeAnnotation[0];\r
1285       // VAMSAS: getGraph is only on derived annotation for alignments - in this way its 'odd' - there is already an existing TODO about removing this flag as being redundant\r
1286       /*if ((annotation.getClass().equals(org.vamsas.objects.core.AlignmentAnnotation.class) && ((org.vamsas.objects.core.AlignmentAnnotation)annotation).getGraph())\r
1287           || (hasSequenceRef=true && ((org.vamsas.objects.core.AlignmentSequenceAnnotation)annotation).getGraph())) {\r
1288       */\r
1289       if (has[HASVALS]) {\r
1290         // make bounds and automatic description strings for jalview user's benefit (these shouldn't be written back to vamsas document)\r
1291         boolean first=true;\r
1292         float min=0,max=1;\r
1293         int lastval=0;\r
1294         for (int i=0;i<arow.length; i++) {\r
1295           if (arow[i]!=null) {\r
1296             if (i-lastval>1) {\r
1297               // do some interpolation *between* points\r
1298               if (arow[lastval]!=null) {\r
1299                 float interval = arow[i].value-arow[lastval].value;\r
1300                 interval/=i-lastval;\r
1301                 float base = arow[lastval].value;\r
1302                 for (int ip=lastval+1,np=0; ip<i; np++,ip++) {\r
1303                   arow[ip] = new jalview.datamodel.Annotation("","",' ', interval*np+base);\r
1304                   // NB - Interpolated points don't get a tooltip and description.\r
1305                 }\r
1306               }\r
1307             }\r
1308             lastval=i;\r
1309             // check range - shouldn't we have a min and max property in the annotation object ?\r
1310             if (first) { min=max=arow[i].value; first=false;}\r
1311             else { if (arow[i].value<min) { min=arow[i].value; }\r
1312             else if (arow[i].value>max) { max=arow[i].value; }\r
1313             }\r
1314             // make tooltip and display char value\r
1315             if (!has[HASDESCSTR]) arow[i].description = arow[i].value + "";\r
1316             if (!has[HASDC]) arow[i].displayCharacter=arow[i].value+"";\r
1317           }\r
1318         }\r
1319         int type=jalview.datamodel.AlignmentAnnotation.LINE_GRAPH;\r
1320         if (has[HASHPHOB]) {\r
1321           type = jalview.datamodel.AlignmentAnnotation.BAR_GRAPH;\r
1322         }\r
1323         jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr, arow, min, max, type);\r
1324       } else {\r
1325         jan = new jalview.datamodel.AlignmentAnnotation(a_label, a_descr, arow);\r
1326         jan.setThreshold(null);\r
1327       }\r
1328       if (annotation.getLinkCount()>0) {\r
1329         Cache.log.warn("Ignoring "+annotation.getLinkCount()+"links added to AlignmentAnnotation.");\r
1330       }\r
1331       if (annotation.getModifiable()) {\r
1332         jan.editable=true;\r
1333       }\r
1334 \r
1335       if (annotation.getPropertyCount()>0) {\r
1336         // look for special jalview properties\r
1337         org.vamsas.objects.core.Property[] props=annotation.getProperty();\r
1338         for (int p=0;p<props.length; p++) {\r
1339           if (props[p].getName().equalsIgnoreCase("jalview:graphType")) {\r
1340             try {\r
1341               // probably a jalview annotation graph so recover the visualization hints.\r
1342               jan.graph = jalview.datamodel.AlignmentAnnotation.getGraphValueFromString(props[p].getContent());\r
1343             } catch (Exception e) {\r
1344               Cache.log.debug("Invalid graph type value in jalview:graphType property.");\r
1345             }\r
1346             try {\r
1347               if (annotation.getGroup()!=null && annotation.getGroup().length()>0)\r
1348                 jan.graphGroup = Integer.parseInt(annotation.getGroup());\r
1349             } catch (Exception e) {\r
1350               Cache.log.info("UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");\r
1351             }\r
1352           }\r
1353         }\r
1354       }\r
1355 \r
1356       return jan;\r
1357 \r
1358     }\r
1359 \r
1360     return null;\r
1361   }\r
1362 \r
1363   private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta) {\r
1364     int[] se = getBounds(dseta);\r
1365     SequenceFeature sf = new jalview.datamodel.SequenceFeature(dseta.getType(),\r
1366         dseta.getDescription(), dseta.getStatus(), se[0], se[1], dseta\r
1367         .getGroup());\r
1368     if (dseta.getLinkCount() > 0)\r
1369     {\r
1370       Link[] links = dseta.getLink();\r
1371       for (int i = 0; i < links.length; i++)\r
1372       {\r
1373         sf.addLink(links[i].getContent() + "|" + links[i].getHref());\r
1374       }\r
1375     }\r
1376     return sf;\r
1377   }\r
1378 \r
1379   /**\r
1380    * get real bounds of a RangeType's specification. start and end are an\r
1381    * inclusive range within which all segments and positions lie.\r
1382    * TODO: refactor to vamsas utils\r
1383    * @param dseta\r
1384    * @return int[] { start, end}\r
1385    */\r
1386   private int[] getBounds(RangeType dseta) {\r
1387     if (dseta != null)\r
1388     {\r
1389       int[] se = null;\r
1390       if (dseta.getSegCount()>0 && dseta.getPosCount()>0)\r
1391         throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");\r
1392       if (dseta.getSegCount() > 0)\r
1393       {\r
1394         se = getSegRange(dseta.getSeg(0),true);\r
1395         for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++)\r
1396         {\r
1397           int nse[] = getSegRange(dseta.getSeg(s), true);\r
1398           if (se[0] > nse[0])\r
1399             se[0] = nse[0];\r
1400           if (se[1] < nse[1])\r
1401             se[1] = nse[1];\r
1402         }\r
1403       }\r
1404       if (dseta.getPosCount() > 0)\r
1405       {\r
1406         // could do a polarity for pos range too. and pass back indication of discontinuities.\r
1407         int pos = dseta.getPos(0).getI();\r
1408         se = new int[] { pos, pos };\r
1409         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)\r
1410         {\r
1411           pos = dseta.getPos(p).getI();\r
1412           if (se[0] > pos)\r
1413             se[0] = pos;\r
1414           if (se[1] < pos)\r
1415             se[1] = pos;\r
1416         }\r
1417       }\r
1418       return se;\r
1419     }\r
1420     return null;\r
1421   }\r
1422   /**\r
1423    * map from a rangeType's internal frame to the referenced object's coordinate frame.\r
1424    * @param dseta\r
1425    * @return int [] { ref(pos)...} for all pos in rangeType's frame.\r
1426    */\r
1427   private int[] getMapping(RangeType dseta) {\r
1428     Vector posList=new Vector();\r
1429     if (dseta != null)\r
1430     {\r
1431       int[] se = null;\r
1432       if (dseta.getSegCount()>0 && dseta.getPosCount()>0)\r
1433         throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");\r
1434       if (dseta.getSegCount() > 0)\r
1435       {\r
1436         for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++)\r
1437         {\r
1438           se = getSegRange(dseta.getSeg(s), false);\r
1439           int se_end=se[1-se[2]]+(se[2]==0 ? 1 : -1);\r
1440           for (int p=se[se[2]]; p!=se_end; p+=se[2]==0 ? 1 : -1 ) {\r
1441             posList.add(new Integer(p));\r
1442           }\r
1443         }\r
1444       }\r
1445       else if (dseta.getPosCount() > 0)\r
1446       {\r
1447         int pos = dseta.getPos(0).getI();\r
1448 \r
1449         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)\r
1450         {\r
1451           pos = dseta.getPos(p).getI();\r
1452           posList.add(new Integer(pos));\r
1453         }\r
1454       }\r
1455     }\r
1456     if (posList!=null && posList.size()>0) {\r
1457       int[] range=new int[posList.size()];\r
1458       for (int i=0; i<range.length; i++)\r
1459         range[i] = ((Integer)posList.elementAt(i)).intValue();\r
1460       posList.clear();\r
1461       return range;\r
1462     }\r
1463     return null;\r
1464   }\r
1465   /* not needed now.\r
1466    * Provenance getVamsasProvenance(jalview.datamodel.Provenance jprov) {\r
1467     jalview.datamodel.ProvenanceEntry[] entries = null;\r
1468     // TODO: fix App and Action here.\r
1469     Provenance prov = new Provenance();\r
1470     org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(\r
1471         new java.util.Date());\r
1472     Entry provEntry;\r
1473 \r
1474     if (jprov != null)\r
1475     {\r
1476       entries = jprov.getEntries();\r
1477       for (int i = 0; i < entries.length; i++)\r
1478       {\r
1479         provEntry = new Entry();\r
1480         try\r
1481         {\r
1482           date = new org.exolab.castor.types.Date(entries[i].getDate());\r
1483         } catch (Exception ex)\r
1484         {\r
1485           ex.printStackTrace();\r
1486 \r
1487           date = new org.exolab.castor.types.Date(entries[i].getDate());\r
1488         }\r
1489         provEntry.setDate(date);\r
1490         provEntry.setUser(entries[i].getUser());\r
1491         provEntry.setAction(entries[i].getAction());\r
1492         prov.addEntry(provEntry);\r
1493       }\r
1494     }\r
1495     else\r
1496     {\r
1497       provEntry = new Entry();\r
1498       provEntry.setDate(date);\r
1499       provEntry.setUser(System.getProperty("user.name")); // TODO: ext string\r
1500       provEntry.setApp("JVAPP"); // TODO: ext string\r
1501       provEntry.setAction(action);\r
1502       prov.addEntry(provEntry);\r
1503     }\r
1504 \r
1505     return prov;\r
1506   }\r
1507    */\r
1508   jalview.datamodel.Provenance getJalviewProvenance(Provenance prov) {\r
1509     // TODO: fix App and Action entries and check use of provenance in jalview.\r
1510     jalview.datamodel.Provenance jprov = new jalview.datamodel.Provenance();\r
1511     for (int i = 0; i < prov.getEntryCount(); i++)\r
1512     {\r
1513       jprov.addEntry(prov.getEntry(i).getUser(), prov.getEntry(i).getAction(),\r
1514           prov.getEntry(i).getDate().toDate(), prov.getEntry(i).getId());\r
1515     }\r
1516 \r
1517     return jprov;\r
1518   }\r
1519 \r
1520   /**\r
1521    *\r
1522    * @return default initial provenance list for a Jalview created vamsas\r
1523    *         object.\r
1524    */\r
1525   Provenance dummyProvenance() {\r
1526     return dummyProvenance(null);\r
1527   }\r
1528 \r
1529   Entry dummyPEntry(String action) {\r
1530     Entry entry = new Entry();\r
1531     entry.setApp(this.provEntry.getApp());\r
1532     if (action != null)\r
1533       entry.setAction(action);\r
1534     else\r
1535       entry.setAction("created.");\r
1536     entry.setDate(new org.exolab.castor.types.Date(new java.util.Date()));\r
1537     entry.setUser(this.provEntry.getUser());\r
1538     return entry;\r
1539   }\r
1540 \r
1541   Provenance dummyProvenance(String action) {\r
1542     Provenance prov = new Provenance();\r
1543     prov.addEntry(dummyPEntry(action));\r
1544     return prov;\r
1545   }\r
1546 \r
1547   void addProvenance(Provenance p, String action) {\r
1548     p.addEntry(dummyPEntry(action));\r
1549   }\r
1550 \r
1551 }\r