Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.gui

File Jalview2XML.java

 

Coverage histogram

../../img/srcFileCovDistChart7.png
28% of files have more coverage

Code metrics

1,050
2,137
97
3
5,999
4,439
730
0.34
22.03
32.33
7.53

Classes

Class Line # Actions
Jalview2XML 163 2,124 721 1,004
0.692024569.2%
Jalview2XML.SeqFref 267 11 8 21
0.00%
Jalview2XML.JvAnnotRow 2827 2 1 0
1.0100%
 

Contributing tests

This file is covered by 18 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.gui;
22   
23    import jalview.analysis.Conservation;
24    import jalview.api.FeatureColourI;
25    import jalview.api.ViewStyleI;
26    import jalview.api.structures.JalviewStructureDisplayI;
27    import jalview.bin.Cache;
28    import jalview.datamodel.AlignedCodonFrame;
29    import jalview.datamodel.Alignment;
30    import jalview.datamodel.AlignmentAnnotation;
31    import jalview.datamodel.AlignmentI;
32    import jalview.datamodel.GraphLine;
33    import jalview.datamodel.PDBEntry;
34    import jalview.datamodel.RnaViewerModel;
35    import jalview.datamodel.SequenceFeature;
36    import jalview.datamodel.SequenceGroup;
37    import jalview.datamodel.SequenceI;
38    import jalview.datamodel.StructureViewerModel;
39    import jalview.datamodel.StructureViewerModel.StructureData;
40    import jalview.datamodel.features.FeatureMatcher;
41    import jalview.datamodel.features.FeatureMatcherI;
42    import jalview.datamodel.features.FeatureMatcherSet;
43    import jalview.datamodel.features.FeatureMatcherSetI;
44    import jalview.ext.varna.RnaModel;
45    import jalview.gui.StructureViewer.ViewerType;
46    import jalview.io.DataSourceType;
47    import jalview.io.FileFormat;
48    import jalview.renderer.ResidueShaderI;
49    import jalview.schemabinding.version2.AlcodMap;
50    import jalview.schemabinding.version2.AlcodonFrame;
51    import jalview.schemabinding.version2.Annotation;
52    import jalview.schemabinding.version2.AnnotationColours;
53    import jalview.schemabinding.version2.AnnotationElement;
54    import jalview.schemabinding.version2.CalcIdParam;
55    import jalview.schemabinding.version2.CompoundMatcher;
56    import jalview.schemabinding.version2.DBRef;
57    import jalview.schemabinding.version2.Features;
58    import jalview.schemabinding.version2.Group;
59    import jalview.schemabinding.version2.HiddenColumns;
60    import jalview.schemabinding.version2.JGroup;
61    import jalview.schemabinding.version2.JSeq;
62    import jalview.schemabinding.version2.JalviewModel;
63    import jalview.schemabinding.version2.JalviewModelSequence;
64    import jalview.schemabinding.version2.MapListFrom;
65    import jalview.schemabinding.version2.MapListTo;
66    import jalview.schemabinding.version2.Mapping;
67    import jalview.schemabinding.version2.MappingChoice;
68    import jalview.schemabinding.version2.MatchCondition;
69    import jalview.schemabinding.version2.MatcherSet;
70    import jalview.schemabinding.version2.OtherData;
71    import jalview.schemabinding.version2.PdbentryItem;
72    import jalview.schemabinding.version2.Pdbids;
73    import jalview.schemabinding.version2.Property;
74    import jalview.schemabinding.version2.RnaViewer;
75    import jalview.schemabinding.version2.SecondaryStructure;
76    import jalview.schemabinding.version2.Sequence;
77    import jalview.schemabinding.version2.SequenceSet;
78    import jalview.schemabinding.version2.SequenceSetProperties;
79    import jalview.schemabinding.version2.Setting;
80    import jalview.schemabinding.version2.StructureState;
81    import jalview.schemabinding.version2.ThresholdLine;
82    import jalview.schemabinding.version2.Tree;
83    import jalview.schemabinding.version2.UserColours;
84    import jalview.schemabinding.version2.Viewport;
85    import jalview.schemabinding.version2.types.ColourThreshTypeType;
86    import jalview.schemabinding.version2.types.FeatureMatcherByType;
87    import jalview.schemabinding.version2.types.NoValueColour;
88    import jalview.schemes.AnnotationColourGradient;
89    import jalview.schemes.ColourSchemeI;
90    import jalview.schemes.ColourSchemeProperty;
91    import jalview.schemes.FeatureColour;
92    import jalview.schemes.ResidueProperties;
93    import jalview.schemes.UserColourScheme;
94    import jalview.structure.StructureSelectionManager;
95    import jalview.structures.models.AAStructureBindingModel;
96    import jalview.util.Format;
97    import jalview.util.MessageManager;
98    import jalview.util.Platform;
99    import jalview.util.StringUtils;
100    import jalview.util.jarInputStreamProvider;
101    import jalview.util.matcher.Condition;
102    import jalview.viewmodel.AlignmentViewport;
103    import jalview.viewmodel.ViewportRanges;
104    import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
105    import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
106    import jalview.ws.jws2.Jws2Discoverer;
107    import jalview.ws.jws2.dm.AAConSettings;
108    import jalview.ws.jws2.jabaws2.Jws2Instance;
109    import jalview.ws.params.ArgumentI;
110    import jalview.ws.params.AutoCalcSetting;
111    import jalview.ws.params.WsParamSetI;
112   
113    import java.awt.Color;
114    import java.awt.Rectangle;
115    import java.io.BufferedReader;
116    import java.io.DataInputStream;
117    import java.io.DataOutputStream;
118    import java.io.File;
119    import java.io.FileInputStream;
120    import java.io.FileOutputStream;
121    import java.io.IOException;
122    import java.io.InputStreamReader;
123    import java.io.OutputStreamWriter;
124    import java.io.PrintWriter;
125    import java.lang.reflect.InvocationTargetException;
126    import java.net.MalformedURLException;
127    import java.net.URL;
128    import java.util.ArrayList;
129    import java.util.Arrays;
130    import java.util.Collections;
131    import java.util.Enumeration;
132    import java.util.HashMap;
133    import java.util.HashSet;
134    import java.util.Hashtable;
135    import java.util.IdentityHashMap;
136    import java.util.Iterator;
137    import java.util.LinkedHashMap;
138    import java.util.List;
139    import java.util.Map;
140    import java.util.Map.Entry;
141    import java.util.Set;
142    import java.util.Vector;
143    import java.util.jar.JarEntry;
144    import java.util.jar.JarInputStream;
145    import java.util.jar.JarOutputStream;
146   
147    import javax.swing.JInternalFrame;
148    import javax.swing.SwingUtilities;
149   
150    import org.exolab.castor.xml.Marshaller;
151    import org.exolab.castor.xml.Unmarshaller;
152   
153    /**
154    * Write out the current jalview desktop state as a Jalview XML stream.
155    *
156    * Note: the vamsas objects referred to here are primitive versions of the
157    * VAMSAS project schema elements - they are not the same and most likely never
158    * will be :)
159    *
160    * @author $author$
161    * @version $Revision: 1.134 $
162    */
 
163    public class Jalview2XML
164    {
165    private static final String VIEWER_PREFIX = "viewer_";
166   
167    private static final String RNA_PREFIX = "rna_";
168   
169    private static final String UTF_8 = "UTF-8";
170   
171    // use this with nextCounter() to make unique names for entities
172    private int counter = 0;
173   
174    /*
175    * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
176    * of sequence objects are created.
177    */
178    IdentityHashMap<SequenceI, String> seqsToIds = null;
179   
180    /**
181    * jalview XML Sequence ID to jalview sequence object reference (both dataset
182    * and alignment sequences. Populated as XML reps of sequence objects are
183    * created.)
184    */
185    Map<String, SequenceI> seqRefIds = null;
186   
187    Map<String, SequenceI> incompleteSeqs = null;
188   
189    List<SeqFref> frefedSequence = null;
190   
191    boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
192   
193    /*
194    * Map of reconstructed AlignFrame objects that appear to have come from
195    * SplitFrame objects (have a dna/protein complement view).
196    */
197    private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
198   
199    /*
200    * Map from displayed rna structure models to their saved session state jar
201    * entry names
202    */
203    private Map<RnaModel, String> rnaSessions = new HashMap<>();
204   
205    /**
206    * create/return unique hash string for sq
207    *
208    * @param sq
209    * @return new or existing unique string for sq
210    */
 
211  836 toggle String seqHash(SequenceI sq)
212    {
213  836 if (seqsToIds == null)
214    {
215  0 initSeqRefs();
216    }
217  836 if (seqsToIds.containsKey(sq))
218    {
219  452 return seqsToIds.get(sq);
220    }
221    else
222    {
223    // create sequential key
224  384 String key = "sq" + (seqsToIds.size() + 1);
225  384 key = makeHashCode(sq, key); // check we don't have an external reference
226    // for it already.
227  384 seqsToIds.put(sq, key);
228  384 return key;
229    }
230    }
231   
 
232  59 toggle void initSeqRefs()
233    {
234  59 if (seqsToIds == null)
235    {
236  33 seqsToIds = new IdentityHashMap<>();
237    }
238  59 if (seqRefIds == null)
239    {
240  33 seqRefIds = new HashMap<>();
241    }
242  59 if (incompleteSeqs == null)
243    {
244  33 incompleteSeqs = new HashMap<>();
245    }
246  59 if (frefedSequence == null)
247    {
248  33 frefedSequence = new ArrayList<>();
249    }
250    }
251   
 
252  8 toggle public Jalview2XML()
253    {
254    }
255   
 
256  25 toggle public Jalview2XML(boolean raiseGUI)
257    {
258  25 this.raiseGUI = raiseGUI;
259    }
260   
261    /**
262    * base class for resolving forward references to sequences by their ID
263    *
264    * @author jprocter
265    *
266    */
 
267    abstract class SeqFref
268    {
269    String sref;
270   
271    String type;
272   
 
273  0 toggle public SeqFref(String _sref, String type)
274    {
275  0 sref = _sref;
276  0 this.type = type;
277    }
278   
 
279  0 toggle public String getSref()
280    {
281  0 return sref;
282    }
283   
 
284  0 toggle public SequenceI getSrefSeq()
285    {
286  0 return seqRefIds.get(sref);
287    }
288   
 
289  0 toggle public boolean isResolvable()
290    {
291  0 return seqRefIds.get(sref) != null;
292    }
293   
 
294  0 toggle public SequenceI getSrefDatasetSeq()
295    {
296  0 SequenceI sq = seqRefIds.get(sref);
297  0 if (sq != null)
298    {
299  0 while (sq.getDatasetSequence() != null)
300    {
301  0 sq = sq.getDatasetSequence();
302    }
303    }
304  0 return sq;
305    }
306   
307    /**
308    * @return true if the forward reference was fully resolved
309    */
310    abstract boolean resolve();
311   
 
312  0 toggle @Override
313    public String toString()
314    {
315  0 return type + " reference to " + sref;
316    }
317    }
318   
319    /**
320    * create forward reference for a mapping
321    *
322    * @param sref
323    * @param _jmap
324    * @return
325    */
 
326  0 toggle public SeqFref newMappingRef(final String sref,
327    final jalview.datamodel.Mapping _jmap)
328    {
329  0 SeqFref fref = new SeqFref(sref, "Mapping")
330    {
331    public jalview.datamodel.Mapping jmap = _jmap;
332   
 
333  0 toggle @Override
334    boolean resolve()
335    {
336  0 SequenceI seq = getSrefDatasetSeq();
337  0 if (seq == null)
338    {
339  0 return false;
340    }
341  0 jmap.setTo(seq);
342  0 return true;
343    }
344    };
345  0 return fref;
346    }
347   
 
348  0 toggle public SeqFref newAlcodMapRef(final String sref,
349    final AlignedCodonFrame _cf,
350    final jalview.datamodel.Mapping _jmap)
351    {
352   
353  0 SeqFref fref = new SeqFref(sref, "Codon Frame")
354    {
355    AlignedCodonFrame cf = _cf;
356   
357    public jalview.datamodel.Mapping mp = _jmap;
358   
 
359  0 toggle @Override
360    public boolean isResolvable()
361    {
362  0 return super.isResolvable() && mp.getTo() != null;
363    };
364   
 
365  0 toggle @Override
366    boolean resolve()
367    {
368  0 SequenceI seq = getSrefDatasetSeq();
369  0 if (seq == null)
370    {
371  0 return false;
372    }
373  0 cf.addMap(seq, mp.getTo(), mp.getMap());
374  0 return true;
375    }
376    };
377  0 return fref;
378    }
379   
 
380  20 toggle public void resolveFrefedSequences()
381    {
382  20 Iterator<SeqFref> nextFref = frefedSequence.iterator();
383  20 int toresolve = frefedSequence.size();
384  20 int unresolved = 0, failedtoresolve = 0;
385  20 while (nextFref.hasNext())
386    {
387  0 SeqFref ref = nextFref.next();
388  0 if (ref.isResolvable())
389    {
390  0 try
391    {
392  0 if (ref.resolve())
393    {
394  0 nextFref.remove();
395    }
396    else
397    {
398  0 failedtoresolve++;
399    }
400    } catch (Exception x)
401    {
402  0 System.err.println(
403    "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
404    + ref.getSref());
405  0 x.printStackTrace();
406  0 failedtoresolve++;
407    }
408    }
409    else
410    {
411  0 unresolved++;
412    }
413    }
414  20 if (unresolved > 0)
415    {
416  0 System.err.println("Jalview Project Import: There were " + unresolved
417    + " forward references left unresolved on the stack.");
418    }
419  20 if (failedtoresolve > 0)
420    {
421  0 System.err.println("SERIOUS! " + failedtoresolve
422    + " resolvable forward references failed to resolve.");
423    }
424  20 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
425    {
426  0 System.err.println(
427    "Jalview Project Import: There are " + incompleteSeqs.size()
428    + " sequences which may have incomplete metadata.");
429  0 if (incompleteSeqs.size() < 10)
430    {
431  0 for (SequenceI s : incompleteSeqs.values())
432    {
433  0 System.err.println(s.toString());
434    }
435    }
436    else
437    {
438  0 System.err.println(
439    "Too many to report. Skipping output of incomplete sequences.");
440    }
441    }
442    }
443   
444    /**
445    * This maintains a map of viewports, the key being the seqSetId. Important to
446    * set historyItem and redoList for multiple views
447    */
448    Map<String, AlignViewport> viewportsAdded = new HashMap<>();
449   
450    Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
451   
452    String uniqueSetSuffix = "";
453   
454    /**
455    * List of pdbfiles added to Jar
456    */
457    List<String> pdbfiles = null;
458   
459    // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
 
460  5 toggle public void saveState(File statefile)
461    {
462  5 FileOutputStream fos = null;
463  5 try
464    {
465  5 fos = new FileOutputStream(statefile);
466  5 JarOutputStream jout = new JarOutputStream(fos);
467  5 saveState(jout);
468   
469    } catch (Exception e)
470    {
471    // TODO: inform user of the problem - they need to know if their data was
472    // not saved !
473  0 if (errorMessage == null)
474    {
475  0 errorMessage = "Couldn't write Jalview Archive to output file '"
476    + statefile + "' - See console error log for details";
477    }
478    else
479    {
480  0 errorMessage += "(output file was '" + statefile + "')";
481    }
482  0 e.printStackTrace();
483    } finally
484    {
485  5 if (fos != null)
486    {
487  5 try
488    {
489  5 fos.close();
490    } catch (IOException e)
491    {
492    // ignore
493    }
494    }
495    }
496  5 reportErrors();
497    }
498   
499    /**
500    * Writes a jalview project archive to the given Jar output stream.
501    *
502    * @param jout
503    */
 
504  5 toggle public void saveState(JarOutputStream jout)
505    {
506  5 AlignFrame[] frames = Desktop.getAlignFrames();
507   
508  5 if (frames == null)
509    {
510  0 return;
511    }
512  5 saveAllFrames(Arrays.asList(frames), jout);
513    }
514   
515    /**
516    * core method for storing state for a set of AlignFrames.
517    *
518    * @param frames
519    * - frames involving all data to be exported (including containing
520    * splitframes)
521    * @param jout
522    * - project output stream
523    */
 
524  10 toggle private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
525    {
526  10 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
527   
528    /*
529    * ensure cached data is clear before starting
530    */
531    // todo tidy up seqRefIds, seqsToIds initialisation / reset
532  10 rnaSessions.clear();
533  10 splitFrameCandidates.clear();
534   
535  10 try
536    {
537   
538    // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
539    // //////////////////////////////////////////////////
540   
541  10 List<String> shortNames = new ArrayList<>();
542  10 List<String> viewIds = new ArrayList<>();
543   
544    // REVERSE ORDER
545  24 for (int i = frames.size() - 1; i > -1; i--)
546    {
547  14 AlignFrame af = frames.get(i);
548    // skip ?
549  14 if (skipList != null && skipList
550    .containsKey(af.getViewport().getSequenceSetId()))
551    {
552  0 continue;
553    }
554   
555  14 String shortName = makeFilename(af, shortNames);
556   
557  14 int ap, apSize = af.alignPanels.size();
558   
559  33 for (ap = 0; ap < apSize; ap++)
560    {
561  19 AlignmentPanel apanel = af.alignPanels.get(ap);
562  19 String fileName = apSize == 1 ? shortName : ap + shortName;
563  19 if (!fileName.endsWith(".xml"))
564    {
565  0 fileName = fileName + ".xml";
566    }
567   
568  19 saveState(apanel, fileName, jout, viewIds);
569   
570  19 String dssid = getDatasetIdRef(
571    af.getViewport().getAlignment().getDataset());
572  19 if (!dsses.containsKey(dssid))
573    {
574  14 dsses.put(dssid, af);
575    }
576    }
577    }
578   
579  10 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
580    jout);
581   
582  10 try
583    {
584  10 jout.flush();
585    } catch (Exception foo)
586    {
587    }
588  10 ;
589  10 jout.close();
590    } catch (Exception ex)
591    {
592    // TODO: inform user of the problem - they need to know if their data was
593    // not saved !
594  0 if (errorMessage == null)
595    {
596  0 errorMessage = "Couldn't write Jalview Archive - see error output for details";
597    }
598  0 ex.printStackTrace();
599    }
600    }
601   
602    /**
603    * Generates a distinct file name, based on the title of the AlignFrame, by
604    * appending _n for increasing n until an unused name is generated. The new
605    * name (without its extension) is added to the list.
606    *
607    * @param af
608    * @param namesUsed
609    * @return the generated name, with .xml extension
610    */
 
611  14 toggle protected String makeFilename(AlignFrame af, List<String> namesUsed)
612    {
613  14 String shortName = af.getTitle();
614   
615  14 if (shortName.indexOf(File.separatorChar) > -1)
616    {
617  7 shortName = shortName
618    .substring(shortName.lastIndexOf(File.separatorChar) + 1);
619    }
620   
621  14 int count = 1;
622   
623  24 while (namesUsed.contains(shortName))
624    {
625  10 if (shortName.endsWith("_" + (count - 1)))
626    {
627  6 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
628    }
629   
630  10 shortName = shortName.concat("_" + count);
631  10 count++;
632    }
633   
634  14 namesUsed.add(shortName);
635   
636  14 if (!shortName.endsWith(".xml"))
637    {
638  14 shortName = shortName + ".xml";
639    }
640  14 return shortName;
641    }
642   
643    // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
 
644  5 toggle public boolean saveAlignment(AlignFrame af, String jarFile,
645    String fileName)
646    {
647  5 try
648    {
649  5 FileOutputStream fos = new FileOutputStream(jarFile);
650  5 JarOutputStream jout = new JarOutputStream(fos);
651  5 List<AlignFrame> frames = new ArrayList<>();
652   
653    // resolve splitframes
654  5 if (af.getViewport().getCodingComplement() != null)
655    {
656  0 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
657    }
658    else
659    {
660  5 frames.add(af);
661    }
662  5 saveAllFrames(frames, jout);
663  5 try
664    {
665  5 jout.flush();
666    } catch (Exception foo)
667    {
668    }
669  5 ;
670  5 jout.close();
671  5 return true;
672    } catch (Exception ex)
673    {
674  0 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
675  0 ex.printStackTrace();
676  0 return false;
677    }
678    }
679   
 
680  10 toggle private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
681    String fileName, JarOutputStream jout)
682    {
683   
684  10 for (String dssids : dsses.keySet())
685    {
686  14 AlignFrame _af = dsses.get(dssids);
687  14 String jfileName = fileName + " Dataset for " + _af.getTitle();
688  14 if (!jfileName.endsWith(".xml"))
689    {
690  14 jfileName = jfileName + ".xml";
691    }
692  14 saveState(_af.alignPanel, jfileName, true, jout, null);
693    }
694    }
695   
696    /**
697    * create a JalviewModel from an alignment view and marshall it to a
698    * JarOutputStream
699    *
700    * @param ap
701    * panel to create jalview model for
702    * @param fileName
703    * name of alignment panel written to output stream
704    * @param jout
705    * jar output stream
706    * @param viewIds
707    * @param out
708    * jar entry name
709    */
 
710  22 toggle public JalviewModel saveState(AlignmentPanel ap, String fileName,
711    JarOutputStream jout, List<String> viewIds)
712    {
713  22 return saveState(ap, fileName, false, jout, viewIds);
714    }
715   
716    /**
717    * create a JalviewModel from an alignment view and marshall it to a
718    * JarOutputStream
719    *
720    * @param ap
721    * panel to create jalview model for
722    * @param fileName
723    * name of alignment panel written to output stream
724    * @param storeDS
725    * when true, only write the dataset for the alignment, not the data
726    * associated with the view.
727    * @param jout
728    * jar output stream
729    * @param out
730    * jar entry name
731    */
 
732  36 toggle public JalviewModel saveState(AlignmentPanel ap, String fileName,
733    boolean storeDS, JarOutputStream jout, List<String> viewIds)
734    {
735  36 if (viewIds == null)
736    {
737  17 viewIds = new ArrayList<>();
738    }
739   
740  36 initSeqRefs();
741   
742  36 List<UserColourScheme> userColours = new ArrayList<>();
743   
744  36 AlignViewport av = ap.av;
745  36 ViewportRanges vpRanges = av.getRanges();
746   
747  36 JalviewModel object = new JalviewModel();
748  36 object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
749   
750  36 object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
751  36 object.setVersion(
752    jalview.bin.Cache.getDefault("VERSION", "Development Build"));
753   
754    /**
755    * rjal is full height alignment, jal is actual alignment with full metadata
756    * but excludes hidden sequences.
757    */
758  36 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
759   
760  36 if (av.hasHiddenRows())
761    {
762  19 rjal = jal.getHiddenSequences().getFullAlignment();
763    }
764   
765  36 SequenceSet vamsasSet = new SequenceSet();
766  36 Sequence vamsasSeq;
767  36 JalviewModelSequence jms = new JalviewModelSequence();
768   
769  36 vamsasSet.setGapChar(jal.getGapCharacter() + "");
770   
771  36 if (jal.getDataset() != null)
772    {
773    // dataset id is the dataset's hashcode
774  36 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
775  36 if (storeDS)
776    {
777    // switch jal and the dataset
778  14 jal = jal.getDataset();
779  14 rjal = jal;
780    }
781    }
782  36 if (jal.getProperties() != null)
783    {
784  1 Enumeration en = jal.getProperties().keys();
785  22 while (en.hasMoreElements())
786    {
787  21 String key = en.nextElement().toString();
788  21 SequenceSetProperties ssp = new SequenceSetProperties();
789  21 ssp.setKey(key);
790  21 ssp.setValue(jal.getProperties().get(key).toString());
791  21 vamsasSet.addSequenceSetProperties(ssp);
792    }
793    }
794   
795  36 JSeq jseq;
796  36 Set<String> calcIdSet = new HashSet<>();
797    // record the set of vamsas sequence XML POJO we create.
798  36 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
799    // SAVE SEQUENCES
800  36 for (final SequenceI jds : rjal.getSequences())
801    {
802  560 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
803    : jds.getDatasetSequence();
804  560 String id = seqHash(jds);
805  560 if (vamsasSetIds.get(id) == null)
806    {
807  560 if (seqRefIds.get(id) != null && !storeDS)
808    {
809    // This happens for two reasons: 1. multiple views are being
810    // serialised.
811    // 2. the hashCode has collided with another sequence's code. This
812    // DOES
813    // HAPPEN! (PF00072.15.stk does this)
814    // JBPNote: Uncomment to debug writing out of files that do not read
815    // back in due to ArrayOutOfBoundExceptions.
816    // System.err.println("vamsasSeq backref: "+id+"");
817    // System.err.println(jds.getName()+"
818    // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
819    // System.err.println("Hashcode: "+seqHash(jds));
820    // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
821    // System.err.println(rsq.getName()+"
822    // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
823    // System.err.println("Hashcode: "+seqHash(rsq));
824    }
825    else
826    {
827  417 vamsasSeq = createVamsasSequence(id, jds);
828  417 vamsasSet.addSequence(vamsasSeq);
829  417 vamsasSetIds.put(id, vamsasSeq);
830  417 seqRefIds.put(id, jds);
831    }
832    }
833  560 jseq = new JSeq();
834  560 jseq.setStart(jds.getStart());
835  560 jseq.setEnd(jds.getEnd());
836  560 jseq.setColour(av.getSequenceColour(jds).getRGB());
837   
838  560 jseq.setId(id); // jseq id should be a string not a number
839  560 if (!storeDS)
840    {
841    // Store any sequences this sequence represents
842  335 if (av.hasHiddenRows())
843    {
844    // use rjal, contains the full height alignment
845  190 jseq.setHidden(
846    av.getAlignment().getHiddenSequences().isHidden(jds));
847   
848  190 if (av.isHiddenRepSequence(jds))
849    {
850  2 jalview.datamodel.SequenceI[] reps = av
851    .getRepresentedSequences(jds).getSequencesInOrder(rjal);
852   
853  6 for (int h = 0; h < reps.length; h++)
854    {
855  4 if (reps[h] != jds)
856    {
857  2 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
858    }
859    }
860    }
861    }
862    // mark sequence as reference - if it is the reference for this view
863  335 if (jal.hasSeqrep())
864    {
865  80 jseq.setViewreference(jds == jal.getSeqrep());
866    }
867    }
868   
869    // TODO: omit sequence features from each alignment view's XML dump if we
870    // are storing dataset
871  560 List<jalview.datamodel.SequenceFeature> sfs = jds
872    .getSequenceFeatures();
873  560 for (SequenceFeature sf : sfs)
874    {
875  10860 Features features = new Features();
876   
877  10860 features.setBegin(sf.getBegin());
878  10860 features.setEnd(sf.getEnd());
879  10860 features.setDescription(sf.getDescription());
880  10860 features.setType(sf.getType());
881  10860 features.setFeatureGroup(sf.getFeatureGroup());
882  10860 features.setScore(sf.getScore());
883  10860 if (sf.links != null)
884    {
885  5344 for (int l = 0; l < sf.links.size(); l++)
886    {
887  2672 OtherData keyValue = new OtherData();
888  2672 keyValue.setKey("LINK_" + l);
889  2672 keyValue.setValue(sf.links.elementAt(l).toString());
890  2672 features.addOtherData(keyValue);
891    }
892    }
893  10860 if (sf.otherDetails != null)
894    {
895    /*
896    * save feature attributes, which may be simple strings or
897    * map valued (have sub-attributes)
898    */
899  3108 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
900    {
901  3128 String key = entry.getKey();
902  3128 Object value = entry.getValue();
903  3128 if (value instanceof Map<?, ?>)
904    {
905  20 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
906    .entrySet())
907    {
908  20 OtherData otherData = new OtherData();
909  20 otherData.setKey(key);
910  20 otherData.setKey2(subAttribute.getKey());
911  20 otherData.setValue(subAttribute.getValue().toString());
912  20 features.addOtherData(otherData);
913    }
914    }
915    else
916    {
917  3108 OtherData otherData = new OtherData();
918  3108 otherData.setKey(key);
919  3108 otherData.setValue(value.toString());
920  3108 features.addOtherData(otherData);
921    }
922    }
923    }
924   
925  10860 jseq.addFeatures(features);
926    }
927   
928  560 if (jdatasq.getAllPDBEntries() != null)
929    {
930  560 Enumeration en = jdatasq.getAllPDBEntries().elements();
931  622 while (en.hasMoreElements())
932    {
933  62 Pdbids pdb = new Pdbids();
934  62 jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
935    .nextElement();
936   
937  62 String pdbId = entry.getId();
938  62 pdb.setId(pdbId);
939  62 pdb.setType(entry.getType());
940   
941    /*
942    * Store any structure views associated with this sequence. This
943    * section copes with duplicate entries in the project, so a dataset
944    * only view *should* be coped with sensibly.
945    */
946    // This must have been loaded, is it still visible?
947  62 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
948  62 String matchedFile = null;
949  346 for (int f = frames.length - 1; f > -1; f--)
950    {
951  284 if (frames[f] instanceof StructureViewerBase)
952    {
953  48 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
954  48 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
955    matchedFile, viewFrame);
956    /*
957    * Only store each structure viewer's state once in the project
958    * jar. First time through only (storeDS==false)
959    */
960  48 String viewId = viewFrame.getViewId();
961  48 if (!storeDS && !viewIds.contains(viewId))
962    {
963  2 viewIds.add(viewId);
964  2 try
965    {
966  2 String viewerState = viewFrame.getStateInfo();
967  2 writeJarEntry(jout, getViewerJarEntryName(viewId),
968    viewerState.getBytes());
969    } catch (IOException e)
970    {
971  0 System.err.println(
972    "Error saving viewer state: " + e.getMessage());
973    }
974    }
975    }
976    }
977   
978  62 if (matchedFile != null || entry.getFile() != null)
979    {
980  46 if (entry.getFile() != null)
981    {
982    // use entry's file
983  46 matchedFile = entry.getFile();
984    }
985  46 pdb.setFile(matchedFile); // entry.getFile());
986  46 if (pdbfiles == null)
987    {
988  4 pdbfiles = new ArrayList<>();
989    }
990   
991  46 if (!pdbfiles.contains(pdbId))
992    {
993  4 pdbfiles.add(pdbId);
994  4 copyFileToJar(jout, matchedFile, pdbId);
995    }
996    }
997   
998  62 Enumeration<String> props = entry.getProperties();
999  62 if (props.hasMoreElements())
1000    {
1001  46 PdbentryItem item = new PdbentryItem();
1002  92 while (props.hasMoreElements())
1003    {
1004  46 Property prop = new Property();
1005  46 String key = props.nextElement();
1006  46 prop.setName(key);
1007  46 prop.setValue(entry.getProperty(key).toString());
1008  46 item.addProperty(prop);
1009    }
1010  46 pdb.addPdbentryItem(item);
1011    }
1012   
1013  62 jseq.addPdbids(pdb);
1014    }
1015    }
1016   
1017  560 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1018   
1019  560 jms.addJSeq(jseq);
1020    }
1021   
1022  36 if (!storeDS && av.hasHiddenRows())
1023    {
1024  12 jal = av.getAlignment();
1025    }
1026    // SAVE MAPPINGS
1027    // FOR DATASET
1028  36 if (storeDS && jal.getCodonFrames() != null)
1029    {
1030  14 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1031  14 for (AlignedCodonFrame acf : jac)
1032    {
1033  0 AlcodonFrame alc = new AlcodonFrame();
1034  0 if (acf.getProtMappings() != null
1035    && acf.getProtMappings().length > 0)
1036    {
1037  0 boolean hasMap = false;
1038  0 SequenceI[] dnas = acf.getdnaSeqs();
1039  0 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1040  0 for (int m = 0; m < pmaps.length; m++)
1041    {
1042  0 AlcodMap alcmap = new AlcodMap();
1043  0 alcmap.setDnasq(seqHash(dnas[m]));
1044  0 alcmap.setMapping(
1045    createVamsasMapping(pmaps[m], dnas[m], null, false));
1046  0 alc.addAlcodMap(alcmap);
1047  0 hasMap = true;
1048    }
1049  0 if (hasMap)
1050    {
1051  0 vamsasSet.addAlcodonFrame(alc);
1052    }
1053    }
1054    // TODO: delete this ? dead code from 2.8.3->2.9 ?
1055    // {
1056    // AlcodonFrame alc = new AlcodonFrame();
1057    // vamsasSet.addAlcodonFrame(alc);
1058    // for (int p = 0; p < acf.aaWidth; p++)
1059    // {
1060    // Alcodon cmap = new Alcodon();
1061    // if (acf.codons[p] != null)
1062    // {
1063    // // Null codons indicate a gapped column in the translated peptide
1064    // // alignment.
1065    // cmap.setPos1(acf.codons[p][0]);
1066    // cmap.setPos2(acf.codons[p][1]);
1067    // cmap.setPos3(acf.codons[p][2]);
1068    // }
1069    // alc.addAlcodon(cmap);
1070    // }
1071    // if (acf.getProtMappings() != null
1072    // && acf.getProtMappings().length > 0)
1073    // {
1074    // SequenceI[] dnas = acf.getdnaSeqs();
1075    // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1076    // for (int m = 0; m < pmaps.length; m++)
1077    // {
1078    // AlcodMap alcmap = new AlcodMap();
1079    // alcmap.setDnasq(seqHash(dnas[m]));
1080    // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1081    // false));
1082    // alc.addAlcodMap(alcmap);
1083    // }
1084    // }
1085    }
1086    }
1087   
1088    // SAVE TREES
1089    // /////////////////////////////////
1090  36 if (!storeDS && av.getCurrentTree() != null)
1091    {
1092    // FIND ANY ASSOCIATED TREES
1093    // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1094  2 if (Desktop.desktop != null)
1095    {
1096  2 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1097   
1098  12 for (int t = 0; t < frames.length; t++)
1099    {
1100  10 if (frames[t] instanceof TreePanel)
1101    {
1102  2 TreePanel tp = (TreePanel) frames[t];
1103   
1104  2 if (tp.treeCanvas.av.getAlignment() == jal)
1105    {
1106  2 Tree tree = new Tree();
1107  2 tree.setTitle(tp.getTitle());
1108  2 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1109  2 tree.setNewick(tp.getTree().print());
1110  2 tree.setThreshold(tp.treeCanvas.threshold);
1111   
1112  2 tree.setFitToWindow(tp.fitToWindow.getState());
1113  2 tree.setFontName(tp.getTreeFont().getName());
1114  2 tree.setFontSize(tp.getTreeFont().getSize());
1115  2 tree.setFontStyle(tp.getTreeFont().getStyle());
1116  2 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1117   
1118  2 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1119  2 tree.setShowDistances(tp.distanceMenu.getState());
1120   
1121  2 tree.setHeight(tp.getHeight());
1122  2 tree.setWidth(tp.getWidth());
1123  2 tree.setXpos(tp.getX());
1124  2 tree.setYpos(tp.getY());
1125  2 tree.setId(makeHashCode(tp, null));
1126  2 jms.addTree(tree);
1127    }
1128    }
1129    }
1130    }
1131    }
1132   
1133    // SAVE ANNOTATIONS
1134    /**
1135    * store forward refs from an annotationRow to any groups
1136    */
1137  36 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1138  36 if (storeDS)
1139    {
1140  14 for (SequenceI sq : jal.getSequences())
1141    {
1142    // Store annotation on dataset sequences only
1143  225 AlignmentAnnotation[] aa = sq.getAnnotation();
1144  225 if (aa != null && aa.length > 0)
1145    {
1146  80 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1147    vamsasSet);
1148    }
1149    }
1150    }
1151    else
1152    {
1153  22 if (jal.getAlignmentAnnotation() != null)
1154    {
1155    // Store the annotation shown on the alignment.
1156  22 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1157  22 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1158    vamsasSet);
1159    }
1160    }
1161    // SAVE GROUPS
1162  36 if (jal.getGroups() != null)
1163    {
1164  36 JGroup[] groups = new JGroup[jal.getGroups().size()];
1165  36 int i = -1;
1166  36 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1167    {
1168  13 JGroup jGroup = new JGroup();
1169  13 groups[++i] = jGroup;
1170   
1171  13 jGroup.setStart(sg.getStartRes());
1172  13 jGroup.setEnd(sg.getEndRes());
1173  13 jGroup.setName(sg.getName());
1174  13 if (groupRefs.containsKey(sg))
1175    {
1176    // group has references so set its ID field
1177  6 jGroup.setId(groupRefs.get(sg));
1178    }
1179  13 ColourSchemeI colourScheme = sg.getColourScheme();
1180  13 if (colourScheme != null)
1181    {
1182  7 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1183  7 if (groupColourScheme.conservationApplied())
1184    {
1185  2 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1186   
1187  2 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1188    {
1189  0 jGroup.setColour(
1190    setUserColourScheme(colourScheme, userColours, jms));
1191    }
1192    else
1193    {
1194  2 jGroup.setColour(colourScheme.getSchemeName());
1195    }
1196    }
1197  5 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1198    {
1199  1 jGroup.setColour("AnnotationColourGradient");
1200  1 jGroup.setAnnotationColours(constructAnnotationColours(
1201    (jalview.schemes.AnnotationColourGradient) colourScheme,
1202    userColours, jms));
1203    }
1204  4 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1205    {
1206  0 jGroup.setColour(
1207    setUserColourScheme(colourScheme, userColours, jms));
1208    }
1209    else
1210    {
1211  4 jGroup.setColour(colourScheme.getSchemeName());
1212    }
1213   
1214  7 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1215    }
1216   
1217  13 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1218  13 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1219  13 jGroup.setDisplayText(sg.getDisplayText());
1220  13 jGroup.setColourText(sg.getColourText());
1221  13 jGroup.setTextCol1(sg.textColour.getRGB());
1222  13 jGroup.setTextCol2(sg.textColour2.getRGB());
1223  13 jGroup.setTextColThreshold(sg.thresholdTextColour);
1224  13 jGroup.setShowUnconserved(sg.getShowNonconserved());
1225  13 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1226  13 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1227  13 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1228  13 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1229  13 for (SequenceI seq : sg.getSequences())
1230    {
1231  84 jGroup.addSeq(seqHash(seq));
1232    }
1233    }
1234   
1235  36 jms.setJGroup(groups);
1236    }
1237  36 if (!storeDS)
1238    {
1239    // /////////SAVE VIEWPORT
1240  22 Viewport view = new Viewport();
1241  22 view.setTitle(ap.alignFrame.getTitle());
1242  22 view.setSequenceSetId(
1243    makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1244  22 view.setId(av.getViewId());
1245  22 if (av.getCodingComplement() != null)
1246    {
1247  0 view.setComplementId(av.getCodingComplement().getViewId());
1248    }
1249  22 view.setViewName(av.viewName);
1250  22 view.setGatheredViews(av.isGatherViewsHere());
1251   
1252  22 Rectangle size = ap.av.getExplodedGeometry();
1253  22 Rectangle position = size;
1254  22 if (size == null)
1255    {
1256  12 size = ap.alignFrame.getBounds();
1257  12 if (av.getCodingComplement() != null)
1258    {
1259  0 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1260    .getBounds();
1261    }
1262    else
1263    {
1264  12 position = size;
1265    }
1266    }
1267  22 view.setXpos(position.x);
1268  22 view.setYpos(position.y);
1269   
1270  22 view.setWidth(size.width);
1271  22 view.setHeight(size.height);
1272   
1273  22 view.setStartRes(vpRanges.getStartRes());
1274  22 view.setStartSeq(vpRanges.getStartSeq());
1275   
1276  22 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1277    {
1278  0 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1279    userColours, jms));
1280    }
1281  22 else if (av
1282    .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1283    {
1284  1 AnnotationColours ac = constructAnnotationColours(
1285    (jalview.schemes.AnnotationColourGradient) av
1286    .getGlobalColourScheme(),
1287    userColours, jms);
1288   
1289  1 view.setAnnotationColours(ac);
1290  1 view.setBgColour("AnnotationColourGradient");
1291    }
1292    else
1293    {
1294  21 view.setBgColour(ColourSchemeProperty
1295    .getColourName(av.getGlobalColourScheme()));
1296    }
1297   
1298  22 ResidueShaderI vcs = av.getResidueShading();
1299  22 ColourSchemeI cs = av.getGlobalColourScheme();
1300   
1301  22 if (cs != null)
1302    {
1303  5 if (vcs.conservationApplied())
1304    {
1305  2 view.setConsThreshold(vcs.getConservationInc());
1306  2 if (cs instanceof jalview.schemes.UserColourScheme)
1307    {
1308  0 view.setBgColour(setUserColourScheme(cs, userColours, jms));
1309    }
1310    }
1311  5 view.setPidThreshold(vcs.getThreshold());
1312    }
1313   
1314  22 view.setConservationSelected(av.getConservationSelected());
1315  22 view.setPidSelected(av.getAbovePIDThreshold());
1316  22 view.setFontName(av.font.getName());
1317  22 view.setFontSize(av.font.getSize());
1318  22 view.setFontStyle(av.font.getStyle());
1319  22 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1320  22 view.setRenderGaps(av.isRenderGaps());
1321  22 view.setShowAnnotation(av.isShowAnnotation());
1322  22 view.setShowBoxes(av.getShowBoxes());
1323  22 view.setShowColourText(av.getColourText());
1324  22 view.setShowFullId(av.getShowJVSuffix());
1325  22 view.setRightAlignIds(av.isRightAlignIds());
1326  22 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1327  22 view.setShowText(av.getShowText());
1328  22 view.setShowUnconserved(av.getShowUnconserved());
1329  22 view.setWrapAlignment(av.getWrapAlignment());
1330  22 view.setTextCol1(av.getTextColour().getRGB());
1331  22 view.setTextCol2(av.getTextColour2().getRGB());
1332  22 view.setTextColThreshold(av.getThresholdTextColour());
1333  22 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1334  22 view.setShowSequenceLogo(av.isShowSequenceLogo());
1335  22 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1336  22 view.setShowGroupConsensus(av.isShowGroupConsensus());
1337  22 view.setShowGroupConservation(av.isShowGroupConservation());
1338  22 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1339  22 view.setShowDbRefTooltip(av.isShowDBRefs());
1340  22 view.setFollowHighlight(av.isFollowHighlight());
1341  22 view.setFollowSelection(av.followSelection);
1342  22 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1343  22 if (av.getFeaturesDisplayed() != null)
1344    {
1345  11 jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
1346   
1347  11 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1348    .getFeatureRenderer();
1349  11 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1350   
1351  11 Vector<String> settingsAdded = new Vector<>();
1352  11 if (renderOrder != null)
1353    {
1354  11 for (String featureType : renderOrder)
1355    {
1356  213 Setting setting = new Setting();
1357  213 setting.setType(featureType);
1358   
1359    /*
1360    * save any filter for the feature type
1361    */
1362  213 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1363  213 if (filter != null) {
1364  3 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1365  3 FeatureMatcherI firstFilter = filters.next();
1366  3 setting.setMatcherSet(Jalview2XML.marshalFilter(
1367    firstFilter, filters, filter.isAnded()));
1368    }
1369   
1370    /*
1371    * save colour scheme for the feature type
1372    */
1373  213 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1374  213 if (!fcol.isSimpleColour())
1375    {
1376  4 setting.setColour(fcol.getMaxColour().getRGB());
1377  4 setting.setMincolour(fcol.getMinColour().getRGB());
1378  4 setting.setMin(fcol.getMin());
1379  4 setting.setMax(fcol.getMax());
1380  4 setting.setColourByLabel(fcol.isColourByLabel());
1381  4 if (fcol.isColourByAttribute())
1382    {
1383  2 setting.setAttributeName(fcol.getAttributeName());
1384    }
1385  4 setting.setAutoScale(fcol.isAutoScaled());
1386  4 setting.setThreshold(fcol.getThreshold());
1387  4 Color noColour = fcol.getNoColour();
1388  4 if (noColour == null)
1389    {
1390  2 setting.setNoValueColour(NoValueColour.NONE);
1391    }
1392  2 else if (noColour.equals(fcol.getMaxColour()))
1393    {
1394  0 setting.setNoValueColour(NoValueColour.MAX);
1395    }
1396    else
1397    {
1398  2 setting.setNoValueColour(NoValueColour.MIN);
1399    }
1400    // -1 = No threshold, 0 = Below, 1 = Above
1401  4 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1402  3 : (fcol.isBelowThreshold() ? 0 : -1));
1403    }
1404    else
1405    {
1406  209 setting.setColour(fcol.getColour().getRGB());
1407    }
1408   
1409  213 setting.setDisplay(
1410    av.getFeaturesDisplayed().isVisible(featureType));
1411  213 float rorder = fr
1412    .getOrder(featureType);
1413  213 if (rorder > -1)
1414    {
1415  213 setting.setOrder(rorder);
1416    }
1417  213 fs.addSetting(setting);
1418  213 settingsAdded.addElement(featureType);
1419    }
1420    }
1421   
1422    // is groups actually supposed to be a map here ?
1423  11 Iterator<String> en = fr.getFeatureGroups().iterator();
1424  11 Vector<String> groupsAdded = new Vector<>();
1425  44 while (en.hasNext())
1426    {
1427  33 String grp = en.next();
1428  33 if (groupsAdded.contains(grp))
1429    {
1430  0 continue;
1431    }
1432  33 Group g = new Group();
1433  33 g.setName(grp);
1434  33 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1435    .booleanValue());
1436  33 fs.addGroup(g);
1437  33 groupsAdded.addElement(grp);
1438    }
1439  11 jms.setFeatureSettings(fs);
1440    }
1441   
1442  22 if (av.hasHiddenColumns())
1443    {
1444  4 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1445    .getHiddenColumns();
1446  4 if (hidden == null)
1447    {
1448  0 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1449    }
1450    else
1451    {
1452  4 Iterator<int[]> hiddenRegions = hidden.iterator();
1453  10 while (hiddenRegions.hasNext())
1454    {
1455  6 int[] region = hiddenRegions.next();
1456  6 HiddenColumns hc = new HiddenColumns();
1457  6 hc.setStart(region[0]);
1458  6 hc.setEnd(region[1]);
1459  6 view.addHiddenColumns(hc);
1460    }
1461    }
1462    }
1463  22 if (calcIdSet.size() > 0)
1464    {
1465  22 for (String calcId : calcIdSet)
1466    {
1467  25 if (calcId.trim().length() > 0)
1468    {
1469  3 CalcIdParam cidp = createCalcIdParam(calcId, av);
1470    // Some calcIds have no parameters.
1471  3 if (cidp != null)
1472    {
1473  0 view.addCalcIdParam(cidp);
1474    }
1475    }
1476    }
1477    }
1478   
1479  22 jms.addViewport(view);
1480    }
1481  36 object.setJalviewModelSequence(jms);
1482  36 object.getVamsasModel().addSequenceSet(vamsasSet);
1483   
1484  36 if (jout != null && fileName != null)
1485    {
1486    // We may not want to write the object to disk,
1487    // eg we can copy the alignViewport to a new view object
1488    // using save and then load
1489  33 try
1490    {
1491  33 System.out.println("Writing jar entry " + fileName);
1492  33 JarEntry entry = new JarEntry(fileName);
1493  33 jout.putNextEntry(entry);
1494  29 PrintWriter pout = new PrintWriter(
1495    new OutputStreamWriter(jout, UTF_8));
1496  29 Marshaller marshaller = new Marshaller(pout);
1497  29 marshaller.marshal(object);
1498  29 pout.flush();
1499  29 jout.closeEntry();
1500    } catch (Exception ex)
1501    {
1502    // TODO: raise error in GUI if marshalling failed.
1503  4 ex.printStackTrace();
1504    }
1505    }
1506  36 return object;
1507    }
1508   
1509    /**
1510    * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1511    * for each viewer, with
1512    * <ul>
1513    * <li>viewer geometry (position, size, split pane divider location)</li>
1514    * <li>index of the selected structure in the viewer (currently shows gapped
1515    * or ungapped)</li>
1516    * <li>the id of the annotation holding RNA secondary structure</li>
1517    * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1518    * </ul>
1519    * Varna viewer state is also written out (in native Varna XML) to separate
1520    * project jar entries. A separate entry is written for each RNA structure
1521    * displayed, with the naming convention
1522    * <ul>
1523    * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1524    * </ul>
1525    *
1526    * @param jout
1527    * @param jseq
1528    * @param jds
1529    * @param viewIds
1530    * @param ap
1531    * @param storeDataset
1532    */
 
1533  560 toggle protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1534    final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1535    boolean storeDataset)
1536    {
1537  560 if (Desktop.desktop == null)
1538    {
1539  0 return;
1540    }
1541  560 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1542  3865 for (int f = frames.length - 1; f > -1; f--)
1543    {
1544  3305 if (frames[f] instanceof AppVarna)
1545    {
1546  0 AppVarna varna = (AppVarna) frames[f];
1547    /*
1548    * link the sequence to every viewer that is showing it and is linked to
1549    * its alignment panel
1550    */
1551  0 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1552    {
1553  0 String viewId = varna.getViewId();
1554  0 RnaViewer rna = new RnaViewer();
1555  0 rna.setViewId(viewId);
1556  0 rna.setTitle(varna.getTitle());
1557  0 rna.setXpos(varna.getX());
1558  0 rna.setYpos(varna.getY());
1559  0 rna.setWidth(varna.getWidth());
1560  0 rna.setHeight(varna.getHeight());
1561  0 rna.setDividerLocation(varna.getDividerLocation());
1562  0 rna.setSelectedRna(varna.getSelectedIndex());
1563  0 jseq.addRnaViewer(rna);
1564   
1565    /*
1566    * Store each Varna panel's state once in the project per sequence.
1567    * First time through only (storeDataset==false)
1568    */
1569    // boolean storeSessions = false;
1570    // String sequenceViewId = viewId + seqsToIds.get(jds);
1571    // if (!storeDataset && !viewIds.contains(sequenceViewId))
1572    // {
1573    // viewIds.add(sequenceViewId);
1574    // storeSessions = true;
1575    // }
1576  0 for (RnaModel model : varna.getModels())
1577    {
1578  0 if (model.seq == jds)
1579    {
1580    /*
1581    * VARNA saves each view (sequence or alignment secondary
1582    * structure, gapped or trimmed) as a separate XML file
1583    */
1584  0 String jarEntryName = rnaSessions.get(model);
1585  0 if (jarEntryName == null)
1586    {
1587   
1588  0 String varnaStateFile = varna.getStateInfo(model.rna);
1589  0 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1590  0 copyFileToJar(jout, varnaStateFile, jarEntryName);
1591  0 rnaSessions.put(model, jarEntryName);
1592    }
1593  0 SecondaryStructure ss = new SecondaryStructure();
1594  0 String annotationId = varna.getAnnotation(jds).annotationId;
1595  0 ss.setAnnotationId(annotationId);
1596  0 ss.setViewerState(jarEntryName);
1597  0 ss.setGapped(model.gapped);
1598  0 ss.setTitle(model.title);
1599  0 rna.addSecondaryStructure(ss);
1600    }
1601    }
1602    }
1603    }
1604    }
1605    }
1606   
1607    /**
1608    * Copy the contents of a file to a new entry added to the output jar
1609    *
1610    * @param jout
1611    * @param infilePath
1612    * @param jarEntryName
1613    */
 
1614  4 toggle protected void copyFileToJar(JarOutputStream jout, String infilePath,
1615    String jarEntryName)
1616    {
1617  4 DataInputStream dis = null;
1618  4 try
1619    {
1620  4 File file = new File(infilePath);
1621  4 if (file.exists() && jout != null)
1622    {
1623  4 dis = new DataInputStream(new FileInputStream(file));
1624  4 byte[] data = new byte[(int) file.length()];
1625  4 dis.readFully(data);
1626  4 writeJarEntry(jout, jarEntryName, data);
1627    }
1628    } catch (Exception ex)
1629    {
1630  0 ex.printStackTrace();
1631    } finally
1632    {
1633  4 if (dis != null)
1634    {
1635  4 try
1636    {
1637  4 dis.close();
1638    } catch (IOException e)
1639    {
1640    // ignore
1641    }
1642    }
1643    }
1644    }
1645   
1646    /**
1647    * Write the data to a new entry of given name in the output jar file
1648    *
1649    * @param jout
1650    * @param jarEntryName
1651    * @param data
1652    * @throws IOException
1653    */
 
1654  6 toggle protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
1655    byte[] data) throws IOException
1656    {
1657  6 if (jout != null)
1658    {
1659  6 System.out.println("Writing jar entry " + jarEntryName);
1660  6 jout.putNextEntry(new JarEntry(jarEntryName));
1661  6 DataOutputStream dout = new DataOutputStream(jout);
1662  6 dout.write(data, 0, data.length);
1663  6 dout.flush();
1664  6 jout.closeEntry();
1665    }
1666    }
1667   
1668    /**
1669    * Save the state of a structure viewer
1670    *
1671    * @param ap
1672    * @param jds
1673    * @param pdb
1674    * the archive XML element under which to save the state
1675    * @param entry
1676    * @param viewIds
1677    * @param matchedFile
1678    * @param viewFrame
1679    * @return
1680    */
 
1681  48 toggle protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
1682    Pdbids pdb, PDBEntry entry, List<String> viewIds,
1683    String matchedFile, StructureViewerBase viewFrame)
1684    {
1685  48 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
1686   
1687    /*
1688    * Look for any bindings for this viewer to the PDB file of interest
1689    * (including part matches excluding chain id)
1690    */
1691  96 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
1692    {
1693  48 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
1694  48 final String pdbId = pdbentry.getId();
1695  48 if (!pdbId.equals(entry.getId())
1696    && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
1697    .startsWith(pdbId.toLowerCase())))
1698    {
1699    /*
1700    * not interested in a binding to a different PDB entry here
1701    */
1702  16 continue;
1703    }
1704  32 if (matchedFile == null)
1705    {
1706  32 matchedFile = pdbentry.getFile();
1707    }
1708  0 else if (!matchedFile.equals(pdbentry.getFile()))
1709    {
1710  0 Cache.log.warn(
1711    "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
1712    + pdbentry.getFile());
1713    }
1714    // record the
1715    // file so we
1716    // can get at it if the ID
1717    // match is ambiguous (e.g.
1718    // 1QIP==1qipA)
1719   
1720  96 for (int smap = 0; smap < viewFrame.getBinding()
1721    .getSequence()[peid].length; smap++)
1722    {
1723    // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
1724  64 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
1725    {
1726  20 StructureState state = new StructureState();
1727  20 state.setVisible(true);
1728  20 state.setXpos(viewFrame.getX());
1729  20 state.setYpos(viewFrame.getY());
1730  20 state.setWidth(viewFrame.getWidth());
1731  20 state.setHeight(viewFrame.getHeight());
1732  20 final String viewId = viewFrame.getViewId();
1733  20 state.setViewId(viewId);
1734  20 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
1735  20 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
1736  20 state.setColourByJmol(viewFrame.isColouredByViewer());
1737  20 state.setType(viewFrame.getViewerType().toString());
1738  20 pdb.addStructureState(state);
1739    }
1740    }
1741    }
1742  48 return matchedFile;
1743    }
1744   
1745    /**
1746    * Populates the AnnotationColours xml for save. This captures the settings of
1747    * the options in the 'Colour by Annotation' dialog.
1748    *
1749    * @param acg
1750    * @param userColours
1751    * @param jms
1752    * @return
1753    */
 
1754  2 toggle private AnnotationColours constructAnnotationColours(
1755    AnnotationColourGradient acg, List<UserColourScheme> userColours,
1756    JalviewModelSequence jms)
1757    {
1758  2 AnnotationColours ac = new AnnotationColours();
1759  2 ac.setAboveThreshold(acg.getAboveThreshold());
1760  2 ac.setThreshold(acg.getAnnotationThreshold());
1761    // 2.10.2 save annotationId (unique) not annotation label
1762  2 ac.setAnnotation(acg.getAnnotation().annotationId);
1763  2 if (acg.getBaseColour() instanceof UserColourScheme)
1764    {
1765  0 ac.setColourScheme(
1766    setUserColourScheme(acg.getBaseColour(), userColours, jms));
1767    }
1768    else
1769    {
1770  2 ac.setColourScheme(
1771    ColourSchemeProperty.getColourName(acg.getBaseColour()));
1772    }
1773   
1774  2 ac.setMaxColour(acg.getMaxColour().getRGB());
1775  2 ac.setMinColour(acg.getMinColour().getRGB());
1776  2 ac.setPerSequence(acg.isSeqAssociated());
1777  2 ac.setPredefinedColours(acg.isPredefinedColours());
1778  2 return ac;
1779    }
1780   
 
1781  102 toggle private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
1782    IdentityHashMap<SequenceGroup, String> groupRefs,
1783    AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
1784    SequenceSet vamsasSet)
1785    {
1786   
1787  433 for (int i = 0; i < aa.length; i++)
1788    {
1789  331 Annotation an = new Annotation();
1790   
1791  331 AlignmentAnnotation annotation = aa[i];
1792  331 if (annotation.annotationId != null)
1793    {
1794  331 annotationIds.put(annotation.annotationId, annotation);
1795    }
1796   
1797  331 an.setId(annotation.annotationId);
1798   
1799  331 an.setVisible(annotation.visible);
1800   
1801  331 an.setDescription(annotation.description);
1802   
1803  331 if (annotation.sequenceRef != null)
1804    {
1805    // 2.9 JAL-1781 xref on sequence id rather than name
1806  219 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
1807    }
1808  331 if (annotation.groupRef != null)
1809    {
1810  6 String groupIdr = groupRefs.get(annotation.groupRef);
1811  6 if (groupIdr == null)
1812    {
1813    // make a locally unique String
1814  6 groupRefs.put(annotation.groupRef,
1815    groupIdr = ("" + System.currentTimeMillis()
1816    + annotation.groupRef.getName()
1817    + groupRefs.size()));
1818    }
1819  6 an.setGroupRef(groupIdr.toString());
1820    }
1821   
1822    // store all visualization attributes for annotation
1823  331 an.setGraphHeight(annotation.graphHeight);
1824  331 an.setCentreColLabels(annotation.centreColLabels);
1825  331 an.setScaleColLabels(annotation.scaleColLabel);
1826  331 an.setShowAllColLabels(annotation.showAllColLabels);
1827  331 an.setBelowAlignment(annotation.belowAlignment);
1828   
1829  331 if (annotation.graph > 0)
1830    {
1831  172 an.setGraph(true);
1832  172 an.setGraphType(annotation.graph);
1833  172 an.setGraphGroup(annotation.graphGroup);
1834  172 if (annotation.getThreshold() != null)
1835    {
1836  30 ThresholdLine line = new ThresholdLine();
1837  30 line.setLabel(annotation.getThreshold().label);
1838  30 line.setValue(annotation.getThreshold().value);
1839  30 line.setColour(annotation.getThreshold().colour.getRGB());
1840  30 an.setThresholdLine(line);
1841    }
1842    }
1843    else
1844    {
1845  159 an.setGraph(false);
1846    }
1847   
1848  331 an.setLabel(annotation.label);
1849   
1850  331 if (annotation == av.getAlignmentQualityAnnot()
1851    || annotation == av.getAlignmentConservationAnnotation()
1852    || annotation == av.getAlignmentConsensusAnnotation()
1853    || annotation.autoCalculated)
1854    {
1855    // new way of indicating autocalculated annotation -
1856  91 an.setAutoCalculated(annotation.autoCalculated);
1857    }
1858  331 if (annotation.hasScore())
1859    {
1860  139 an.setScore(annotation.getScore());
1861    }
1862   
1863  331 if (annotation.getCalcId() != null)
1864    {
1865  307 calcIdSet.add(annotation.getCalcId());
1866  307 an.setCalcId(annotation.getCalcId());
1867    }
1868  331 if (annotation.hasProperties())
1869    {
1870  0 for (String pr : annotation.getProperties())
1871    {
1872  0 Property prop = new Property();
1873  0 prop.setName(pr);
1874  0 prop.setValue(annotation.getProperty(pr));
1875  0 an.addProperty(prop);
1876    }
1877    }
1878   
1879  331 AnnotationElement ae;
1880  331 if (annotation.annotations != null)
1881    {
1882  331 an.setScoreOnly(false);
1883  43011 for (int a = 0; a < annotation.annotations.length; a++)
1884    {
1885  42680 if ((annotation == null) || (annotation.annotations[a] == null))
1886    {
1887  7459 continue;
1888    }
1889   
1890  35221 ae = new AnnotationElement();
1891  35221 if (annotation.annotations[a].description != null)
1892    {
1893  30802 ae.setDescription(annotation.annotations[a].description);
1894    }
1895  35221 if (annotation.annotations[a].displayCharacter != null)
1896    {
1897  31724 ae.setDisplayCharacter(
1898    annotation.annotations[a].displayCharacter);
1899    }
1900   
1901  35221 if (!Float.isNaN(annotation.annotations[a].value))
1902    {
1903  33517 ae.setValue(annotation.annotations[a].value);
1904    }
1905   
1906  35221 ae.setPosition(a);
1907  35221 if (annotation.annotations[a].secondaryStructure > ' ')
1908    {
1909  6484 ae.setSecondaryStructure(
1910    annotation.annotations[a].secondaryStructure + "");
1911    }
1912   
1913  35221 if (annotation.annotations[a].colour != null
1914    && annotation.annotations[a].colour != java.awt.Color.black)
1915    {
1916  17109 ae.setColour(annotation.annotations[a].colour.getRGB());
1917    }
1918   
1919  35221 an.addAnnotationElement(ae);
1920  35221 if (annotation.autoCalculated)
1921    {
1922    // only write one non-null entry into the annotation row -
1923    // sufficient to get the visualization attributes necessary to
1924    // display data
1925  14007 continue;
1926    }
1927    }
1928    }
1929    else
1930    {
1931  0 an.setScoreOnly(true);
1932    }
1933  331 if (!storeDS || (storeDS && !annotation.autoCalculated))
1934    {
1935    // skip autocalculated annotation - these are only provided for
1936    // alignments
1937  331 vamsasSet.addAnnotation(an);
1938    }
1939    }
1940   
1941    }
1942   
 
1943  3 toggle private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
1944    {
1945  3 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
1946  3 if (settings != null)
1947    {
1948  0 CalcIdParam vCalcIdParam = new CalcIdParam();
1949  0 vCalcIdParam.setCalcId(calcId);
1950  0 vCalcIdParam.addServiceURL(settings.getServiceURI());
1951    // generic URI allowing a third party to resolve another instance of the
1952    // service used for this calculation
1953  0 for (String urls : settings.getServiceURLs())
1954    {
1955  0 vCalcIdParam.addServiceURL(urls);
1956    }
1957  0 vCalcIdParam.setVersion("1.0");
1958  0 if (settings.getPreset() != null)
1959    {
1960  0 WsParamSetI setting = settings.getPreset();
1961  0 vCalcIdParam.setName(setting.getName());
1962  0 vCalcIdParam.setDescription(setting.getDescription());
1963    }
1964    else
1965    {
1966  0 vCalcIdParam.setName("");
1967  0 vCalcIdParam.setDescription("Last used parameters");
1968    }
1969    // need to be able to recover 1) settings 2) user-defined presets or
1970    // recreate settings from preset 3) predefined settings provided by
1971    // service - or settings that can be transferred (or discarded)
1972  0 vCalcIdParam.setParameters(
1973    settings.getWsParamFile().replace("\n", "|\\n|"));
1974  0 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
1975    // todo - decide if updateImmediately is needed for any projects.
1976   
1977  0 return vCalcIdParam;
1978    }
1979  3 return null;
1980    }
1981   
 
1982  0 toggle private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
1983    AlignViewport av)
1984    {
1985  0 if (calcIdParam.getVersion().equals("1.0"))
1986    {
1987  0 Jws2Instance service = Jws2Discoverer.getDiscoverer()
1988    .getPreferredServiceFor(calcIdParam.getServiceURL());
1989  0 if (service != null)
1990    {
1991  0 WsParamSetI parmSet = null;
1992  0 try
1993    {
1994  0 parmSet = service.getParamStore().parseServiceParameterFile(
1995    calcIdParam.getName(), calcIdParam.getDescription(),
1996    calcIdParam.getServiceURL(),
1997    calcIdParam.getParameters().replace("|\\n|", "\n"));
1998    } catch (IOException x)
1999    {
2000  0 warn("Couldn't parse parameter data for "
2001    + calcIdParam.getCalcId(), x);
2002  0 return false;
2003    }
2004  0 List<ArgumentI> argList = null;
2005  0 if (calcIdParam.getName().length() > 0)
2006    {
2007  0 parmSet = service.getParamStore()
2008    .getPreset(calcIdParam.getName());
2009  0 if (parmSet != null)
2010    {
2011    // TODO : check we have a good match with settings in AACon -
2012    // otherwise we'll need to create a new preset
2013    }
2014    }
2015    else
2016    {
2017  0 argList = parmSet.getArguments();
2018  0 parmSet = null;
2019    }
2020  0 AAConSettings settings = new AAConSettings(
2021    calcIdParam.isAutoUpdate(), service, parmSet, argList);
2022  0 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2023    calcIdParam.isNeedsUpdate());
2024  0 return true;
2025    }
2026    else
2027    {
2028  0 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2029  0 return false;
2030    }
2031    }
2032  0 throw new Error(MessageManager.formatMessage(
2033    "error.unsupported_version_calcIdparam", new Object[]
2034    { calcIdParam.toString() }));
2035    }
2036   
2037    /**
2038    * External mapping between jalview objects and objects yielding a valid and
2039    * unique object ID string. This is null for normal Jalview project IO, but
2040    * non-null when a jalview project is being read or written as part of a
2041    * vamsas session.
2042    */
2043    IdentityHashMap jv2vobj = null;
2044   
2045    /**
2046    * Construct a unique ID for jvobj using either existing bindings or if none
2047    * exist, the result of the hashcode call for the object.
2048    *
2049    * @param jvobj
2050    * jalview data object
2051    * @return unique ID for referring to jvobj
2052    */
 
2053  463 toggle private String makeHashCode(Object jvobj, String altCode)
2054    {
2055  463 if (jv2vobj != null)
2056    {
2057  0 Object id = jv2vobj.get(jvobj);
2058  0 if (id != null)
2059    {
2060  0 return id.toString();
2061    }
2062    // check string ID mappings
2063  0 if (jvids2vobj != null && jvobj instanceof String)
2064    {
2065  0 id = jvids2vobj.get(jvobj);
2066    }
2067  0 if (id != null)
2068    {
2069  0 return id.toString();
2070    }
2071    // give up and warn that something has gone wrong
2072  0 warn("Cannot find ID for object in external mapping : " + jvobj);
2073    }
2074  463 return altCode;
2075    }
2076   
2077    /**
2078    * return local jalview object mapped to ID, if it exists
2079    *
2080    * @param idcode
2081    * (may be null)
2082    * @return null or object bound to idcode
2083    */
 
2084  12 toggle private Object retrieveExistingObj(String idcode)
2085    {
2086  12 if (idcode != null && vobj2jv != null)
2087    {
2088  0 return vobj2jv.get(idcode);
2089    }
2090  12 return null;
2091    }
2092   
2093    /**
2094    * binding from ID strings from external mapping table to jalview data model
2095    * objects.
2096    */
2097    private Hashtable vobj2jv;
2098   
 
2099  417 toggle private Sequence createVamsasSequence(String id, SequenceI jds)
2100    {
2101  417 return createVamsasSequence(true, id, jds, null);
2102    }
2103   
 
2104  417 toggle private Sequence createVamsasSequence(boolean recurse, String id,
2105    SequenceI jds, SequenceI parentseq)
2106    {
2107  417 Sequence vamsasSeq = new Sequence();
2108  417 vamsasSeq.setId(id);
2109  417 vamsasSeq.setName(jds.getName());
2110  417 vamsasSeq.setSequence(jds.getSequenceAsString());
2111  417 vamsasSeq.setDescription(jds.getDescription());
2112  417 jalview.datamodel.DBRefEntry[] dbrefs = null;
2113  417 if (jds.getDatasetSequence() != null)
2114    {
2115  192 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2116    }
2117    else
2118    {
2119    // seqId==dsseqid so we can tell which sequences really are
2120    // dataset sequences only
2121  225 vamsasSeq.setDsseqid(id);
2122  225 dbrefs = jds.getDBRefs();
2123  225 if (parentseq == null)
2124    {
2125  225 parentseq = jds;
2126    }
2127    }
2128  417 if (dbrefs != null)
2129    {
2130  389 for (int d = 0; d < dbrefs.length; d++)
2131    {
2132  231 DBRef dbref = new DBRef();
2133  231 dbref.setSource(dbrefs[d].getSource());
2134  231 dbref.setVersion(dbrefs[d].getVersion());
2135  231 dbref.setAccessionId(dbrefs[d].getAccessionId());
2136  231 if (dbrefs[d].hasMap())
2137    {
2138  0 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2139    jds, recurse);
2140  0 dbref.setMapping(mp);
2141    }
2142  231 vamsasSeq.addDBRef(dbref);
2143    }
2144    }
2145  417 return vamsasSeq;
2146    }
2147   
 
2148  0 toggle private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2149    SequenceI parentseq, SequenceI jds, boolean recurse)
2150    {
2151  0 Mapping mp = null;
2152  0 if (jmp.getMap() != null)
2153    {
2154  0 mp = new Mapping();
2155   
2156  0 jalview.util.MapList mlst = jmp.getMap();
2157  0 List<int[]> r = mlst.getFromRanges();
2158  0 for (int[] range : r)
2159    {
2160  0 MapListFrom mfrom = new MapListFrom();
2161  0 mfrom.setStart(range[0]);
2162  0 mfrom.setEnd(range[1]);
2163  0 mp.addMapListFrom(mfrom);
2164    }
2165  0 r = mlst.getToRanges();
2166  0 for (int[] range : r)
2167    {
2168  0 MapListTo mto = new MapListTo();
2169  0 mto.setStart(range[0]);
2170  0 mto.setEnd(range[1]);
2171  0 mp.addMapListTo(mto);
2172    }
2173  0 mp.setMapFromUnit(mlst.getFromRatio());
2174  0 mp.setMapToUnit(mlst.getToRatio());
2175  0 if (jmp.getTo() != null)
2176    {
2177  0 MappingChoice mpc = new MappingChoice();
2178   
2179    // check/create ID for the sequence referenced by getTo()
2180   
2181  0 String jmpid = "";
2182  0 SequenceI ps = null;
2183  0 if (parentseq != jmp.getTo()
2184    && parentseq.getDatasetSequence() != jmp.getTo())
2185    {
2186    // chaining dbref rather than a handshaking one
2187  0 jmpid = seqHash(ps = jmp.getTo());
2188    }
2189    else
2190    {
2191  0 jmpid = seqHash(ps = parentseq);
2192    }
2193  0 mpc.setDseqFor(jmpid);
2194  0 if (!seqRefIds.containsKey(mpc.getDseqFor()))
2195    {
2196  0 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2197  0 seqRefIds.put(mpc.getDseqFor(), ps);
2198    }
2199    else
2200    {
2201  0 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2202    }
2203   
2204  0 mp.setMappingChoice(mpc);
2205    }
2206    }
2207  0 return mp;
2208    }
2209   
 
2210  0 toggle String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2211    List<UserColourScheme> userColours, JalviewModelSequence jms)
2212    {
2213  0 String id = null;
2214  0 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2215  0 boolean newucs = false;
2216  0 if (!userColours.contains(ucs))
2217    {
2218  0 userColours.add(ucs);
2219  0 newucs = true;
2220    }
2221  0 id = "ucs" + userColours.indexOf(ucs);
2222  0 if (newucs)
2223    {
2224    // actually create the scheme's entry in the XML model
2225  0 java.awt.Color[] colours = ucs.getColours();
2226  0 jalview.schemabinding.version2.UserColours uc = new jalview.schemabinding.version2.UserColours();
2227  0 jalview.schemabinding.version2.UserColourScheme jbucs = new jalview.schemabinding.version2.UserColourScheme();
2228   
2229  0 for (int i = 0; i < colours.length; i++)
2230    {
2231  0 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2232  0 col.setName(ResidueProperties.aa[i]);
2233  0 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2234  0 jbucs.addColour(col);
2235    }
2236  0 if (ucs.getLowerCaseColours() != null)
2237    {
2238  0 colours = ucs.getLowerCaseColours();
2239  0 for (int i = 0; i < colours.length; i++)
2240    {
2241  0 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
2242  0 col.setName(ResidueProperties.aa[i].toLowerCase());
2243  0 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2244  0 jbucs.addColour(col);
2245    }
2246    }
2247   
2248  0 uc.setId(id);
2249  0 uc.setUserColourScheme(jbucs);
2250  0 jms.addUserColours(uc);
2251    }
2252   
2253  0 return id;
2254    }
2255   
 
2256  0 toggle jalview.schemes.UserColourScheme getUserColourScheme(
2257    JalviewModelSequence jms, String id)
2258    {
2259  0 UserColours[] uc = jms.getUserColours();
2260  0 UserColours colours = null;
2261   
2262  0 for (int i = 0; i < uc.length; i++)
2263    {
2264  0 if (uc[i].getId().equals(id))
2265    {
2266  0 colours = uc[i];
2267   
2268  0 break;
2269    }
2270    }
2271   
2272  0 java.awt.Color[] newColours = new java.awt.Color[24];
2273   
2274  0 for (int i = 0; i < 24; i++)
2275    {
2276  0 newColours[i] = new java.awt.Color(Integer.parseInt(
2277    colours.getUserColourScheme().getColour(i).getRGB(), 16));
2278    }
2279   
2280  0 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2281    newColours);
2282   
2283  0 if (colours.getUserColourScheme().getColourCount() > 24)
2284    {
2285  0 newColours = new java.awt.Color[23];
2286  0 for (int i = 0; i < 23; i++)
2287    {
2288  0 newColours[i] = new java.awt.Color(Integer.parseInt(
2289    colours.getUserColourScheme().getColour(i + 24).getRGB(),
2290    16));
2291    }
2292  0 ucs.setLowerCaseColours(newColours);
2293    }
2294   
2295  0 return ucs;
2296    }
2297   
2298    /**
2299    * contains last error message (if any) encountered by XML loader.
2300    */
2301    String errorMessage = null;
2302   
2303    /**
2304    * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2305    * exceptions are raised during project XML parsing
2306    */
2307    public boolean attemptversion1parse = true;
2308   
2309    /**
2310    * Load a jalview project archive from a jar file
2311    *
2312    * @param file
2313    * - HTTP URL or filename
2314    */
 
2315  20 toggle public AlignFrame loadJalviewAlign(final String file)
2316    {
2317   
2318  20 jalview.gui.AlignFrame af = null;
2319   
2320  20 try
2321    {
2322    // create list to store references for any new Jmol viewers created
2323  20 newStructureViewers = new Vector<>();
2324    // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2325    // Workaround is to make sure caller implements the JarInputStreamProvider
2326    // interface
2327    // so we can re-open the jar input stream for each entry.
2328   
2329  20 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2330  20 af = loadJalviewAlign(jprovider);
2331  20 af.setMenusForViewport();
2332   
2333    } catch (MalformedURLException e)
2334    {
2335  0 errorMessage = "Invalid URL format for '" + file + "'";
2336  0 reportErrors();
2337    } finally
2338    {
2339  20 try
2340    {
2341  20 SwingUtilities.invokeAndWait(new Runnable()
2342    {
 
2343  20 toggle @Override
2344    public void run()
2345    {
2346  20 setLoadingFinishedForNewStructureViewers();
2347    };
2348    });
2349    } catch (Exception x)
2350    {
2351  0 System.err.println("Error loading alignment: " + x.getMessage());
2352    }
2353    }
2354  20 return af;
2355    }
2356   
 
2357  20 toggle private jarInputStreamProvider createjarInputStreamProvider(
2358    final String file) throws MalformedURLException
2359    {
2360  20 URL url = null;
2361  20 errorMessage = null;
2362  20 uniqueSetSuffix = null;
2363  20 seqRefIds = null;
2364  20 viewportsAdded.clear();
2365  20 frefedSequence = null;
2366   
2367  20 if (file.startsWith("http://"))
2368    {
2369  4 url = new URL(file);
2370    }
2371  20 final URL _url = url;
2372  20 return new jarInputStreamProvider()
2373    {
2374   
 
2375  131 toggle @Override
2376    public JarInputStream getJarInputStream() throws IOException
2377    {
2378  131 if (_url != null)
2379    {
2380  32 return new JarInputStream(_url.openStream());
2381    }
2382    else
2383    {
2384  99 return new JarInputStream(new FileInputStream(file));
2385    }
2386    }
2387   
 
2388  20 toggle @Override
2389    public String getFilename()
2390    {
2391  20 return file;
2392    }
2393    };
2394    }
2395   
2396    /**
2397    * Recover jalview session from a jalview project archive. Caller may
2398    * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2399    * themselves. Any null fields will be initialised with default values,
2400    * non-null fields are left alone.
2401    *
2402    * @param jprovider
2403    * @return
2404    */
 
2405  20 toggle public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2406    {
2407  20 errorMessage = null;
2408  20 if (uniqueSetSuffix == null)
2409    {
2410  20 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2411    }
2412  20 if (seqRefIds == null)
2413    {
2414  20 initSeqRefs();
2415    }
2416  20 AlignFrame af = null, _af = null;
2417  20 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2418  20 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2419  20 final String file = jprovider.getFilename();
2420  20 try
2421    {
2422  20 JarInputStream jin = null;
2423  20 JarEntry jarentry = null;
2424  20 int entryCount = 1;
2425   
2426  20 do
2427    {
2428  115 jin = jprovider.getJarInputStream();
2429  545 for (int i = 0; i < entryCount; i++)
2430    {
2431  430 jarentry = jin.getNextJarEntry();
2432    }
2433   
2434  115 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2435    {
2436  79 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2437  79 JalviewModel object = new JalviewModel();
2438   
2439  79 Unmarshaller unmar = new Unmarshaller(object);
2440  79 unmar.setValidation(false);
2441  79 object = (JalviewModel) unmar.unmarshal(in);
2442  79 if (true) // !skipViewport(object))
2443    {
2444  79 _af = loadFromObject(object, file, true, jprovider);
2445  79 if (_af != null && object.getJalviewModelSequence()
2446    .getViewportCount() > 0)
2447    {
2448  69 if (af == null)
2449    {
2450    // store a reference to the first view
2451  20 af = _af;
2452    }
2453  69 if (_af.viewport.isGatherViewsHere())
2454    {
2455    // if this is a gathered view, keep its reference since
2456    // after gathering views, only this frame will remain
2457  12 af = _af;
2458  12 gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
2459    }
2460    // Save dataset to register mappings once all resolved
2461  69 importedDatasets.put(af.viewport.getAlignment().getDataset(),
2462    af.viewport.getAlignment().getDataset());
2463    }
2464    }
2465  79 entryCount++;
2466    }
2467  36 else if (jarentry != null)
2468    {
2469    // Some other file here.
2470  16 entryCount++;
2471    }
2472  115 } while (jarentry != null);
2473  20 resolveFrefedSequences();
2474    } catch (IOException ex)
2475    {
2476  0 ex.printStackTrace();
2477  0 errorMessage = "Couldn't locate Jalview XML file : " + file;
2478  0 System.err.println(
2479    "Exception whilst loading jalview XML file : " + ex + "\n");
2480    } catch (Exception ex)
2481    {
2482  0 System.err.println("Parsing as Jalview Version 2 file failed.");
2483  0 ex.printStackTrace(System.err);
2484  0 if (attemptversion1parse)
2485    {
2486    // Is Version 1 Jar file?
2487  0 try
2488    {
2489  0 af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider);
2490    } catch (Exception ex2)
2491    {
2492  0 System.err.println("Exception whilst loading as jalviewXMLV1:");
2493  0 ex2.printStackTrace();
2494  0 af = null;
2495    }
2496    }
2497  0 if (Desktop.instance != null)
2498    {
2499  0 Desktop.instance.stopLoading();
2500    }
2501  0 if (af != null)
2502    {
2503  0 System.out.println("Successfully loaded archive file");
2504  0 return af;
2505    }
2506  0 ex.printStackTrace();
2507   
2508  0 System.err.println(
2509    "Exception whilst loading jalview XML file : " + ex + "\n");
2510    } catch (OutOfMemoryError e)
2511    {
2512    // Don't use the OOM Window here
2513  0 errorMessage = "Out of memory loading jalview XML file";
2514  0 System.err.println("Out of memory whilst loading jalview XML file");
2515  0 e.printStackTrace();
2516    }
2517   
2518    /*
2519    * Regather multiple views (with the same sequence set id) to the frame (if
2520    * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2521    * views instead of separate frames. Note this doesn't restore a state where
2522    * some expanded views in turn have tabbed views - the last "first tab" read
2523    * in will play the role of gatherer for all.
2524    */
2525  20 for (AlignFrame fr : gatherToThisFrame.values())
2526    {
2527  12 Desktop.instance.gatherViews(fr);
2528    }
2529   
2530  20 restoreSplitFrames();
2531  20 for (AlignmentI ds : importedDatasets.keySet())
2532    {
2533  20 if (ds.getCodonFrames() != null)
2534    {
2535  20 StructureSelectionManager
2536    .getStructureSelectionManager(Desktop.instance)
2537    .registerMappings(ds.getCodonFrames());
2538    }
2539    }
2540  20 if (errorMessage != null)
2541    {
2542  0 reportErrors();
2543    }
2544   
2545  20 if (Desktop.instance != null)
2546    {
2547  20 Desktop.instance.stopLoading();
2548    }
2549   
2550  20 return af;
2551    }
2552   
2553    /**
2554    * Try to reconstruct and display SplitFrame windows, where each contains
2555    * complementary dna and protein alignments. Done by pairing up AlignFrame
2556    * objects (created earlier) which have complementary viewport ids associated.
2557    */
 
2558  20 toggle protected void restoreSplitFrames()
2559    {
2560  20 List<SplitFrame> gatherTo = new ArrayList<>();
2561  20 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2562  20 Map<String, AlignFrame> dna = new HashMap<>();
2563   
2564    /*
2565    * Identify the DNA alignments
2566    */
2567  20 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2568    .entrySet())
2569    {
2570  0 AlignFrame af = candidate.getValue();
2571  0 if (af.getViewport().getAlignment().isNucleotide())
2572    {
2573  0 dna.put(candidate.getKey().getId(), af);
2574    }
2575    }
2576   
2577    /*
2578    * Try to match up the protein complements
2579    */
2580  20 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2581    .entrySet())
2582    {
2583  0 AlignFrame af = candidate.getValue();
2584  0 if (!af.getViewport().getAlignment().isNucleotide())
2585    {
2586  0 String complementId = candidate.getKey().getComplementId();
2587    // only non-null complements should be in the Map
2588  0 if (complementId != null && dna.containsKey(complementId))
2589    {
2590  0 final AlignFrame dnaFrame = dna.get(complementId);
2591  0 SplitFrame sf = createSplitFrame(dnaFrame, af);
2592  0 addedToSplitFrames.add(dnaFrame);
2593  0 addedToSplitFrames.add(af);
2594  0 dnaFrame.setMenusForViewport();
2595  0 af.setMenusForViewport();
2596  0 if (af.viewport.isGatherViewsHere())
2597    {
2598  0 gatherTo.add(sf);
2599    }
2600    }
2601    }
2602    }
2603   
2604    /*
2605    * Open any that we failed to pair up (which shouldn't happen!) as
2606    * standalone AlignFrame's.
2607    */
2608  20 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2609    .entrySet())
2610    {
2611  0 AlignFrame af = candidate.getValue();
2612  0 if (!addedToSplitFrames.contains(af))
2613    {
2614  0 Viewport view = candidate.getKey();
2615  0 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
2616    view.getHeight());
2617  0 af.setMenusForViewport();
2618  0 System.err.println("Failed to restore view " + view.getTitle()
2619    + " to split frame");
2620    }
2621    }
2622   
2623    /*
2624    * Gather back into tabbed views as flagged.
2625    */
2626  20 for (SplitFrame sf : gatherTo)
2627    {
2628  0 Desktop.instance.gatherViews(sf);
2629    }
2630   
2631  20 splitFrameCandidates.clear();
2632    }
2633   
2634    /**
2635    * Construct and display one SplitFrame holding DNA and protein alignments.
2636    *
2637    * @param dnaFrame
2638    * @param proteinFrame
2639    * @return
2640    */
 
2641  0 toggle protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
2642    AlignFrame proteinFrame)
2643    {
2644  0 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
2645  0 String title = MessageManager.getString("label.linked_view_title");
2646  0 int width = (int) dnaFrame.getBounds().getWidth();
2647  0 int height = (int) (dnaFrame.getBounds().getHeight()
2648    + proteinFrame.getBounds().getHeight() + 50);
2649   
2650    /*
2651    * SplitFrame location is saved to both enclosed frames
2652    */
2653  0 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
2654  0 Desktop.addInternalFrame(splitFrame, title, width, height);
2655   
2656    /*
2657    * And compute cDNA consensus (couldn't do earlier with consensus as
2658    * mappings were not yet present)
2659    */
2660  0 proteinFrame.viewport.alignmentChanged(proteinFrame.alignPanel);
2661   
2662  0 return splitFrame;
2663    }
2664   
2665    /**
2666    * check errorMessage for a valid error message and raise an error box in the
2667    * GUI or write the current errorMessage to stderr and then clear the error
2668    * state.
2669    */
 
2670  5 toggle protected void reportErrors()
2671    {
2672  5 reportErrors(false);
2673    }
2674   
 
2675  5 toggle protected void reportErrors(final boolean saving)
2676    {
2677  5 if (errorMessage != null)
2678    {
2679  0 final String finalErrorMessage = errorMessage;
2680  0 errorMessage = null;
2681  0 if (raiseGUI)
2682    {
2683  0 javax.swing.SwingUtilities.invokeLater(new Runnable()
2684    {
 
2685  0 toggle @Override
2686    public void run()
2687    {
2688  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2689    finalErrorMessage,
2690  0 "Error " + (saving ? "saving" : "loading")
2691    + " Jalview file",
2692    JvOptionPane.WARNING_MESSAGE);
2693    }
2694    });
2695    }
2696    else
2697    {
2698  0 System.err.println(
2699    "Problem loading Jalview file: " + finalErrorMessage);
2700    }
2701    }
2702    }
2703   
2704    Map<String, String> alreadyLoadedPDB = new HashMap<>();
2705   
2706    /**
2707    * when set, local views will be updated from view stored in JalviewXML
2708    * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
2709    * sync if this is set to true.
2710    */
2711    private final boolean updateLocalViews = false;
2712   
2713    /**
2714    * Returns the path to a temporary file holding the PDB file for the given PDB
2715    * id. The first time of asking, searches for a file of that name in the
2716    * Jalview project jar, and copies it to a new temporary file. Any repeat
2717    * requests just return the path to the file previously created.
2718    *
2719    * @param jprovider
2720    * @param pdbId
2721    * @return
2722    */
 
2723  282 toggle String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
2724    String origFile)
2725    {
2726  282 if (alreadyLoadedPDB.containsKey(pdbId))
2727    {
2728  268 return alreadyLoadedPDB.get(pdbId).toString();
2729    }
2730   
2731  14 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
2732    origFile);
2733  14 if (tempFile != null)
2734    {
2735  14 alreadyLoadedPDB.put(pdbId, tempFile);
2736    }
2737  14 return tempFile;
2738    }
2739   
2740    /**
2741    * Copies the jar entry of given name to a new temporary file and returns the
2742    * path to the file, or null if the entry is not found.
2743    *
2744    * @param jprovider
2745    * @param jarEntryName
2746    * @param prefix
2747    * a prefix for the temporary file name, must be at least three
2748    * characters long
2749    * @param origFile
2750    * null or original file - so new file can be given the same suffix
2751    * as the old one
2752    * @return
2753    */
 
2754  14 toggle protected String copyJarEntry(jarInputStreamProvider jprovider,
2755    String jarEntryName, String prefix, String origFile)
2756    {
2757  14 BufferedReader in = null;
2758  14 PrintWriter out = null;
2759  14 String suffix = ".tmp";
2760  14 if (origFile == null)
2761    {
2762  0 origFile = jarEntryName;
2763    }
2764  14 int sfpos = origFile.lastIndexOf(".");
2765  14 if (sfpos > -1 && sfpos < (origFile.length() - 3))
2766    {
2767  14 suffix = "." + origFile.substring(sfpos + 1);
2768    }
2769  14 try
2770    {
2771  14 JarInputStream jin = jprovider.getJarInputStream();
2772    /*
2773    * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
2774    * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
2775    * FileInputStream(jprovider)); }
2776    */
2777   
2778  14 JarEntry entry = null;
2779  14 do
2780    {
2781  16 entry = jin.getNextJarEntry();
2782  16 } while (entry != null && !entry.getName().equals(jarEntryName));
2783  14 if (entry != null)
2784    {
2785  14 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
2786  14 File outFile = File.createTempFile(prefix, suffix);
2787  14 outFile.deleteOnExit();
2788  14 out = new PrintWriter(new FileOutputStream(outFile));
2789  14 String data;
2790   
2791  ? while ((data = in.readLine()) != null)
2792    {
2793  20379 out.println(data);
2794    }
2795  14 out.flush();
2796  14 String t = outFile.getAbsolutePath();
2797  14 return t;
2798    }
2799    else
2800    {
2801  0 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
2802    }
2803    } catch (Exception ex)
2804    {
2805  0 ex.printStackTrace();
2806    } finally
2807    {
2808  14 if (in != null)
2809    {
2810  14 try
2811    {
2812  14 in.close();
2813    } catch (IOException e)
2814    {
2815    // ignore
2816    }
2817    }
2818  14 if (out != null)
2819    {
2820  14 out.close();
2821    }
2822    }
2823   
2824  0 return null;
2825    }
2826   
 
2827    private class JvAnnotRow
2828    {
 
2829  434 toggle public JvAnnotRow(int i, AlignmentAnnotation jaa)
2830    {
2831  434 order = i;
2832  434 template = jaa;
2833    }
2834   
2835    /**
2836    * persisted version of annotation row from which to take vis properties
2837    */
2838    public jalview.datamodel.AlignmentAnnotation template;
2839   
2840    /**
2841    * original position of the annotation row in the alignment
2842    */
2843    public int order;
2844    }
2845   
2846    /**
2847    * Load alignment frame from jalview XML DOM object
2848    *
2849    * @param object
2850    * DOM
2851    * @param file
2852    * filename source string
2853    * @param loadTreesAndStructures
2854    * when false only create Viewport
2855    * @param jprovider
2856    * data source provider
2857    * @return alignment frame created from view stored in DOM
2858    */
 
2859  82 toggle AlignFrame loadFromObject(JalviewModel object, String file,
2860    boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
2861    {
2862  82 SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
2863  82 Sequence[] vamsasSeq = vamsasSet.getSequence();
2864   
2865  82 JalviewModelSequence jms = object.getJalviewModelSequence();
2866   
2867  82 Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
2868    : null;
2869   
2870    // ////////////////////////////////
2871    // LOAD SEQUENCES
2872   
2873  82 List<SequenceI> hiddenSeqs = null;
2874   
2875  82 List<SequenceI> tmpseqs = new ArrayList<>();
2876   
2877  82 boolean multipleView = false;
2878  82 SequenceI referenceseqForView = null;
2879  82 JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
2880  82 int vi = 0; // counter in vamsasSeq array
2881  1378 for (int i = 0; i < jseqs.length; i++)
2882    {
2883  1296 String seqId = jseqs[i].getId();
2884   
2885  1296 SequenceI tmpSeq = seqRefIds.get(seqId);
2886  1296 if (tmpSeq != null)
2887    {
2888  975 if (!incompleteSeqs.containsKey(seqId))
2889    {
2890    // may not need this check, but keep it for at least 2.9,1 release
2891  975 if (tmpSeq.getStart() != jseqs[i].getStart()
2892    || tmpSeq.getEnd() != jseqs[i].getEnd())
2893    {
2894  0 System.err.println(
2895    "Warning JAL-2154 regression: updating start/end for sequence "
2896    + tmpSeq.toString() + " to " + jseqs[i]);
2897    }
2898    }
2899    else
2900    {
2901  0 incompleteSeqs.remove(seqId);
2902    }
2903  975 if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
2904    {
2905    // most likely we are reading a dataset XML document so
2906    // update from vamsasSeq section of XML for this sequence
2907  192 tmpSeq.setName(vamsasSeq[vi].getName());
2908  192 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2909  192 tmpSeq.setSequence(vamsasSeq[vi].getSequence());
2910  192 vi++;
2911    }
2912    else
2913    {
2914    // reading multiple views, so vamsasSeq set is a subset of JSeq
2915  783 multipleView = true;
2916    }
2917  975 tmpSeq.setStart(jseqs[i].getStart());
2918  975 tmpSeq.setEnd(jseqs[i].getEnd());
2919  975 tmpseqs.add(tmpSeq);
2920    }
2921    else
2922    {
2923  321 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
2924    vamsasSeq[vi].getSequence());
2925  321 tmpSeq.setDescription(vamsasSeq[vi].getDescription());
2926  321 tmpSeq.setStart(jseqs[i].getStart());
2927  321 tmpSeq.setEnd(jseqs[i].getEnd());
2928  321 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
2929  321 seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
2930  321 tmpseqs.add(tmpSeq);
2931  321 vi++;
2932    }
2933   
2934  1296 if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
2935    {
2936  5 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
2937    }
2938   
2939  1296 if (jseqs[i].getHidden())
2940    {
2941  278 if (hiddenSeqs == null)
2942    {
2943  62 hiddenSeqs = new ArrayList<>();
2944    }
2945   
2946  278 hiddenSeqs.add(tmpSeq);
2947    }
2948    }
2949   
2950    // /
2951    // Create the alignment object from the sequence set
2952    // ///////////////////////////////
2953  82 SequenceI[] orderedSeqs = tmpseqs
2954    .toArray(new SequenceI[tmpseqs.size()]);
2955   
2956  82 AlignmentI al = null;
2957    // so we must create or recover the dataset alignment before going further
2958    // ///////////////////////////////
2959  82 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
2960    {
2961    // older jalview projects do not have a dataset - so creat alignment and
2962    // dataset
2963  50 al = new Alignment(orderedSeqs);
2964  50 al.setDataset(null);
2965    }
2966    else
2967    {
2968  32 boolean isdsal = object.getJalviewModelSequence()
2969    .getViewportCount() == 0;
2970  32 if (isdsal)
2971    {
2972    // we are importing a dataset record, so
2973    // recover reference to an alignment already materialsed as dataset
2974  10 al = getDatasetFor(vamsasSet.getDatasetId());
2975    }
2976  32 if (al == null)
2977    {
2978    // materialse the alignment
2979  22 al = new Alignment(orderedSeqs);
2980    }
2981  32 if (isdsal)
2982    {
2983  10 addDatasetRef(vamsasSet.getDatasetId(), al);
2984    }
2985   
2986    // finally, verify all data in vamsasSet is actually present in al
2987    // passing on flag indicating if it is actually a stored dataset
2988  32 recoverDatasetFor(vamsasSet, al, isdsal);
2989    }
2990   
2991  82 if (referenceseqForView != null)
2992    {
2993  5 al.setSeqrep(referenceseqForView);
2994    }
2995    // / Add the alignment properties
2996  103 for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
2997    {
2998  21 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
2999  21 al.setProperty(ssp.getKey(), ssp.getValue());
3000    }
3001   
3002    // ///////////////////////////////
3003   
3004  82 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3005  82 if (!multipleView)
3006    {
3007    // load sequence features, database references and any associated PDB
3008    // structures for the alignment
3009    //
3010    // prior to 2.10, this part would only be executed the first time a
3011    // sequence was encountered, but not afterwards.
3012    // now, for 2.10 projects, this is also done if the xml doc includes
3013    // dataset sequences not actually present in any particular view.
3014    //
3015  546 for (int i = 0; i < vamsasSeq.length; i++)
3016    {
3017  513 if (jseqs[i].getFeaturesCount() > 0)
3018    {
3019  240 Features[] features = jseqs[i].getFeatures();
3020  10114 for (int f = 0; f < features.length; f++)
3021    {
3022  9874 SequenceFeature sf = new SequenceFeature(features[f].getType(),
3023    features[f].getDescription(), features[f].getBegin(),
3024    features[f].getEnd(), features[f].getScore(),
3025    features[f].getFeatureGroup());
3026  9874 sf.setStatus(features[f].getStatus());
3027   
3028    /*
3029    * load any feature attributes - include map-valued attributes
3030    */
3031  9874 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3032  14954 for (int od = 0; od < features[f].getOtherDataCount(); od++)
3033    {
3034  5080 OtherData keyValue = features[f].getOtherData(od);
3035  5080 String attributeName = keyValue.getKey();
3036  5080 String attributeValue = keyValue.getValue();
3037  5080 if (attributeName.startsWith("LINK"))
3038    {
3039  2338 sf.addLink(attributeValue);
3040    }
3041    else
3042    {
3043  2742 String subAttribute = keyValue.getKey2();
3044  2742 if (subAttribute == null)
3045    {
3046    // simple string-valued attribute
3047  2722 sf.setValue(attributeName, attributeValue);
3048    }
3049    else
3050    {
3051    // attribute 'key' has sub-attribute 'key2'
3052  20 if (!mapAttributes.containsKey(attributeName))
3053    {
3054  20 mapAttributes.put(attributeName, new HashMap<>());
3055    }
3056  20 mapAttributes.get(attributeName).put(subAttribute,
3057    attributeValue);
3058    }
3059    }
3060    }
3061  9874 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3062    .entrySet())
3063    {
3064  20 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3065    }
3066   
3067    // adds feature to datasequence's feature set (since Jalview 2.10)
3068  9874 al.getSequenceAt(i).addSequenceFeature(sf);
3069    }
3070    }
3071  513 if (vamsasSeq[i].getDBRefCount() > 0)
3072    {
3073    // adds dbrefs to datasequence's set (since Jalview 2.10)
3074  248 addDBRefs(
3075  248 al.getSequenceAt(i).getDatasetSequence() == null
3076    ? al.getSequenceAt(i)
3077    : al.getSequenceAt(i).getDatasetSequence(),
3078    vamsasSeq[i]);
3079    }
3080  513 if (jseqs[i].getPdbidsCount() > 0)
3081    {
3082  56 Pdbids[] ids = jseqs[i].getPdbids();
3083  112 for (int p = 0; p < ids.length; p++)
3084    {
3085  56 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3086  56 entry.setId(ids[p].getId());
3087  56 if (ids[p].getType() != null)
3088    {
3089  46 if (PDBEntry.Type.getType(ids[p].getType()) != null)
3090    {
3091  46 entry.setType(PDBEntry.Type.getType(ids[p].getType()));
3092    }
3093    else
3094    {
3095  0 entry.setType(PDBEntry.Type.FILE);
3096    }
3097    }
3098    // jprovider is null when executing 'New View'
3099  56 if (ids[p].getFile() != null && jprovider != null)
3100    {
3101  42 if (!pdbloaded.containsKey(ids[p].getFile()))
3102    {
3103  42 entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
3104    ids[p].getFile()));
3105    }
3106    else
3107    {
3108  0 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
3109    }
3110    }
3111  56 if (ids[p].getPdbentryItem() != null)
3112    {
3113  56 for (PdbentryItem item : ids[p].getPdbentryItem())
3114    {
3115  22 for (Property pr : item.getProperty())
3116    {
3117  22 entry.setProperty(pr.getName(), pr.getValue());
3118    }
3119    }
3120    }
3121  56 StructureSelectionManager
3122    .getStructureSelectionManager(Desktop.instance)
3123    .registerPDBEntry(entry);
3124    // adds PDBEntry to datasequence's set (since Jalview 2.10)
3125  56 if (al.getSequenceAt(i).getDatasetSequence() != null)
3126    {
3127  43 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3128    }
3129    else
3130    {
3131  13 al.getSequenceAt(i).addPDBId(entry);
3132    }
3133    }
3134    }
3135    }
3136    } // end !multipleview
3137   
3138    // ///////////////////////////////
3139    // LOAD SEQUENCE MAPPINGS
3140   
3141  82 if (vamsasSet.getAlcodonFrameCount() > 0)
3142    {
3143    // TODO Potentially this should only be done once for all views of an
3144    // alignment
3145  0 AlcodonFrame[] alc = vamsasSet.getAlcodonFrame();
3146  0 for (int i = 0; i < alc.length; i++)
3147    {
3148  0 AlignedCodonFrame cf = new AlignedCodonFrame();
3149  0 if (alc[i].getAlcodMapCount() > 0)
3150    {
3151  0 AlcodMap[] maps = alc[i].getAlcodMap();
3152  0 for (int m = 0; m < maps.length; m++)
3153    {
3154  0 SequenceI dnaseq = seqRefIds.get(maps[m].getDnasq());
3155    // Load Mapping
3156  0 jalview.datamodel.Mapping mapping = null;
3157    // attach to dna sequence reference.
3158  0 if (maps[m].getMapping() != null)
3159    {
3160  0 mapping = addMapping(maps[m].getMapping());
3161  0 if (dnaseq != null && mapping.getTo() != null)
3162    {
3163  0 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3164    }
3165    else
3166    {
3167    // defer to later
3168  0 frefedSequence.add(
3169    newAlcodMapRef(maps[m].getDnasq(), cf, mapping));
3170    }
3171    }
3172    }
3173  0 al.addCodonFrame(cf);
3174    }
3175    }
3176    }
3177   
3178    // ////////////////////////////////
3179    // LOAD ANNOTATIONS
3180  82 List<JvAnnotRow> autoAlan = new ArrayList<>();
3181   
3182    /*
3183    * store any annotations which forward reference a group's ID
3184    */
3185  82 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3186   
3187  82 if (vamsasSet.getAnnotationCount() > 0)
3188    {
3189  77 Annotation[] an = vamsasSet.getAnnotation();
3190   
3191  632 for (int i = 0; i < an.length; i++)
3192    {
3193  555 Annotation annotation = an[i];
3194   
3195    /**
3196    * test if annotation is automatically calculated for this view only
3197    */
3198  555 boolean autoForView = false;
3199  555 if (annotation.getLabel().equals("Quality")
3200    || annotation.getLabel().equals("Conservation")
3201    || annotation.getLabel().equals("Consensus"))
3202    {
3203    // Kludge for pre 2.5 projects which lacked the autocalculated flag
3204  182 autoForView = true;
3205  182 if (!annotation.hasAutoCalculated())
3206    {
3207  0 annotation.setAutoCalculated(true);
3208    }
3209    }
3210  555 if (autoForView || (annotation.hasAutoCalculated()
3211    && annotation.isAutoCalculated()))
3212    {
3213    // remove ID - we don't recover annotation from other views for
3214    // view-specific annotation
3215  241 annotation.setId(null);
3216    }
3217   
3218    // set visiblity for other annotation in this view
3219  555 String annotationId = annotation.getId();
3220  555 if (annotationId != null && annotationIds.containsKey(annotationId))
3221    {
3222  0 AlignmentAnnotation jda = annotationIds.get(annotationId);
3223    // in principle Visible should always be true for annotation displayed
3224    // in multiple views
3225  0 if (annotation.hasVisible())
3226    {
3227  0 jda.visible = annotation.getVisible();
3228    }
3229   
3230  0 al.addAnnotation(jda);
3231   
3232  0 continue;
3233    }
3234    // Construct new annotation from model.
3235  555 AnnotationElement[] ae = annotation.getAnnotationElement();
3236  555 jalview.datamodel.Annotation[] anot = null;
3237  555 java.awt.Color firstColour = null;
3238  555 int anpos;
3239  555 if (!annotation.getScoreOnly())
3240    {
3241  555 anot = new jalview.datamodel.Annotation[al.getWidth()];
3242  63868 for (int aa = 0; aa < ae.length && aa < anot.length; aa++)
3243    {
3244  63313 anpos = ae[aa].getPosition();
3245   
3246  63313 if (anpos >= anot.length)
3247    {
3248  0 continue;
3249    }
3250   
3251  63313 anot[anpos] = new jalview.datamodel.Annotation(
3252   
3253    ae[aa].getDisplayCharacter(), ae[aa].getDescription(),
3254  63313 (ae[aa].getSecondaryStructure() == null
3255    || ae[aa].getSecondaryStructure().length() == 0)
3256    ? ' '
3257    : ae[aa].getSecondaryStructure()
3258    .charAt(0),
3259    ae[aa].getValue()
3260   
3261    );
3262    // JBPNote: Consider verifying dataflow for IO of secondary
3263    // structure annotation read from Stockholm files
3264    // this was added to try to ensure that
3265    // if (anot[ae[aa].getPosition()].secondaryStructure>' ')
3266    // {
3267    // anot[ae[aa].getPosition()].displayCharacter = "";
3268    // }
3269  63313 anot[anpos].colour = new java.awt.Color(ae[aa].getColour());
3270  63313 if (firstColour == null)
3271    {
3272  553 firstColour = anot[anpos].colour;
3273    }
3274    }
3275    }
3276  555 jalview.datamodel.AlignmentAnnotation jaa = null;
3277   
3278  555 if (annotation.getGraph())
3279    {
3280  364 float llim = 0, hlim = 0;
3281    // if (autoForView || an[i].isAutoCalculated()) {
3282    // hlim=11f;
3283    // }
3284  364 jaa = new jalview.datamodel.AlignmentAnnotation(
3285    annotation.getLabel(), annotation.getDescription(), anot,
3286    llim, hlim, annotation.getGraphType());
3287   
3288  364 jaa.graphGroup = annotation.getGraphGroup();
3289  364 jaa._linecolour = firstColour;
3290  364 if (annotation.getThresholdLine() != null)
3291    {
3292  30 jaa.setThreshold(new jalview.datamodel.GraphLine(
3293    annotation.getThresholdLine().getValue(),
3294    annotation.getThresholdLine().getLabel(),
3295    new java.awt.Color(
3296    annotation.getThresholdLine().getColour())));
3297   
3298    }
3299  364 if (autoForView || annotation.isAutoCalculated())
3300    {
3301    // Hardwire the symbol display line to ensure that labels for
3302    // histograms are displayed
3303  241 jaa.hasText = true;
3304    }
3305    }
3306    else
3307    {
3308  191 jaa = new jalview.datamodel.AlignmentAnnotation(an[i].getLabel(),
3309    an[i].getDescription(), anot);
3310  191 jaa._linecolour = firstColour;
3311    }
3312    // register new annotation
3313  555 if (an[i].getId() != null)
3314    {
3315  314 annotationIds.put(an[i].getId(), jaa);
3316  314 jaa.annotationId = an[i].getId();
3317    }
3318    // recover sequence association
3319  555 String sequenceRef = an[i].getSequenceRef();
3320  555 if (sequenceRef != null)
3321    {
3322    // from 2.9 sequenceRef is to sequence id (JAL-1781)
3323  203 SequenceI sequence = seqRefIds.get(sequenceRef);
3324  203 if (sequence == null)
3325    {
3326    // in pre-2.9 projects sequence ref is to sequence name
3327  0 sequence = al.findName(sequenceRef);
3328    }
3329  203 if (sequence != null)
3330    {
3331  203 jaa.createSequenceMapping(sequence, 1, true);
3332  203 sequence.addAlignmentAnnotation(jaa);
3333    }
3334    }
3335    // and make a note of any group association
3336  555 if (an[i].getGroupRef() != null && an[i].getGroupRef().length() > 0)
3337    {
3338  36 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3339    .get(an[i].getGroupRef());
3340  36 if (aal == null)
3341    {
3342  36 aal = new ArrayList<>();
3343  36 groupAnnotRefs.put(an[i].getGroupRef(), aal);
3344    }
3345  36 aal.add(jaa);
3346    }
3347   
3348  555 if (an[i].hasScore())
3349    {
3350  139 jaa.setScore(an[i].getScore());
3351    }
3352  555 if (an[i].hasVisible())
3353    {
3354  555 jaa.visible = an[i].getVisible();
3355    }
3356   
3357  555 if (an[i].hasCentreColLabels())
3358    {
3359  555 jaa.centreColLabels = an[i].getCentreColLabels();
3360    }
3361   
3362  555 if (an[i].hasScaleColLabels())
3363    {
3364  555 jaa.scaleColLabel = an[i].getScaleColLabels();
3365    }
3366  555 if (an[i].hasAutoCalculated() && an[i].isAutoCalculated())
3367    {
3368    // newer files have an 'autoCalculated' flag and store calculation
3369    // state in viewport properties
3370  241 jaa.autoCalculated = true; // means annotation will be marked for
3371    // update at end of load.
3372    }
3373  555 if (an[i].hasGraphHeight())
3374    {
3375  555 jaa.graphHeight = an[i].getGraphHeight();
3376    }
3377  555 if (an[i].hasBelowAlignment())
3378    {
3379  315 jaa.belowAlignment = an[i].isBelowAlignment();
3380    }
3381  555 jaa.setCalcId(an[i].getCalcId());
3382  555 if (an[i].getPropertyCount() > 0)
3383    {
3384  0 for (jalview.schemabinding.version2.Property prop : an[i]
3385    .getProperty())
3386    {
3387  0 jaa.setProperty(prop.getName(), prop.getValue());
3388    }
3389    }
3390  555 if (jaa.autoCalculated)
3391    {
3392  241 autoAlan.add(new JvAnnotRow(i, jaa));
3393    }
3394    else
3395    // if (!autoForView)
3396    {
3397    // add autocalculated group annotation and any user created annotation
3398    // for the view
3399  314 al.addAnnotation(jaa);
3400    }
3401    }
3402    }
3403    // ///////////////////////
3404    // LOAD GROUPS
3405    // Create alignment markup and styles for this view
3406  82 if (jms.getJGroupCount() > 0)
3407    {
3408  39 JGroup[] groups = jms.getJGroup();
3409  39 boolean addAnnotSchemeGroup = false;
3410  102 for (int i = 0; i < groups.length; i++)
3411    {
3412  63 JGroup jGroup = groups[i];
3413  63 ColourSchemeI cs = null;
3414  63 if (jGroup.getColour() != null)
3415    {
3416  27 if (jGroup.getColour().startsWith("ucs"))
3417    {
3418  0 cs = getUserColourScheme(jms, jGroup.getColour());
3419    }
3420  27 else if (jGroup.getColour().equals("AnnotationColourGradient")
3421    && jGroup.getAnnotationColours() != null)
3422    {
3423  1 addAnnotSchemeGroup = true;
3424    }
3425    else
3426    {
3427  26 cs = ColourSchemeProperty.getColourScheme(al,
3428    jGroup.getColour());
3429    }
3430    }
3431  63 int pidThreshold = jGroup.getPidThreshold();
3432   
3433  63 Vector<SequenceI> seqs = new Vector<>();
3434   
3435  547 for (int s = 0; s < jGroup.getSeqCount(); s++)
3436    {
3437  484 String seqId = jGroup.getSeq(s) + "";
3438  484 SequenceI ts = seqRefIds.get(seqId);
3439   
3440  484 if (ts != null)
3441    {
3442  484 seqs.addElement(ts);
3443    }
3444    }
3445   
3446  63 if (seqs.size() < 1)
3447    {
3448  0 continue;
3449    }
3450   
3451  63 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3452    jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
3453    jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
3454  63 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3455  63 sg.getGroupColourScheme()
3456    .setConservationInc(jGroup.getConsThreshold());
3457  63 sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
3458   
3459  63 sg.textColour = new java.awt.Color(jGroup.getTextCol1());
3460  63 sg.textColour2 = new java.awt.Color(jGroup.getTextCol2());
3461  63 sg.setShowNonconserved(
3462  63 jGroup.hasShowUnconserved() ? jGroup.isShowUnconserved()
3463    : false);
3464  63 sg.thresholdTextColour = jGroup.getTextColThreshold();
3465  63 if (jGroup.hasShowConsensusHistogram())
3466    {
3467  63 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3468    }
3469  63 ;
3470  63 if (jGroup.hasShowSequenceLogo())
3471    {
3472  63 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3473    }
3474  63 if (jGroup.hasNormaliseSequenceLogo())
3475    {
3476  13 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3477    }
3478  63 if (jGroup.hasIgnoreGapsinConsensus())
3479    {
3480  63 sg.setIgnoreGapsConsensus(jGroup.getIgnoreGapsinConsensus());
3481    }
3482  63 if (jGroup.getConsThreshold() != 0)
3483    {
3484  2 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3485    sg.getWidth() - 1);
3486  2 c.calculate();
3487  2 c.verdict(false, 25);
3488  2 sg.cs.setConservation(c);
3489    }
3490   
3491  63 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3492    {
3493    // re-instate unique group/annotation row reference
3494  36 List<AlignmentAnnotation> jaal = groupAnnotRefs
3495    .get(jGroup.getId());
3496  36 if (jaal != null)
3497    {
3498  36 for (AlignmentAnnotation jaa : jaal)
3499    {
3500  36 jaa.groupRef = sg;
3501  36 if (jaa.autoCalculated)
3502    {
3503    // match up and try to set group autocalc alignment row for this
3504    // annotation
3505  36 if (jaa.label.startsWith("Consensus for "))
3506    {
3507  36 sg.setConsensus(jaa);
3508    }
3509    // match up and try to set group autocalc alignment row for this
3510    // annotation
3511  36 if (jaa.label.startsWith("Conservation for "))
3512    {
3513  0 sg.setConservationRow(jaa);
3514    }
3515    }
3516    }
3517    }
3518    }
3519  63 al.addGroup(sg);
3520  63 if (addAnnotSchemeGroup)
3521    {
3522    // reconstruct the annotation colourscheme
3523  1 sg.setColourScheme(constructAnnotationColour(
3524    jGroup.getAnnotationColours(), null, al, jms, false));
3525    }
3526    }
3527    }
3528  82 if (view == null)
3529    {
3530    // only dataset in this model, so just return.
3531  10 return null;
3532    }
3533    // ///////////////////////////////
3534    // LOAD VIEWPORT
3535   
3536    // If we just load in the same jar file again, the sequenceSetId
3537    // will be the same, and we end up with multiple references
3538    // to the same sequenceSet. We must modify this id on load
3539    // so that each load of the file gives a unique id
3540  72 String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3541  72 String viewId = (view.getId() == null ? null
3542    : view.getId() + uniqueSetSuffix);
3543  72 AlignFrame af = null;
3544  72 AlignViewport av = null;
3545    // now check to see if we really need to create a new viewport.
3546  72 if (multipleView && viewportsAdded.size() == 0)
3547    {
3548    // We recovered an alignment for which a viewport already exists.
3549    // TODO: fix up any settings necessary for overlaying stored state onto
3550    // state recovered from another document. (may not be necessary).
3551    // we may need a binding from a viewport in memory to one recovered from
3552    // XML.
3553    // and then recover its containing af to allow the settings to be applied.
3554    // TODO: fix for vamsas demo
3555  0 System.err.println(
3556    "About to recover a viewport for existing alignment: Sequence set ID is "
3557    + uniqueSeqSetId);
3558  0 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3559  0 if (seqsetobj != null)
3560    {
3561  0 if (seqsetobj instanceof String)
3562    {
3563  0 uniqueSeqSetId = (String) seqsetobj;
3564  0 System.err.println(
3565    "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3566    + uniqueSeqSetId);
3567    }
3568    else
3569    {
3570  0 System.err.println(
3571    "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3572    }
3573   
3574    }
3575    }
3576    /**
3577    * indicate that annotation colours are applied across all groups (pre
3578    * Jalview 2.8.1 behaviour)
3579    */
3580  72 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3581    object.getVersion());
3582   
3583  72 AlignmentPanel ap = null;
3584  72 boolean isnewview = true;
3585  72 if (viewId != null)
3586    {
3587    // Check to see if this alignment already has a view id == viewId
3588  69 jalview.gui.AlignmentPanel views[] = Desktop
3589    .getAlignmentPanels(uniqueSeqSetId);
3590  69 if (views != null && views.length > 0)
3591    {
3592  170 for (int v = 0; v < views.length; v++)
3593    {
3594  121 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
3595    {
3596    // recover the existing alignpanel, alignframe, viewport
3597  0 af = views[v].alignFrame;
3598  0 av = views[v].av;
3599  0 ap = views[v];
3600    // TODO: could even skip resetting view settings if we don't want to
3601    // change the local settings from other jalview processes
3602  0 isnewview = false;
3603    }
3604    }
3605    }
3606    }
3607   
3608  72 if (isnewview)
3609    {
3610  72 af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
3611    uniqueSeqSetId, viewId, autoAlan);
3612  72 av = af.viewport;
3613  72 ap = af.alignPanel;
3614    }
3615   
3616    /*
3617    * Load any trees, PDB structures and viewers
3618    *
3619    * Not done if flag is false (when this method is used for New View)
3620    */
3621  72 if (loadTreesAndStructures)
3622    {
3623  69 loadTrees(jms, view, af, av, ap);
3624  69 loadPDBStructures(jprovider, jseqs, af, ap);
3625  69 loadRnaViewers(jprovider, jseqs, ap);
3626    }
3627    // and finally return.
3628  72 return af;
3629    }
3630   
3631    /**
3632    * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
3633    * panel is restored from separate jar entries, two (gapped and trimmed) per
3634    * sequence and secondary structure.
3635    *
3636    * Currently each viewer shows just one sequence and structure (gapped and
3637    * trimmed), however this method is designed to support multiple sequences or
3638    * structures in viewers if wanted in future.
3639    *
3640    * @param jprovider
3641    * @param jseqs
3642    * @param ap
3643    */
 
3644  69 toggle private void loadRnaViewers(jarInputStreamProvider jprovider,
3645    JSeq[] jseqs, AlignmentPanel ap)
3646    {
3647    /*
3648    * scan the sequences for references to viewers; create each one the first
3649    * time it is referenced, add Rna models to existing viewers
3650    */
3651  69 for (JSeq jseq : jseqs)
3652    {
3653  1104 for (int i = 0; i < jseq.getRnaViewerCount(); i++)
3654    {
3655  0 RnaViewer viewer = jseq.getRnaViewer(i);
3656  0 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
3657    ap);
3658   
3659  0 for (int j = 0; j < viewer.getSecondaryStructureCount(); j++)
3660    {
3661  0 SecondaryStructure ss = viewer.getSecondaryStructure(j);
3662  0 SequenceI seq = seqRefIds.get(jseq.getId());
3663  0 AlignmentAnnotation ann = this.annotationIds
3664    .get(ss.getAnnotationId());
3665   
3666    /*
3667    * add the structure to the Varna display (with session state copied
3668    * from the jar to a temporary file)
3669    */
3670  0 boolean gapped = ss.isGapped();
3671  0 String rnaTitle = ss.getTitle();
3672  0 String sessionState = ss.getViewerState();
3673  0 String tempStateFile = copyJarEntry(jprovider, sessionState,
3674    "varna", null);
3675  0 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
3676  0 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
3677    }
3678  0 appVarna.setInitialSelection(viewer.getSelectedRna());
3679    }
3680    }
3681    }
3682   
3683    /**
3684    * Locate and return an already instantiated matching AppVarna, or create one
3685    * if not found
3686    *
3687    * @param viewer
3688    * @param viewIdSuffix
3689    * @param ap
3690    * @return
3691    */
 
3692  0 toggle protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
3693    String viewIdSuffix, AlignmentPanel ap)
3694    {
3695    /*
3696    * on each load a suffix is appended to the saved viewId, to avoid conflicts
3697    * if load is repeated
3698    */
3699  0 String postLoadId = viewer.getViewId() + viewIdSuffix;
3700  0 for (JInternalFrame frame : getAllFrames())
3701    {
3702  0 if (frame instanceof AppVarna)
3703    {
3704  0 AppVarna varna = (AppVarna) frame;
3705  0 if (postLoadId.equals(varna.getViewId()))
3706    {
3707    // this viewer is already instantiated
3708    // could in future here add ap as another 'parent' of the
3709    // AppVarna window; currently just 1-to-many
3710  0 return varna;
3711    }
3712    }
3713    }
3714   
3715    /*
3716    * viewer not found - make it
3717    */
3718  0 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
3719    viewer.getXpos(), viewer.getYpos(), viewer.getWidth(),
3720    viewer.getHeight(), viewer.getDividerLocation());
3721  0 AppVarna varna = new AppVarna(model, ap);
3722   
3723  0 return varna;
3724    }
3725   
3726    /**
3727    * Load any saved trees
3728    *
3729    * @param jms
3730    * @param view
3731    * @param af
3732    * @param av
3733    * @param ap
3734    */
 
3735  69 toggle protected void loadTrees(JalviewModelSequence jms, Viewport view,
3736    AlignFrame af, AlignViewport av, AlignmentPanel ap)
3737    {
3738    // TODO result of automated refactoring - are all these parameters needed?
3739  69 try
3740    {
3741  81 for (int t = 0; t < jms.getTreeCount(); t++)
3742    {
3743   
3744  12 Tree tree = jms.getTree(t);
3745   
3746  12 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
3747  12 if (tp == null)
3748    {
3749  12 tp = af.showNewickTree(
3750    new jalview.io.NewickFile(tree.getNewick()),
3751    tree.getTitle(), tree.getWidth(), tree.getHeight(),
3752    tree.getXpos(), tree.getYpos());
3753  12 if (tree.getId() != null)
3754    {
3755    // perhaps bind the tree id to something ?
3756    }
3757    }
3758    else
3759    {
3760    // update local tree attributes ?
3761    // TODO: should check if tp has been manipulated by user - if so its
3762    // settings shouldn't be modified
3763  0 tp.setTitle(tree.getTitle());
3764  0 tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
3765    tree.getWidth(), tree.getHeight()));
3766  0 tp.av = av; // af.viewport; // TODO: verify 'associate with all
3767    // views'
3768    // works still
3769  0 tp.treeCanvas.av = av; // af.viewport;
3770  0 tp.treeCanvas.ap = ap; // af.alignPanel;
3771   
3772    }
3773  12 if (tp == null)
3774    {
3775  0 warn("There was a problem recovering stored Newick tree: \n"
3776    + tree.getNewick());
3777  0 continue;
3778    }
3779   
3780  12 tp.fitToWindow.setState(tree.getFitToWindow());
3781  12 tp.fitToWindow_actionPerformed(null);
3782   
3783  12 if (tree.getFontName() != null)
3784    {
3785  12 tp.setTreeFont(new java.awt.Font(tree.getFontName(),
3786    tree.getFontStyle(), tree.getFontSize()));
3787    }
3788    else
3789    {
3790  0 tp.setTreeFont(new java.awt.Font(view.getFontName(),
3791    view.getFontStyle(), tree.getFontSize()));
3792    }
3793   
3794  12 tp.showPlaceholders(tree.getMarkUnlinked());
3795  12 tp.showBootstrap(tree.getShowBootstrap());
3796  12 tp.showDistances(tree.getShowDistances());
3797   
3798  12 tp.treeCanvas.threshold = tree.getThreshold();
3799   
3800  12 if (tree.getCurrentTree())
3801    {
3802  12 af.viewport.setCurrentTree(tp.getTree());
3803    }
3804    }
3805   
3806    } catch (Exception ex)
3807    {
3808  0 ex.printStackTrace();
3809    }
3810    }
3811   
3812    /**
3813    * Load and link any saved structure viewers.
3814    *
3815    * @param jprovider
3816    * @param jseqs
3817    * @param af
3818    * @param ap
3819    */
 
3820  69 toggle protected void loadPDBStructures(jarInputStreamProvider jprovider,
3821    JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
3822    {
3823    /*
3824    * Run through all PDB ids on the alignment, and collect mappings between
3825    * distinct view ids and all sequences referring to that view.
3826    */
3827  69 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
3828   
3829  1173 for (int i = 0; i < jseqs.length; i++)
3830    {
3831  1104 if (jseqs[i].getPdbidsCount() > 0)
3832    {
3833  187 Pdbids[] ids = jseqs[i].getPdbids();
3834  374 for (int p = 0; p < ids.length; p++)
3835    {
3836  187 final int structureStateCount = ids[p].getStructureStateCount();
3837  307 for (int s = 0; s < structureStateCount; s++)
3838    {
3839    // check to see if we haven't already created this structure view
3840  120 final StructureState structureState = ids[p]
3841    .getStructureState(s);
3842  120 String sviewid = (structureState.getViewId() == null) ? null
3843    : structureState.getViewId() + uniqueSetSuffix;
3844  120 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
3845    // Originally : ids[p].getFile()
3846    // : TODO: verify external PDB file recovery still works in normal
3847    // jalview project load
3848  120 jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
3849    ids[p].getFile()));
3850  120 jpdb.setId(ids[p].getId());
3851   
3852  120 int x = structureState.getXpos();
3853  120 int y = structureState.getYpos();
3854  120 int width = structureState.getWidth();
3855  120 int height = structureState.getHeight();
3856   
3857    // Probably don't need to do this anymore...
3858    // Desktop.desktop.getComponentAt(x, y);
3859    // TODO: NOW: check that this recovers the PDB file correctly.
3860  120 String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
3861    ids[p].getFile());
3862  120 jalview.datamodel.SequenceI seq = seqRefIds
3863    .get(jseqs[i].getId() + "");
3864  120 if (sviewid == null)
3865    {
3866  0 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
3867    + height;
3868    }
3869  120 if (!structureViewers.containsKey(sviewid))
3870    {
3871  60 structureViewers.put(sviewid,
3872    new StructureViewerModel(x, y, width, height, false,
3873    false, true, structureState.getViewId(),
3874    structureState.getType()));
3875    // Legacy pre-2.7 conversion JAL-823 :
3876    // do not assume any view has to be linked for colour by
3877    // sequence
3878    }
3879   
3880    // assemble String[] { pdb files }, String[] { id for each
3881    // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
3882    // seqs_file 2}, boolean[] {
3883    // linkAlignPanel,superposeWithAlignpanel}} from hash
3884  120 StructureViewerModel jmoldat = structureViewers.get(sviewid);
3885  120 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
3886  120 | (structureState.hasAlignwithAlignPanel()
3887    ? structureState.getAlignwithAlignPanel()
3888    : false));
3889   
3890    /*
3891    * Default colour by linked panel to false if not specified (e.g.
3892    * for pre-2.7 projects)
3893    */
3894  120 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
3895  120 colourWithAlignPanel |= (structureState
3896    .hasColourwithAlignPanel()
3897    ? structureState.getColourwithAlignPanel()
3898    : false);
3899  120 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
3900   
3901    /*
3902    * Default colour by viewer to true if not specified (e.g. for
3903    * pre-2.7 projects)
3904    */
3905  120 boolean colourByViewer = jmoldat.isColourByViewer();
3906  120 colourByViewer &= structureState.hasColourByJmol()
3907    ? structureState.getColourByJmol()
3908    : true;
3909  120 jmoldat.setColourByViewer(colourByViewer);
3910   
3911  120 if (jmoldat.getStateData().length() < structureState
3912    .getContent().length())
3913    {
3914    {
3915  50 jmoldat.setStateData(structureState.getContent());
3916    }
3917    }
3918  120 if (ids[p].getFile() != null)
3919    {
3920  120 File mapkey = new File(ids[p].getFile());
3921  120 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
3922  120 if (seqstrmaps == null)
3923    {
3924  60 jmoldat.getFileData().put(mapkey,
3925    seqstrmaps = jmoldat.new StructureData(pdbFile,
3926    ids[p].getId()));
3927    }
3928  120 if (!seqstrmaps.getSeqList().contains(seq))
3929    {
3930  120 seqstrmaps.getSeqList().add(seq);
3931    // TODO and chains?
3932    }
3933    }
3934    else
3935    {
3936  0 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");
3937  0 warn(errorMessage);
3938    }
3939    }
3940    }
3941    }
3942    }
3943    // Instantiate the associated structure views
3944  69 for (Entry<String, StructureViewerModel> entry : structureViewers
3945    .entrySet())
3946    {
3947  60 try
3948    {
3949  60 createOrLinkStructureViewer(entry, af, ap, jprovider);
3950    } catch (Exception e)
3951    {
3952  0 System.err.println(
3953    "Error loading structure viewer: " + e.getMessage());
3954    // failed - try the next one
3955    }
3956    }
3957    }
3958   
3959    /**
3960    *
3961    * @param viewerData
3962    * @param af
3963    * @param ap
3964    * @param jprovider
3965    */
 
3966  60 toggle protected void createOrLinkStructureViewer(
3967    Entry<String, StructureViewerModel> viewerData, AlignFrame af,
3968    AlignmentPanel ap, jarInputStreamProvider jprovider)
3969    {
3970  60 final StructureViewerModel stateData = viewerData.getValue();
3971   
3972    /*
3973    * Search for any viewer windows already open from other alignment views
3974    * that exactly match the stored structure state
3975    */
3976  60 StructureViewerBase comp = findMatchingViewer(viewerData);
3977   
3978  60 if (comp != null)
3979    {
3980  52 linkStructureViewer(ap, comp, stateData);
3981  52 return;
3982    }
3983   
3984    /*
3985    * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
3986    * "viewer_"+stateData.viewId
3987    */
3988  8 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
3989    {
3990  0 createChimeraViewer(viewerData, af, jprovider);
3991    }
3992    else
3993    {
3994    /*
3995    * else Jmol (if pre-2.9, stateData contains JMOL state string)
3996    */
3997  8 createJmolViewer(viewerData, af, jprovider);
3998    }
3999    }
4000   
4001    /**
4002    * Create a new Chimera viewer.
4003    *
4004    * @param data
4005    * @param af
4006    * @param jprovider
4007    */
 
4008  0 toggle protected void createChimeraViewer(
4009    Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4010    jarInputStreamProvider jprovider)
4011    {
4012  0 StructureViewerModel data = viewerData.getValue();
4013  0 String chimeraSessionFile = data.getStateData();
4014   
4015    /*
4016    * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4017    *
4018    * NB this is the 'saved' viewId as in the project file XML, _not_ the
4019    * 'uniquified' sviewid used to reconstruct the viewer here
4020    */
4021  0 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4022  0 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4023    "chimera", null);
4024   
4025  0 Set<Entry<File, StructureData>> fileData = data.getFileData()
4026    .entrySet();
4027  0 List<PDBEntry> pdbs = new ArrayList<>();
4028  0 List<SequenceI[]> allseqs = new ArrayList<>();
4029  0 for (Entry<File, StructureData> pdb : fileData)
4030    {
4031  0 String filePath = pdb.getValue().getFilePath();
4032  0 String pdbId = pdb.getValue().getPdbId();
4033    // pdbs.add(new PDBEntry(filePath, pdbId));
4034  0 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4035  0 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4036  0 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4037  0 allseqs.add(seqs);
4038    }
4039   
4040  0 boolean colourByChimera = data.isColourByViewer();
4041  0 boolean colourBySequence = data.isColourWithAlignPanel();
4042   
4043    // TODO use StructureViewer as a factory here, see JAL-1761
4044  0 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4045  0 final SequenceI[][] seqsArray = allseqs
4046    .toArray(new SequenceI[allseqs.size()][]);
4047  0 String newViewId = viewerData.getKey();
4048   
4049  0 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4050    af.alignPanel, pdbArray, seqsArray, colourByChimera,
4051    colourBySequence, newViewId);
4052  0 cvf.setSize(data.getWidth(), data.getHeight());
4053  0 cvf.setLocation(data.getX(), data.getY());
4054    }
4055   
4056    /**
4057    * Create a new Jmol window. First parse the Jmol state to translate filenames
4058    * loaded into the view, and record the order in which files are shown in the
4059    * Jmol view, so we can add the sequence mappings in same order.
4060    *
4061    * @param viewerData
4062    * @param af
4063    * @param jprovider
4064    */
 
4065  8 toggle protected void createJmolViewer(
4066    final Entry<String, StructureViewerModel> viewerData,
4067    AlignFrame af, jarInputStreamProvider jprovider)
4068    {
4069  8 final StructureViewerModel svattrib = viewerData.getValue();
4070  8 String state = svattrib.getStateData();
4071   
4072    /*
4073    * Pre-2.9: state element value is the Jmol state string
4074    *
4075    * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4076    * + viewId
4077    */
4078  8 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4079    {
4080  2 state = readJarEntry(jprovider,
4081    getViewerJarEntryName(svattrib.getViewId()));
4082    }
4083   
4084  8 List<String> pdbfilenames = new ArrayList<>();
4085  8 List<SequenceI[]> seqmaps = new ArrayList<>();
4086  8 List<String> pdbids = new ArrayList<>();
4087  8 StringBuilder newFileLoc = new StringBuilder(64);
4088  8 int cp = 0, ncp, ecp;
4089  8 Map<File, StructureData> oldFiles = svattrib.getFileData();
4090  ? while ((ncp = state.indexOf("load ", cp)) > -1)
4091    {
4092  8 do
4093    {
4094    // look for next filename in load statement
4095  8 newFileLoc.append(state.substring(cp,
4096    ncp = (state.indexOf("\"", ncp + 1) + 1)));
4097  8 String oldfilenam = state.substring(ncp,
4098    ecp = state.indexOf("\"", ncp));
4099    // recover the new mapping data for this old filename
4100    // have to normalize filename - since Jmol and jalview do
4101    // filename
4102    // translation differently.
4103  8 StructureData filedat = oldFiles.get(new File(oldfilenam));
4104  8 if (filedat == null)
4105    {
4106  0 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4107  0 filedat = oldFiles.get(new File(reformatedOldFilename));
4108    }
4109  8 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4110  8 pdbfilenames.add(filedat.getFilePath());
4111  8 pdbids.add(filedat.getPdbId());
4112  8 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4113  8 newFileLoc.append("\"");
4114  8 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4115    // look for next file statement.
4116  ? } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4117    }
4118  8 if (cp > 0)
4119    {
4120    // just append rest of state
4121  8 newFileLoc.append(state.substring(cp));
4122    }
4123    else
4124    {
4125  0 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4126  0 newFileLoc = new StringBuilder(state);
4127  0 newFileLoc.append("; load append ");
4128  0 for (File id : oldFiles.keySet())
4129    {
4130    // add this and any other pdb files that should be present in
4131    // the viewer
4132  0 StructureData filedat = oldFiles.get(id);
4133  0 newFileLoc.append(filedat.getFilePath());
4134  0 pdbfilenames.add(filedat.getFilePath());
4135  0 pdbids.add(filedat.getPdbId());
4136  0 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4137  0 newFileLoc.append(" \"");
4138  0 newFileLoc.append(filedat.getFilePath());
4139  0 newFileLoc.append("\"");
4140   
4141    }
4142  0 newFileLoc.append(";");
4143    }
4144   
4145  8 if (newFileLoc.length() == 0)
4146    {
4147  0 return;
4148    }
4149  8 int histbug = newFileLoc.indexOf("history = ");
4150  8 if (histbug > -1)
4151    {
4152    /*
4153    * change "history = [true|false];" to "history = [1|0];"
4154    */
4155  0 histbug += 10;
4156  0 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4157  0 String val = (diff == -1) ? null
4158    : newFileLoc.substring(histbug, diff);
4159  0 if (val != null && val.length() >= 4)
4160    {
4161  0 if (val.contains("e")) // eh? what can it be?
4162    {
4163  0 if (val.trim().equals("true"))
4164    {
4165  0 val = "1";
4166    }
4167    else
4168    {
4169  0 val = "0";
4170    }
4171  0 newFileLoc.replace(histbug, diff, val);
4172    }
4173    }
4174    }
4175   
4176  8 final String[] pdbf = pdbfilenames
4177    .toArray(new String[pdbfilenames.size()]);
4178  8 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4179  8 final SequenceI[][] sq = seqmaps
4180    .toArray(new SequenceI[seqmaps.size()][]);
4181  8 final String fileloc = newFileLoc.toString();
4182  8 final String sviewid = viewerData.getKey();
4183  8 final AlignFrame alf = af;
4184  8 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4185    svattrib.getWidth(), svattrib.getHeight());
4186  8 try
4187    {
4188  8 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4189    {
 
4190  8 toggle @Override
4191    public void run()
4192    {
4193  8 JalviewStructureDisplayI sview = null;
4194  8 try
4195    {
4196  8 sview = new StructureViewer(
4197    alf.alignPanel.getStructureSelectionManager())
4198    .createView(StructureViewer.ViewerType.JMOL,
4199    pdbf, id, sq, alf.alignPanel, svattrib,
4200    fileloc, rect, sviewid);
4201  8 addNewStructureViewer(sview);
4202    } catch (OutOfMemoryError ex)
4203    {
4204  0 new OOMWarning("restoring structure view for PDB id " + id,
4205    (OutOfMemoryError) ex.getCause());
4206  0 if (sview != null && sview.isVisible())
4207    {
4208  0 sview.closeViewer(false);
4209  0 sview.setVisible(false);
4210  0 sview.dispose();
4211    }
4212    }
4213    }
4214    });
4215    } catch (InvocationTargetException ex)
4216    {
4217  0 warn("Unexpected error when opening Jmol view.", ex);
4218   
4219    } catch (InterruptedException e)
4220    {
4221    // e.printStackTrace();
4222    }
4223   
4224    }
4225   
4226    /**
4227    * Generates a name for the entry in the project jar file to hold state
4228    * information for a structure viewer
4229    *
4230    * @param viewId
4231    * @return
4232    */
 
4233  4 toggle protected String getViewerJarEntryName(String viewId)
4234    {
4235  4 return VIEWER_PREFIX + viewId;
4236    }
4237   
4238    /**
4239    * Returns any open frame that matches given structure viewer data. The match
4240    * is based on the unique viewId, or (for older project versions) the frame's
4241    * geometry.
4242    *
4243    * @param viewerData
4244    * @return
4245    */
 
4246  60 toggle protected StructureViewerBase findMatchingViewer(
4247    Entry<String, StructureViewerModel> viewerData)
4248    {
4249  60 final String sviewid = viewerData.getKey();
4250  60 final StructureViewerModel svattrib = viewerData.getValue();
4251  60 StructureViewerBase comp = null;
4252  60 JInternalFrame[] frames = getAllFrames();
4253  60 for (JInternalFrame frame : frames)
4254    {
4255  345 if (frame instanceof StructureViewerBase)
4256    {
4257    /*
4258    * Post jalview 2.4 schema includes structure view id
4259    */
4260  52 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4261    .equals(sviewid))
4262    {
4263  32 comp = (StructureViewerBase) frame;
4264  32 break; // break added in 2.9
4265    }
4266    /*
4267    * Otherwise test for matching position and size of viewer frame
4268    */
4269  20 else if (frame.getX() == svattrib.getX()
4270    && frame.getY() == svattrib.getY()
4271    && frame.getHeight() == svattrib.getHeight()
4272    && frame.getWidth() == svattrib.getWidth())
4273    {
4274  20 comp = (StructureViewerBase) frame;
4275    // no break in faint hope of an exact match on viewId
4276    }
4277    }
4278    }
4279  60 return comp;
4280    }
4281   
4282    /**
4283    * Link an AlignmentPanel to an existing structure viewer.
4284    *
4285    * @param ap
4286    * @param viewer
4287    * @param oldFiles
4288    * @param useinViewerSuperpos
4289    * @param usetoColourbyseq
4290    * @param viewerColouring
4291    */
 
4292  52 toggle protected void linkStructureViewer(AlignmentPanel ap,
4293    StructureViewerBase viewer, StructureViewerModel stateData)
4294    {
4295    // NOTE: if the jalview project is part of a shared session then
4296    // view synchronization should/could be done here.
4297   
4298  52 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4299  52 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4300  52 final boolean viewerColouring = stateData.isColourByViewer();
4301  52 Map<File, StructureData> oldFiles = stateData.getFileData();
4302   
4303    /*
4304    * Add mapping for sequences in this view to an already open viewer
4305    */
4306  52 final AAStructureBindingModel binding = viewer.getBinding();
4307  52 for (File id : oldFiles.keySet())
4308    {
4309    // add this and any other pdb files that should be present in the
4310    // viewer
4311  52 StructureData filedat = oldFiles.get(id);
4312  52 String pdbFile = filedat.getFilePath();
4313  52 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4314  52 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4315    null);
4316  52 binding.addSequenceForStructFile(pdbFile, seq);
4317    }
4318    // and add the AlignmentPanel's reference to the view panel
4319  52 viewer.addAlignmentPanel(ap);
4320  52 if (useinViewerSuperpos)
4321    {
4322  0 viewer.useAlignmentPanelForSuperposition(ap);
4323    }
4324    else
4325    {
4326  52 viewer.excludeAlignmentPanelForSuperposition(ap);
4327    }
4328  52 if (usetoColourbyseq)
4329    {
4330  12 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4331    }
4332    else
4333    {
4334  40 viewer.excludeAlignmentPanelForColourbyseq(ap);
4335    }
4336    }
4337   
4338    /**
4339    * Get all frames within the Desktop.
4340    *
4341    * @return
4342    */
 
4343  60 toggle protected JInternalFrame[] getAllFrames()
4344    {
4345  60 JInternalFrame[] frames = null;
4346    // TODO is this necessary - is it safe - risk of hanging?
4347  60 do
4348    {
4349  60 try
4350    {
4351  60 frames = Desktop.desktop.getAllFrames();
4352    } catch (ArrayIndexOutOfBoundsException e)
4353    {
4354    // occasional No such child exceptions are thrown here...
4355  0 try
4356    {
4357  0 Thread.sleep(10);
4358    } catch (InterruptedException f)
4359    {
4360    }
4361    }
4362  60 } while (frames == null);
4363  60 return frames;
4364    }
4365   
4366    /**
4367    * Answers true if 'version' is equal to or later than 'supported', where each
4368    * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4369    * changes. Development and test values for 'version' are leniently treated
4370    * i.e. answer true.
4371    *
4372    * @param supported
4373    * - minimum version we are comparing against
4374    * @param version
4375    * - version of data being processsed
4376    * @return
4377    */
 
4378  99 toggle public static boolean isVersionStringLaterThan(String supported,
4379    String version)
4380    {
4381  99 if (supported == null || version == null
4382    || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4383    || version.equalsIgnoreCase("Test")
4384    || version.equalsIgnoreCase("AUTOMATED BUILD"))
4385    {
4386  34 System.err.println("Assuming project file with "
4387  34 + (version == null ? "null" : version)
4388    + " is compatible with Jalview version " + supported);
4389  34 return true;
4390    }
4391    else
4392    {
4393  65 return StringUtils.compareVersions(version, supported, "b") >= 0;
4394    }
4395    }
4396   
4397    Vector<JalviewStructureDisplayI> newStructureViewers = null;
4398   
 
4399  8 toggle protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4400    {
4401  8 if (newStructureViewers != null)
4402    {
4403  8 sview.getBinding().setFinishedLoadingFromArchive(false);
4404  8 newStructureViewers.add(sview);
4405    }
4406    }
4407   
 
4408  20 toggle protected void setLoadingFinishedForNewStructureViewers()
4409    {
4410  20 if (newStructureViewers != null)
4411    {
4412  20 for (JalviewStructureDisplayI sview : newStructureViewers)
4413    {
4414  8 sview.getBinding().setFinishedLoadingFromArchive(true);
4415    }
4416  20 newStructureViewers.clear();
4417  20 newStructureViewers = null;
4418    }
4419    }
4420   
 
4421  72 toggle AlignFrame loadViewport(String file, JSeq[] JSEQ,
4422    List<SequenceI> hiddenSeqs, AlignmentI al,
4423    JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
4424    String viewId, List<JvAnnotRow> autoAlan)
4425    {
4426  72 AlignFrame af = null;
4427  72 af = new AlignFrame(al, view.getWidth(), view.getHeight(),
4428    uniqueSeqSetId, viewId);
4429   
4430  72 af.setFileName(file, FileFormat.Jalview);
4431   
4432  1207 for (int i = 0; i < JSEQ.length; i++)
4433    {
4434  1135 af.viewport.setSequenceColour(
4435    af.viewport.getAlignment().getSequenceAt(i),
4436    new java.awt.Color(JSEQ[i].getColour()));
4437    }
4438   
4439  72 if (al.hasSeqrep())
4440    {
4441  5 af.getViewport().setColourByReferenceSeq(true);
4442  5 af.getViewport().setDisplayReferenceSeq(true);
4443    }
4444   
4445  72 af.viewport.setGatherViewsHere(view.getGatheredViews());
4446   
4447  72 if (view.getSequenceSetId() != null)
4448    {
4449  72 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4450   
4451  72 af.viewport.setSequenceSetId(uniqueSeqSetId);
4452  72 if (av != null)
4453    {
4454    // propagate shared settings to this new view
4455  49 af.viewport.setHistoryList(av.getHistoryList());
4456  49 af.viewport.setRedoList(av.getRedoList());
4457    }
4458    else
4459    {
4460  23 viewportsAdded.put(uniqueSeqSetId, af.viewport);
4461    }
4462    // TODO: check if this method can be called repeatedly without
4463    // side-effects if alignpanel already registered.
4464  72 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4465    }
4466    // apply Hidden regions to view.
4467  72 if (hiddenSeqs != null)
4468    {
4469  1052 for (int s = 0; s < JSEQ.length; s++)
4470    {
4471  990 SequenceGroup hidden = new SequenceGroup();
4472  990 boolean isRepresentative = false;
4473  992 for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
4474    {
4475  2 isRepresentative = true;
4476  2 SequenceI sequenceToHide = al
4477    .getSequenceAt(JSEQ[s].getHiddenSequences(r));
4478  2 hidden.addSequence(sequenceToHide, false);
4479    // remove from hiddenSeqs list so we don't try to hide it twice
4480  2 hiddenSeqs.remove(sequenceToHide);
4481    }
4482  990 if (isRepresentative)
4483    {
4484  2 SequenceI representativeSequence = al.getSequenceAt(s);
4485  2 hidden.addSequence(representativeSequence, false);
4486  2 af.viewport.hideRepSequences(representativeSequence, hidden);
4487    }
4488    }
4489   
4490  62 SequenceI[] hseqs = hiddenSeqs
4491    .toArray(new SequenceI[hiddenSeqs.size()]);
4492  62 af.viewport.hideSequence(hseqs);
4493   
4494    }
4495    // recover view properties and display parameters
4496   
4497  72 af.viewport.setShowAnnotation(view.getShowAnnotation());
4498  72 af.viewport.setAbovePIDThreshold(view.getPidSelected());
4499  72 af.viewport.setThreshold(view.getPidThreshold());
4500   
4501  72 af.viewport.setColourText(view.getShowColourText());
4502   
4503  72 af.viewport.setConservationSelected(view.getConservationSelected());
4504  72 af.viewport.setIncrement(view.getConsThreshold());
4505  72 af.viewport.setShowJVSuffix(view.getShowFullId());
4506  72 af.viewport.setRightAlignIds(view.getRightAlignIds());
4507  72 af.viewport.setFont(new java.awt.Font(view.getFontName(),
4508    view.getFontStyle(), view.getFontSize()), true);
4509  72 ViewStyleI vs = af.viewport.getViewStyle();
4510  72 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4511  72 af.viewport.setViewStyle(vs);
4512    // TODO: allow custom charWidth/Heights to be restored by updating them
4513    // after setting font - which means set above to false
4514  72 af.viewport.setRenderGaps(view.getRenderGaps());
4515  72 af.viewport.setWrapAlignment(view.getWrapAlignment());
4516  72 af.viewport.setShowAnnotation(view.getShowAnnotation());
4517   
4518  72 af.viewport.setShowBoxes(view.getShowBoxes());
4519   
4520  72 af.viewport.setShowText(view.getShowText());
4521   
4522  72 af.viewport.setTextColour(new java.awt.Color(view.getTextCol1()));
4523  72 af.viewport.setTextColour2(new java.awt.Color(view.getTextCol2()));
4524  72 af.viewport.setThresholdTextColour(view.getTextColThreshold());
4525  72 af.viewport.setShowUnconserved(
4526  72 view.hasShowUnconserved() ? view.isShowUnconserved() : false);
4527  72 af.viewport.getRanges().setStartRes(view.getStartRes());
4528   
4529  72 if (view.getViewName() != null)
4530    {
4531  62 af.viewport.viewName = view.getViewName();
4532  62 af.setInitialTabVisible();
4533    }
4534  72 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
4535    view.getHeight());
4536    // startSeq set in af.alignPanel.updateLayout below
4537  72 af.alignPanel.updateLayout();
4538  72 ColourSchemeI cs = null;
4539    // apply colourschemes
4540  72 if (view.getBgColour() != null)
4541    {
4542  72 if (view.getBgColour().startsWith("ucs"))
4543    {
4544  0 cs = getUserColourScheme(jms, view.getBgColour());
4545    }
4546  72 else if (view.getBgColour().startsWith("Annotation"))
4547    {
4548  1 AnnotationColours viewAnnColour = view.getAnnotationColours();
4549  1 cs = constructAnnotationColour(viewAnnColour, af, al, jms, true);
4550   
4551    // annpos
4552   
4553    }
4554    else
4555    {
4556  71 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4557    }
4558    }
4559   
4560  72 af.viewport.setGlobalColourScheme(cs);
4561  72 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(),
4562    view.getIgnoreGapsinConsensus());
4563  72 af.viewport.getResidueShading()
4564    .setConsensus(af.viewport.getSequenceConsensusHash());
4565  72 af.viewport.setColourAppliesToAllGroups(false);
4566   
4567  72 if (view.getConservationSelected() && cs != null)
4568    {
4569  2 af.viewport.getResidueShading()
4570    .setConservationInc(view.getConsThreshold());
4571    }
4572   
4573  72 af.changeColour(cs);
4574   
4575  72 af.viewport.setColourAppliesToAllGroups(true);
4576   
4577  72 af.viewport.setShowSequenceFeatures(view.getShowSequenceFeatures());
4578   
4579  72 if (view.hasCentreColumnLabels())
4580    {
4581  0 af.viewport.setCentreColumnLabels(view.getCentreColumnLabels());
4582    }
4583  72 if (view.hasIgnoreGapsinConsensus())
4584    {
4585  72 af.viewport.setIgnoreGapsConsensus(view.getIgnoreGapsinConsensus(),
4586    null);
4587    }
4588  72 if (view.hasFollowHighlight())
4589    {
4590  72 af.viewport.setFollowHighlight(view.getFollowHighlight());
4591    }
4592  72 if (view.hasFollowSelection())
4593    {
4594  72 af.viewport.followSelection = view.getFollowSelection();
4595    }
4596  72 if (view.hasShowConsensusHistogram())
4597    {
4598  72 af.viewport
4599    .setShowConsensusHistogram(view.getShowConsensusHistogram());
4600    }
4601    else
4602    {
4603  0 af.viewport.setShowConsensusHistogram(true);
4604    }
4605  72 if (view.hasShowSequenceLogo())
4606    {
4607  72 af.viewport.setShowSequenceLogo(view.getShowSequenceLogo());
4608    }
4609    else
4610    {
4611  0 af.viewport.setShowSequenceLogo(false);
4612    }
4613  72 if (view.hasNormaliseSequenceLogo())
4614    {
4615  22 af.viewport.setNormaliseSequenceLogo(view.getNormaliseSequenceLogo());
4616    }
4617  72 if (view.hasShowDbRefTooltip())
4618    {
4619  72 af.viewport.setShowDBRefs(view.getShowDbRefTooltip());
4620    }
4621  72 if (view.hasShowNPfeatureTooltip())
4622    {
4623  72 af.viewport.setShowNPFeats(view.hasShowNPfeatureTooltip());
4624    }
4625  72 if (view.hasShowGroupConsensus())
4626    {
4627  72 af.viewport.setShowGroupConsensus(view.getShowGroupConsensus());
4628    }
4629    else
4630    {
4631  0 af.viewport.setShowGroupConsensus(false);
4632    }
4633  72 if (view.hasShowGroupConservation())
4634    {
4635  72 af.viewport.setShowGroupConservation(view.getShowGroupConservation());
4636    }
4637    else
4638    {
4639  0 af.viewport.setShowGroupConservation(false);
4640    }
4641   
4642    // recover feature settings
4643  72 if (jms.getFeatureSettings() != null)
4644    {
4645  51 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
4646    .getFeatureRenderer();
4647  51 FeaturesDisplayed fdi;
4648  51 af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4649  51 String[] renderOrder = new String[jms.getFeatureSettings()
4650    .getSettingCount()];
4651  51 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4652  51 Map<String, Float> featureOrder = new Hashtable<>();
4653   
4654  1294 for (int fs = 0; fs < jms.getFeatureSettings()
4655    .getSettingCount(); fs++)
4656    {
4657  1243 Setting setting = jms.getFeatureSettings().getSetting(fs);
4658  1243 String featureType = setting.getType();
4659   
4660    /*
4661    * restore feature filters (if any)
4662    */
4663  1243 MatcherSet filters = setting.getMatcherSet();
4664  1243 if (filters != null)
4665    {
4666  3 FeatureMatcherSetI filter = Jalview2XML
4667    .unmarshalFilter(featureType, filters);
4668  3 if (!filter.isEmpty())
4669    {
4670  3 fr.setFeatureFilter(featureType, filter);
4671    }
4672    }
4673   
4674    /*
4675    * restore feature colour scheme
4676    */
4677  1243 Color maxColour = new Color(setting.getColour());
4678  1243 if (setting.hasMincolour())
4679    {
4680    /*
4681    * minColour is always set unless a simple colour
4682    * (including for colour by label though it doesn't use it)
4683    */
4684  4 Color minColour = new Color(setting.getMincolour());
4685  4 Color noValueColour = minColour;
4686  4 NoValueColour noColour = setting.getNoValueColour();
4687  4 if (noColour == NoValueColour.NONE)
4688    {
4689  2 noValueColour = null;
4690    }
4691  2 else if (noColour == NoValueColour.MAX)
4692    {
4693  0 noValueColour = maxColour;
4694    }
4695  4 float min = setting.hasMin() ? setting.getMin() : 0f;
4696  4 float max = setting.hasMin() ? setting.getMax() : 1f;
4697  4 FeatureColourI gc = new FeatureColour(minColour, maxColour,
4698    noValueColour, min, max);
4699  4 if (setting.getAttributeNameCount() > 0)
4700    {
4701  2 gc.setAttributeName(setting.getAttributeName());
4702    }
4703  4 if (setting.hasThreshold())
4704    {
4705  4 gc.setThreshold(setting.getThreshold());
4706  4 int threshstate = setting.getThreshstate();
4707    // -1 = None, 0 = Below, 1 = Above threshold
4708  4 if (threshstate == 0)
4709    {
4710  1 gc.setBelowThreshold(true);
4711    }
4712  3 else if (threshstate == 1)
4713    {
4714  1 gc.setAboveThreshold(true);
4715    }
4716    }
4717  4 gc.setAutoScaled(true); // default
4718  4 if (setting.hasAutoScale())
4719    {
4720  4 gc.setAutoScaled(setting.getAutoScale());
4721    }
4722  4 if (setting.hasColourByLabel())
4723    {
4724  4 gc.setColourByLabel(setting.getColourByLabel());
4725    }
4726    // and put in the feature colour table.
4727  4 featureColours.put(featureType, gc);
4728    }
4729    else
4730    {
4731  1239 featureColours.put(featureType,
4732    new FeatureColour(maxColour));
4733    }
4734  1243 renderOrder[fs] = featureType;
4735  1243 if (setting.hasOrder())
4736    {
4737  1243 featureOrder.put(featureType, setting.getOrder());
4738    }
4739    else
4740    {
4741  0 featureOrder.put(featureType, new Float(
4742    fs / jms.getFeatureSettings().getSettingCount()));
4743    }
4744  1243 if (setting.getDisplay())
4745    {
4746  355 fdi.setVisible(featureType);
4747    }
4748    }
4749  51 Map<String, Boolean> fgtable = new Hashtable<>();
4750  234 for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
4751    {
4752  183 Group grp = jms.getFeatureSettings().getGroup(gs);
4753  183 fgtable.put(grp.getName(), new Boolean(grp.getDisplay()));
4754    }
4755    // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4756    // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4757    // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4758  51 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4759    fgtable, featureColours, 1.0f, featureOrder);
4760  51 fr.transferSettings(frs);
4761    }
4762   
4763  72 if (view.getHiddenColumnsCount() > 0)
4764    {
4765  60 for (int c = 0; c < view.getHiddenColumnsCount(); c++)
4766    {
4767  36 af.viewport.hideColumns(view.getHiddenColumns(c).getStart(),
4768    view.getHiddenColumns(c).getEnd() // +1
4769    );
4770    }
4771    }
4772  72 if (view.getCalcIdParam() != null)
4773    {
4774  72 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4775    {
4776  0 if (calcIdParam != null)
4777    {
4778  0 if (recoverCalcIdParam(calcIdParam, af.viewport))
4779    {
4780    }
4781    else
4782    {
4783  0 warn("Couldn't recover parameters for "
4784    + calcIdParam.getCalcId());
4785    }
4786    }
4787    }
4788    }
4789  72 af.setMenusFromViewport(af.viewport);
4790  72 af.setTitle(view.getTitle());
4791    // TODO: we don't need to do this if the viewport is aready visible.
4792    /*
4793    * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4794    * has a 'cdna/protein complement' view, in which case save it in order to
4795    * populate a SplitFrame once all views have been read in.
4796    */
4797  72 String complementaryViewId = view.getComplementId();
4798  72 if (complementaryViewId == null)
4799    {
4800  72 Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
4801    view.getHeight());
4802    // recompute any autoannotation
4803  72 af.alignPanel.updateAnnotation(false, true);
4804  72 reorderAutoannotation(af, al, autoAlan);
4805  72 af.alignPanel.alignmentChanged();
4806    }
4807    else
4808    {
4809  0 splitFrameCandidates.put(view, af);
4810    }
4811  72 return af;
4812    }
4813   
4814    /**
4815    * Reads saved data to restore Colour by Annotation settings
4816    *
4817    * @param viewAnnColour
4818    * @param af
4819    * @param al
4820    * @param jms
4821    * @param checkGroupAnnColour
4822    * @return
4823    */
 
4824  2 toggle private ColourSchemeI constructAnnotationColour(
4825    AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
4826    JalviewModelSequence jms, boolean checkGroupAnnColour)
4827    {
4828  2 boolean propagateAnnColour = false;
4829  2 AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
4830  2 if (checkGroupAnnColour && al.getGroups() != null
4831    && al.getGroups().size() > 0)
4832    {
4833    // pre 2.8.1 behaviour
4834    // check to see if we should transfer annotation colours
4835  1 propagateAnnColour = true;
4836  1 for (SequenceGroup sg : al.getGroups())
4837    {
4838  1 if (sg.getColourScheme() instanceof AnnotationColourGradient)
4839    {
4840  1 propagateAnnColour = false;
4841    }
4842    }
4843    }
4844   
4845    /*
4846    * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
4847    */
4848  2 String annotationId = viewAnnColour.getAnnotation();
4849  2 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
4850   
4851    /*
4852    * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
4853    */
4854  2 if (matchedAnnotation == null
4855    && annAlignment.getAlignmentAnnotation() != null)
4856    {
4857  0 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
4858    {
4859  0 if (annotationId
4860    .equals(annAlignment.getAlignmentAnnotation()[i].label))
4861    {
4862  0 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
4863  0 break;
4864    }
4865    }
4866    }
4867  2 if (matchedAnnotation == null)
4868    {
4869  0 System.err.println("Failed to match annotation colour scheme for "
4870    + annotationId);
4871  0 return null;
4872    }
4873  2 if (matchedAnnotation.getThreshold() == null)
4874    {
4875  0 matchedAnnotation.setThreshold(new GraphLine(
4876    viewAnnColour.getThreshold(), "Threshold", Color.black));
4877    }
4878   
4879  2 AnnotationColourGradient cs = null;
4880  2 if (viewAnnColour.getColourScheme().equals("None"))
4881    {
4882  2 cs = new AnnotationColourGradient(matchedAnnotation,
4883    new Color(viewAnnColour.getMinColour()),
4884    new Color(viewAnnColour.getMaxColour()),
4885    viewAnnColour.getAboveThreshold());
4886    }
4887  0 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
4888    {
4889  0 cs = new AnnotationColourGradient(matchedAnnotation,
4890    getUserColourScheme(jms, viewAnnColour.getColourScheme()),
4891    viewAnnColour.getAboveThreshold());
4892    }
4893    else
4894    {
4895  0 cs = new AnnotationColourGradient(matchedAnnotation,
4896    ColourSchemeProperty.getColourScheme(al,
4897    viewAnnColour.getColourScheme()),
4898    viewAnnColour.getAboveThreshold());
4899    }
4900   
4901  2 boolean perSequenceOnly = viewAnnColour.isPerSequence();
4902  2 boolean useOriginalColours = viewAnnColour.isPredefinedColours();
4903  2 cs.setSeqAssociated(perSequenceOnly);
4904  2 cs.setPredefinedColours(useOriginalColours);
4905   
4906  2 if (propagateAnnColour && al.getGroups() != null)
4907    {
4908    // Also use these settings for all the groups
4909  0 for (int g = 0; g < al.getGroups().size(); g++)
4910    {
4911  0 SequenceGroup sg = al.getGroups().get(g);
4912  0 if (sg.getGroupColourScheme() == null)
4913    {
4914  0 continue;
4915    }
4916   
4917  0 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
4918    matchedAnnotation, sg.getColourScheme(),
4919    viewAnnColour.getAboveThreshold());
4920  0 sg.setColourScheme(groupScheme);
4921  0 groupScheme.setSeqAssociated(perSequenceOnly);
4922  0 groupScheme.setPredefinedColours(useOriginalColours);
4923    }
4924    }
4925  2 return cs;
4926    }
4927   
 
4928  72 toggle private void reorderAutoannotation(AlignFrame af, AlignmentI al,
4929    List<JvAnnotRow> autoAlan)
4930    {
4931    // copy over visualization settings for autocalculated annotation in the
4932    // view
4933  72 if (al.getAlignmentAnnotation() != null)
4934    {
4935    /**
4936    * Kludge for magic autoannotation names (see JAL-811)
4937    */
4938  72 String[] magicNames = new String[] { "Consensus", "Quality",
4939    "Conservation" };
4940  72 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
4941  72 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
4942  72 for (String nm : magicNames)
4943    {
4944  216 visan.put(nm, nullAnnot);
4945    }
4946  72 for (JvAnnotRow auan : autoAlan)
4947    {
4948  241 visan.put(auan.template.label
4949  241 + (auan.template.getCalcId() == null ? ""
4950    : "\t" + auan.template.getCalcId()),
4951    auan);
4952    }
4953  72 int hSize = al.getAlignmentAnnotation().length;
4954  72 List<JvAnnotRow> reorder = new ArrayList<>();
4955    // work through any autoCalculated annotation already on the view
4956    // removing it if it should be placed in a different location on the
4957    // annotation panel.
4958  72 List<String> remains = new ArrayList<>(visan.keySet());
4959  624 for (int h = 0; h < hSize; h++)
4960    {
4961  552 jalview.datamodel.AlignmentAnnotation jalan = al
4962    .getAlignmentAnnotation()[h];
4963  552 if (jalan.autoCalculated)
4964    {
4965  321 String k;
4966  321 JvAnnotRow valan = visan.get(k = jalan.label);
4967  321 if (jalan.getCalcId() != null)
4968    {
4969  285 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
4970    }
4971   
4972  321 if (valan != null)
4973    {
4974    // delete the auto calculated row from the alignment
4975  121 al.deleteAnnotation(jalan, false);
4976  121 remains.remove(k);
4977  121 hSize--;
4978  121 h--;
4979  121 if (valan != nullAnnot)
4980    {
4981  121 if (jalan != valan.template)
4982    {
4983    // newly created autoannotation row instance
4984    // so keep a reference to the visible annotation row
4985    // and copy over all relevant attributes
4986  85 if (valan.template.graphHeight >= 0)
4987   
4988    {
4989  85 jalan.graphHeight = valan.template.graphHeight;
4990    }
4991  85 jalan.visible = valan.template.visible;
4992    }
4993  121 reorder.add(new JvAnnotRow(valan.order, jalan));
4994    }
4995    }
4996    }
4997    }
4998    // Add any (possibly stale) autocalculated rows that were not appended to
4999    // the view during construction
5000  72 for (String other : remains)
5001    {
5002  216 JvAnnotRow othera = visan.get(other);
5003  216 if (othera != nullAnnot && othera.template.getCalcId() != null
5004    && othera.template.getCalcId().length() > 0)
5005    {
5006  0 reorder.add(othera);
5007    }
5008    }
5009    // now put the automatic annotation in its correct place
5010  72 int s = 0, srt[] = new int[reorder.size()];
5011  72 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5012  72 for (JvAnnotRow jvar : reorder)
5013    {
5014  121 rws[s] = jvar;
5015  121 srt[s++] = jvar.order;
5016    }
5017  72 reorder.clear();
5018  72 jalview.util.QuickSort.sort(srt, rws);
5019    // and re-insert the annotation at its correct position
5020  72 for (JvAnnotRow jvar : rws)
5021    {
5022  121 al.addAnnotation(jvar.template, jvar.order);
5023    }
5024  72 af.alignPanel.adjustAnnotationHeight();
5025    }
5026    }
5027   
5028    Hashtable skipList = null;
5029   
5030    /**
5031    * TODO remove this method
5032    *
5033    * @param view
5034    * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5035    * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5036    * throw new Error("Implementation Error. No skipList defined for this
5037    * Jalview2XML instance."); } return (AlignFrame)
5038    * skipList.get(view.getSequenceSetId()); }
5039    */
5040   
5041    /**
5042    * Check if the Jalview view contained in object should be skipped or not.
5043    *
5044    * @param object
5045    * @return true if view's sequenceSetId is a key in skipList
5046    */
 
5047  0 toggle private boolean skipViewport(JalviewModel object)
5048    {
5049  0 if (skipList == null)
5050    {
5051  0 return false;
5052    }
5053  0 String id;
5054  0 if (skipList.containsKey(
5055    id = object.getJalviewModelSequence().getViewport()[0]
5056    .getSequenceSetId()))
5057    {
5058  0 if (Cache.log != null && Cache.log.isDebugEnabled())
5059    {
5060  0 Cache.log.debug("Skipping seuqence set id " + id);
5061    }
5062  0 return true;
5063    }
5064  0 return false;
5065    }
5066   
 
5067  0 toggle public void addToSkipList(AlignFrame af)
5068    {
5069  0 if (skipList == null)
5070    {
5071  0 skipList = new Hashtable();
5072    }
5073  0 skipList.put(af.getViewport().getSequenceSetId(), af);
5074    }
5075   
 
5076  0 toggle public void clearSkipList()
5077    {
5078  0 if (skipList != null)
5079    {
5080  0 skipList.clear();
5081  0 skipList = null;
5082    }
5083    }
5084   
 
5085  32 toggle private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5086    boolean ignoreUnrefed)
5087    {
5088  32 jalview.datamodel.AlignmentI ds = getDatasetFor(
5089    vamsasSet.getDatasetId());
5090  32 Vector dseqs = null;
5091  32 if (ds == null)
5092    {
5093    // create a list of new dataset sequences
5094  22 dseqs = new Vector();
5095    }
5096  385 for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
5097    {
5098  353 Sequence vamsasSeq = vamsasSet.getSequence(i);
5099  353 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5100    }
5101    // create a new dataset
5102  32 if (ds == null)
5103    {
5104  22 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5105  22 dseqs.copyInto(dsseqs);
5106  22 ds = new jalview.datamodel.Alignment(dsseqs);
5107  22 debug("Created new dataset " + vamsasSet.getDatasetId()
5108    + " for alignment " + System.identityHashCode(al));
5109  22 addDatasetRef(vamsasSet.getDatasetId(), ds);
5110    }
5111    // set the dataset for the newly imported alignment.
5112  32 if (al.getDataset() == null && !ignoreUnrefed)
5113    {
5114  22 al.setDataset(ds);
5115    }
5116    }
5117   
5118    /**
5119    *
5120    * @param vamsasSeq
5121    * sequence definition to create/merge dataset sequence for
5122    * @param ds
5123    * dataset alignment
5124    * @param dseqs
5125    * vector to add new dataset sequence to
5126    * @param ignoreUnrefed
5127    * - when true, don't create new sequences from vamsasSeq if it's id
5128    * doesn't already have an asssociated Jalview sequence.
5129    * @param vseqpos
5130    * - used to reorder the sequence in the alignment according to the
5131    * vamsasSeq array ordering, to preserve ordering of dataset
5132    */
 
5133  353 toggle private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5134    AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5135    {
5136    // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5137    // xRef Codon Maps
5138  353 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5139  353 boolean reorder = false;
5140  353 SequenceI dsq = null;
5141  353 if (sq != null && sq.getDatasetSequence() != null)
5142    {
5143  31 dsq = sq.getDatasetSequence();
5144    }
5145    else
5146    {
5147  322 reorder = true;
5148    }
5149  353 if (sq == null && ignoreUnrefed)
5150    {
5151  0 return;
5152    }
5153  353 String sqid = vamsasSeq.getDsseqid();
5154  353 if (dsq == null)
5155    {
5156    // need to create or add a new dataset sequence reference to this sequence
5157  322 if (sqid != null)
5158    {
5159  322 dsq = seqRefIds.get(sqid);
5160    }
5161    // check again
5162  322 if (dsq == null)
5163    {
5164    // make a new dataset sequence
5165  161 dsq = sq.createDatasetSequence();
5166  161 if (sqid == null)
5167    {
5168    // make up a new dataset reference for this sequence
5169  0 sqid = seqHash(dsq);
5170    }
5171  161 dsq.setVamsasId(uniqueSetSuffix + sqid);
5172  161 seqRefIds.put(sqid, dsq);
5173  161 if (ds == null)
5174    {
5175  161 if (dseqs != null)
5176    {
5177  161 dseqs.addElement(dsq);
5178    }
5179    }
5180    else
5181    {
5182  0 ds.addSequence(dsq);
5183    }
5184    }
5185    else
5186    {
5187  161 if (sq != dsq)
5188    { // make this dataset sequence sq's dataset sequence
5189  0 sq.setDatasetSequence(dsq);
5190    // and update the current dataset alignment
5191  0 if (ds == null)
5192    {
5193  0 if (dseqs != null)
5194    {
5195  0 if (!dseqs.contains(dsq))
5196    {
5197  0 dseqs.add(dsq);
5198    }
5199    }
5200    else
5201    {
5202  0 if (ds.findIndex(dsq) < 0)
5203    {
5204  0 ds.addSequence(dsq);
5205    }
5206    }
5207    }
5208    }
5209    }
5210    }
5211    // TODO: refactor this as a merge dataset sequence function
5212    // now check that sq (the dataset sequence) sequence really is the union of
5213    // all references to it
5214    // boolean pre = sq.getStart() < dsq.getStart();
5215    // boolean post = sq.getEnd() > dsq.getEnd();
5216    // if (pre || post)
5217  353 if (sq != dsq)
5218    {
5219    // StringBuffer sb = new StringBuffer();
5220  192 String newres = jalview.analysis.AlignSeq.extractGaps(
5221    jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5222  192 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5223    && newres.length() > dsq.getLength())
5224    {
5225    // Update with the longer sequence.
5226  0 synchronized (dsq)
5227    {
5228    /*
5229    * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5230    * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5231    * sb.append(newres.substring(newres.length() - sq.getEnd() -
5232    * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5233    */
5234  0 dsq.setSequence(newres);
5235    }
5236    // TODO: merges will never happen if we 'know' we have the real dataset
5237    // sequence - this should be detected when id==dssid
5238  0 System.err.println(
5239    "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5240    // + (pre ? "prepended" : "") + " "
5241    // + (post ? "appended" : ""));
5242    }
5243    }
5244    else
5245    {
5246    // sequence refs are identical. We may need to update the existing dataset
5247    // alignment with this one, though.
5248  161 if (ds != null && dseqs == null)
5249    {
5250  161 int opos = ds.findIndex(dsq);
5251  161 SequenceI tseq = null;
5252  161 if (opos != -1 && vseqpos != opos)
5253    {
5254    // remove from old position
5255  0 ds.deleteSequence(dsq);
5256    }
5257  161 if (vseqpos < ds.getHeight())
5258    {
5259  161 if (vseqpos != opos)
5260    {
5261    // save sequence at destination position
5262  0 tseq = ds.getSequenceAt(vseqpos);
5263  0 ds.replaceSequenceAt(vseqpos, dsq);
5264  0 ds.addSequence(tseq);
5265    }
5266    }
5267    else
5268    {
5269  0 ds.addSequence(dsq);
5270    }
5271    }
5272    }
5273    }
5274   
5275    /*
5276    * TODO use AlignmentI here and in related methods - needs
5277    * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5278    */
5279    Hashtable<String, AlignmentI> datasetIds = null;
5280   
5281    IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5282   
 
5283  42 toggle private AlignmentI getDatasetFor(String datasetId)
5284    {
5285  42 if (datasetIds == null)
5286    {
5287  13 datasetIds = new Hashtable<>();
5288  13 return null;
5289    }
5290  29 if (datasetIds.containsKey(datasetId))
5291    {
5292  20 return datasetIds.get(datasetId);
5293    }
5294  9 return null;
5295    }
5296   
 
5297  32 toggle private void addDatasetRef(String datasetId, AlignmentI dataset)
5298    {
5299  32 if (datasetIds == null)
5300    {
5301  0 datasetIds = new Hashtable<>();
5302    }
5303  32 datasetIds.put(datasetId, dataset);
5304    }
5305   
5306    /**
5307    * make a new dataset ID for this jalview dataset alignment
5308    *
5309    * @param dataset
5310    * @return
5311    */
 
5312  55 toggle private String getDatasetIdRef(AlignmentI dataset)
5313    {
5314  55 if (dataset.getDataset() != null)
5315    {
5316  0 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5317    }
5318  55 String datasetId = makeHashCode(dataset, null);
5319  55 if (datasetId == null)
5320    {
5321    // make a new datasetId and record it
5322  55 if (dataset2Ids == null)
5323    {
5324  13 dataset2Ids = new IdentityHashMap<>();
5325    }
5326    else
5327    {
5328  42 datasetId = dataset2Ids.get(dataset);
5329    }
5330  55 if (datasetId == null)
5331    {
5332  22 datasetId = "ds" + dataset2Ids.size() + 1;
5333  22 dataset2Ids.put(dataset, datasetId);
5334    }
5335    }
5336  55 return datasetId;
5337    }
5338   
 
5339  248 toggle private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5340    {
5341  581 for (int d = 0; d < sequence.getDBRefCount(); d++)
5342    {
5343  333 DBRef dr = sequence.getDBRef(d);
5344  333 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5345    sequence.getDBRef(d).getSource(),
5346    sequence.getDBRef(d).getVersion(),
5347    sequence.getDBRef(d).getAccessionId());
5348  333 if (dr.getMapping() != null)
5349    {
5350  0 entry.setMap(addMapping(dr.getMapping()));
5351    }
5352  333 datasetSequence.addDBRef(entry);
5353    }
5354    }
5355   
 
5356  0 toggle private jalview.datamodel.Mapping addMapping(Mapping m)
5357    {
5358  0 SequenceI dsto = null;
5359    // Mapping m = dr.getMapping();
5360  0 int fr[] = new int[m.getMapListFromCount() * 2];
5361  0 Enumeration f = m.enumerateMapListFrom();
5362  0 for (int _i = 0; f.hasMoreElements(); _i += 2)
5363    {
5364  0 MapListFrom mf = (MapListFrom) f.nextElement();
5365  0 fr[_i] = mf.getStart();
5366  0 fr[_i + 1] = mf.getEnd();
5367    }
5368  0 int fto[] = new int[m.getMapListToCount() * 2];
5369  0 f = m.enumerateMapListTo();
5370  0 for (int _i = 0; f.hasMoreElements(); _i += 2)
5371    {
5372  0 MapListTo mf = (MapListTo) f.nextElement();
5373  0 fto[_i] = mf.getStart();
5374  0 fto[_i + 1] = mf.getEnd();
5375    }
5376  0 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5377    fto, (int) m.getMapFromUnit(), (int) m.getMapToUnit());
5378  0 if (m.getMappingChoice() != null)
5379    {
5380  0 MappingChoice mc = m.getMappingChoice();
5381  0 if (mc.getDseqFor() != null)
5382    {
5383  0 String dsfor = "" + mc.getDseqFor();
5384  0 if (seqRefIds.containsKey(dsfor))
5385    {
5386    /**
5387    * recover from hash
5388    */
5389  0 jmap.setTo(seqRefIds.get(dsfor));
5390    }
5391    else
5392    {
5393  0 frefedSequence.add(newMappingRef(dsfor, jmap));
5394    }
5395    }
5396    else
5397    {
5398    /**
5399    * local sequence definition
5400    */
5401  0 Sequence ms = mc.getSequence();
5402  0 SequenceI djs = null;
5403  0 String sqid = ms.getDsseqid();
5404  0 if (sqid != null && sqid.length() > 0)
5405    {
5406    /*
5407    * recover dataset sequence
5408    */
5409  0 djs = seqRefIds.get(sqid);
5410    }
5411    else
5412    {
5413  0 System.err.println(
5414    "Warning - making up dataset sequence id for DbRef sequence map reference");
5415  0 sqid = ((Object) ms).toString(); // make up a new hascode for
5416    // undefined dataset sequence hash
5417    // (unlikely to happen)
5418    }
5419   
5420  0 if (djs == null)
5421    {
5422    /**
5423    * make a new dataset sequence and add it to refIds hash
5424    */
5425  0 djs = new jalview.datamodel.Sequence(ms.getName(),
5426    ms.getSequence());
5427  0 djs.setStart(jmap.getMap().getToLowest());
5428  0 djs.setEnd(jmap.getMap().getToHighest());
5429  0 djs.setVamsasId(uniqueSetSuffix + sqid);
5430  0 jmap.setTo(djs);
5431  0 incompleteSeqs.put(sqid, djs);
5432  0 seqRefIds.put(sqid, djs);
5433   
5434    }
5435  0 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5436  0 addDBRefs(djs, ms);
5437   
5438    }
5439    }
5440  0 return (jmap);
5441   
5442    }
5443   
5444    /**
5445    * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5446    * view as XML (but not to file), and then reloading it
5447    *
5448    * @param ap
5449    * @return
5450    */
 
5451  3 toggle public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5452    {
5453  3 initSeqRefs();
5454  3 JalviewModel jm = saveState(ap, null, null, null);
5455   
5456  3 uniqueSetSuffix = "";
5457  3 jm.getJalviewModelSequence().getViewport(0).setId(null);
5458    // we don't overwrite the view we just copied
5459   
5460  3 if (this.frefedSequence == null)
5461    {
5462  0 frefedSequence = new Vector<>();
5463    }
5464   
5465  3 viewportsAdded.clear();
5466   
5467  3 AlignFrame af = loadFromObject(jm, null, false, null);
5468  3 af.alignPanels.clear();
5469  3 af.closeMenuItem_actionPerformed(true);
5470   
5471    /*
5472    * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5473    * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5474    * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5475    * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5476    * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5477    */
5478   
5479  3 return af.alignPanel;
5480    }
5481   
5482    private Hashtable jvids2vobj;
5483   
 
5484  0 toggle private void warn(String msg)
5485    {
5486  0 warn(msg, null);
5487    }
5488   
 
5489  0 toggle private void warn(String msg, Exception e)
5490    {
5491  0 if (Cache.log != null)
5492    {
5493  0 if (e != null)
5494    {
5495  0 Cache.log.warn(msg, e);
5496    }
5497    else
5498    {
5499  0 Cache.log.warn(msg);
5500    }
5501    }
5502    else
5503    {
5504  0 System.err.println("Warning: " + msg);
5505  0 if (e != null)
5506    {
5507  0 e.printStackTrace();
5508    }
5509    }
5510    }
5511   
 
5512  22 toggle private void debug(String string)
5513    {
5514  22 debug(string, null);
5515    }
5516   
 
5517  22 toggle private void debug(String msg, Exception e)
5518    {
5519  22 if (Cache.log != null)
5520    {
5521  22 if (e != null)
5522    {
5523  0 Cache.log.debug(msg, e);
5524    }
5525    else
5526    {
5527  22 Cache.log.debug(msg);
5528    }
5529    }
5530    else
5531    {
5532  0 System.err.println("Warning: " + msg);
5533  0 if (e != null)
5534    {
5535  0 e.printStackTrace();
5536    }
5537    }
5538    }
5539   
5540    /**
5541    * set the object to ID mapping tables used to write/recover objects and XML
5542    * ID strings for the jalview project. If external tables are provided then
5543    * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5544    * object goes out of scope. - also populates the datasetIds hashtable with
5545    * alignment objects containing dataset sequences
5546    *
5547    * @param vobj2jv
5548    * Map from ID strings to jalview datamodel
5549    * @param jv2vobj
5550    * Map from jalview datamodel to ID strings
5551    *
5552    *
5553    */
 
5554  0 toggle public void setObjectMappingTables(Hashtable vobj2jv,
5555    IdentityHashMap jv2vobj)
5556    {
5557  0 this.jv2vobj = jv2vobj;
5558  0 this.vobj2jv = vobj2jv;
5559  0 Iterator ds = jv2vobj.keySet().iterator();
5560  0 String id;
5561  0 while (ds.hasNext())
5562    {
5563  0 Object jvobj = ds.next();
5564  0 id = jv2vobj.get(jvobj).toString();
5565  0 if (jvobj instanceof jalview.datamodel.Alignment)
5566    {
5567  0 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5568    {
5569  0 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5570    }
5571    }
5572  0 else if (jvobj instanceof jalview.datamodel.Sequence)
5573    {
5574    // register sequence object so the XML parser can recover it.
5575  0 if (seqRefIds == null)
5576    {
5577  0 seqRefIds = new HashMap<>();
5578    }
5579  0 if (seqsToIds == null)
5580    {
5581  0 seqsToIds = new IdentityHashMap<>();
5582    }
5583  0 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5584  0 seqsToIds.put((SequenceI) jvobj, id);
5585    }
5586  0 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5587    {
5588  0 String anid;
5589  0 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5590  0 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5591  0 if (jvann.annotationId == null)
5592    {
5593  0 jvann.annotationId = anid;
5594    }
5595  0 if (!jvann.annotationId.equals(anid))
5596    {
5597    // TODO verify that this is the correct behaviour
5598  0 this.warn("Overriding Annotation ID for " + anid
5599    + " from different id : " + jvann.annotationId);
5600  0 jvann.annotationId = anid;
5601    }
5602    }
5603  0 else if (jvobj instanceof String)
5604    {
5605  0 if (jvids2vobj == null)
5606    {
5607  0 jvids2vobj = new Hashtable();
5608  0 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5609    }
5610    }
5611    else
5612    {
5613  0 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5614    }
5615    }
5616    }
5617   
5618    /**
5619    * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5620    * objects created from the project archive. If string is null (default for
5621    * construction) then suffix will be set automatically.
5622    *
5623    * @param string
5624    */
 
5625  0 toggle public void setUniqueSetSuffix(String string)
5626    {
5627  0 uniqueSetSuffix = string;
5628   
5629    }
5630   
5631    /**
5632    * uses skipList2 as the skipList for skipping views on sequence sets
5633    * associated with keys in the skipList
5634    *
5635    * @param skipList2
5636    */
 
5637  0 toggle public void setSkipList(Hashtable skipList2)
5638    {
5639  0 skipList = skipList2;
5640    }
5641   
5642    /**
5643    * Reads the jar entry of given name and returns its contents, or null if the
5644    * entry is not found.
5645    *
5646    * @param jprovider
5647    * @param jarEntryName
5648    * @return
5649    */
 
5650  2 toggle protected String readJarEntry(jarInputStreamProvider jprovider,
5651    String jarEntryName)
5652    {
5653  2 String result = null;
5654  2 BufferedReader in = null;
5655   
5656  2 try
5657    {
5658    /*
5659    * Reopen the jar input stream and traverse its entries to find a matching
5660    * name
5661    */
5662  2 JarInputStream jin = jprovider.getJarInputStream();
5663  2 JarEntry entry = null;
5664  2 do
5665    {
5666  2 entry = jin.getNextJarEntry();
5667  2 } while (entry != null && !entry.getName().equals(jarEntryName));
5668   
5669  2 if (entry != null)
5670    {
5671  2 StringBuilder out = new StringBuilder(256);
5672  2 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5673  2 String data;
5674   
5675  ? while ((data = in.readLine()) != null)
5676    {
5677  698 out.append(data);
5678    }
5679  2 result = out.toString();
5680    }
5681    else
5682    {
5683  0 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5684    }
5685    } catch (Exception ex)
5686    {
5687  0 ex.printStackTrace();
5688    } finally
5689    {
5690  2 if (in != null)
5691    {
5692  2 try
5693    {
5694  2 in.close();
5695    } catch (IOException e)
5696    {
5697    // ignore
5698    }
5699    }
5700    }
5701   
5702  2 return result;
5703    }
5704   
5705    /**
5706    * Returns an incrementing counter (0, 1, 2...)
5707    *
5708    * @return
5709    */
 
5710  0 toggle private synchronized int nextCounter()
5711    {
5712  0 return counter++;
5713    }
5714   
5715    /**
5716    * Populates an XML model of the feature colour scheme for one feature type
5717    *
5718    * @param featureType
5719    * @param fcol
5720    * @return
5721    */
 
5722  5 toggle protected static jalview.schemabinding.version2.Colour marshalColour(
5723    String featureType, FeatureColourI fcol)
5724    {
5725  5 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
5726  5 if (fcol.isSimpleColour())
5727    {
5728  1 col.setRGB(Format.getHexString(fcol.getColour()));
5729    }
5730    else
5731    {
5732  4 col.setRGB(Format.getHexString(fcol.getMaxColour()));
5733  4 col.setMin(fcol.getMin());
5734  4 col.setMax(fcol.getMax());
5735  4 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
5736  4 col.setAutoScale(fcol.isAutoScaled());
5737  4 col.setThreshold(fcol.getThreshold());
5738  4 col.setColourByLabel(fcol.isColourByLabel());
5739  4 col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
5740  3 : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
5741    : ColourThreshTypeType.NONE));
5742  4 if (fcol.isColourByAttribute())
5743    {
5744  2 col.setAttributeName(fcol.getAttributeName());
5745    }
5746  4 Color noColour = fcol.getNoColour();
5747  4 if (noColour == null)
5748    {
5749  2 col.setNoValueColour(NoValueColour.NONE);
5750    }
5751  2 else if (noColour == fcol.getMaxColour())
5752    {
5753  0 col.setNoValueColour(NoValueColour.MAX);
5754    }
5755    else
5756    {
5757  2 col.setNoValueColour(NoValueColour.MIN);
5758    }
5759    }
5760  5 col.setName(featureType);
5761  5 return col;
5762    }
5763   
5764    /**
5765    * Populates an XML model of the feature filter(s) for one feature type
5766    *
5767    * @param firstMatcher
5768    * the first (or only) match condition)
5769    * @param filter
5770    * remaining match conditions (if any)
5771    * @param and
5772    * if true, conditions are and-ed, else or-ed
5773    */
 
5774  14 toggle protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
5775    Iterator<FeatureMatcherI> filters, boolean and)
5776    {
5777  14 MatcherSet result = new MatcherSet();
5778   
5779  14 if (filters.hasNext())
5780    {
5781    /*
5782    * compound matcher
5783    */
5784  4 CompoundMatcher compound = new CompoundMatcher();
5785  4 compound.setAnd(and);
5786  4 MatcherSet matcher1 = marshalFilter(firstMatcher,
5787    Collections.emptyIterator(), and);
5788  4 compound.addMatcherSet(matcher1);
5789  4 FeatureMatcherI nextMatcher = filters.next();
5790  4 MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
5791  4 compound.addMatcherSet(matcher2);
5792  4 result.setCompoundMatcher(compound);
5793    }
5794    else
5795    {
5796    /*
5797    * single condition matcher
5798    */
5799  10 MatchCondition matcherModel = new MatchCondition();
5800  10 matcherModel.setCondition(
5801    firstMatcher.getMatcher().getCondition().getStableName());
5802  10 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
5803  10 if (firstMatcher.isByAttribute())
5804    {
5805  4 matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
5806  4 matcherModel.setAttributeName(firstMatcher.getAttribute());
5807    }
5808  6 else if (firstMatcher.isByLabel())
5809    {
5810  2 matcherModel.setBy(FeatureMatcherByType.BYLABEL);
5811    }
5812  4 else if (firstMatcher.isByScore())
5813    {
5814  4 matcherModel.setBy(FeatureMatcherByType.BYSCORE);
5815    }
5816  10 result.setMatchCondition(matcherModel);
5817    }
5818   
5819  14 return result;
5820    }
5821   
5822    /**
5823    * Loads one XML model of a feature filter to a Jalview object
5824    *
5825    * @param featureType
5826    * @param matcherSetModel
5827    * @return
5828    */
 
5829  6 toggle protected static FeatureMatcherSetI unmarshalFilter(
5830    String featureType, MatcherSet matcherSetModel)
5831    {
5832  6 FeatureMatcherSetI result = new FeatureMatcherSet();
5833  6 try
5834    {
5835  6 unmarshalFilterConditions(result, matcherSetModel, true);
5836    } catch (IllegalStateException e)
5837    {
5838    // mixing AND and OR conditions perhaps
5839  0 System.err.println(
5840    String.format("Error reading filter conditions for '%s': %s",
5841    featureType, e.getMessage()));
5842    // return as much as was parsed up to the error
5843    }
5844   
5845  6 return result;
5846    }
5847   
5848    /**
5849    * Adds feature match conditions to matcherSet as unmarshalled from XML
5850    * (possibly recursively for compound conditions)
5851    *
5852    * @param matcherSet
5853    * @param matcherSetModel
5854    * @param and
5855    * if true, multiple conditions are AND-ed, else they are OR-ed
5856    * @throws IllegalStateException
5857    * if AND and OR conditions are mixed
5858    */
 
5859  14 toggle protected static void unmarshalFilterConditions(
5860    FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
5861    boolean and)
5862    {
5863  14 MatchCondition mc = matcherSetModel.getMatchCondition();
5864  14 if (mc != null)
5865    {
5866    /*
5867    * single condition
5868    */
5869  10 FeatureMatcherByType filterBy = mc.getBy();
5870  10 Condition cond = Condition.fromString(mc.getCondition());
5871  10 String pattern = mc.getValue();
5872  10 FeatureMatcherI matchCondition = null;
5873  10 if (filterBy == FeatureMatcherByType.BYLABEL)
5874    {
5875  2 matchCondition = FeatureMatcher.byLabel(cond, pattern);
5876    }
5877  8 else if (filterBy == FeatureMatcherByType.BYSCORE)
5878    {
5879  4 matchCondition = FeatureMatcher.byScore(cond, pattern);
5880   
5881    }
5882  4 else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
5883    {
5884  4 String[] attNames = mc.getAttributeName();
5885  4 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
5886    attNames);
5887    }
5888   
5889    /*
5890    * note this throws IllegalStateException if AND-ing to a
5891    * previously OR-ed compound condition, or vice versa
5892    */
5893  10 if (and)
5894    {
5895  6 matcherSet.and(matchCondition);
5896    }
5897    else
5898    {
5899  4 matcherSet.or(matchCondition);
5900    }
5901    }
5902    else
5903    {
5904    /*
5905    * compound condition
5906    */
5907  4 MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
5908    .getMatcherSet();
5909  4 boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
5910  4 if (matchers.length == 2)
5911    {
5912  4 unmarshalFilterConditions(matcherSet, matchers[0], anded);
5913  4 unmarshalFilterConditions(matcherSet, matchers[1], anded);
5914    }
5915    else
5916    {
5917  0 System.err.println("Malformed compound filter condition");
5918    }
5919    }
5920    }
5921   
5922    /**
5923    * Loads one XML model of a feature colour to a Jalview object
5924    *
5925    * @param colourModel
5926    * @return
5927    */
 
5928  5 toggle protected static FeatureColourI unmarshalColour(
5929    jalview.schemabinding.version2.Colour colourModel)
5930    {
5931  5 FeatureColourI colour = null;
5932   
5933  5 if (colourModel.hasMax())
5934    {
5935  4 Color mincol = null;
5936  4 Color maxcol = null;
5937  4 Color noValueColour = null;
5938   
5939  4 try
5940    {
5941  4 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
5942  4 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5943    } catch (Exception e)
5944    {
5945  0 Cache.log.warn("Couldn't parse out graduated feature color.", e);
5946    }
5947   
5948  4 NoValueColour noCol = colourModel.getNoValueColour();
5949  4 if (noCol == NoValueColour.MIN)
5950    {
5951  2 noValueColour = mincol;
5952    }
5953  2 else if (noCol == NoValueColour.MAX)
5954    {
5955  0 noValueColour = maxcol;
5956    }
5957   
5958  4 colour = new FeatureColour(mincol, maxcol, noValueColour,
5959    colourModel.getMin(),
5960    colourModel.getMax());
5961  4 String[] attributes = colourModel.getAttributeName();
5962  4 if (attributes != null && attributes.length > 0)
5963    {
5964  2 colour.setAttributeName(attributes);
5965    }
5966  4 if (colourModel.hasAutoScale())
5967    {
5968  4 colour.setAutoScaled(colourModel.getAutoScale());
5969    }
5970  4 if (colourModel.hasColourByLabel())
5971    {
5972  4 colour.setColourByLabel(colourModel.getColourByLabel());
5973    }
5974  4 if (colourModel.hasThreshold())
5975    {
5976  4 colour.setThreshold(colourModel.getThreshold());
5977    }
5978  4 ColourThreshTypeType ttyp = colourModel.getThreshType();
5979  4 if (ttyp != null)
5980    {
5981  4 if (ttyp == ColourThreshTypeType.ABOVE)
5982    {
5983  1 colour.setAboveThreshold(true);
5984    }
5985  3 else if (ttyp == ColourThreshTypeType.BELOW)
5986    {
5987  1 colour.setBelowThreshold(true);
5988    }
5989    }
5990    }
5991    else
5992    {
5993  1 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
5994  1 colour = new FeatureColour(color);
5995    }
5996   
5997  5 return colour;
5998    }
5999    }