3bca941fc3f8a30988b197327cf14942b1a0dc87
[jalview.git] / src / jalview / gui / Jalview2XML.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.gui;
20
21 import java.awt.Rectangle;
22 import java.io.*;
23 import java.lang.reflect.InvocationTargetException;
24 import java.net.*;
25 import java.util.*;
26 import java.util.Map.Entry;
27 import java.util.jar.*;
28
29 import javax.swing.*;
30
31 import org.exolab.castor.xml.*;
32
33 import jalview.bin.Cache;
34 import jalview.datamodel.Alignment;
35 import jalview.datamodel.AlignmentAnnotation;
36 import jalview.datamodel.AlignmentI;
37 import jalview.datamodel.SequenceI;
38 import jalview.schemabinding.version2.*;
39 import jalview.schemes.*;
40 import jalview.util.Platform;
41 import jalview.util.jarInputStreamProvider;
42 import jalview.viewmodel.AlignmentViewport;
43 import jalview.ws.jws2.Jws2Discoverer;
44 import jalview.ws.jws2.dm.AAConSettings;
45 import jalview.ws.jws2.jabaws2.Jws2Instance;
46 import jalview.ws.params.ArgumentI;
47 import jalview.ws.params.AutoCalcSetting;
48 import jalview.ws.params.WsParamSetI;
49
50 /**
51  * Write out the current jalview desktop state as a Jalview XML stream.
52  * 
53  * Note: the vamsas objects referred to here are primitive versions of the
54  * VAMSAS project schema elements - they are not the same and most likely never
55  * will be :)
56  * 
57  * @author $author$
58  * @version $Revision: 1.134 $
59  */
60 public class Jalview2XML
61 {
62   /**
63    * create/return unique hash string for sq
64    * 
65    * @param sq
66    * @return new or existing unique string for sq
67    */
68   String seqHash(SequenceI sq)
69   {
70     if (seqsToIds == null)
71     {
72       initSeqRefs();
73     }
74     if (seqsToIds.containsKey(sq))
75     {
76       return (String) seqsToIds.get(sq);
77     }
78     else
79     {
80       // create sequential key
81       String key = "sq" + (seqsToIds.size() + 1);
82       key = makeHashCode(sq, key); // check we don't have an external reference
83       // for it already.
84       seqsToIds.put(sq, key);
85       return key;
86     }
87   }
88
89   void clearSeqRefs()
90   {
91     if (_cleartables)
92     {
93       if (seqRefIds != null)
94       {
95         seqRefIds.clear();
96       }
97       if (seqsToIds != null)
98       {
99         seqsToIds.clear();
100       }
101       // seqRefIds = null;
102       // seqsToIds = null;
103     }
104     else
105     {
106       // do nothing
107       warn("clearSeqRefs called when _cleartables was not set. Doing nothing.");
108       // seqRefIds = new Hashtable();
109       // seqsToIds = new IdentityHashMap();
110     }
111   }
112
113   void initSeqRefs()
114   {
115     if (seqsToIds == null)
116     {
117       seqsToIds = new IdentityHashMap();
118     }
119     if (seqRefIds == null)
120     {
121       seqRefIds = new Hashtable();
122     }
123   }
124
125   /**
126    * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
127    * of sequence objects are created.
128    */
129   java.util.IdentityHashMap seqsToIds = null;
130
131   /**
132    * jalview XML Sequence ID to jalview sequence object reference (both dataset
133    * and alignment sequences. Populated as XML reps of sequence objects are
134    * created.)
135    */
136   java.util.Hashtable seqRefIds = null; // key->SequenceI resolution
137
138   Vector frefedSequence = null;
139
140   boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
141
142   public Jalview2XML()
143   {
144   }
145
146   public Jalview2XML(boolean raiseGUI)
147   {
148     this.raiseGUI = raiseGUI;
149   }
150
151   public void resolveFrefedSequences()
152   {
153     if (frefedSequence.size() > 0)
154     {
155       int r = 0, rSize = frefedSequence.size();
156       while (r < rSize)
157       {
158         Object[] ref = (Object[]) frefedSequence.elementAt(r);
159         if (ref != null)
160         {
161           String sref = (String) ref[0];
162           if (seqRefIds.containsKey(sref))
163           {
164             if (ref[1] instanceof jalview.datamodel.Mapping)
165             {
166               SequenceI seq = (SequenceI) seqRefIds.get(sref);
167               while (seq.getDatasetSequence() != null)
168               {
169                 seq = seq.getDatasetSequence();
170               }
171               ((jalview.datamodel.Mapping) ref[1]).setTo(seq);
172             }
173             else
174             {
175               if (ref[1] instanceof jalview.datamodel.AlignedCodonFrame)
176               {
177                 SequenceI seq = (SequenceI) seqRefIds.get(sref);
178                 while (seq.getDatasetSequence() != null)
179                 {
180                   seq = seq.getDatasetSequence();
181                 }
182                 if (ref[2] != null
183                         && ref[2] instanceof jalview.datamodel.Mapping)
184                 {
185                   jalview.datamodel.Mapping mp = (jalview.datamodel.Mapping) ref[2];
186                   ((jalview.datamodel.AlignedCodonFrame) ref[1]).addMap(
187                           seq, mp.getTo(), mp.getMap());
188                 }
189                 else
190                 {
191                   System.err
192                           .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for AlcodonFrames involving "
193                                   + ref[2].getClass() + " type objects.");
194                 }
195               }
196               else
197               {
198                 System.err
199                         .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for "
200                                 + ref[1].getClass() + " type objects.");
201               }
202             }
203             frefedSequence.remove(r);
204             rSize--;
205           }
206           else
207           {
208             System.err
209                     .println("IMPLEMENTATION WARNING: Unresolved forward reference for hash string "
210                             + ref[0]
211                             + " with objecttype "
212                             + ref[1].getClass());
213             r++;
214           }
215         }
216         else
217         {
218           // empty reference
219           frefedSequence.remove(r);
220           rSize--;
221         }
222       }
223     }
224   }
225
226   /**
227    * This maintains a list of viewports, the key being the seqSetId. Important
228    * to set historyItem and redoList for multiple views
229    */
230   Hashtable viewportsAdded;
231
232   Hashtable annotationIds = new Hashtable();
233
234   String uniqueSetSuffix = "";
235
236   /**
237    * List of pdbfiles added to Jar
238    */
239   Vector pdbfiles = null;
240
241   // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
242   public void SaveState(File statefile)
243   {
244     try
245     {
246       FileOutputStream fos = new FileOutputStream(statefile);
247       JarOutputStream jout = new JarOutputStream(fos);
248       SaveState(jout);
249
250     } catch (Exception e)
251     {
252       // TODO: inform user of the problem - they need to know if their data was
253       // not saved !
254       if (errorMessage == null)
255       {
256         errorMessage = "Couldn't write Jalview Archive to output file '"
257                 + statefile + "' - See console error log for details";
258       }
259       else
260       {
261         errorMessage += "(output file was '" + statefile + "')";
262       }
263       e.printStackTrace();
264     }
265     reportErrors();
266   }
267
268   /**
269    * Writes a jalview project archive to the given Jar output stream.
270    * 
271    * @param jout
272    */
273   public void SaveState(JarOutputStream jout)
274   {
275     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
276
277     if (frames == null)
278     {
279       return;
280     }
281
282     Hashtable<String,AlignFrame> dsses = new Hashtable<String,AlignFrame>();
283
284     try
285     {
286
287       // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
288       // //////////////////////////////////////////////////
289       // NOTE ALSO new PrintWriter must be used for each new JarEntry
290       PrintWriter out = null;
291
292       Vector shortNames = new Vector();
293
294       // REVERSE ORDER
295       for (int i = frames.length - 1; i > -1; i--)
296       {
297         if (frames[i] instanceof AlignFrame)
298         {
299           AlignFrame af = (AlignFrame) frames[i];
300           // skip ?
301           if (skipList != null
302                   && skipList.containsKey(af.getViewport()
303                           .getSequenceSetId()))
304           {
305             continue;
306           }
307
308           String shortName = af.getTitle();
309
310           if (shortName.indexOf(File.separatorChar) > -1)
311           {
312             shortName = shortName.substring(shortName
313                     .lastIndexOf(File.separatorChar) + 1);
314           }
315
316           int count = 1;
317
318           while (shortNames.contains(shortName))
319           {
320             if (shortName.endsWith("_" + (count - 1)))
321             {
322               shortName = shortName
323                       .substring(0, shortName.lastIndexOf("_"));
324             }
325
326             shortName = shortName.concat("_" + count);
327             count++;
328           }
329
330           shortNames.addElement(shortName);
331
332           if (!shortName.endsWith(".xml"))
333           {
334             shortName = shortName + ".xml";
335           }
336
337           int ap, apSize = af.alignPanels.size();
338
339           for (ap = 0; ap < apSize; ap++)
340           {
341             AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
342                     .elementAt(ap);
343             String fileName = apSize == 1 ? shortName : ap + shortName;
344             if (!fileName.endsWith(".xml"))
345             {
346               fileName = fileName + ".xml";
347             }
348
349             SaveState(apanel, fileName, jout);
350
351             String dssid = getDatasetIdRef(af.getViewport().getAlignment().getDataset());
352             if (!dsses.containsKey(dssid))
353             {
354               dsses.put(dssid, af);
355             }
356
357           }
358         }
359       }
360
361       writeDatasetFor(dsses, ""+jout.hashCode()+" "+uniqueSetSuffix, jout);
362       
363       try
364       {
365         jout.flush();
366       } catch (Exception foo)
367       {
368       }
369       ;
370       jout.close();
371     } catch (Exception ex)
372     {
373       // TODO: inform user of the problem - they need to know if their data was
374       // not saved !
375       if (errorMessage == null)
376       {
377         errorMessage = "Couldn't write Jalview Archive - see error output for details";
378       }
379       ex.printStackTrace();
380     }
381   }
382
383   // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
384   public boolean SaveAlignment(AlignFrame af, String jarFile,
385           String fileName)
386   {
387     try
388     {
389       int ap, apSize = af.alignPanels.size();
390       FileOutputStream fos = new FileOutputStream(jarFile);
391       JarOutputStream jout = new JarOutputStream(fos);
392       Hashtable<String,AlignFrame> dsses = new Hashtable<String,AlignFrame>();
393       for (ap = 0; ap < apSize; ap++)
394       {
395         AlignmentPanel apanel = (AlignmentPanel) af.alignPanels
396                 .elementAt(ap);
397         String jfileName = apSize == 1 ? fileName : fileName + ap;
398         if (!jfileName.endsWith(".xml"))
399         {
400           jfileName = jfileName + ".xml";
401         }
402         SaveState(apanel, jfileName, jout);
403         String dssid = getDatasetIdRef(af.getViewport().getAlignment().getDataset());
404         if (!dsses.containsKey(dssid))
405         {
406           dsses.put(dssid, af);
407         }
408       }
409       writeDatasetFor(dsses, fileName, jout);
410       try
411       {
412         jout.flush();
413       } catch (Exception foo)
414       {
415       }
416       ;
417       jout.close();
418       return true;
419     } catch (Exception ex)
420     {
421       errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
422       ex.printStackTrace();
423       return false;
424     }
425   }
426
427   private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
428           String fileName, JarOutputStream jout)
429   {
430
431     for (String dssids:dsses.keySet())
432     {
433       AlignFrame _af = dsses.get(dssids);
434       String jfileName = fileName + " Dataset for "+ _af.getTitle();
435       if (!jfileName.endsWith(".xml"))
436       {
437         jfileName = jfileName + ".xml";
438       }
439       SaveState(_af.alignPanel, jfileName, true, jout);
440     }
441   }
442
443   /**
444    * create a JalviewModel from an algnment view and marshall it to a
445    * JarOutputStream
446    * 
447    * @param ap
448    *          panel to create jalview model for
449    * @param fileName
450    *          name of alignment panel written to output stream
451    * @param jout
452    *          jar output stream
453    * @param out
454    *          jar entry name
455    */
456   public JalviewModel SaveState(AlignmentPanel ap, String fileName,
457           JarOutputStream jout)
458   {
459     return SaveState(ap, fileName, false,jout);
460   }
461   /**
462   * create a JalviewModel from an algnment view and marshall it to a
463   * JarOutputStream
464   * 
465   * @param ap
466   *          panel to create jalview model for
467   * @param fileName
468   *          name of alignment panel written to output stream
469   * @param storeDS
470   *          when true, only write the dataset for the alignment, not the data associated with the view.
471   * @param jout
472   *          jar output stream
473   * @param out
474   *          jar entry name
475   */
476   public JalviewModel SaveState(AlignmentPanel ap, String fileName, boolean storeDS,
477           JarOutputStream jout)
478   {
479     initSeqRefs();
480     Vector jmolViewIds = new Vector(); //
481     Vector userColours = new Vector();
482
483     AlignViewport av = ap.av;
484
485     JalviewModel object = new JalviewModel();
486     object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
487
488     object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
489     object.setVersion(jalview.bin.Cache.getDefault("VERSION","Development Build"));
490
491     jalview.datamodel.AlignmentI jal = av.getAlignment();
492
493     if (av.hasHiddenRows())
494     {
495       jal = jal.getHiddenSequences().getFullAlignment();
496     }
497
498     SequenceSet vamsasSet = new SequenceSet();
499     Sequence vamsasSeq;
500     JalviewModelSequence jms = new JalviewModelSequence();
501
502     vamsasSet.setGapChar(jal.getGapCharacter() + "");
503
504     if (jal.getDataset() != null)
505     {
506       // dataset id is the dataset's hashcode
507       vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
508       if (storeDS)
509       {
510         // switch jal and the dataset
511         jal = jal.getDataset();
512       }
513     }
514     if (jal.getProperties() != null)
515     {
516       Enumeration en = jal.getProperties().keys();
517       while (en.hasMoreElements())
518       {
519         String key = en.nextElement().toString();
520         SequenceSetProperties ssp = new SequenceSetProperties();
521         ssp.setKey(key);
522         ssp.setValue(jal.getProperties().get(key).toString());
523         vamsasSet.addSequenceSetProperties(ssp);
524       }
525     }
526
527     JSeq jseq;
528     Set<String> calcIdSet = new HashSet<String>();
529
530     // SAVE SEQUENCES
531     String id = "";
532     jalview.datamodel.SequenceI jds,jdatasq;
533     for (int i = 0; i < jal.getHeight(); i++)
534     {
535       jds = jal.getSequenceAt(i);
536       jdatasq=jds.getDatasetSequence() == null ? jds : jds.getDatasetSequence();
537       id = seqHash(jds);
538
539       if (seqRefIds.get(id) != null)
540       {
541         // This happens for two reasons: 1. multiple views are being serialised.
542         // 2. the hashCode has collided with another sequence's code. This DOES
543         // HAPPEN! (PF00072.15.stk does this)
544         // JBPNote: Uncomment to debug writing out of files that do not read
545         // back in due to ArrayOutOfBoundExceptions.
546         // System.err.println("vamsasSeq backref: "+id+"");
547         // System.err.println(jds.getName()+"
548         // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
549         // System.err.println("Hashcode: "+seqHash(jds));
550         // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
551         // System.err.println(rsq.getName()+"
552         // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
553         // System.err.println("Hashcode: "+seqHash(rsq));
554       }
555       else
556       {
557         vamsasSeq = createVamsasSequence(id, jds);
558         vamsasSet.addSequence(vamsasSeq);
559         seqRefIds.put(id, jds);
560       }
561
562       jseq = new JSeq();
563       jseq.setStart(jds.getStart());
564       jseq.setEnd(jds.getEnd());
565       jseq.setColour(av.getSequenceColour(jds).getRGB());
566
567       jseq.setId(id); // jseq id should be a string not a number
568       if (!storeDS)
569       {
570         // Store any sequences this sequence represents
571         if (av.hasHiddenRows())
572         {
573           jseq.setHidden(av.getAlignment().getHiddenSequences()
574                   .isHidden(jds));
575
576           if (av.isHiddenRepSequence(jal.getSequenceAt(i)))
577           {
578             jalview.datamodel.SequenceI[] reps = av
579                     .getRepresentedSequences(jal.getSequenceAt(i))
580                     .getSequencesInOrder(jal);
581
582             for (int h = 0; h < reps.length; h++)
583             {
584               if (reps[h] != jal.getSequenceAt(i))
585               {
586                 jseq.addHiddenSequences(jal.findIndex(reps[h]));
587               }
588             }
589           }
590         }
591       }
592
593       if (jdatasq.getSequenceFeatures() != null)
594       {
595         jalview.datamodel.SequenceFeature[] sf = jdatasq
596                 .getSequenceFeatures();
597         int index = 0;
598         while (index < sf.length)
599         {
600           Features features = new Features();
601
602           features.setBegin(sf[index].getBegin());
603           features.setEnd(sf[index].getEnd());
604           features.setDescription(sf[index].getDescription());
605           features.setType(sf[index].getType());
606           features.setFeatureGroup(sf[index].getFeatureGroup());
607           features.setScore(sf[index].getScore());
608           if (sf[index].links != null)
609           {
610             for (int l = 0; l < sf[index].links.size(); l++)
611             {
612               OtherData keyValue = new OtherData();
613               keyValue.setKey("LINK_" + l);
614               keyValue.setValue(sf[index].links.elementAt(l).toString());
615               features.addOtherData(keyValue);
616             }
617           }
618           if (sf[index].otherDetails != null)
619           {
620             String key;
621             Enumeration keys = sf[index].otherDetails.keys();
622             while (keys.hasMoreElements())
623             {
624               key = keys.nextElement().toString();
625               OtherData keyValue = new OtherData();
626               keyValue.setKey(key);
627               keyValue.setValue(sf[index].otherDetails.get(key).toString());
628               features.addOtherData(keyValue);
629             }
630           }
631
632           jseq.addFeatures(features);
633           index++;
634         }
635       }
636
637       if (jdatasq.getPDBId() != null)
638       {
639         Enumeration en = jdatasq.getPDBId().elements();
640         while (en.hasMoreElements())
641         {
642           Pdbids pdb = new Pdbids();
643           jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
644                   .nextElement();
645
646           pdb.setId(entry.getId());
647           pdb.setType(entry.getType());
648           //
649           // store any JMol views associated with this seqeunce
650           // this section copes with duplicate entries in the project, so a
651           // dataset only view *should* be coped with sensibly
652           AppJmol jmol;
653           // This must have been loaded, is it still visible?
654           JInternalFrame[] frames = Desktop.desktop.getAllFrames();
655           String matchedFile = null;
656           for (int f = frames.length - 1; f > -1; f--)
657           {
658             if (frames[f] instanceof AppJmol)
659             {
660               jmol = (AppJmol) frames[f];
661               for (int peid = 0; peid < jmol.jmb.pdbentry.length; peid++)
662               {
663                 if (!jmol.jmb.pdbentry[peid].getId().equals(entry.getId())
664                         && !(entry.getId().length() > 4 && entry
665                                 .getId()
666                                 .toLowerCase()
667                                 .startsWith(
668                                         jmol.jmb.pdbentry[peid].getId()
669                                                 .toLowerCase())))
670                   continue;
671                 if (matchedFile == null)
672                 {
673                   matchedFile = jmol.jmb.pdbentry[peid].getFile();
674                 }
675                 else if (!matchedFile.equals(jmol.jmb.pdbentry[peid]
676                         .getFile()))
677                 {
678                   Cache.log
679                           .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
680                                   + jmol.jmb.pdbentry[peid].getFile());
681                   ; // record the
682                 }
683                 // file so we
684                 // can get at it if the ID
685                 // match is ambiguous (e.g.
686                 // 1QIP==1qipA)
687                 String statestring = jmol.jmb.viewer.getStateInfo();
688
689                 for (int smap = 0; smap < jmol.jmb.sequence[peid].length; smap++)
690                 {
691                   // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
692                   if (jds == jmol.jmb.sequence[peid][smap])
693                   {
694                     StructureState state = new StructureState();
695                     state.setVisible(true);
696                     state.setXpos(jmol.getX());
697                     state.setYpos(jmol.getY());
698                     state.setWidth(jmol.getWidth());
699                     state.setHeight(jmol.getHeight());
700                     state.setViewId(jmol.getViewId());
701                     state.setAlignwithAlignPanel(jmol.isUsedforaligment(ap));
702                     state.setColourwithAlignPanel(jmol
703                             .isUsedforcolourby(ap));
704                     state.setColourByJmol(jmol.isColouredByJmol());
705                     if (!jmolViewIds.contains(state.getViewId()))
706                     {
707                       // Make sure we only store a Jmol state once in each XML
708                       // document.
709                       jmolViewIds.addElement(state.getViewId());
710                       state.setContent(statestring.replaceAll("\n", ""));
711                     }
712                     else
713                     {
714                       state.setContent("# duplicate state");
715                     }
716                     pdb.addStructureState(state);
717                   }
718
719                 }
720               }
721             }
722           }
723
724           if (matchedFile != null || entry.getFile() != null)
725           {
726             if (entry.getFile() != null)
727             {
728               // use entry's file
729               matchedFile = entry.getFile();
730             }
731             pdb.setFile(matchedFile); // entry.getFile());
732             if (pdbfiles == null)
733             {
734               pdbfiles = new Vector();
735             }
736
737             if (!pdbfiles.contains(entry.getId()))
738             {
739               pdbfiles.addElement(entry.getId());
740               try
741               {
742                 File file = new File(matchedFile);
743                 if (file.exists() && jout != null)
744                 {
745                   byte[] data = new byte[(int) file.length()];
746                   jout.putNextEntry(new JarEntry(entry.getId()));
747                   DataInputStream dis = new DataInputStream(
748                           new FileInputStream(file));
749                   dis.readFully(data);
750
751                   DataOutputStream dout = new DataOutputStream(jout);
752                   dout.write(data, 0, data.length);
753                   dout.flush();
754                   jout.closeEntry();
755                 }
756               } catch (Exception ex)
757               {
758                 ex.printStackTrace();
759               }
760
761             }
762           }
763
764           if (entry.getProperty() != null)
765           {
766             PdbentryItem item = new PdbentryItem();
767             Hashtable properties = entry.getProperty();
768             Enumeration en2 = properties.keys();
769             while (en2.hasMoreElements())
770             {
771               Property prop = new Property();
772               String key = en2.nextElement().toString();
773               prop.setName(key);
774               prop.setValue(properties.get(key).toString());
775               item.addProperty(prop);
776             }
777             pdb.addPdbentryItem(item);
778           }
779
780           jseq.addPdbids(pdb);
781         }
782       }
783
784       jms.addJSeq(jseq);
785     }
786
787     if (!storeDS && av.hasHiddenRows())
788     {
789       jal = av.getAlignment();
790     }
791     // SAVE MAPPINGS
792     if (jal.getCodonFrames() != null && jal.getCodonFrames().length > 0)
793     {
794       jalview.datamodel.AlignedCodonFrame[] jac = jal.getCodonFrames();
795       for (int i = 0; i < jac.length; i++)
796       {
797         AlcodonFrame alc = new AlcodonFrame();
798         vamsasSet.addAlcodonFrame(alc);
799         for (int p = 0; p < jac[i].aaWidth; p++)
800         {
801           Alcodon cmap = new Alcodon();
802           if (jac[i].codons[p] != null)
803           {
804             // Null codons indicate a gapped column in the translated peptide
805             // alignment.
806             cmap.setPos1(jac[i].codons[p][0]);
807             cmap.setPos2(jac[i].codons[p][1]);
808             cmap.setPos3(jac[i].codons[p][2]);
809           }
810           alc.addAlcodon(cmap);
811         }
812         if (jac[i].getProtMappings() != null
813                 && jac[i].getProtMappings().length > 0)
814         {
815           SequenceI[] dnas = jac[i].getdnaSeqs();
816           jalview.datamodel.Mapping[] pmaps = jac[i].getProtMappings();
817           for (int m = 0; m < pmaps.length; m++)
818           {
819             AlcodMap alcmap = new AlcodMap();
820             alcmap.setDnasq(seqHash(dnas[m]));
821             alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
822                     false));
823             alc.addAlcodMap(alcmap);
824           }
825         }
826       }
827     }
828
829     // SAVE TREES
830     // /////////////////////////////////
831     if (!storeDS && av.currentTree != null)
832     {
833       // FIND ANY ASSOCIATED TREES
834       // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
835       if (Desktop.desktop != null)
836       {
837         JInternalFrame[] frames = Desktop.desktop.getAllFrames();
838
839         for (int t = 0; t < frames.length; t++)
840         {
841           if (frames[t] instanceof TreePanel)
842           {
843             TreePanel tp = (TreePanel) frames[t];
844
845             if (tp.treeCanvas.av.getAlignment() == jal)
846             {
847               Tree tree = new Tree();
848               tree.setTitle(tp.getTitle());
849               tree.setCurrentTree((av.currentTree == tp.getTree()));
850               tree.setNewick(tp.getTree().toString());
851               tree.setThreshold(tp.treeCanvas.threshold);
852
853               tree.setFitToWindow(tp.fitToWindow.getState());
854               tree.setFontName(tp.getTreeFont().getName());
855               tree.setFontSize(tp.getTreeFont().getSize());
856               tree.setFontStyle(tp.getTreeFont().getStyle());
857               tree.setMarkUnlinked(tp.placeholdersMenu.getState());
858
859               tree.setShowBootstrap(tp.bootstrapMenu.getState());
860               tree.setShowDistances(tp.distanceMenu.getState());
861
862               tree.setHeight(tp.getHeight());
863               tree.setWidth(tp.getWidth());
864               tree.setXpos(tp.getX());
865               tree.setYpos(tp.getY());
866               tree.setId(makeHashCode(tp, null));
867               jms.addTree(tree);
868             }
869           }
870         }
871       }
872     }
873     // SAVE ANNOTATIONS
874     /**
875      * store forward refs from an annotationRow to any groups
876      */
877     IdentityHashMap groupRefs = new IdentityHashMap();
878     if (storeDS)
879     {
880         for (SequenceI sq:jal.getSequences())
881         {
882        // Store annotation on dataset sequences only
883           jalview.datamodel.AlignmentAnnotation[] aa = sq.getAnnotation();
884           if (aa!=null && aa.length>0)
885           {
886             storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
887                     vamsasSet);
888           }
889         }
890     } else {
891       if (jal.getAlignmentAnnotation() != null)
892       {
893         // Store the annotation shown on the alignment.
894         jalview.datamodel.AlignmentAnnotation[] aa = jal
895                 .getAlignmentAnnotation();
896         storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
897                 vamsasSet);
898       }
899     }
900     // SAVE GROUPS
901     if (jal.getGroups() != null)
902     {
903       JGroup[] groups = new JGroup[jal.getGroups().size()];
904       int i = -1;
905       for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
906       {
907         groups[++i] = new JGroup();
908
909         groups[i].setStart(sg.getStartRes());
910         groups[i].setEnd(sg.getEndRes());
911         groups[i].setName(sg.getName());
912         if (groupRefs.containsKey(sg))
913         {
914           // group has references so set it's ID field
915           groups[i].setId(groupRefs.get(sg).toString());
916         }
917         if (sg.cs != null)
918         {
919           if (sg.cs.conservationApplied())
920           {
921             groups[i].setConsThreshold(sg.cs.getConservationInc());
922
923             if (sg.cs instanceof jalview.schemes.UserColourScheme)
924             {
925               groups[i].setColour(SetUserColourScheme(sg.cs, userColours,
926                       jms));
927             }
928             else
929             {
930               groups[i]
931                       .setColour(ColourSchemeProperty.getColourName(sg.cs));
932             }
933           }
934           else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient)
935           {
936             groups[i]
937                     .setColour(ColourSchemeProperty
938                             .getColourName(((jalview.schemes.AnnotationColourGradient) sg.cs)
939                                     .getBaseColour()));
940           }
941           else if (sg.cs instanceof jalview.schemes.UserColourScheme)
942           {
943             groups[i]
944                     .setColour(SetUserColourScheme(sg.cs, userColours, jms));
945           }
946           else
947           {
948             groups[i].setColour(ColourSchemeProperty.getColourName(sg.cs));
949           }
950
951           groups[i].setPidThreshold(sg.cs.getThreshold());
952         }
953
954         groups[i].setOutlineColour(sg.getOutlineColour().getRGB());
955         groups[i].setDisplayBoxes(sg.getDisplayBoxes());
956         groups[i].setDisplayText(sg.getDisplayText());
957         groups[i].setColourText(sg.getColourText());
958         groups[i].setTextCol1(sg.textColour.getRGB());
959         groups[i].setTextCol2(sg.textColour2.getRGB());
960         groups[i].setTextColThreshold(sg.thresholdTextColour);
961         groups[i].setShowUnconserved(sg.getShowNonconserved());
962         groups[i].setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
963         groups[i].setShowConsensusHistogram(sg.isShowConsensusHistogram());
964         groups[i].setShowSequenceLogo(sg.isShowSequenceLogo());
965         groups[i].setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
966         for (int s = 0; s < sg.getSize(); s++)
967         {
968           jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg
969                   .getSequenceAt(s);
970           groups[i].addSeq(seqHash(seq));
971         }
972       }
973
974       jms.setJGroup(groups);
975     }
976     if (!storeDS)
977     {
978       // /////////SAVE VIEWPORT
979       Viewport view = new Viewport();
980       view.setTitle(ap.alignFrame.getTitle());
981       view.setSequenceSetId(makeHashCode(av.getSequenceSetId(),
982               av.getSequenceSetId()));
983       view.setId(av.getViewId());
984       view.setViewName(av.viewName);
985       view.setGatheredViews(av.gatherViewsHere);
986
987       if (ap.av.explodedPosition != null)
988       {
989         view.setXpos(av.explodedPosition.x);
990         view.setYpos(av.explodedPosition.y);
991         view.setWidth(av.explodedPosition.width);
992         view.setHeight(av.explodedPosition.height);
993       }
994       else
995       {
996         view.setXpos(ap.alignFrame.getBounds().x);
997         view.setYpos(ap.alignFrame.getBounds().y);
998         view.setWidth(ap.alignFrame.getBounds().width);
999         view.setHeight(ap.alignFrame.getBounds().height);
1000       }
1001
1002       view.setStartRes(av.startRes);
1003       view.setStartSeq(av.startSeq);
1004
1005       if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1006       {
1007         view.setBgColour(SetUserColourScheme(av.getGlobalColourScheme(),
1008                 userColours, jms));
1009       }
1010       else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1011       {
1012         jalview.schemes.AnnotationColourGradient acg = (jalview.schemes.AnnotationColourGradient) av
1013                 .getGlobalColourScheme();
1014
1015         AnnotationColours ac = new AnnotationColours();
1016         ac.setAboveThreshold(acg.getAboveThreshold());
1017         ac.setThreshold(acg.getAnnotationThreshold());
1018         ac.setAnnotation(acg.getAnnotation());
1019         if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
1020         {
1021           ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(),
1022                   userColours, jms));
1023         }
1024         else
1025         {
1026           ac.setColourScheme(ColourSchemeProperty.getColourName(acg
1027                   .getBaseColour()));
1028         }
1029
1030         ac.setMaxColour(acg.getMaxColour().getRGB());
1031         ac.setMinColour(acg.getMinColour().getRGB());
1032         ac.setPerSequence(acg.isSeqAssociated());
1033         ac.setPredefinedColours(acg.isPredefinedColours());
1034         view.setAnnotationColours(ac);
1035         view.setBgColour("AnnotationColourGradient");
1036       }
1037       else
1038       {
1039         view.setBgColour(ColourSchemeProperty.getColourName(av
1040                 .getGlobalColourScheme()));
1041       }
1042
1043       ColourSchemeI cs = av.getGlobalColourScheme();
1044
1045       if (cs != null)
1046       {
1047         if (cs.conservationApplied())
1048         {
1049           view.setConsThreshold(cs.getConservationInc());
1050           if (cs instanceof jalview.schemes.UserColourScheme)
1051           {
1052             view.setBgColour(SetUserColourScheme(cs, userColours, jms));
1053           }
1054         }
1055
1056         if (cs instanceof ResidueColourScheme)
1057         {
1058           view.setPidThreshold(cs.getThreshold());
1059         }
1060       }
1061
1062       view.setConservationSelected(av.getConservationSelected());
1063       view.setPidSelected(av.getAbovePIDThreshold());
1064       view.setFontName(av.font.getName());
1065       view.setFontSize(av.font.getSize());
1066       view.setFontStyle(av.font.getStyle());
1067       view.setRenderGaps(av.renderGaps);
1068       view.setShowAnnotation(av.getShowAnnotation());
1069       view.setShowBoxes(av.getShowBoxes());
1070       view.setShowColourText(av.getColourText());
1071       view.setShowFullId(av.getShowJVSuffix());
1072       view.setRightAlignIds(av.rightAlignIds);
1073       view.setShowSequenceFeatures(av.showSequenceFeatures);
1074       view.setShowText(av.getShowText());
1075       view.setShowUnconserved(av.getShowUnconserved());
1076       view.setWrapAlignment(av.getWrapAlignment());
1077       view.setTextCol1(av.textColour.getRGB());
1078       view.setTextCol2(av.textColour2.getRGB());
1079       view.setTextColThreshold(av.thresholdTextColour);
1080       view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1081       view.setShowSequenceLogo(av.isShowSequenceLogo());
1082       view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1083       view.setShowGroupConsensus(av.isShowGroupConsensus());
1084       view.setShowGroupConservation(av.isShowGroupConservation());
1085       view.setShowNPfeatureTooltip(av.isShowNpFeats());
1086       view.setShowDbRefTooltip(av.isShowDbRefs());
1087       view.setFollowHighlight(av.followHighlight);
1088       view.setFollowSelection(av.followSelection);
1089       view.setIgnoreGapsinConsensus(av.getIgnoreGapsConsensus());
1090       if (av.featuresDisplayed != null)
1091       {
1092         jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1093
1094         String[] renderOrder = ap.seqPanel.seqCanvas.getFeatureRenderer().renderOrder;
1095
1096         Vector settingsAdded = new Vector();
1097         Object gstyle = null;
1098         GraduatedColor gcol = null;
1099         if (renderOrder != null)
1100         {
1101           for (int ro = 0; ro < renderOrder.length; ro++)
1102           {
1103             gstyle = ap.seqPanel.seqCanvas.getFeatureRenderer()
1104                     .getFeatureStyle(renderOrder[ro]);
1105             Setting setting = new Setting();
1106             setting.setType(renderOrder[ro]);
1107             if (gstyle instanceof GraduatedColor)
1108             {
1109               gcol = (GraduatedColor) gstyle;
1110               setting.setColour(gcol.getMaxColor().getRGB());
1111               setting.setMincolour(gcol.getMinColor().getRGB());
1112               setting.setMin(gcol.getMin());
1113               setting.setMax(gcol.getMax());
1114               setting.setColourByLabel(gcol.isColourByLabel());
1115               setting.setAutoScale(gcol.isAutoScale());
1116               setting.setThreshold(gcol.getThresh());
1117               setting.setThreshstate(gcol.getThreshType());
1118             }
1119             else
1120             {
1121               setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
1122                       .getColour(renderOrder[ro]).getRGB());
1123             }
1124
1125             setting.setDisplay(av.featuresDisplayed
1126                     .containsKey(renderOrder[ro]));
1127             float rorder = ap.seqPanel.seqCanvas.getFeatureRenderer()
1128                     .getOrder(renderOrder[ro]);
1129             if (rorder > -1)
1130             {
1131               setting.setOrder(rorder);
1132             }
1133             fs.addSetting(setting);
1134             settingsAdded.addElement(renderOrder[ro]);
1135           }
1136         }
1137
1138         // Make sure we save none displayed feature settings
1139         Iterator en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours
1140                 .keySet().iterator();
1141         while (en.hasNext())
1142         {
1143           String key = en.next().toString();
1144           if (settingsAdded.contains(key))
1145           {
1146             continue;
1147           }
1148
1149           Setting setting = new Setting();
1150           setting.setType(key);
1151           setting.setColour(ap.seqPanel.seqCanvas.getFeatureRenderer()
1152                   .getColour(key).getRGB());
1153
1154           setting.setDisplay(false);
1155           float rorder = ap.seqPanel.seqCanvas.getFeatureRenderer()
1156                   .getOrder(key);
1157           if (rorder > -1)
1158           {
1159             setting.setOrder(rorder);
1160           }
1161           fs.addSetting(setting);
1162           settingsAdded.addElement(key);
1163         }
1164         en = ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups
1165                 .keySet().iterator();
1166         Vector groupsAdded = new Vector();
1167         while (en.hasNext())
1168         {
1169           String grp = en.next().toString();
1170           if (groupsAdded.contains(grp))
1171           {
1172             continue;
1173           }
1174           Group g = new Group();
1175           g.setName(grp);
1176           g.setDisplay(((Boolean) ap.seqPanel.seqCanvas
1177                   .getFeatureRenderer().featureGroups.get(grp))
1178                   .booleanValue());
1179           fs.addGroup(g);
1180           groupsAdded.addElement(grp);
1181         }
1182         jms.setFeatureSettings(fs);
1183
1184       }
1185
1186       if (av.hasHiddenColumns())
1187       {
1188         if (av.getColumnSelection() == null
1189                 || av.getColumnSelection().getHiddenColumns() == null)
1190         {
1191           warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1192         }
1193         else
1194         {
1195           for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
1196                   .size(); c++)
1197           {
1198             int[] region = (int[]) av.getColumnSelection()
1199                     .getHiddenColumns().elementAt(c);
1200             HiddenColumns hc = new HiddenColumns();
1201             hc.setStart(region[0]);
1202             hc.setEnd(region[1]);
1203             view.addHiddenColumns(hc);
1204           }
1205         }
1206       }
1207       if (calcIdSet.size() > 0)
1208       {
1209         for (String calcId : calcIdSet)
1210         {
1211           if (calcId.trim().length() > 0)
1212           {
1213             CalcIdParam cidp = createCalcIdParam(calcId, av);
1214             // Some calcIds have no parameters.
1215             if (cidp != null)
1216             {
1217               view.addCalcIdParam(cidp);
1218             }
1219           }
1220         }
1221       }
1222
1223       jms.addViewport(view);
1224     }
1225     object.setJalviewModelSequence(jms);
1226     object.getVamsasModel().addSequenceSet(vamsasSet);
1227
1228     if (jout != null && fileName != null)
1229     {
1230       // We may not want to write the object to disk,
1231       // eg we can copy the alignViewport to a new view object
1232       // using save and then load
1233       try
1234       {
1235         JarEntry entry = new JarEntry(fileName);
1236         jout.putNextEntry(entry);
1237         PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout,
1238                 "UTF-8"));
1239         org.exolab.castor.xml.Marshaller marshaller = new org.exolab.castor.xml.Marshaller(
1240                 pout);
1241         marshaller.marshal(object);
1242         pout.flush();
1243         jout.closeEntry();
1244       } catch (Exception ex)
1245       {
1246         // TODO: raise error in GUI if marshalling failed.
1247         ex.printStackTrace();
1248       }
1249     }
1250     return object;
1251   }
1252
1253   private void storeAlignmentAnnotation(AlignmentAnnotation[] aa, IdentityHashMap groupRefs, AlignmentViewport av, Set<String> calcIdSet, boolean storeDS, SequenceSet vamsasSet)
1254   {
1255
1256     for (int i = 0; i < aa.length; i++)
1257     {
1258       Annotation an = new Annotation();
1259
1260       if (aa[i].annotationId != null)
1261       {
1262         annotationIds.put(aa[i].annotationId, aa[i]);
1263       }
1264
1265       an.setId(aa[i].annotationId);
1266
1267       an.setVisible(aa[i].visible);
1268
1269       an.setDescription(aa[i].description);
1270
1271       if (aa[i].sequenceRef != null)
1272       {
1273         // TODO later annotation sequenceRef should be the XML ID of the
1274         // sequence rather than its display name
1275         an.setSequenceRef(aa[i].sequenceRef.getName());
1276       }
1277       if (aa[i].groupRef != null)
1278       {
1279         Object groupIdr = groupRefs.get(aa[i].groupRef);
1280         if (groupIdr == null)
1281         {
1282           // make a locally unique String
1283           groupRefs.put(aa[i].groupRef,
1284                   groupIdr = ("" + System.currentTimeMillis()
1285                           + aa[i].groupRef.getName() + groupRefs.size()));
1286         }
1287         an.setGroupRef(groupIdr.toString());
1288       }
1289
1290       // store all visualization attributes for annotation
1291       an.setGraphHeight(aa[i].graphHeight);
1292       an.setCentreColLabels(aa[i].centreColLabels);
1293       an.setScaleColLabels(aa[i].scaleColLabel);
1294       an.setShowAllColLabels(aa[i].showAllColLabels);
1295       an.setBelowAlignment(aa[i].belowAlignment);
1296
1297       if (aa[i].graph > 0)
1298       {
1299         an.setGraph(true);
1300         an.setGraphType(aa[i].graph);
1301         an.setGraphGroup(aa[i].graphGroup);
1302         if (aa[i].getThreshold() != null)
1303         {
1304           ThresholdLine line = new ThresholdLine();
1305           line.setLabel(aa[i].getThreshold().label);
1306           line.setValue(aa[i].getThreshold().value);
1307           line.setColour(aa[i].getThreshold().colour.getRGB());
1308           an.setThresholdLine(line);
1309         }
1310       }
1311       else
1312       {
1313         an.setGraph(false);
1314       }
1315
1316       an.setLabel(aa[i].label);
1317
1318       if (aa[i] == av.getAlignmentQualityAnnot()
1319               || aa[i] == av.getAlignmentConservationAnnotation()
1320               || aa[i] == av.getAlignmentConsensusAnnotation()
1321               || aa[i].autoCalculated)
1322       {
1323         // new way of indicating autocalculated annotation -
1324         an.setAutoCalculated(aa[i].autoCalculated);
1325       }
1326       if (aa[i].hasScore())
1327       {
1328         an.setScore(aa[i].getScore());
1329       }
1330
1331       if (aa[i].getCalcId() != null)
1332       {
1333         calcIdSet.add(aa[i].getCalcId());
1334         an.setCalcId(aa[i].getCalcId());
1335       }
1336
1337       AnnotationElement ae;
1338       if (aa[i].annotations != null)
1339       {
1340         an.setScoreOnly(false);
1341         for (int a = 0; a < aa[i].annotations.length; a++)
1342         {
1343           if ((aa[i] == null) || (aa[i].annotations[a] == null))
1344           {
1345             continue;
1346           }
1347
1348           ae = new AnnotationElement();
1349           if (aa[i].annotations[a].description != null)
1350             ae.setDescription(aa[i].annotations[a].description);
1351           if (aa[i].annotations[a].displayCharacter != null)
1352             ae.setDisplayCharacter(aa[i].annotations[a].displayCharacter);
1353
1354           if (!Float.isNaN(aa[i].annotations[a].value))
1355             ae.setValue(aa[i].annotations[a].value);
1356
1357           ae.setPosition(a);
1358           if (aa[i].annotations[a].secondaryStructure != ' '
1359                   && aa[i].annotations[a].secondaryStructure != '\0')
1360             ae.setSecondaryStructure(aa[i].annotations[a].secondaryStructure
1361                     + "");
1362
1363           if (aa[i].annotations[a].colour != null
1364                   && aa[i].annotations[a].colour != java.awt.Color.black)
1365           {
1366             ae.setColour(aa[i].annotations[a].colour.getRGB());
1367           }
1368
1369           an.addAnnotationElement(ae);
1370           if (aa[i].autoCalculated)
1371           {
1372             // only write one non-null entry into the annotation row -
1373             // sufficient to get the visualization attributes necessary to
1374             // display data
1375             continue;
1376           }
1377         }
1378       }
1379       else
1380       {
1381         an.setScoreOnly(true);
1382       }
1383       if (!storeDS || (storeDS && !aa[i].autoCalculated))
1384       {
1385         // skip autocalculated annotation - these are only provided for alignments
1386         vamsasSet.addAnnotation(an);
1387       }
1388     }
1389     
1390   }
1391
1392   private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1393   {
1394     AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1395     if (settings != null)
1396     {
1397       CalcIdParam vCalcIdParam = new CalcIdParam();
1398       vCalcIdParam.setCalcId(calcId);
1399       vCalcIdParam.addServiceURL(settings.getServiceURI());
1400       // generic URI allowing a third party to resolve another instance of the
1401       // service used for this calculation
1402       for (String urls : settings.getServiceURLs())
1403       {
1404         vCalcIdParam.addServiceURL(urls);
1405       }
1406       vCalcIdParam.setVersion("1.0");
1407       if (settings.getPreset() != null)
1408       {
1409         WsParamSetI setting = settings.getPreset();
1410         vCalcIdParam.setName(setting.getName());
1411         vCalcIdParam.setDescription(setting.getDescription());
1412       }
1413       else
1414       {
1415         vCalcIdParam.setName("");
1416         vCalcIdParam.setDescription("Last used parameters");
1417       }
1418       // need to be able to recover 1) settings 2) user-defined presets or
1419       // recreate settings from preset 3) predefined settings provided by
1420       // service - or settings that can be transferred (or discarded)
1421       vCalcIdParam.setParameters(settings.getWsParamFile().replace("\n",
1422               "|\\n|"));
1423       vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1424       // todo - decide if updateImmediately is needed for any projects.
1425
1426       return vCalcIdParam;
1427     }
1428     return null;
1429   }
1430
1431   private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1432           AlignViewport av)
1433   {
1434     if (calcIdParam.getVersion().equals("1.0"))
1435     {
1436       Jws2Instance service = Jws2Discoverer.getDiscoverer()
1437               .getPreferredServiceFor(calcIdParam.getServiceURL());
1438       if (service != null)
1439       {
1440         WsParamSetI parmSet = null;
1441         try
1442         {
1443           parmSet = service.getParamStore().parseServiceParameterFile(
1444                   calcIdParam.getName(), calcIdParam.getDescription(),
1445                   calcIdParam.getServiceURL(),
1446                   calcIdParam.getParameters().replace("|\\n|", "\n"));
1447         } catch (IOException x)
1448         {
1449           warn("Couldn't parse parameter data for "
1450                   + calcIdParam.getCalcId(), x);
1451           return false;
1452         }
1453         List<ArgumentI> argList = null;
1454         if (calcIdParam.getName().length() > 0)
1455         {
1456           parmSet = service.getParamStore()
1457                   .getPreset(calcIdParam.getName());
1458           if (parmSet != null)
1459           {
1460             // TODO : check we have a good match with settings in AACon -
1461             // otherwise we'll need to create a new preset
1462           }
1463         }
1464         else
1465         {
1466           argList = parmSet.getArguments();
1467           parmSet = null;
1468         }
1469         AAConSettings settings = new AAConSettings(
1470                 calcIdParam.isAutoUpdate(), service, parmSet, argList);
1471         av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
1472                 calcIdParam.isNeedsUpdate());
1473         return true;
1474       }
1475       else
1476       {
1477         warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
1478         return false;
1479       }
1480     }
1481     throw new Error("Unsupported Version for calcIdparam "
1482             + calcIdParam.toString());
1483   }
1484
1485   /**
1486    * External mapping between jalview objects and objects yielding a valid and
1487    * unique object ID string. This is null for normal Jalview project IO, but
1488    * non-null when a jalview project is being read or written as part of a
1489    * vamsas session.
1490    */
1491   IdentityHashMap jv2vobj = null;
1492
1493   /**
1494    * Construct a unique ID for jvobj using either existing bindings or if none
1495    * exist, the result of the hashcode call for the object.
1496    * 
1497    * @param jvobj
1498    *          jalview data object
1499    * @return unique ID for referring to jvobj
1500    */
1501   private String makeHashCode(Object jvobj, String altCode)
1502   {
1503     if (jv2vobj != null)
1504     {
1505       Object id = jv2vobj.get(jvobj);
1506       if (id != null)
1507       {
1508         return id.toString();
1509       }
1510       // check string ID mappings
1511       if (jvids2vobj != null && jvobj instanceof String)
1512       {
1513         id = jvids2vobj.get(jvobj);
1514       }
1515       if (id != null)
1516       {
1517         return id.toString();
1518       }
1519       // give up and warn that something has gone wrong
1520       warn("Cannot find ID for object in external mapping : " + jvobj);
1521     }
1522     return altCode;
1523   }
1524
1525   /**
1526    * return local jalview object mapped to ID, if it exists
1527    * 
1528    * @param idcode
1529    *          (may be null)
1530    * @return null or object bound to idcode
1531    */
1532   private Object retrieveExistingObj(String idcode)
1533   {
1534     if (idcode != null && vobj2jv != null)
1535     {
1536       return vobj2jv.get(idcode);
1537     }
1538     return null;
1539   }
1540
1541   /**
1542    * binding from ID strings from external mapping table to jalview data model
1543    * objects.
1544    */
1545   private Hashtable vobj2jv;
1546
1547   private Sequence createVamsasSequence(String id, SequenceI jds)
1548   {
1549     return createVamsasSequence(true, id, jds, null);
1550   }
1551
1552   private Sequence createVamsasSequence(boolean recurse, String id,
1553           SequenceI jds, SequenceI parentseq)
1554   {
1555     Sequence vamsasSeq = new Sequence();
1556     vamsasSeq.setId(id);
1557     vamsasSeq.setName(jds.getName());
1558     vamsasSeq.setSequence(jds.getSequenceAsString());
1559     vamsasSeq.setDescription(jds.getDescription());
1560     jalview.datamodel.DBRefEntry[] dbrefs = null;
1561     if (jds.getDatasetSequence() != null)
1562     {
1563       vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
1564       if (jds.getDatasetSequence().getDBRef() != null)
1565       {
1566         dbrefs = jds.getDatasetSequence().getDBRef();
1567       }
1568     }
1569     else
1570     {
1571       vamsasSeq.setDsseqid(id); // so we can tell which sequences really are
1572       // dataset sequences only
1573       dbrefs = jds.getDBRef();
1574     }
1575     if (dbrefs != null)
1576     {
1577       for (int d = 0; d < dbrefs.length; d++)
1578       {
1579         DBRef dbref = new DBRef();
1580         dbref.setSource(dbrefs[d].getSource());
1581         dbref.setVersion(dbrefs[d].getVersion());
1582         dbref.setAccessionId(dbrefs[d].getAccessionId());
1583         if (dbrefs[d].hasMap())
1584         {
1585           Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
1586                   jds, recurse);
1587           dbref.setMapping(mp);
1588         }
1589         vamsasSeq.addDBRef(dbref);
1590       }
1591     }
1592     return vamsasSeq;
1593   }
1594
1595   private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
1596           SequenceI parentseq, SequenceI jds, boolean recurse)
1597   {
1598     Mapping mp = null;
1599     if (jmp.getMap() != null)
1600     {
1601       mp = new Mapping();
1602
1603       jalview.util.MapList mlst = jmp.getMap();
1604       int r[] = mlst.getFromRanges();
1605       for (int s = 0; s < r.length; s += 2)
1606       {
1607         MapListFrom mfrom = new MapListFrom();
1608         mfrom.setStart(r[s]);
1609         mfrom.setEnd(r[s + 1]);
1610         mp.addMapListFrom(mfrom);
1611       }
1612       r = mlst.getToRanges();
1613       for (int s = 0; s < r.length; s += 2)
1614       {
1615         MapListTo mto = new MapListTo();
1616         mto.setStart(r[s]);
1617         mto.setEnd(r[s + 1]);
1618         mp.addMapListTo(mto);
1619       }
1620       mp.setMapFromUnit(mlst.getFromRatio());
1621       mp.setMapToUnit(mlst.getToRatio());
1622       if (jmp.getTo() != null)
1623       {
1624         MappingChoice mpc = new MappingChoice();
1625         if (recurse
1626                 && (parentseq != jmp.getTo() || parentseq
1627                         .getDatasetSequence() != jmp.getTo()))
1628         {
1629           mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo()),
1630                   jmp.getTo(), jds));
1631         }
1632         else
1633         {
1634           String jmpid = "";
1635           SequenceI ps = null;
1636           if (parentseq != jmp.getTo()
1637                   && parentseq.getDatasetSequence() != jmp.getTo())
1638           {
1639             // chaining dbref rather than a handshaking one
1640             jmpid = seqHash(ps = jmp.getTo());
1641           }
1642           else
1643           {
1644             jmpid = seqHash(ps = parentseq);
1645           }
1646           mpc.setDseqFor(jmpid);
1647           if (!seqRefIds.containsKey(mpc.getDseqFor()))
1648           {
1649             jalview.bin.Cache.log.debug("creatign new DseqFor ID");
1650             seqRefIds.put(mpc.getDseqFor(), ps);
1651           }
1652           else
1653           {
1654             jalview.bin.Cache.log.debug("reusing DseqFor ID");
1655           }
1656         }
1657         mp.setMappingChoice(mpc);
1658       }
1659     }
1660     return mp;
1661   }
1662
1663   String SetUserColourScheme(jalview.schemes.ColourSchemeI cs,
1664           Vector userColours, JalviewModelSequence jms)
1665   {
1666     String id = null;
1667     jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
1668     boolean newucs = false;
1669     if (!userColours.contains(ucs))
1670     {
1671       userColours.add(ucs);
1672       newucs = true;
1673     }
1674     id = "ucs" + userColours.indexOf(ucs);
1675     if (newucs)
1676     {
1677       // actually create the scheme's entry in the XML model
1678       java.awt.Color[] colours = ucs.getColours();
1679       jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
1680       jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
1681
1682       for (int i = 0; i < colours.length; i++)
1683       {
1684         jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
1685         col.setName(ResidueProperties.aa[i]);
1686         col.setRGB(jalview.util.Format.getHexString(colours[i]));
1687         jbucs.addColour(col);
1688       }
1689       if (ucs.getLowerCaseColours() != null)
1690       {
1691         colours = ucs.getLowerCaseColours();
1692         for (int i = 0; i < colours.length; i++)
1693         {
1694           jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
1695           col.setName(ResidueProperties.aa[i].toLowerCase());
1696           col.setRGB(jalview.util.Format.getHexString(colours[i]));
1697           jbucs.addColour(col);
1698         }
1699       }
1700
1701       uc.setId(id);
1702       uc.setUserColourScheme(jbucs);
1703       jms.addUserColours(uc);
1704     }
1705
1706     return id;
1707   }
1708
1709   jalview.schemes.UserColourScheme GetUserColourScheme(
1710           JalviewModelSequence jms, String id)
1711   {
1712     UserColours[] uc = jms.getUserColours();
1713     UserColours colours = null;
1714
1715     for (int i = 0; i < uc.length; i++)
1716     {
1717       if (uc[i].getId().equals(id))
1718       {
1719         colours = uc[i];
1720
1721         break;
1722       }
1723     }
1724
1725     java.awt.Color[] newColours = new java.awt.Color[24];
1726
1727     for (int i = 0; i < 24; i++)
1728     {
1729       newColours[i] = new java.awt.Color(Integer.parseInt(colours
1730               .getUserColourScheme().getColour(i).getRGB(), 16));
1731     }
1732
1733     jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
1734             newColours);
1735
1736     if (colours.getUserColourScheme().getColourCount() > 24)
1737     {
1738       newColours = new java.awt.Color[23];
1739       for (int i = 0; i < 23; i++)
1740       {
1741         newColours[i] = new java.awt.Color(Integer.parseInt(colours
1742                 .getUserColourScheme().getColour(i + 24).getRGB(), 16));
1743       }
1744       ucs.setLowerCaseColours(newColours);
1745     }
1746
1747     return ucs;
1748   }
1749
1750   /**
1751    * contains last error message (if any) encountered by XML loader.
1752    */
1753   String errorMessage = null;
1754
1755   /**
1756    * flag to control whether the Jalview2XML_V1 parser should be deferred to if
1757    * exceptions are raised during project XML parsing
1758    */
1759   public boolean attemptversion1parse = true;
1760
1761   /**
1762    * Load a jalview project archive from a jar file
1763    * 
1764    * @param file
1765    *          - HTTP URL or filename
1766    */
1767   public AlignFrame LoadJalviewAlign(final String file)
1768   {
1769
1770     jalview.gui.AlignFrame af = null;
1771
1772     try
1773     {
1774       // create list to store references for any new Jmol viewers created
1775       newStructureViewers=new Vector<AppJmol>();
1776       // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
1777       // Workaround is to make sure caller implements the JarInputStreamProvider
1778       // interface
1779       // so we can re-open the jar input stream for each entry.
1780
1781       jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
1782       af = LoadJalviewAlign(jprovider);
1783       
1784     } catch (MalformedURLException e)
1785     {
1786       errorMessage = "Invalid URL format for '" + file + "'";
1787       reportErrors();
1788     }
1789     finally {
1790       try
1791       {
1792         SwingUtilities.invokeAndWait(new Runnable()
1793         {
1794           public void run()
1795           {
1796             setLoadingFinishedForNewStructureViewers();
1797           };
1798         });
1799       } catch (Exception x)
1800       {
1801
1802       }
1803     }
1804     return af;
1805   }
1806
1807   private jarInputStreamProvider createjarInputStreamProvider(
1808           final String file) throws MalformedURLException
1809   {
1810     URL url = null;
1811     errorMessage = null;
1812     uniqueSetSuffix = null;
1813     seqRefIds = null;
1814     viewportsAdded = null;
1815     frefedSequence = null;
1816
1817     if (file.startsWith("http://"))
1818     {
1819       url = new URL(file);
1820     }
1821     final URL _url = url;
1822     return new jarInputStreamProvider()
1823     {
1824
1825       @Override
1826       public JarInputStream getJarInputStream() throws IOException
1827       {
1828         if (_url != null)
1829         {
1830           return new JarInputStream(_url.openStream());
1831         }
1832         else
1833         {
1834           return new JarInputStream(new FileInputStream(file));
1835         }
1836       }
1837
1838       @Override
1839       public String getFilename()
1840       {
1841         return file;
1842       }
1843     };
1844   }
1845
1846   /**
1847    * Recover jalview session from a jalview project archive. Caller may
1848    * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
1849    * themselves. Any null fields will be initialised with default values,
1850    * non-null fields are left alone.
1851    * 
1852    * @param jprovider
1853    * @return
1854    */
1855   public AlignFrame LoadJalviewAlign(final jarInputStreamProvider jprovider)
1856   {
1857     errorMessage = null;
1858     if (uniqueSetSuffix == null)
1859     {
1860       uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
1861     }
1862     if (seqRefIds == null)
1863     {
1864       seqRefIds = new Hashtable();
1865     }
1866     if (viewportsAdded == null)
1867     {
1868       viewportsAdded = new Hashtable();
1869     }
1870     if (frefedSequence == null)
1871     {
1872       frefedSequence = new Vector();
1873     }
1874
1875     jalview.gui.AlignFrame af= null,_af = null;
1876     Hashtable gatherToThisFrame = new Hashtable();
1877     final String file = jprovider.getFilename();
1878     try
1879     {
1880       JarInputStream jin = null;
1881       JarEntry jarentry = null;
1882       int entryCount = 1;
1883
1884       do
1885       {
1886         jin = jprovider.getJarInputStream();
1887         for (int i = 0; i < entryCount; i++)
1888         {
1889           jarentry = jin.getNextJarEntry();
1890         }
1891
1892         if (jarentry != null && jarentry.getName().endsWith(".xml"))
1893         {
1894           InputStreamReader in = new InputStreamReader(jin, "UTF-8");
1895           JalviewModel object = new JalviewModel();
1896
1897           Unmarshaller unmar = new Unmarshaller(object);
1898           unmar.setValidation(false);
1899           object = (JalviewModel) unmar.unmarshal(in);
1900           if (true) // !skipViewport(object))
1901           {
1902             _af = LoadFromObject(object, file, true, jprovider);
1903             if (object.getJalviewModelSequence().getViewportCount() > 0)
1904             {
1905               af = _af;
1906               if (object.getJalviewModelSequence().getViewportCount() > 1
1907                       && af.viewport.gatherViewsHere)
1908               {
1909                 gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
1910               }
1911             }
1912           }
1913           entryCount++;
1914         }
1915         else if (jarentry != null)
1916         {
1917           // Some other file here.
1918           entryCount++;
1919         }
1920       } while (jarentry != null);
1921       resolveFrefedSequences();
1922     } catch (java.io.FileNotFoundException ex)
1923     {
1924       ex.printStackTrace();
1925       errorMessage = "Couldn't locate Jalview XML file : " + file;
1926       System.err.println("Exception whilst loading jalview XML file : "
1927               + ex + "\n");
1928     } catch (java.net.UnknownHostException ex)
1929     {
1930       ex.printStackTrace();
1931       errorMessage = "Couldn't locate Jalview XML file : " + file;
1932       System.err.println("Exception whilst loading jalview XML file : "
1933               + ex + "\n");
1934     } catch (Exception ex)
1935     {
1936       System.err.println("Parsing as Jalview Version 2 file failed.");
1937       ex.printStackTrace(System.err);
1938       if (attemptversion1parse)
1939       {
1940         // Is Version 1 Jar file?
1941         try
1942         {
1943           af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
1944         } catch (Exception ex2)
1945         {
1946           System.err.println("Exception whilst loading as jalviewXMLV1:");
1947           ex2.printStackTrace();
1948           af = null;
1949         }
1950       }
1951       if (Desktop.instance != null)
1952       {
1953         Desktop.instance.stopLoading();
1954       }
1955       if (af != null)
1956       {
1957         System.out.println("Successfully loaded archive file");
1958         return af;
1959       }
1960       ex.printStackTrace();
1961
1962       System.err.println("Exception whilst loading jalview XML file : "
1963               + ex + "\n");
1964     } catch (OutOfMemoryError e)
1965     {
1966       // Don't use the OOM Window here
1967       errorMessage = "Out of memory loading jalview XML file";
1968       System.err.println("Out of memory whilst loading jalview XML file");
1969       e.printStackTrace();
1970     }
1971
1972     if (Desktop.instance != null)
1973     {
1974       Desktop.instance.stopLoading();
1975     }
1976
1977     Enumeration en = gatherToThisFrame.elements();
1978     while (en.hasMoreElements())
1979     {
1980       Desktop.instance.gatherViews((AlignFrame) en.nextElement());
1981     }
1982     if (errorMessage != null)
1983     {
1984       reportErrors();
1985     }
1986     return af;
1987   }
1988
1989   /**
1990    * check errorMessage for a valid error message and raise an error box in the
1991    * GUI or write the current errorMessage to stderr and then clear the error
1992    * state.
1993    */
1994   protected void reportErrors()
1995   {
1996     reportErrors(false);
1997   }
1998
1999   protected void reportErrors(final boolean saving)
2000   {
2001     if (errorMessage != null)
2002     {
2003       final String finalErrorMessage = errorMessage;
2004       if (raiseGUI)
2005       {
2006         javax.swing.SwingUtilities.invokeLater(new Runnable()
2007         {
2008           @Override
2009           public void run()
2010           {
2011             JOptionPane.showInternalMessageDialog(Desktop.desktop,
2012                     finalErrorMessage, "Error "
2013                             + (saving ? "saving" : "loading")
2014                             + " Jalview file", JOptionPane.WARNING_MESSAGE);
2015           }
2016         });
2017       }
2018       else
2019       {
2020         System.err.println("Problem loading Jalview file: " + errorMessage);
2021       }
2022     }
2023     errorMessage = null;
2024   }
2025
2026   Hashtable alreadyLoadedPDB;
2027
2028   /**
2029    * when set, local views will be updated from view stored in JalviewXML
2030    * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2031    * sync if this is set to true.
2032    */
2033   private final boolean updateLocalViews = false;
2034
2035   String loadPDBFile(jarInputStreamProvider jprovider, String pdbId)
2036   {
2037     if (alreadyLoadedPDB == null)
2038       alreadyLoadedPDB = new Hashtable();
2039
2040     if (alreadyLoadedPDB.containsKey(pdbId))
2041       return alreadyLoadedPDB.get(pdbId).toString();
2042
2043     try
2044     {
2045       JarInputStream jin = jprovider.getJarInputStream();
2046       /*
2047        * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2048        * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2049        * FileInputStream(jprovider)); }
2050        */
2051
2052       JarEntry entry = null;
2053       do
2054       {
2055         entry = jin.getNextJarEntry();
2056       } while (entry != null && !entry.getName().equals(pdbId));
2057       if (entry != null)
2058       {
2059         BufferedReader in = new BufferedReader(new InputStreamReader(jin));
2060         File outFile = File.createTempFile("jalview_pdb", ".txt");
2061         outFile.deleteOnExit();
2062         PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
2063         String data;
2064
2065         while ((data = in.readLine()) != null)
2066         {
2067           out.println(data);
2068         }
2069         try
2070         {
2071           out.flush();
2072         } catch (Exception foo)
2073         {
2074         }
2075         ;
2076         out.close();
2077         String t = outFile.getAbsolutePath();
2078         alreadyLoadedPDB.put(pdbId, t);
2079         return t;
2080       }
2081       else
2082       {
2083         warn("Couldn't find PDB file entry in Jalview Jar for " + pdbId);
2084       }
2085     } catch (Exception ex)
2086     {
2087       ex.printStackTrace();
2088     }
2089
2090     return null;
2091   }
2092
2093   private class JvAnnotRow
2094   {
2095     public JvAnnotRow(int i, AlignmentAnnotation jaa)
2096     {
2097       order = i;
2098       template = jaa;
2099     }
2100
2101     /**
2102      * persisted version of annotation row from which to take vis properties
2103      */
2104     public jalview.datamodel.AlignmentAnnotation template;
2105
2106     /**
2107      * original position of the annotation row in the alignment
2108      */
2109     public int order;
2110   }
2111
2112   /**
2113    * Load alignment frame from jalview XML DOM object
2114    * 
2115    * @param object
2116    *          DOM
2117    * @param file
2118    *          filename source string
2119    * @param loadTreesAndStructures
2120    *          when false only create Viewport
2121    * @param jprovider
2122    *          data source provider
2123    * @return alignment frame created from view stored in DOM
2124    */
2125   AlignFrame LoadFromObject(JalviewModel object, String file,
2126           boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2127   {
2128     SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2129     Sequence[] vamsasSeq = vamsasSet.getSequence();
2130
2131     JalviewModelSequence jms = object.getJalviewModelSequence();
2132
2133     Viewport view = (jms.getViewportCount()>0) ? jms.getViewport(0) : null;
2134     
2135     // ////////////////////////////////
2136     // LOAD SEQUENCES
2137
2138     Vector hiddenSeqs = null;
2139     jalview.datamodel.Sequence jseq;
2140
2141     ArrayList tmpseqs = new ArrayList();
2142
2143     boolean multipleView = false;
2144
2145     JSeq[] JSEQ = object.getJalviewModelSequence().getJSeq();
2146     int vi = 0; // counter in vamsasSeq array
2147     for (int i = 0; i < JSEQ.length; i++)
2148     {
2149       String seqId = JSEQ[i].getId();
2150
2151       if (seqRefIds.get(seqId) != null)
2152       {
2153         tmpseqs.add(seqRefIds.get(seqId));
2154         multipleView = true;
2155       }
2156       else
2157       {
2158         jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2159                 vamsasSeq[vi].getSequence());
2160         jseq.setDescription(vamsasSeq[vi].getDescription());
2161         jseq.setStart(JSEQ[i].getStart());
2162         jseq.setEnd(JSEQ[i].getEnd());
2163         jseq.setVamsasId(uniqueSetSuffix + seqId);
2164         seqRefIds.put(vamsasSeq[vi].getId(), jseq);
2165         tmpseqs.add(jseq);
2166         vi++;
2167       }
2168
2169       if (JSEQ[i].getHidden())
2170       {
2171         if (hiddenSeqs == null)
2172         {
2173           hiddenSeqs = new Vector();
2174         }
2175
2176         hiddenSeqs.addElement(seqRefIds.get(seqId));
2177       }
2178
2179     }
2180
2181     // /
2182     // Create the alignment object from the sequence set
2183     // ///////////////////////////////
2184     jalview.datamodel.Sequence[] orderedSeqs = new jalview.datamodel.Sequence[tmpseqs
2185             .size()];
2186
2187     tmpseqs.toArray(orderedSeqs);
2188
2189     jalview.datamodel.Alignment al = new jalview.datamodel.Alignment(
2190             orderedSeqs);
2191
2192     // / Add the alignment properties
2193     for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
2194     {
2195       SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
2196       al.setProperty(ssp.getKey(), ssp.getValue());
2197     }
2198
2199     // /
2200     // SequenceFeatures are added to the DatasetSequence,
2201     // so we must create or recover the dataset before loading features
2202     // ///////////////////////////////
2203     if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2204     {
2205       // older jalview projects do not have a dataset id.
2206       al.setDataset(null);
2207     }
2208     else
2209     {
2210       recoverDatasetFor(vamsasSet, al);
2211     }
2212     // ///////////////////////////////
2213
2214     Hashtable pdbloaded = new Hashtable();
2215     if (!multipleView)
2216     {
2217       // load sequence features, database references and any associated PDB
2218       // structures for the alignment
2219       for (int i = 0; i < vamsasSeq.length; i++)
2220       {
2221         if (JSEQ[i].getFeaturesCount() > 0)
2222         {
2223           Features[] features = JSEQ[i].getFeatures();
2224           for (int f = 0; f < features.length; f++)
2225           {
2226             jalview.datamodel.SequenceFeature sf = new jalview.datamodel.SequenceFeature(
2227                     features[f].getType(), features[f].getDescription(),
2228                     features[f].getStatus(), features[f].getBegin(),
2229                     features[f].getEnd(), features[f].getFeatureGroup());
2230
2231             sf.setScore(features[f].getScore());
2232             for (int od = 0; od < features[f].getOtherDataCount(); od++)
2233             {
2234               OtherData keyValue = features[f].getOtherData(od);
2235               if (keyValue.getKey().startsWith("LINK"))
2236               {
2237                 sf.addLink(keyValue.getValue());
2238               }
2239               else
2240               {
2241                 sf.setValue(keyValue.getKey(), keyValue.getValue());
2242               }
2243
2244             }
2245
2246             al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf);
2247           }
2248         }
2249         if (vamsasSeq[i].getDBRefCount() > 0)
2250         {
2251           addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]);
2252         }
2253         if (JSEQ[i].getPdbidsCount() > 0)
2254         {
2255           Pdbids[] ids = JSEQ[i].getPdbids();
2256           for (int p = 0; p < ids.length; p++)
2257           {
2258             jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
2259             entry.setId(ids[p].getId());
2260             entry.setType(ids[p].getType());
2261             if (ids[p].getFile() != null)
2262             {
2263               if (!pdbloaded.containsKey(ids[p].getFile()))
2264               {
2265                 entry.setFile(loadPDBFile(jprovider, ids[p].getId()));
2266               }
2267               else
2268               {
2269                 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
2270               }
2271             }
2272
2273             al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
2274           }
2275         }
2276       }
2277     } // end !multipleview
2278
2279     // ///////////////////////////////
2280     // LOAD SEQUENCE MAPPINGS
2281
2282     if (vamsasSet.getAlcodonFrameCount() > 0)
2283     {
2284       // TODO Potentially this should only be done once for all views of an
2285       // alignment
2286       AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
2287       for (int i = 0; i < alc.length; i++)
2288       {
2289         jalview.datamodel.AlignedCodonFrame cf = new jalview.datamodel.AlignedCodonFrame(
2290                 alc[i].getAlcodonCount());
2291         if (alc[i].getAlcodonCount() > 0)
2292         {
2293           Alcodon[] alcods = alc[i].getAlcodon();
2294           for (int p = 0; p < cf.codons.length; p++)
2295           {
2296             if (alcods[p].hasPos1() && alcods[p].hasPos2()
2297                     && alcods[p].hasPos3())
2298             {
2299               // translated codons require three valid positions
2300               cf.codons[p] = new int[3];
2301               cf.codons[p][0] = (int) alcods[p].getPos1();
2302               cf.codons[p][1] = (int) alcods[p].getPos2();
2303               cf.codons[p][2] = (int) alcods[p].getPos3();
2304             }
2305             else
2306             {
2307               cf.codons[p] = null;
2308             }
2309           }
2310         }
2311         if (alc[i].getAlcodMapCount() > 0)
2312         {
2313           AlcodMap[] maps = alc[i].getAlcodMap();
2314           for (int m = 0; m < maps.length; m++)
2315           {
2316             SequenceI dnaseq = (SequenceI) seqRefIds
2317                     .get(maps[m].getDnasq());
2318             // Load Mapping
2319             jalview.datamodel.Mapping mapping = null;
2320             // attach to dna sequence reference.
2321             if (maps[m].getMapping() != null)
2322             {
2323               mapping = addMapping(maps[m].getMapping());
2324             }
2325             if (dnaseq != null)
2326             {
2327               cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
2328             }
2329             else
2330             {
2331               // defer to later
2332               frefedSequence.add(new Object[]
2333               { maps[m].getDnasq(), cf, mapping });
2334             }
2335           }
2336         }
2337         al.addCodonFrame(cf);
2338       }
2339
2340     }
2341
2342     // ////////////////////////////////
2343     // LOAD ANNOTATIONS
2344     ArrayList<JvAnnotRow> autoAlan = new ArrayList<JvAnnotRow>();
2345     /**
2346      * store any annotations which forward reference a group's ID
2347      */
2348     Hashtable<String, ArrayList<jalview.datamodel.AlignmentAnnotation>> groupAnnotRefs = new Hashtable<String, ArrayList<jalview.datamodel.AlignmentAnnotation>>();
2349
2350     if (vamsasSet.getAnnotationCount() > 0)
2351     {
2352       Annotation[] an = vamsasSet.getAnnotation();
2353
2354       for (int i = 0; i < an.length; i++)
2355       {
2356         /**
2357          * test if annotation is automatically calculated for this view only
2358          */
2359         boolean autoForView = false;
2360         if (an[i].getLabel().equals("Quality")
2361                 || an[i].getLabel().equals("Conservation")
2362                 || an[i].getLabel().equals("Consensus"))
2363         {
2364           // Kludge for pre 2.5 projects which lacked the autocalculated flag
2365           autoForView = true;
2366           if (!an[i].hasAutoCalculated())
2367           {
2368             an[i].setAutoCalculated(true);
2369           }
2370         }
2371         if (autoForView
2372                 || (an[i].hasAutoCalculated() && an[i].isAutoCalculated()))
2373         {
2374           // remove ID - we don't recover annotation from other views for
2375           // view-specific annotation
2376           an[i].setId(null);
2377         }
2378
2379         // set visiblity for other annotation in this view
2380         if (an[i].getId() != null
2381                 && annotationIds.containsKey(an[i].getId()))
2382         {
2383           jalview.datamodel.AlignmentAnnotation jda = (jalview.datamodel.AlignmentAnnotation) annotationIds
2384                   .get(an[i].getId());
2385           // in principle Visible should always be true for annotation displayed
2386           // in multiple views
2387           if (an[i].hasVisible())
2388             jda.visible = an[i].getVisible();
2389
2390           al.addAnnotation(jda);
2391
2392           continue;
2393         }
2394         // Construct new annotation from model.
2395         AnnotationElement[] ae = an[i].getAnnotationElement();
2396         jalview.datamodel.Annotation[] anot = null;
2397         java.awt.Color firstColour = null;
2398         int anpos;
2399         if (!an[i].getScoreOnly())
2400         {
2401           anot = new jalview.datamodel.Annotation[al.getWidth()];
2402           for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
2403           {
2404             anpos = ae[aa].getPosition();
2405
2406             if (anpos >= anot.length)
2407               continue;
2408
2409             anot[anpos] = new jalview.datamodel.Annotation(
2410
2411             ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
2412                     (ae[aa].getSecondaryStructure() == null || ae[aa]
2413                             .getSecondaryStructure().length() == 0) ? ' '
2414                             : ae[aa].getSecondaryStructure().charAt(0),
2415                     ae[aa].getValue()
2416
2417             );
2418             // JBPNote: Consider verifying dataflow for IO of secondary
2419             // structure annotation read from Stockholm files
2420             // this was added to try to ensure that
2421             // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
2422             // {
2423             // anot[ae[aa].getPosition()].displayCharacter = "";
2424             // }
2425             anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
2426             if (firstColour == null)
2427             {
2428               firstColour = anot[anpos].colour;
2429             }
2430           }
2431         }
2432         jalview.datamodel.AlignmentAnnotation jaa = null;
2433
2434         if (an[i].getGraph())
2435         {
2436           float llim = 0, hlim = 0;
2437           // if (autoForView || an[i].isAutoCalculated()) {
2438           // hlim=11f;
2439           // }
2440           jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
2441                   an[i].getDescription(), anot, llim, hlim,
2442                   an[i].getGraphType());
2443
2444           jaa.graphGroup = an[i].getGraphGroup();
2445           jaa._linecolour = firstColour;
2446           if (an[i].getThresholdLine() != null)
2447           {
2448             jaa.setThreshold(new jalview.datamodel.GraphLine(an[i]
2449                     .getThresholdLine().getValue(), an[i]
2450                     .getThresholdLine().getLabel(), new java.awt.Color(
2451                     an[i].getThresholdLine().getColour())));
2452
2453           }
2454           if (autoForView || an[i].isAutoCalculated())
2455           {
2456             // Hardwire the symbol display line to ensure that labels for
2457             // histograms are displayed
2458             jaa.hasText = true;
2459           }
2460         }
2461         else
2462         {
2463           jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
2464                   an[i].getDescription(), anot);
2465           jaa._linecolour = firstColour;
2466         }
2467         // register new annotation
2468         if (an[i].getId() != null)
2469         {
2470           annotationIds.put(an[i].getId(), jaa);
2471           jaa.annotationId = an[i].getId();
2472         }
2473         // recover sequence association
2474         if (an[i].getSequenceRef() != null)
2475         {
2476           if (al.findName(an[i].getSequenceRef()) != null)
2477           {
2478             jaa.createSequenceMapping(al.findName(an[i].getSequenceRef()),
2479                     1, true);
2480             al.findName(an[i].getSequenceRef()).addAlignmentAnnotation(jaa);
2481           }
2482         }
2483         // and make a note of any group association
2484         if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
2485         {
2486           ArrayList<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
2487                   .get(an[i].getGroupRef());
2488           if (aal == null)
2489           {
2490             aal = new ArrayList<jalview.datamodel.AlignmentAnnotation>();
2491             groupAnnotRefs.put(an[i].getGroupRef(), aal);
2492           }
2493           aal.add(jaa);
2494         }
2495
2496         if (an[i].hasScore())
2497         {
2498           jaa.setScore(an[i].getScore());
2499         }
2500         if (an[i].hasVisible())
2501           jaa.visible = an[i].getVisible();
2502
2503         if (an[i].hasCentreColLabels())
2504           jaa.centreColLabels = an[i].getCentreColLabels();
2505
2506         if (an[i].hasScaleColLabels())
2507         {
2508           jaa.scaleColLabel = an[i].getScaleColLabels();
2509         }
2510         if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
2511         {
2512           // newer files have an 'autoCalculated' flag and store calculation
2513           // state in viewport properties
2514           jaa.autoCalculated = true; // means annotation will be marked for
2515           // update at end of load.
2516         }
2517         if (an[i].hasGraphHeight())
2518         {
2519           jaa.graphHeight = an[i].getGraphHeight();
2520         }
2521         if (an[i].hasBelowAlignment())
2522         {
2523           jaa.belowAlignment = an[i].isBelowAlignment();
2524         }
2525         jaa.setCalcId(an[i].getCalcId());
2526
2527         if (jaa.autoCalculated)
2528         {
2529           autoAlan.add(new JvAnnotRow(i, jaa));
2530         }
2531         else
2532         // if (!autoForView)
2533         {
2534           // add autocalculated group annotation and any user created annotation
2535           // for the view
2536           al.addAnnotation(jaa);
2537         }
2538       }
2539     }
2540
2541     // ///////////////////////
2542     // LOAD GROUPS
2543     // Create alignment markup and styles for this view
2544     if (jms.getJGroupCount() > 0)
2545     {
2546       JGroup[] groups = jms.getJGroup();
2547
2548       for (int i = 0; i < groups.length; i++)
2549       {
2550         ColourSchemeI cs = null;
2551
2552         if (groups[i].getColour() != null)
2553         {
2554           if (groups[i].getColour().startsWith("ucs"))
2555           {
2556             cs = GetUserColourScheme(jms, groups[i].getColour());
2557           }
2558           else
2559           {
2560             cs = ColourSchemeProperty.getColour(al, groups[i].getColour());
2561           }
2562
2563           if (cs != null)
2564           {
2565             cs.setThreshold(groups[i].getPidThreshold(), true);
2566           }
2567         }
2568
2569         Vector seqs = new Vector();
2570
2571         for (int s = 0; s < groups[i].getSeqCount(); s++)
2572         {
2573           String seqId = groups[i].getSeq(s) + "";
2574           jalview.datamodel.SequenceI ts = (jalview.datamodel.SequenceI) seqRefIds
2575                   .get(seqId);
2576
2577           if (ts != null)
2578           {
2579             seqs.addElement(ts);
2580           }
2581         }
2582
2583         if (seqs.size() < 1)
2584         {
2585           continue;
2586         }
2587
2588         jalview.datamodel.SequenceGroup sg = new jalview.datamodel.SequenceGroup(
2589                 seqs, groups[i].getName(), cs, groups[i].getDisplayBoxes(),
2590                 groups[i].getDisplayText(), groups[i].getColourText(),
2591                 groups[i].getStart(), groups[i].getEnd());
2592
2593         sg.setOutlineColour(new java.awt.Color(groups[i].getOutlineColour()));
2594
2595         sg.textColour = new java.awt.Color(groups[i].getTextCol1());
2596         sg.textColour2 = new java.awt.Color(groups[i].getTextCol2());
2597         sg.setShowNonconserved(groups[i].hasShowUnconserved() ? groups[i]
2598                 .isShowUnconserved() : false);
2599         sg.thresholdTextColour = groups[i].getTextColThreshold();
2600         if (groups[i].hasShowConsensusHistogram())
2601         {
2602           sg.setShowConsensusHistogram(groups[i].isShowConsensusHistogram());
2603         }
2604         ;
2605         if (groups[i].hasShowSequenceLogo())
2606         {
2607           sg.setshowSequenceLogo(groups[i].isShowSequenceLogo());
2608         }
2609         if (groups[i].hasNormaliseSequenceLogo())
2610         {
2611           sg.setNormaliseSequenceLogo(groups[i].isNormaliseSequenceLogo());
2612         }
2613         if (groups[i].hasIgnoreGapsinConsensus())
2614         {
2615           sg.setIgnoreGapsConsensus(groups[i].getIgnoreGapsinConsensus());
2616         }
2617         if (groups[i].getConsThreshold() != 0)
2618         {
2619           jalview.analysis.Conservation c = new jalview.analysis.Conservation(
2620                   "All", ResidueProperties.propHash, 3,
2621                   sg.getSequences(null), 0, sg.getWidth() - 1);
2622           c.calculate();
2623           c.verdict(false, 25);
2624           sg.cs.setConservation(c);
2625         }
2626
2627         if (groups[i].getId() != null && groupAnnotRefs.size() > 0)
2628         {
2629           // re-instate unique group/annotation row reference
2630           ArrayList<jalview.datamodel.AlignmentAnnotation> jaal = groupAnnotRefs
2631                   .get(groups[i].getId());
2632           if (jaal != null)
2633           {
2634             for (jalview.datamodel.AlignmentAnnotation jaa : jaal)
2635             {
2636               jaa.groupRef = sg;
2637               if (jaa.autoCalculated)
2638               {
2639                 // match up and try to set group autocalc alignment row for this
2640                 // annotation
2641                 if (jaa.label.startsWith("Consensus for "))
2642                 {
2643                   sg.setConsensus(jaa);
2644                 }
2645                 // match up and try to set group autocalc alignment row for this
2646                 // annotation
2647                 if (jaa.label.startsWith("Conservation for "))
2648                 {
2649                   sg.setConservationRow(jaa);
2650                 }
2651               }
2652             }
2653           }
2654         }
2655         al.addGroup(sg);
2656
2657       }
2658     }
2659     if (view==null)
2660     {
2661       // only dataset in this model, so just return.
2662       return null;
2663     }
2664     // ///////////////////////////////
2665     // LOAD VIEWPORT
2666
2667     // If we just load in the same jar file again, the sequenceSetId
2668     // will be the same, and we end up with multiple references
2669     // to the same sequenceSet. We must modify this id on load
2670     // so that each load of the file gives a unique id
2671     String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
2672     String viewId = (view.getId() == null ? null : view.getId()
2673             + uniqueSetSuffix);
2674     AlignFrame af = null;
2675     AlignViewport av = null;
2676     // now check to see if we really need to create a new viewport.
2677     if (multipleView && viewportsAdded.size() == 0)
2678     {
2679       // We recovered an alignment for which a viewport already exists.
2680       // TODO: fix up any settings necessary for overlaying stored state onto
2681       // state recovered from another document. (may not be necessary).
2682       // we may need a binding from a viewport in memory to one recovered from
2683       // XML.
2684       // and then recover its containing af to allow the settings to be applied.
2685       // TODO: fix for vamsas demo
2686       System.err
2687               .println("About to recover a viewport for existing alignment: Sequence set ID is "
2688                       + uniqueSeqSetId);
2689       Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
2690       if (seqsetobj != null)
2691       {
2692         if (seqsetobj instanceof String)
2693         {
2694           uniqueSeqSetId = (String) seqsetobj;
2695           System.err
2696                   .println("Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
2697                           + uniqueSeqSetId);
2698         }
2699         else
2700         {
2701           System.err
2702                   .println("Warning : Collision between sequence set ID string and existing jalview object mapping.");
2703         }
2704
2705       }
2706     }
2707     AlignmentPanel ap = null;
2708     boolean isnewview = true;
2709     if (viewId != null)
2710     {
2711       // Check to see if this alignment already has a view id == viewId
2712       jalview.gui.AlignmentPanel views[] = Desktop
2713               .getAlignmentPanels(uniqueSeqSetId);
2714       if (views != null && views.length > 0)
2715       {
2716         for (int v = 0; v < views.length; v++)
2717         {
2718           if (views[v].av.getViewId().equalsIgnoreCase(viewId))
2719           {
2720             // recover the existing alignpanel, alignframe, viewport
2721             af = views[v].alignFrame;
2722             av = views[v].av;
2723             ap = views[v];
2724             // TODO: could even skip resetting view settings if we don't want to
2725             // change the local settings from other jalview processes
2726             isnewview = false;
2727           }
2728         }
2729       }
2730     }
2731
2732     if (isnewview)
2733     {
2734       af = loadViewport(file, JSEQ, hiddenSeqs, al, jms, view,
2735               uniqueSeqSetId, viewId, autoAlan);
2736       av = af.viewport;
2737       ap = af.alignPanel;
2738     }
2739     // LOAD TREES
2740     // /////////////////////////////////////
2741     if (loadTreesAndStructures && jms.getTreeCount() > 0)
2742     {
2743       try
2744       {
2745         for (int t = 0; t < jms.getTreeCount(); t++)
2746         {
2747
2748           Tree tree = jms.getTree(t);
2749
2750           TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
2751           if (tp == null)
2752           {
2753             tp = af.ShowNewickTree(
2754                     new jalview.io.NewickFile(tree.getNewick()),
2755                     tree.getTitle(), tree.getWidth(), tree.getHeight(),
2756                     tree.getXpos(), tree.getYpos());
2757             if (tree.getId() != null)
2758             {
2759               // perhaps bind the tree id to something ?
2760             }
2761           }
2762           else
2763           {
2764             // update local tree attributes ?
2765             // TODO: should check if tp has been manipulated by user - if so its
2766             // settings shouldn't be modified
2767             tp.setTitle(tree.getTitle());
2768             tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(), tree
2769                     .getWidth(), tree.getHeight()));
2770             tp.av = av; // af.viewport; // TODO: verify 'associate with all
2771             // views'
2772             // works still
2773             tp.treeCanvas.av = av; // af.viewport;
2774             tp.treeCanvas.ap = ap; // af.alignPanel;
2775
2776           }
2777           if (tp == null)
2778           {
2779             warn("There was a problem recovering stored Newick tree: \n"
2780                     + tree.getNewick());
2781             continue;
2782           }
2783
2784           tp.fitToWindow.setState(tree.getFitToWindow());
2785           tp.fitToWindow_actionPerformed(null);
2786
2787           if (tree.getFontName() != null)
2788           {
2789             tp.setTreeFont(new java.awt.Font(tree.getFontName(), tree
2790                     .getFontStyle(), tree.getFontSize()));
2791           }
2792           else
2793           {
2794             tp.setTreeFont(new java.awt.Font(view.getFontName(), view
2795                     .getFontStyle(), tree.getFontSize()));
2796           }
2797
2798           tp.showPlaceholders(tree.getMarkUnlinked());
2799           tp.showBootstrap(tree.getShowBootstrap());
2800           tp.showDistances(tree.getShowDistances());
2801
2802           tp.treeCanvas.threshold = tree.getThreshold();
2803
2804           if (tree.getCurrentTree())
2805           {
2806             af.viewport.setCurrentTree(tp.getTree());
2807           }
2808         }
2809
2810       } catch (Exception ex)
2811       {
2812         ex.printStackTrace();
2813       }
2814     }
2815
2816     // //LOAD STRUCTURES
2817     if (loadTreesAndStructures)
2818     {
2819       // run through all PDB ids on the alignment, and collect mappings between
2820       // jmol view ids and all sequences referring to it
2821       Hashtable<String, Object[]> jmolViewIds = new Hashtable();
2822
2823       for (int i = 0; i < JSEQ.length; i++)
2824       {
2825         if (JSEQ[i].getPdbidsCount() > 0)
2826         {
2827           Pdbids[] ids = JSEQ[i].getPdbids();
2828           for (int p = 0; p < ids.length; p++)
2829           {
2830             for (int s = 0; s < ids[p].getStructureStateCount(); s++)
2831             {
2832               // check to see if we haven't already created this structure view
2833               String sviewid = (ids[p].getStructureState(s).getViewId() == null) ? null
2834                       : ids[p].getStructureState(s).getViewId()
2835                               + uniqueSetSuffix;
2836               jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
2837               // Originally : ids[p].getFile()
2838               // : TODO: verify external PDB file recovery still works in normal
2839               // jalview project load
2840               jpdb.setFile(loadPDBFile(jprovider, ids[p].getId()));
2841               jpdb.setId(ids[p].getId());
2842
2843               int x = ids[p].getStructureState(s).getXpos();
2844               int y = ids[p].getStructureState(s).getYpos();
2845               int width = ids[p].getStructureState(s).getWidth();
2846               int height = ids[p].getStructureState(s).getHeight();
2847
2848               // Probably don't need to do this anymore...
2849               // Desktop.desktop.getComponentAt(x, y);
2850               // TODO: NOW: check that this recovers the PDB file correctly.
2851               String pdbFile = loadPDBFile(jprovider, ids[p].getId());
2852               jalview.datamodel.SequenceI seq = (jalview.datamodel.SequenceI) seqRefIds
2853                       .get(JSEQ[i].getId() + "");
2854               if (sviewid == null)
2855               {
2856                 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width
2857                         + "," + height;
2858               }
2859               if (!jmolViewIds.containsKey(sviewid))
2860               {
2861                 jmolViewIds.put(sviewid, new Object[]
2862                 { new int[]
2863                 { x, y, width, height }, "",
2864                     new Hashtable<String, Object[]>(), new boolean[]
2865                     { false, false, true } });
2866                 // Legacy pre-2.7 conversion JAL-823 :
2867                 // do not assume any view has to be linked for colour by
2868                 // sequence
2869               }
2870
2871               // assemble String[] { pdb files }, String[] { id for each
2872               // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
2873               // seqs_file 2}, boolean[] {
2874               // linkAlignPanel,superposeWithAlignpanel}} from hash
2875               Object[] jmoldat = jmolViewIds.get(sviewid);
2876               ((boolean[]) jmoldat[3])[0] |= ids[p].getStructureState(s)
2877                       .hasAlignwithAlignPanel() ? ids[p].getStructureState(
2878                       s).getAlignwithAlignPanel() : false;
2879               // never colour by linked panel if not specified
2880               ((boolean[]) jmoldat[3])[1] |= ids[p].getStructureState(s)
2881                       .hasColourwithAlignPanel() ? ids[p]
2882                       .getStructureState(s).getColourwithAlignPanel()
2883                       : false;
2884               // default for pre-2.7 projects is that Jmol colouring is enabled
2885               ((boolean[]) jmoldat[3])[2] &= ids[p].getStructureState(s)
2886                       .hasColourByJmol() ? ids[p].getStructureState(s)
2887                       .getColourByJmol() : true;
2888
2889               if (((String) jmoldat[1]).length() < ids[p]
2890                       .getStructureState(s).getContent().length())
2891               {
2892                 {
2893                   jmoldat[1] = ids[p].getStructureState(s).getContent();
2894                 }
2895               }
2896               if (ids[p].getFile() != null)
2897               {
2898                 File mapkey = new File(ids[p].getFile());
2899                 Object[] seqstrmaps = (Object[]) ((Hashtable) jmoldat[2])
2900                         .get(mapkey);
2901                 if (seqstrmaps == null)
2902                 {
2903                   ((Hashtable) jmoldat[2]).put(mapkey,
2904                           seqstrmaps = new Object[]
2905                           { pdbFile, ids[p].getId(), new Vector(),
2906                               new Vector() });
2907                 }
2908                 if (!((Vector) seqstrmaps[2]).contains(seq))
2909                 {
2910                   ((Vector) seqstrmaps[2]).addElement(seq);
2911                   // ((Vector)seqstrmaps[3]).addElement(n) :
2912                   // in principle, chains
2913                   // should be stored here : do we need to
2914                   // TODO: store and recover seq/pdb_id :
2915                   // chain mappings
2916                 }
2917               }
2918               else
2919               {
2920                 errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
2921                 warn(errorMessage);
2922               }
2923             }
2924           }
2925         }
2926       }
2927       {
2928
2929         // Instantiate the associated Jmol views
2930         for (Entry<String, Object[]> entry : jmolViewIds.entrySet())
2931         {
2932           String sviewid = entry.getKey();
2933           Object[] svattrib = entry.getValue();
2934           int[] geom = (int[]) svattrib[0];
2935           String state = (String) svattrib[1];
2936           Hashtable<File, Object[]> oldFiles = (Hashtable<File, Object[]>) svattrib[2];
2937           final boolean useinJmolsuperpos = ((boolean[]) svattrib[3])[0], usetoColourbyseq = ((boolean[]) svattrib[3])[1], jmolColouring = ((boolean[]) svattrib[3])[2];
2938           int x = geom[0], y = geom[1], width = geom[2], height = geom[3];
2939           // collate the pdbfile -> sequence mappings from this view
2940           Vector<String> pdbfilenames = new Vector<String>();
2941           Vector<SequenceI[]> seqmaps = new Vector<SequenceI[]>();
2942           Vector<String> pdbids = new Vector<String>();
2943
2944           // Search to see if we've already created this Jmol view
2945           AppJmol comp = null;
2946           JInternalFrame[] frames = null;
2947           do
2948           {
2949             try
2950             {
2951               frames = Desktop.desktop.getAllFrames();
2952             } catch (ArrayIndexOutOfBoundsException e)
2953             {
2954               // occasional No such child exceptions are thrown here...
2955               frames = null;
2956               try
2957               {
2958                 Thread.sleep(10);
2959               } catch (Exception f)
2960               {
2961               }
2962               ;
2963             }
2964           } while (frames == null);
2965           // search for any Jmol windows already open from other
2966           // alignment views that exactly match the stored structure state
2967           for (int f = 0; comp == null && f < frames.length; f++)
2968           {
2969             if (frames[f] instanceof AppJmol)
2970             {
2971               if (sviewid != null
2972                       && ((AppJmol) frames[f]).getViewId().equals(sviewid))
2973               {
2974                 // post jalview 2.4 schema includes structure view id
2975                 comp = (AppJmol) frames[f];
2976               }
2977               else if (frames[f].getX() == x && frames[f].getY() == y
2978                       && frames[f].getHeight() == height
2979                       && frames[f].getWidth() == width)
2980               {
2981                 comp = (AppJmol) frames[f];
2982               }
2983             }
2984           }
2985
2986           if (comp == null)
2987           {
2988             // create a new Jmol window.
2989             // First parse the Jmol state to translate filenames loaded into the
2990             // view, and record the order in which files are shown in the Jmol
2991             // view, so we can add the sequence mappings in same order.
2992             StringBuffer newFileLoc = null;
2993             int cp = 0, ncp, ecp;
2994             while ((ncp = state.indexOf("load ", cp)) > -1)
2995             {
2996               if (newFileLoc == null)
2997               {
2998                 newFileLoc = new StringBuffer();
2999               }
3000               do
3001               {
3002                 // look for next filename in load statement
3003                 newFileLoc.append(state.substring(cp,
3004                         ncp = (state.indexOf("\"", ncp + 1) + 1)));
3005                 String oldfilenam = state.substring(ncp,
3006                         ecp = state.indexOf("\"", ncp));
3007                 // recover the new mapping data for this old filename
3008                 // have to normalize filename - since Jmol and jalview do
3009                 // filename
3010                 // translation differently.
3011                 Object[] filedat = oldFiles.get(new File(oldfilenam));
3012                 newFileLoc.append(Platform
3013                         .escapeString((String) filedat[0]));
3014                 pdbfilenames.addElement((String) filedat[0]);
3015                 pdbids.addElement((String) filedat[1]);
3016                 seqmaps.addElement(((Vector<SequenceI>) filedat[2])
3017                         .toArray(new SequenceI[0]));
3018                 newFileLoc.append("\"");
3019                 cp = ecp + 1; // advance beyond last \" and set cursor so we can
3020                               // look for next file statement.
3021               } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
3022             }
3023             if (cp > 0)
3024             {
3025               // just append rest of state
3026               newFileLoc.append(state.substring(cp));
3027             }
3028             else
3029             {
3030               System.err
3031                       .print("Ignoring incomplete Jmol state for PDB ids: ");
3032               newFileLoc = new StringBuffer(state);
3033               newFileLoc.append("; load append ");
3034               for (File id : oldFiles.keySet())
3035               {
3036                 // add this and any other pdb files that should be present in
3037                 // the viewer
3038                 Object[] filedat = oldFiles.get(id);
3039                 String nfilename;
3040                 newFileLoc.append(((String) filedat[0]));
3041                 pdbfilenames.addElement((String) filedat[0]);
3042                 pdbids.addElement((String) filedat[1]);
3043                 seqmaps.addElement(((Vector<SequenceI>) filedat[2])
3044                         .toArray(new SequenceI[0]));
3045                 newFileLoc.append(" \"");
3046                 newFileLoc.append((String) filedat[0]);
3047                 newFileLoc.append("\"");
3048
3049               }
3050               newFileLoc.append(";");
3051             }
3052
3053             if (newFileLoc != null)
3054             {
3055               int histbug = newFileLoc.indexOf("history = ");
3056               histbug += 10;
3057               int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";",
3058                       histbug);
3059               String val = (diff == -1) ? null : newFileLoc.substring(
3060                       histbug, diff);
3061               if (val != null && val.length() >= 4)
3062               {
3063                 if (val.contains("e"))
3064                 {
3065                   if (val.trim().equals("true"))
3066                   {
3067                     val = "1";
3068                   }
3069                   else
3070                   {
3071                     val = "0";
3072                   }
3073                   newFileLoc.replace(histbug, diff, val);
3074                 }
3075               }
3076               // TODO: assemble String[] { pdb files }, String[] { id for each
3077               // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3078               // seqs_file 2}} from hash
3079               final String[] pdbf = pdbfilenames
3080                       .toArray(new String[pdbfilenames.size()]), id = pdbids
3081                       .toArray(new String[pdbids.size()]);
3082               final SequenceI[][] sq = seqmaps
3083                       .toArray(new SequenceI[seqmaps.size()][]);
3084               final String fileloc = newFileLoc.toString(), vid = sviewid;
3085               final AlignFrame alf = af;
3086               final java.awt.Rectangle rect = new java.awt.Rectangle(x, y,
3087                       width, height);
3088               try
3089               {
3090                 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
3091                 {
3092                   @Override
3093                   public void run()
3094                   {
3095                     AppJmol sview = null;
3096                     try
3097                     {
3098                       sview = new AppJmol(pdbf, id, sq, alf.alignPanel,
3099                               useinJmolsuperpos, usetoColourbyseq,
3100                               jmolColouring, fileloc, rect, vid);
3101                       addNewStructureViewer(sview);
3102                     } catch (OutOfMemoryError ex)
3103                     {
3104                       new OOMWarning("restoring structure view for PDB id "
3105                               + id, (OutOfMemoryError) ex.getCause());
3106                       if (sview != null && sview.isVisible())
3107                       {
3108                         sview.closeViewer();
3109                         sview.setVisible(false);
3110                         sview.dispose();
3111                       }
3112                     }
3113                   }
3114                 });
3115               } catch (InvocationTargetException ex)
3116               {
3117                 warn("Unexpected error when opening Jmol view.", ex);
3118
3119               } catch (InterruptedException e)
3120               {
3121                 // e.printStackTrace();
3122               }
3123             }
3124
3125           }
3126           else
3127           // if (comp != null)
3128           {
3129             // NOTE: if the jalview project is part of a shared session then
3130             // view synchronization should/could be done here.
3131
3132             // add mapping for sequences in this view to an already open Jmol
3133             // instance
3134             for (File id : oldFiles.keySet())
3135             {
3136               // add this and any other pdb files that should be present in the
3137               // viewer
3138               Object[] filedat = oldFiles.get(id);
3139               String pdbFile = (String) filedat[0];
3140               SequenceI[] seq = ((Vector<SequenceI>) filedat[2])
3141                       .toArray(new SequenceI[0]);
3142               comp.jmb.ssm.setMapping(seq, null, pdbFile,
3143                       jalview.io.AppletFormatAdapter.FILE);
3144               comp.jmb.addSequenceForStructFile(pdbFile, seq);
3145             }
3146             // and add the AlignmentPanel's reference to the Jmol view
3147             comp.addAlignmentPanel(ap);
3148             if (useinJmolsuperpos)
3149             {
3150               comp.useAlignmentPanelForSuperposition(ap);
3151             }
3152             else
3153             {
3154               comp.excludeAlignmentPanelForSuperposition(ap);
3155             }
3156             if (usetoColourbyseq)
3157             {
3158               comp.useAlignmentPanelForColourbyseq(ap, !jmolColouring);
3159             }
3160             else
3161             {
3162               comp.excludeAlignmentPanelForColourbyseq(ap);
3163             }
3164           }
3165         }
3166       }
3167     }
3168     // and finally return.
3169     return af;
3170   }
3171   Vector<AppJmol> newStructureViewers=null;
3172   protected void addNewStructureViewer(AppJmol sview)
3173   {
3174     if (newStructureViewers!=null)
3175     {
3176       sview.jmb.setFinishedLoadingFromArchive(false);
3177       newStructureViewers.add(sview);
3178     }
3179   }
3180   protected void setLoadingFinishedForNewStructureViewers()
3181   {
3182     if (newStructureViewers!=null)
3183     {
3184       for (AppJmol sview:newStructureViewers)
3185       {
3186         sview.jmb.setFinishedLoadingFromArchive(true);
3187       }
3188       newStructureViewers.clear();
3189       newStructureViewers=null;
3190     }
3191   }
3192
3193   AlignFrame loadViewport(String file, JSeq[] JSEQ, Vector hiddenSeqs,
3194           Alignment al, JalviewModelSequence jms, Viewport view,
3195           String uniqueSeqSetId, String viewId,
3196           ArrayList<JvAnnotRow> autoAlan)
3197   {
3198     AlignFrame af = null;
3199     af = new AlignFrame(al, view.getWidth(), view.getHeight(),
3200             uniqueSeqSetId, viewId);
3201
3202     af.setFileName(file, "Jalview");
3203
3204     for (int i = 0; i < JSEQ.length; i++)
3205     {
3206       af.viewport.setSequenceColour(af.viewport.getAlignment()
3207               .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour()));
3208     }
3209
3210     af.viewport.gatherViewsHere = view.getGatheredViews();
3211
3212     if (view.getSequenceSetId() != null)
3213     {
3214       jalview.gui.AlignViewport av = (jalview.gui.AlignViewport) viewportsAdded
3215               .get(uniqueSeqSetId);
3216
3217       af.viewport.setSequenceSetId(uniqueSeqSetId);
3218       if (av != null)
3219       {
3220         // propagate shared settings to this new view
3221         af.viewport.historyList = av.historyList;
3222         af.viewport.redoList = av.redoList;
3223       }
3224       else
3225       {
3226         viewportsAdded.put(uniqueSeqSetId, af.viewport);
3227       }
3228       // TODO: check if this method can be called repeatedly without
3229       // side-effects if alignpanel already registered.
3230       PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
3231     }
3232     // apply Hidden regions to view.
3233     if (hiddenSeqs != null)
3234     {
3235       for (int s = 0; s < JSEQ.length; s++)
3236       {
3237         jalview.datamodel.SequenceGroup hidden = new jalview.datamodel.SequenceGroup();
3238
3239         for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
3240         {
3241           hidden.addSequence(
3242                   al.getSequenceAt(JSEQ[s].getHiddenSequences(r)), false);
3243         }
3244         af.viewport.hideRepSequences(al.getSequenceAt(s), hidden);
3245       }
3246
3247       jalview.datamodel.SequenceI[] hseqs = new jalview.datamodel.SequenceI[hiddenSeqs
3248               .size()];
3249
3250       for (int s = 0; s < hiddenSeqs.size(); s++)
3251       {
3252         hseqs[s] = (jalview.datamodel.SequenceI) hiddenSeqs.elementAt(s);
3253       }
3254
3255       af.viewport.hideSequence(hseqs);
3256
3257     }
3258     // recover view properties and display parameters
3259     if (view.getViewName() != null)
3260     {
3261       af.viewport.viewName = view.getViewName();
3262       af.setInitialTabVisible();
3263     }
3264     af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
3265             view.getHeight());
3266
3267     af.viewport.setShowAnnotation(view.getShowAnnotation());
3268     af.viewport.setAbovePIDThreshold(view.getPidSelected());
3269
3270     af.viewport.setColourText(view.getShowColourText());
3271
3272     af.viewport.setConservationSelected(view.getConservationSelected());
3273     af.viewport.setShowJVSuffix(view.getShowFullId());
3274     af.viewport.rightAlignIds = view.getRightAlignIds();
3275     af.viewport.setFont(new java.awt.Font(view.getFontName(), view
3276             .getFontStyle(), view.getFontSize()));
3277     af.alignPanel.fontChanged();
3278     af.viewport.setRenderGaps(view.getRenderGaps());
3279     af.viewport.setWrapAlignment(view.getWrapAlignment());
3280     af.alignPanel.setWrapAlignment(view.getWrapAlignment());
3281     af.viewport.setShowAnnotation(view.getShowAnnotation());
3282     af.alignPanel.setAnnotationVisible(view.getShowAnnotation());
3283
3284     af.viewport.setShowBoxes(view.getShowBoxes());
3285
3286     af.viewport.setShowText(view.getShowText());
3287
3288     af.viewport.textColour = new java.awt.Color(view.getTextCol1());
3289     af.viewport.textColour2 = new java.awt.Color(view.getTextCol2());
3290     af.viewport.thresholdTextColour = view.getTextColThreshold();
3291     af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
3292             .isShowUnconserved() : false);
3293     af.viewport.setStartRes(view.getStartRes());
3294     af.viewport.setStartSeq(view.getStartSeq());
3295
3296     ColourSchemeI cs = null;
3297     // apply colourschemes
3298     if (view.getBgColour() != null)
3299     {
3300       if (view.getBgColour().startsWith("ucs"))
3301       {
3302         cs = GetUserColourScheme(jms, view.getBgColour());
3303       }
3304       else if (view.getBgColour().startsWith("Annotation"))
3305       {
3306         // int find annotation
3307         if (af.viewport.getAlignment().getAlignmentAnnotation() != null)
3308         {
3309           for (int i = 0; i < af.viewport.getAlignment()
3310                   .getAlignmentAnnotation().length; i++)
3311           {
3312             if (af.viewport.getAlignment().getAlignmentAnnotation()[i].label
3313                     .equals(view.getAnnotationColours().getAnnotation()))
3314             {
3315               if (af.viewport.getAlignment().getAlignmentAnnotation()[i]
3316                       .getThreshold() == null)
3317               {
3318                 af.viewport.getAlignment().getAlignmentAnnotation()[i]
3319                         .setThreshold(new jalview.datamodel.GraphLine(view
3320                                 .getAnnotationColours().getThreshold(),
3321                                 "Threshold", java.awt.Color.black)
3322
3323                         );
3324               }
3325
3326               if (view.getAnnotationColours().getColourScheme()
3327                       .equals("None"))
3328               {
3329                 cs = new AnnotationColourGradient(af.viewport
3330                         .getAlignment().getAlignmentAnnotation()[i],
3331                         new java.awt.Color(view.getAnnotationColours()
3332                                 .getMinColour()), new java.awt.Color(view
3333                                 .getAnnotationColours().getMaxColour()),
3334                         view.getAnnotationColours().getAboveThreshold());
3335               }
3336               else if (view.getAnnotationColours().getColourScheme()
3337                       .startsWith("ucs"))
3338               {
3339                 cs = new AnnotationColourGradient(af.viewport
3340                         .getAlignment().getAlignmentAnnotation()[i],
3341                         GetUserColourScheme(jms, view
3342                                 .getAnnotationColours().getColourScheme()),
3343                         view.getAnnotationColours().getAboveThreshold());
3344               }
3345               else
3346               {
3347                 cs = new AnnotationColourGradient(af.viewport
3348                         .getAlignment().getAlignmentAnnotation()[i],
3349                         ColourSchemeProperty.getColour(al, view
3350                                 .getAnnotationColours().getColourScheme()),
3351                         view.getAnnotationColours().getAboveThreshold());
3352               }
3353               if (view.getAnnotationColours().hasPerSequence())
3354               {
3355                 ((AnnotationColourGradient)cs).setSeqAssociated(view.getAnnotationColours().isPerSequence());
3356               }
3357               if (view.getAnnotationColours().hasPredefinedColours())
3358               {
3359                 ((AnnotationColourGradient)cs).setPredefinedColours(view.getAnnotationColours().isPredefinedColours());
3360               }
3361               // Also use these settings for all the groups
3362               if (al.getGroups() != null)
3363               {
3364                 for (int g = 0; g < al.getGroups().size(); g++)
3365                 {
3366                   jalview.datamodel.SequenceGroup sg = al.getGroups()
3367                           .get(g);
3368
3369                   if (sg.cs == null)
3370                   {
3371                     continue;
3372                   }
3373
3374                   /*
3375                    * if
3376                    * (view.getAnnotationColours().getColourScheme().equals("None"
3377                    * )) { sg.cs = new AnnotationColourGradient(
3378                    * af.viewport.getAlignment().getAlignmentAnnotation()[i], new
3379                    * java.awt.Color(view.getAnnotationColours().
3380                    * getMinColour()), new
3381                    * java.awt.Color(view.getAnnotationColours().
3382                    * getMaxColour()),
3383                    * view.getAnnotationColours().getAboveThreshold()); } else
3384                    */
3385                   {
3386                     sg.cs = new AnnotationColourGradient(af.viewport
3387                             .getAlignment().getAlignmentAnnotation()[i],
3388                             sg.cs, view.getAnnotationColours()
3389                                     .getAboveThreshold());
3390                     if (cs instanceof AnnotationColourGradient) 
3391                     {
3392                       if (view.getAnnotationColours().hasPerSequence())
3393                       { 
3394                         ((AnnotationColourGradient)cs).setSeqAssociated(view.getAnnotationColours().isPerSequence());
3395                       }
3396                       if (view.getAnnotationColours().hasPredefinedColours())
3397                       {
3398                         ((AnnotationColourGradient)cs).setPredefinedColours(view.getAnnotationColours().isPredefinedColours());
3399                       }
3400                     }
3401                   }
3402
3403                 }
3404               }
3405
3406               break;
3407             }
3408
3409           }
3410         }
3411       }
3412       else
3413       {
3414         cs = ColourSchemeProperty.getColour(al, view.getBgColour());
3415       }
3416
3417       if (cs != null)
3418       {
3419         cs.setThreshold(view.getPidThreshold(), true);
3420         cs.setConsensus(af.viewport.getSequenceConsensusHash());
3421       }
3422     }
3423
3424     af.viewport.setGlobalColourScheme(cs);
3425     af.viewport.setColourAppliesToAllGroups(false);
3426
3427     if (view.getConservationSelected() && cs != null)
3428     {
3429       cs.setConservationInc(view.getConsThreshold());
3430     }
3431
3432     af.changeColour(cs);
3433
3434     af.viewport.setColourAppliesToAllGroups(true);
3435
3436     if (view.getShowSequenceFeatures())
3437     {
3438       af.viewport.showSequenceFeatures = true;
3439     }
3440     if (view.hasCentreColumnLabels())
3441     {
3442       af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
3443     }
3444     if (view.hasIgnoreGapsinConsensus())
3445     {
3446       af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
3447               null);
3448     }
3449     if (view.hasFollowHighlight())
3450     {
3451       af.viewport.followHighlight = view.getFollowHighlight();
3452     }
3453     if (view.hasFollowSelection())
3454     {
3455       af.viewport.followSelection = view.getFollowSelection();
3456     }
3457     if (view.hasShowConsensusHistogram())
3458     {
3459       af.viewport.setShowConsensusHistogram(view
3460               .getShowConsensusHistogram());
3461     }
3462     else
3463     {
3464       af.viewport.setShowConsensusHistogram(true);
3465     }
3466     if (view.hasShowSequenceLogo())
3467     {
3468       af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
3469     }
3470     else
3471     {
3472       af.viewport.setShowSequenceLogo(false);
3473     }
3474     if (view.hasNormaliseSequenceLogo())
3475     {
3476       af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
3477     }
3478     if (view.hasShowDbRefTooltip())
3479     {
3480       af.viewport.setShowDbRefs(view.getShowDbRefTooltip());
3481     }
3482     if (view.hasShowNPfeatureTooltip())
3483     {
3484       af.viewport.setShowNpFeats(view.hasShowNPfeatureTooltip());
3485     }
3486     if (view.hasShowGroupConsensus())
3487     {
3488       af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
3489     }
3490     else
3491     {
3492       af.viewport.setShowGroupConsensus(false);
3493     }
3494     if (view.hasShowGroupConservation())
3495     {
3496       af.viewport.setShowGroupConservation(view.getShowGroupConservation());
3497     }
3498     else
3499     {
3500       af.viewport.setShowGroupConservation(false);
3501     }
3502
3503     // recover featre settings
3504     if (jms.getFeatureSettings() != null)
3505     {
3506       af.viewport.featuresDisplayed = new Hashtable();
3507       String[] renderOrder = new String[jms.getFeatureSettings()
3508               .getSettingCount()];
3509       for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++)
3510       {
3511         Setting setting = jms.getFeatureSettings().getSetting(fs);
3512         if (setting.hasMincolour())
3513         {
3514           GraduatedColor gc = setting.hasMin() ? new GraduatedColor(
3515                   new java.awt.Color(setting.getMincolour()),
3516                   new java.awt.Color(setting.getColour()),
3517                   setting.getMin(), setting.getMax()) : new GraduatedColor(
3518                   new java.awt.Color(setting.getMincolour()),
3519                   new java.awt.Color(setting.getColour()), 0, 1);
3520           if (setting.hasThreshold())
3521           {
3522             gc.setThresh(setting.getThreshold());
3523             gc.setThreshType(setting.getThreshstate());
3524           }
3525           gc.setAutoScaled(true); // default
3526           if (setting.hasAutoScale())
3527           {
3528             gc.setAutoScaled(setting.getAutoScale());
3529           }
3530           if (setting.hasColourByLabel())
3531           {
3532             gc.setColourByLabel(setting.getColourByLabel());
3533           }
3534           // and put in the feature colour table.
3535           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setColour(
3536                   setting.getType(), gc);
3537         }
3538         else
3539         {
3540           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setColour(
3541                   setting.getType(),
3542                   new java.awt.Color(setting.getColour()));
3543         }
3544         renderOrder[fs] = setting.getType();
3545         if (setting.hasOrder())
3546           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setOrder(
3547                   setting.getType(), setting.getOrder());
3548         else
3549           af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().setOrder(
3550                   setting.getType(),
3551                   fs / jms.getFeatureSettings().getSettingCount());
3552         if (setting.getDisplay())
3553         {
3554           af.viewport.featuresDisplayed.put(setting.getType(), new Integer(
3555                   setting.getColour()));
3556         }
3557       }
3558       af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().renderOrder = renderOrder;
3559       Hashtable fgtable;
3560       af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureGroups = fgtable = new Hashtable();
3561       for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
3562       {
3563         Group grp = jms.getFeatureSettings().getGroup(gs);
3564         fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
3565       }
3566     }
3567
3568     if (view.getHiddenColumnsCount() > 0)
3569     {
3570       for (int c = 0; c < view.getHiddenColumnsCount(); c++)
3571       {
3572         af.viewport.hideColumns(view.getHiddenColumns(c).getStart(), view
3573                 .getHiddenColumns(c).getEnd() // +1
3574                 );
3575       }
3576     }
3577     if (view.getCalcIdParam() != null)
3578     {
3579       for (CalcIdParam calcIdParam : view.getCalcIdParam())
3580       {
3581         if (calcIdParam != null)
3582         {
3583           if (recoverCalcIdParam(calcIdParam, af.viewport))
3584           {
3585           }
3586           else
3587           {
3588             warn("Couldn't recover parameters for "
3589                     + calcIdParam.getCalcId());
3590           }
3591         }
3592       }
3593     }
3594     af.setMenusFromViewport(af.viewport);
3595     // TODO: we don't need to do this if the viewport is aready visible.
3596     Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
3597             view.getHeight());
3598     af.alignPanel.updateAnnotation(false, true); // recompute any autoannotation
3599     reorderAutoannotation(af, al, autoAlan);
3600     af.alignPanel.alignmentChanged();
3601     return af;
3602   }
3603
3604   private void reorderAutoannotation(AlignFrame af, Alignment al,
3605           ArrayList<JvAnnotRow> autoAlan)
3606   {
3607     // copy over visualization settings for autocalculated annotation in the
3608     // view
3609     if (al.getAlignmentAnnotation() != null)
3610     {
3611       /**
3612        * Kludge for magic autoannotation names (see JAL-811)
3613        */
3614       String[] magicNames = new String[]
3615       { "Consensus", "Quality", "Conservation" };
3616       JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
3617       Hashtable<String, JvAnnotRow> visan = new Hashtable<String, JvAnnotRow>();
3618       for (String nm : magicNames)
3619       {
3620         visan.put(nm, nullAnnot);
3621       }
3622       for (JvAnnotRow auan : autoAlan)
3623       {
3624         visan.put(auan.template.label
3625                 + (auan.template.getCalcId() == null ? "" : "\t"
3626                         + auan.template.getCalcId()), auan);
3627       }
3628       int hSize = al.getAlignmentAnnotation().length;
3629       ArrayList<JvAnnotRow> reorder = new ArrayList<JvAnnotRow>();
3630       // work through any autoCalculated annotation already on the view
3631       // removing it if it should be placed in a different location on the
3632       // annotation panel.
3633       List<String> remains = new ArrayList(visan.keySet());
3634       for (int h = 0; h < hSize; h++)
3635       {
3636         jalview.datamodel.AlignmentAnnotation jalan = al
3637                 .getAlignmentAnnotation()[h];
3638         if (jalan.autoCalculated)
3639         {
3640           String k;
3641           JvAnnotRow valan = visan.get(k = jalan.label);
3642           if (jalan.getCalcId() != null)
3643           {
3644             valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
3645           }
3646
3647           if (valan != null)
3648           {
3649             // delete the auto calculated row from the alignment
3650             al.deleteAnnotation(jalan, false);
3651             remains.remove(k);
3652             hSize--;
3653             h--;
3654             if (valan != nullAnnot)
3655             {
3656               if (jalan != valan.template)
3657               {
3658                 // newly created autoannotation row instance
3659                 // so keep a reference to the visible annotation row
3660                 // and copy over all relevant attributes
3661                 if (valan.template.graphHeight >= 0)
3662
3663                 {
3664                   jalan.graphHeight = valan.template.graphHeight;
3665                 }
3666                 jalan.visible = valan.template.visible;
3667               }
3668               reorder.add(new JvAnnotRow(valan.order, jalan));
3669             }
3670           }
3671         }
3672       }
3673       // Add any (possibly stale) autocalculated rows that were not appended to
3674       // the view during construction
3675       for (String other : remains)
3676       {
3677         JvAnnotRow othera = visan.get(other);
3678         if (othera != nullAnnot && othera.template.getCalcId() != null
3679                 && othera.template.getCalcId().length() > 0)
3680         {
3681           reorder.add(othera);
3682         }
3683       }
3684       // now put the automatic annotation in its correct place
3685       int s = 0, srt[] = new int[reorder.size()];
3686       JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
3687       for (JvAnnotRow jvar : reorder)
3688       {
3689         rws[s] = jvar;
3690         srt[s++] = jvar.order;
3691       }
3692       reorder.clear();
3693       jalview.util.QuickSort.sort(srt, rws);
3694       // and re-insert the annotation at its correct position
3695       for (JvAnnotRow jvar : rws)
3696       {
3697         al.addAnnotation(jvar.template, jvar.order);
3698       }
3699       af.alignPanel.adjustAnnotationHeight();
3700     }
3701   }
3702
3703   Hashtable skipList = null;
3704
3705   /**
3706    * TODO remove this method
3707    * 
3708    * @param view
3709    * @return AlignFrame bound to sequenceSetId from view, if one exists. private
3710    *         AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
3711    *         throw new Error("Implementation Error. No skipList defined for this
3712    *         Jalview2XML instance."); } return (AlignFrame)
3713    *         skipList.get(view.getSequenceSetId()); }
3714    */
3715
3716   /**
3717    * Check if the Jalview view contained in object should be skipped or not.
3718    * 
3719    * @param object
3720    * @return true if view's sequenceSetId is a key in skipList
3721    */
3722   private boolean skipViewport(JalviewModel object)
3723   {
3724     if (skipList == null)
3725     {
3726       return false;
3727     }
3728     String id;
3729     if (skipList.containsKey(id = object.getJalviewModelSequence()
3730             .getViewport()[0].getSequenceSetId()))
3731     {
3732       if (Cache.log != null && Cache.log.isDebugEnabled())
3733       {
3734         Cache.log.debug("Skipping seuqence set id " + id);
3735       }
3736       return true;
3737     }
3738     return false;
3739   }
3740
3741   public void AddToSkipList(AlignFrame af)
3742   {
3743     if (skipList == null)
3744     {
3745       skipList = new Hashtable();
3746     }
3747     skipList.put(af.getViewport().getSequenceSetId(), af);
3748   }
3749
3750   public void clearSkipList()
3751   {
3752     if (skipList != null)
3753     {
3754       skipList.clear();
3755       skipList = null;
3756     }
3757   }
3758
3759   private void recoverDatasetFor(SequenceSet vamsasSet, Alignment al)
3760   {
3761     jalview.datamodel.Alignment ds = getDatasetFor(vamsasSet.getDatasetId());
3762     Vector dseqs = null;
3763     if (ds == null)
3764     {
3765       // create a list of new dataset sequences
3766       dseqs = new Vector();
3767     }
3768     for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
3769     {
3770       Sequence vamsasSeq = vamsasSet.getSequence(i);
3771       ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs);
3772     }
3773     // create a new dataset
3774     if (ds == null)
3775     {
3776       SequenceI[] dsseqs = new SequenceI[dseqs.size()];
3777       dseqs.copyInto(dsseqs);
3778       ds = new jalview.datamodel.Alignment(dsseqs);
3779       debug("Created new dataset " + vamsasSet.getDatasetId()
3780               + " for alignment " + System.identityHashCode(al));
3781       addDatasetRef(vamsasSet.getDatasetId(), ds);
3782     }
3783     // set the dataset for the newly imported alignment.
3784     if (al.getDataset() == null)
3785     {
3786       al.setDataset(ds);
3787     }
3788   }
3789
3790   /**
3791    * 
3792    * @param vamsasSeq
3793    *          sequence definition to create/merge dataset sequence for
3794    * @param ds
3795    *          dataset alignment
3796    * @param dseqs
3797    *          vector to add new dataset sequence to
3798    */
3799   private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
3800           AlignmentI ds, Vector dseqs)
3801   {
3802     // JBP TODO: Check this is called for AlCodonFrames to support recovery of
3803     // xRef Codon Maps
3804     jalview.datamodel.Sequence sq = (jalview.datamodel.Sequence) seqRefIds
3805             .get(vamsasSeq.getId());
3806     jalview.datamodel.SequenceI dsq = null;
3807     if (sq != null && sq.getDatasetSequence() != null)
3808     {
3809       dsq = sq.getDatasetSequence();
3810     }
3811
3812     String sqid = vamsasSeq.getDsseqid();
3813     if (dsq == null)
3814     {
3815       // need to create or add a new dataset sequence reference to this sequence
3816       if (sqid != null)
3817       {
3818         dsq = (jalview.datamodel.SequenceI) seqRefIds.get(sqid);
3819       }
3820       // check again
3821       if (dsq == null)
3822       {
3823         // make a new dataset sequence
3824         dsq = sq.createDatasetSequence();
3825         if (sqid == null)
3826         {
3827           // make up a new dataset reference for this sequence
3828           sqid = seqHash(dsq);
3829         }
3830         dsq.setVamsasId(uniqueSetSuffix + sqid);
3831         seqRefIds.put(sqid, dsq);
3832         if (ds == null)
3833         {
3834           if (dseqs != null)
3835           {
3836             dseqs.addElement(dsq);
3837           }
3838         }
3839         else
3840         {
3841           ds.addSequence(dsq);
3842         }
3843       }
3844       else
3845       {
3846         if (sq != dsq)
3847         { // make this dataset sequence sq's dataset sequence
3848           sq.setDatasetSequence(dsq);
3849           // and update the current dataset alignment
3850           if (ds==null) {
3851             if (dseqs!=null) {
3852               if (!dseqs.contains(dsq))
3853               {
3854                 dseqs.add(dsq);
3855               }
3856             } else {
3857               if (ds.findIndex(dsq)<0)
3858               {
3859                 ds.addSequence(dsq);
3860               }
3861             }
3862           }
3863         }
3864       }
3865     }
3866     // TODO: refactor this as a merge dataset sequence function
3867     // now check that sq (the dataset sequence) sequence really is the union of
3868     // all references to it
3869     // boolean pre = sq.getStart() < dsq.getStart();
3870     // boolean post = sq.getEnd() > dsq.getEnd();
3871     // if (pre || post)
3872     if (sq != dsq)
3873     {
3874       StringBuffer sb = new StringBuffer();
3875       String newres = jalview.analysis.AlignSeq.extractGaps(
3876               jalview.util.Comparison.GapChars, sq.getSequenceAsString());
3877       if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
3878               && newres.length() > dsq.getLength())
3879       {
3880         // Update with the longer sequence.
3881         synchronized (dsq)
3882         {
3883           /*
3884            * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
3885            * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
3886            * sb.append(newres.substring(newres.length() - sq.getEnd() -
3887            * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
3888            */
3889           dsq.setSequence(newres);
3890         }
3891         // TODO: merges will never happen if we 'know' we have the real dataset
3892         // sequence - this should be detected when id==dssid
3893         System.err.println("DEBUG Notice:  Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
3894         // + (pre ? "prepended" : "") + " "
3895         // + (post ? "appended" : ""));
3896       }
3897     }
3898   }
3899
3900   java.util.Hashtable datasetIds = null;
3901
3902   java.util.IdentityHashMap dataset2Ids = null;
3903
3904   private Alignment getDatasetFor(String datasetId)
3905   {
3906     if (datasetIds == null)
3907     {
3908       datasetIds = new Hashtable();
3909       return null;
3910     }
3911     if (datasetIds.containsKey(datasetId))
3912     {
3913       return (Alignment) datasetIds.get(datasetId);
3914     }
3915     return null;
3916   }
3917
3918   private void addDatasetRef(String datasetId, Alignment dataset)
3919   {
3920     if (datasetIds == null)
3921     {
3922       datasetIds = new Hashtable();
3923     }
3924     datasetIds.put(datasetId, dataset);
3925   }
3926
3927   /**
3928    * make a new dataset ID for this jalview dataset alignment
3929    * 
3930    * @param dataset
3931    * @return
3932    */
3933   private String getDatasetIdRef(jalview.datamodel.Alignment dataset)
3934   {
3935     if (dataset.getDataset() != null)
3936     {
3937       warn("Serious issue!  Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
3938     }
3939     String datasetId = makeHashCode(dataset, null);
3940     if (datasetId == null)
3941     {
3942       // make a new datasetId and record it
3943       if (dataset2Ids == null)
3944       {
3945         dataset2Ids = new IdentityHashMap();
3946       }
3947       else
3948       {
3949         datasetId = (String) dataset2Ids.get(dataset);
3950       }
3951       if (datasetId == null)
3952       {
3953         datasetId = "ds" + dataset2Ids.size() + 1;
3954         dataset2Ids.put(dataset, datasetId);
3955       }
3956     }
3957     return datasetId;
3958   }
3959
3960   private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
3961   {
3962     for (int d = 0; d < sequence.getDBRefCount(); d++)
3963     {
3964       DBRef dr = sequence.getDBRef(d);
3965       jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
3966               sequence.getDBRef(d).getSource(), sequence.getDBRef(d)
3967                       .getVersion(), sequence.getDBRef(d).getAccessionId());
3968       if (dr.getMapping() != null)
3969       {
3970         entry.setMap(addMapping(dr.getMapping()));
3971       }
3972       datasetSequence.addDBRef(entry);
3973     }
3974   }
3975
3976   private jalview.datamodel.Mapping addMapping(Mapping m)
3977   {
3978     SequenceI dsto = null;
3979     // Mapping m = dr.getMapping();
3980     int fr[] = new int[m.getMapListFromCount() * 2];
3981     Enumeration f = m.enumerateMapListFrom();
3982     for (int _i = 0; f.hasMoreElements(); _i += 2)
3983     {
3984       MapListFrom mf = (MapListFrom) f.nextElement();
3985       fr[_i] = mf.getStart();
3986       fr[_i + 1] = mf.getEnd();
3987     }
3988     int fto[] = new int[m.getMapListToCount() * 2];
3989     f = m.enumerateMapListTo();
3990     for (int _i = 0; f.hasMoreElements(); _i += 2)
3991     {
3992       MapListTo mf = (MapListTo) f.nextElement();
3993       fto[_i] = mf.getStart();
3994       fto[_i + 1] = mf.getEnd();
3995     }
3996     jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto,
3997             fr, fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
3998     if (m.getMappingChoice() != null)
3999     {
4000       MappingChoice mc = m.getMappingChoice();
4001       if (mc.getDseqFor() != null)
4002       {
4003         String dsfor = "" + mc.getDseqFor();
4004         if (seqRefIds.containsKey(dsfor))
4005         {
4006           /**
4007            * recover from hash
4008            */
4009           jmap.setTo((SequenceI) seqRefIds.get(dsfor));
4010         }
4011         else
4012         {
4013           frefedSequence.add(new Object[]
4014           { dsfor, jmap });
4015         }
4016       }
4017       else
4018       {
4019         /**
4020          * local sequence definition
4021          */
4022         Sequence ms = mc.getSequence();
4023         jalview.datamodel.Sequence djs = null;
4024         String sqid = ms.getDsseqid();
4025         if (sqid != null && sqid.length() > 0)
4026         {
4027           /*
4028            * recover dataset sequence
4029            */
4030           djs = (jalview.datamodel.Sequence) seqRefIds.get(sqid);
4031         }
4032         else
4033         {
4034           System.err
4035                   .println("Warning - making up dataset sequence id for DbRef sequence map reference");
4036           sqid = ((Object) ms).toString(); // make up a new hascode for
4037           // undefined dataset sequence hash
4038           // (unlikely to happen)
4039         }
4040
4041         if (djs == null)
4042         {
4043           /**
4044            * make a new dataset sequence and add it to refIds hash
4045            */
4046           djs = new jalview.datamodel.Sequence(ms.getName(),
4047                   ms.getSequence());
4048           djs.setStart(jmap.getMap().getToLowest());
4049           djs.setEnd(jmap.getMap().getToHighest());
4050           djs.setVamsasId(uniqueSetSuffix + sqid);
4051           jmap.setTo(djs);
4052           seqRefIds.put(sqid, djs);
4053
4054         }
4055         jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
4056         addDBRefs(djs, ms);
4057
4058       }
4059     }
4060     return (jmap);
4061
4062   }
4063
4064   public jalview.gui.AlignmentPanel copyAlignPanel(AlignmentPanel ap,
4065           boolean keepSeqRefs)
4066   {
4067     initSeqRefs();
4068     jalview.schemabinding.version2.JalviewModel jm = SaveState(ap, null,
4069             null);
4070
4071     if (!keepSeqRefs)
4072     {
4073       clearSeqRefs();
4074       jm.getJalviewModelSequence().getViewport(0).setSequenceSetId(null);
4075     }
4076     else
4077     {
4078       uniqueSetSuffix = "";
4079       jm.getJalviewModelSequence().getViewport(0).setId(null); // we don't
4080       // overwrite the
4081       // view we just
4082       // copied
4083     }
4084     if (this.frefedSequence == null)
4085     {
4086       frefedSequence = new Vector();
4087     }
4088
4089     viewportsAdded = new Hashtable();
4090
4091     AlignFrame af = LoadFromObject(jm, null, false, null);
4092     af.alignPanels.clear();
4093     af.closeMenuItem_actionPerformed(true);
4094
4095     /*
4096      * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
4097      * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
4098      * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
4099      * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
4100      * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
4101      */
4102
4103     return af.alignPanel;
4104   }
4105
4106   /**
4107    * flag indicating if hashtables should be cleared on finalization TODO this
4108    * flag may not be necessary
4109    */
4110   private final boolean _cleartables = true;
4111
4112   private Hashtable jvids2vobj;
4113
4114   /*
4115    * (non-Javadoc)
4116    * 
4117    * @see java.lang.Object#finalize()
4118    */
4119   @Override
4120   protected void finalize() throws Throwable
4121   {
4122     // really make sure we have no buried refs left.
4123     if (_cleartables)
4124     {
4125       clearSeqRefs();
4126     }
4127     this.seqRefIds = null;
4128     this.seqsToIds = null;
4129     super.finalize();
4130   }
4131
4132   private void warn(String msg)
4133   {
4134     warn(msg, null);
4135   }
4136
4137   private void warn(String msg, Exception e)
4138   {
4139     if (Cache.log != null)
4140     {
4141       if (e != null)
4142       {
4143         Cache.log.warn(msg, e);
4144       }
4145       else
4146       {
4147         Cache.log.warn(msg);
4148       }
4149     }
4150     else
4151     {
4152       System.err.println("Warning: " + msg);
4153       if (e != null)
4154       {
4155         e.printStackTrace();
4156       }
4157     }
4158   }
4159
4160   private void debug(String string)
4161   {
4162     debug(string, null);
4163   }
4164
4165   private void debug(String msg, Exception e)
4166   {
4167     if (Cache.log != null)
4168     {
4169       if (e != null)
4170       {
4171         Cache.log.debug(msg, e);
4172       }
4173       else
4174       {
4175         Cache.log.debug(msg);
4176       }
4177     }
4178     else
4179     {
4180       System.err.println("Warning: " + msg);
4181       if (e != null)
4182       {
4183         e.printStackTrace();
4184       }
4185     }
4186   }
4187
4188   /**
4189    * set the object to ID mapping tables used to write/recover objects and XML
4190    * ID strings for the jalview project. If external tables are provided then
4191    * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
4192    * object goes out of scope. - also populates the datasetIds hashtable with
4193    * alignment objects containing dataset sequences
4194    * 
4195    * @param vobj2jv
4196    *          Map from ID strings to jalview datamodel
4197    * @param jv2vobj
4198    *          Map from jalview datamodel to ID strings
4199    * 
4200    * 
4201    */
4202   public void setObjectMappingTables(Hashtable vobj2jv,
4203           IdentityHashMap jv2vobj)
4204   {
4205     this.jv2vobj = jv2vobj;
4206     this.vobj2jv = vobj2jv;
4207     Iterator ds = jv2vobj.keySet().iterator();
4208     String id;
4209     while (ds.hasNext())
4210     {
4211       Object jvobj = ds.next();
4212       id = jv2vobj.get(jvobj).toString();
4213       if (jvobj instanceof jalview.datamodel.Alignment)
4214       {
4215         if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
4216         {
4217           addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
4218         }
4219       }
4220       else if (jvobj instanceof jalview.datamodel.Sequence)
4221       {
4222         // register sequence object so the XML parser can recover it.
4223         if (seqRefIds == null)
4224         {
4225           seqRefIds = new Hashtable();
4226         }
4227         if (seqsToIds == null)
4228         {
4229           seqsToIds = new IdentityHashMap();
4230         }
4231         seqRefIds.put(jv2vobj.get(jvobj).toString(), jvobj);
4232         seqsToIds.put(jvobj, id);
4233       }
4234       else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
4235       {
4236         if (annotationIds == null)
4237         {
4238           annotationIds = new Hashtable();
4239         }
4240         String anid;
4241         annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvobj);
4242         jalview.datamodel.AlignmentAnnotation jvann = (jalview.datamodel.AlignmentAnnotation) jvobj;
4243         if (jvann.annotationId == null)
4244         {
4245           jvann.annotationId = anid;
4246         }
4247         if (!jvann.annotationId.equals(anid))
4248         {
4249           // TODO verify that this is the correct behaviour
4250           this.warn("Overriding Annotation ID for " + anid
4251                   + " from different id : " + jvann.annotationId);
4252           jvann.annotationId = anid;
4253         }
4254       }
4255       else if (jvobj instanceof String)
4256       {
4257         if (jvids2vobj == null)
4258         {
4259           jvids2vobj = new Hashtable();
4260           jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
4261         }
4262       }
4263       else
4264         Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
4265     }
4266   }
4267
4268   /**
4269    * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
4270    * objects created from the project archive. If string is null (default for
4271    * construction) then suffix will be set automatically.
4272    * 
4273    * @param string
4274    */
4275   public void setUniqueSetSuffix(String string)
4276   {
4277     uniqueSetSuffix = string;
4278
4279   }
4280
4281   /**
4282    * uses skipList2 as the skipList for skipping views on sequence sets
4283    * associated with keys in the skipList
4284    * 
4285    * @param skipList2
4286    */
4287   public void setSkipList(Hashtable skipList2)
4288   {
4289     skipList = skipList2;
4290   }
4291
4292 }