Clover icon

Coverage Report

  1. Project Clover database Thu Feb 19 2026 11:15:34 GMT
  2. Package jalview.project

File Jalview2XML.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
21% of files have more coverage

Code metrics

1,226
2,793
130
4
7,826
5,678
879
0.31
21.48
32.5
6.76

Classes

Class Line # Actions
Jalview2XML 235 2,779 869
0.754062675.4%
Jalview2XML.forwardRef 429 4 3
0.4285714342.9%
Jalview2XML.SeqFref 465 8 6
0.00%
Jalview2XML.JvAnnotRow 3940 2 1
1.0100%
 

Contributing tests

This file is covered by 44 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.project;
22   
23    import static jalview.math.RotatableMatrix.Axis.X;
24    import static jalview.math.RotatableMatrix.Axis.Y;
25    import static jalview.math.RotatableMatrix.Axis.Z;
26   
27    import java.awt.Color;
28    import java.awt.Dimension;
29    import java.awt.Font;
30    import java.awt.Rectangle;
31    import java.io.BufferedReader;
32    import java.io.ByteArrayInputStream;
33    import java.io.DataOutputStream;
34    import java.io.File;
35    import java.io.FileInputStream;
36    import java.io.FileOutputStream;
37    import java.io.IOException;
38    import java.io.InputStream;
39    import java.io.InputStreamReader;
40    import java.io.OutputStream;
41    import java.io.OutputStreamWriter;
42    import java.io.PrintWriter;
43    import java.math.BigInteger;
44    import java.net.MalformedURLException;
45    import java.net.URL;
46    import java.util.ArrayList;
47    import java.util.Arrays;
48    import java.util.BitSet;
49    import java.util.Collections;
50    import java.util.Enumeration;
51    import java.util.GregorianCalendar;
52    import java.util.HashMap;
53    import java.util.HashSet;
54    import java.util.Hashtable;
55    import java.util.IdentityHashMap;
56    import java.util.Iterator;
57    import java.util.LinkedHashMap;
58    import java.util.List;
59    import java.util.Locale;
60    import java.util.Map;
61    import java.util.Map.Entry;
62    import java.util.Optional;
63    import java.util.Set;
64    import java.util.Vector;
65    import java.util.jar.JarEntry;
66    import java.util.jar.JarInputStream;
67    import java.util.jar.JarOutputStream;
68   
69    import javax.swing.JInternalFrame;
70    import javax.swing.SwingUtilities;
71    import javax.xml.bind.JAXBContext;
72    import javax.xml.bind.JAXBElement;
73    import javax.xml.bind.Marshaller;
74    import javax.xml.datatype.DatatypeConfigurationException;
75    import javax.xml.datatype.DatatypeFactory;
76    import javax.xml.datatype.XMLGregorianCalendar;
77    import javax.xml.stream.XMLInputFactory;
78    import javax.xml.stream.XMLStreamReader;
79   
80    import jalview.analysis.Conservation;
81    import jalview.analysis.PCA;
82    import jalview.analysis.PaSiMap;
83    import jalview.analysis.scoremodels.ScoreModels;
84    import jalview.analysis.scoremodels.SimilarityParams;
85    import jalview.api.AlignmentViewPanel;
86    import jalview.api.FeatureColourI;
87    import jalview.api.ViewStyleI;
88    import jalview.api.analysis.ScoreModelI;
89    import jalview.api.analysis.SimilarityParamsI;
90    import jalview.api.structures.JalviewStructureDisplayI;
91    import jalview.bin.Cache;
92    import jalview.bin.Console;
93    import jalview.bin.Jalview;
94    import jalview.datamodel.AlignedCodonFrame;
95    import jalview.datamodel.Alignment;
96    import jalview.datamodel.AlignmentAnnotation;
97    import jalview.datamodel.AlignmentI;
98    import jalview.datamodel.ContactMatrix;
99    import jalview.datamodel.ContactMatrixI;
100    import jalview.datamodel.DBRefEntry;
101    import jalview.datamodel.FloatContactMatrix;
102    import jalview.datamodel.GeneLocus;
103    import jalview.datamodel.GraphLine;
104    import jalview.datamodel.GroupSet;
105    import jalview.datamodel.HiddenMarkovModel;
106    import jalview.datamodel.PDBEntry;
107    import jalview.datamodel.Point;
108    import jalview.datamodel.RnaViewerModel;
109    import jalview.datamodel.SequenceFeature;
110    import jalview.datamodel.SequenceGroup;
111    import jalview.datamodel.SequenceI;
112    import jalview.datamodel.StructureViewerModel;
113    import jalview.datamodel.StructureViewerModel.StructureData;
114    import jalview.datamodel.features.FeatureMatcher;
115    import jalview.datamodel.features.FeatureMatcherI;
116    import jalview.datamodel.features.FeatureMatcherSet;
117    import jalview.datamodel.features.FeatureMatcherSetI;
118    import jalview.ext.varna.RnaModel;
119    import jalview.gui.AlignFrame;
120    import jalview.gui.AlignViewport;
121    import jalview.gui.AlignmentPanel;
122    import jalview.gui.AppVarna;
123    import jalview.gui.Desktop;
124    import jalview.gui.JvOptionPane;
125    import jalview.gui.JvSwingUtils;
126    import jalview.gui.OOMWarning;
127    import jalview.gui.OverviewPanel;
128    import jalview.gui.PCAPanel;
129    import jalview.gui.PaSiMapPanel;
130    import jalview.gui.PaintRefresher;
131    import jalview.gui.SplitFrame;
132    import jalview.gui.StructureViewer;
133    import jalview.gui.StructureViewer.ViewerType;
134    import jalview.gui.StructureViewerBase;
135    import jalview.gui.TreePanel;
136    import jalview.io.BackupFiles;
137    import jalview.io.DataSourceType;
138    import jalview.io.FileFormat;
139    import jalview.io.HMMFile;
140    import jalview.io.NewickFile;
141    import jalview.math.Matrix;
142    import jalview.math.MatrixI;
143    import jalview.renderer.ResidueShaderI;
144    import jalview.schemes.AnnotationColourGradient;
145    import jalview.schemes.ColourSchemeI;
146    import jalview.schemes.ColourSchemeProperty;
147    import jalview.schemes.FeatureColour;
148    import jalview.schemes.ResidueProperties;
149    import jalview.schemes.UserColourScheme;
150    import jalview.structures.models.AAStructureBindingModel;
151    import jalview.util.Format;
152    import jalview.util.HttpUtils;
153    import jalview.util.MessageManager;
154    import jalview.util.Platform;
155    import jalview.util.StringUtils;
156    import jalview.util.jarInputStreamProvider;
157    import jalview.util.matcher.Condition;
158    import jalview.viewmodel.AlignmentViewport;
159    import jalview.viewmodel.PCAModel;
160    import jalview.viewmodel.PaSiMapModel;
161    import jalview.viewmodel.ViewportRanges;
162    import jalview.viewmodel.seqfeatures.FeatureRendererModel;
163    import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
164    import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
165    import jalview.ws.api.ServiceWithParameters;
166    import jalview.ws.datamodel.MappableContactMatrixI;
167    import jalview.ws.datamodel.alphafold.PAEContactMatrix;
168    import jalview.ws.jws2.PreferredServiceRegistry;
169    import jalview.ws.jws2.dm.AAConSettings;
170    import jalview.ws.params.ArgumentI;
171    import jalview.ws.params.AutoCalcSetting;
172    import jalview.ws.params.WsParamSetI;
173    import jalview.xml.binding.jalview.AlcodonFrame;
174    import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
175    import jalview.xml.binding.jalview.Annotation;
176    import jalview.xml.binding.jalview.Annotation.ThresholdLine;
177    import jalview.xml.binding.jalview.AnnotationColourScheme;
178    import jalview.xml.binding.jalview.AnnotationElement;
179    import jalview.xml.binding.jalview.DoubleMatrix;
180    import jalview.xml.binding.jalview.DoubleVector;
181    import jalview.xml.binding.jalview.Feature;
182    import jalview.xml.binding.jalview.Feature.OtherData;
183    import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
184    import jalview.xml.binding.jalview.FilterBy;
185    import jalview.xml.binding.jalview.JalviewModel;
186    import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
187    import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
188    import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
189    import jalview.xml.binding.jalview.JalviewModel.JGroup;
190    import jalview.xml.binding.jalview.JalviewModel.JSeq;
191    import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
192    import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
193    import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
194    import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
195    import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
196    import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
197    import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
198    import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
199    import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
200    import jalview.xml.binding.jalview.JalviewModel.Tree;
201    import jalview.xml.binding.jalview.JalviewModel.UserColours;
202    import jalview.xml.binding.jalview.JalviewModel.Viewport;
203    import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
204    import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
205    import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
206    import jalview.xml.binding.jalview.JalviewUserColours;
207    import jalview.xml.binding.jalview.JalviewUserColours.Colour;
208    import jalview.xml.binding.jalview.MapListType;
209    import jalview.xml.binding.jalview.MapListType.MapListFrom;
210    import jalview.xml.binding.jalview.MapListType.MapListTo;
211    import jalview.xml.binding.jalview.MapOnAMatrixType;
212    import jalview.xml.binding.jalview.Mapping;
213    import jalview.xml.binding.jalview.MatrixType;
214    import jalview.xml.binding.jalview.NoValueColour;
215    import jalview.xml.binding.jalview.ObjectFactory;
216    import jalview.xml.binding.jalview.PcaDataType;
217    import jalview.xml.binding.jalview.Pdbentry.Property;
218    import jalview.xml.binding.jalview.Sequence;
219    import jalview.xml.binding.jalview.Sequence.DBRef;
220    import jalview.xml.binding.jalview.SequenceSet;
221    import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
222    import jalview.xml.binding.jalview.ThresholdType;
223    import jalview.xml.binding.jalview.VAMSAS;
224   
225    /**
226    * Write out the current jalview desktop state as a Jalview XML stream.
227    *
228    * Note: the vamsas objects referred to here are primitive versions of the
229    * VAMSAS project schema elements - they are not the same and most likely never
230    * will be :)
231    *
232    * @author $author$
233    * @version $Revision: 1.134 $
234    */
 
235    public class Jalview2XML
236    {
237   
238    // BH 2018 we add the .jvp binary extension to J2S so that
239    // it will declare that binary when we do the file save from the browser
240   
 
241  4 toggle static
242    {
243  4 Platform.addJ2SBinaryType(".jvp?");
244    }
245   
246    private static final String VIEWER_PREFIX = "viewer_";
247   
248    private static final String RNA_PREFIX = "rna_";
249   
250    private static final String HMMER_PREFIX = "hmmer_";
251   
252    private static final String UTF_8 = "UTF-8";
253   
254    /**
255    * used in decision if quit confirmation should be issued
256    */
257    private static boolean stateSavedUpToDate = false;
258   
259    /**
260    * prefix for recovering datasets for alignments with multiple views where
261    * non-existent dataset IDs were written for some views
262    */
263    private static final String UNIQSEQSETID = "uniqueSeqSetId.";
264   
265    // use this with nextCounter() to make unique names for entities
266    private int counter = 0;
267   
268    /*
269    * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
270    * of sequence objects are created.
271    */
272    IdentityHashMap<SequenceI, String> seqsToIds = null;
273   
274    /**
275    * jalview XML Sequence ID to jalview sequence object reference (both dataset
276    * and alignment sequences. Populated as XML reps of sequence objects are
277    * created.)
278    */
279    Map<String, SequenceI> seqRefIds = null;
280   
281    Map<String, SequenceI> incompleteSeqs = null;
282   
283    List<forwardRef> frefedSequence = null;
284   
285    boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
286   
287    /*
288    * Map of reconstructed AlignFrame objects that appear to have come from
289    * SplitFrame objects (have a dna/protein complement view).
290    */
291    private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
292   
293    /*
294    * Map from displayed rna structure models to their saved session state jar
295    * entry names
296    */
297    private Map<RnaModel, String> rnaSessions = new HashMap<>();
298   
299    /**
300    * map from contact matrices to their XML ids
301    */
302    private Map<ContactMatrixI, String> contactMatrices = new HashMap<>();
303   
304    private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
305   
306    private List<jalview.xml.binding.jalview.MatrixType> xmlMatrices = new ArrayList<>();
307   
308    /**
309    * contains last error message (if any) encountered by XML loader.
310    */
311    String errorMessage = null;
312   
313    /**
314    * flag to control whether the Jalview2XML_V1 parser should be deferred to if
315    * exceptions are raised during project XML parsing
316    */
317    public boolean attemptversion1parse = false;
318   
319    /*
320    * JalviewJS only -- to allow read file bytes to be saved in the
321    * created AlignFrame, allowing File | Reload of a project file to work
322    *
323    * BH 2019 JAL-3436
324    */
325    private File jarFile;
326   
327    /**
328    * A helper method for safely using the value of an optional attribute that
329    * may be null if not present in the XML. Answers the boolean value, or false
330    * if null.
331    *
332    * @param b
333    * @return
334    */
 
335  27063 toggle public static boolean safeBoolean(Boolean b)
336    {
337  27063 return b == null ? false : b.booleanValue();
338    }
339   
340    /**
341    * A helper method for safely using the value of an optional attribute that
342    * may be null if not present in the XML. Answers the integer value, or zero
343    * if null.
344    *
345    * @param i
346    * @return
347    */
 
348  385932 toggle public static int safeInt(Integer i)
349    {
350  385932 return i == null ? 0 : i.intValue();
351    }
352   
353    /**
354    * A helper method for safely using the value of an optional attribute that
355    * may be null if not present in the XML. Answers the float value, or zero if
356    * null.
357    *
358    * @param f
359    * @return
360    */
 
361  535228 toggle public static float safeFloat(Float f)
362    {
363  535228 return f == null ? 0f : f.floatValue();
364    }
365   
366    /**
367    * create/return unique hash string for sq
368    *
369    * @param sq
370    * @return new or existing unique string for sq
371    */
 
372  12846 toggle String seqHash(SequenceI sq)
373    {
374  12846 if (seqsToIds == null)
375    {
376  0 initSeqRefs();
377    }
378  12846 if (seqsToIds.containsKey(sq))
379    {
380  818 return seqsToIds.get(sq);
381    }
382    else
383    {
384    // create sequential key
385  12028 String key = "sq" + (seqsToIds.size() + 1);
386  12028 key = makeHashCode(sq, key); // check we don't have an external reference
387    // for it already.
388  12028 seqsToIds.put(sq, key);
389  12028 return key;
390    }
391    }
392   
 
393  142 toggle void initSeqRefs()
394    {
395  142 if (seqsToIds == null)
396    {
397  82 seqsToIds = new IdentityHashMap<>();
398    }
399  142 if (seqRefIds == null)
400    {
401  82 seqRefIds = new HashMap<>();
402    }
403  142 if (incompleteSeqs == null)
404    {
405  82 incompleteSeqs = new HashMap<>();
406    }
407  142 if (frefedSequence == null)
408    {
409  82 frefedSequence = new ArrayList<>();
410    }
411    }
412   
 
413  22 toggle public Jalview2XML()
414    {
415    }
416   
 
417  60 toggle public Jalview2XML(boolean raiseGUI)
418    {
419  60 this.raiseGUI = raiseGUI;
420    }
421   
422    /**
423    * base class for resolving forward references to an as-yet unmarshalled
424    * object referenced by already unmarshalled objects
425    *
426    * @author jprocter
427    *
428    */
 
429    abstract class forwardRef
430    {
431    String sref;
432   
433    String type;
434   
 
435  31 toggle public forwardRef(String _sref, String type)
436    {
437  31 sref = _sref;
438  31 this.type = type;
439    }
440   
 
441  0 toggle public String getSref()
442    {
443  0 return sref;
444    }
445   
446    public abstract boolean isResolvable();
447   
448    /**
449    * @return true if the forward reference was fully resolved
450    */
451    abstract boolean resolve();
452   
 
453  0 toggle @Override
454    public String toString()
455    {
456  0 return type + " reference to " + sref;
457    }
458    }
459   
460    /**
461    * resolve forward references to sequences by their ID
462    *
463    * @author jprocter
464    */
 
465    abstract class SeqFref extends forwardRef
466    {
 
467  0 toggle public SeqFref(String _sref, String type)
468    {
469  0 super(_sref, type);
470    }
471   
 
472  0 toggle public SequenceI getSrefSeq()
473    {
474  0 return seqRefIds.get(sref);
475    }
476   
 
477  0 toggle @Override
478    public boolean isResolvable()
479    {
480  0 return seqRefIds.get(sref) != null;
481    }
482   
 
483  0 toggle public SequenceI getSrefDatasetSeq()
484    {
485  0 SequenceI sq = seqRefIds.get(sref);
486  0 if (sq != null)
487    {
488  0 while (sq.getDatasetSequence() != null)
489    {
490  0 sq = sq.getDatasetSequence();
491    }
492    }
493  0 return sq;
494    }
495    }
496   
497    /**
498    * create forward reference for a mapping
499    *
500    * @param sref
501    * @param _jmap
502    * @return
503    */
 
504  0 toggle protected SeqFref newMappingRef(final String sref,
505    final jalview.datamodel.Mapping _jmap)
506    {
507  0 SeqFref fref = new SeqFref(sref, "Mapping")
508    {
509    public jalview.datamodel.Mapping jmap = _jmap;
510   
 
511  0 toggle @Override
512    boolean resolve()
513    {
514  0 SequenceI seq = getSrefDatasetSeq();
515  0 if (seq == null)
516    {
517  0 return false;
518    }
519  0 jmap.setTo(seq);
520  0 return true;
521    }
522    };
523  0 return fref;
524    }
525   
 
526  0 toggle protected SeqFref newAlcodMapRef(final String sref,
527    final AlignedCodonFrame _cf,
528    final jalview.datamodel.Mapping _jmap)
529    {
530   
531  0 SeqFref fref = new SeqFref(sref, "Codon Frame")
532    {
533    AlignedCodonFrame cf = _cf;
534   
535    public jalview.datamodel.Mapping mp = _jmap;
536   
 
537  0 toggle @Override
538    public boolean isResolvable()
539    {
540  0 return super.isResolvable() && mp.getTo() != null;
541    }
542   
 
543  0 toggle @Override
544    boolean resolve()
545    {
546  0 SequenceI seq = getSrefDatasetSeq();
547  0 if (seq == null)
548    {
549  0 return false;
550    }
551  0 cf.addMap(seq, mp.getTo(), mp.getMap());
552  0 return true;
553    }
554    };
555  0 return fref;
556    }
557   
 
558  31 toggle public forwardRef newMatrixFref(final String matRef,
559    final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
560    {
561  31 forwardRef fref = new forwardRef(matRef,
562    "Matrix Reference for sequence and annotation")
563    {
564   
 
565  31 toggle @Override
566    boolean resolve()
567    {
568  31 ContactMatrixI cm = contactMatrixRefs.get(matRef);
569  31 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
570    mapping, cm);
571   
572  31 jaa.sequenceRef.addContactListFor(jaa, newpae);
573  31 return true;
574    }
575   
 
576  31 toggle @Override
577    public boolean isResolvable()
578    {
579  31 return (contactMatrixRefs.get(matRef) != null);
580    }
581    };
582  31 return fref;
583    }
584   
 
585  42 toggle public void resolveFrefedSequences()
586    {
587  42 Iterator<forwardRef> nextFref = frefedSequence.iterator();
588  42 int toresolve = frefedSequence.size();
589  42 int unresolved = 0, failedtoresolve = 0;
590  73 while (nextFref.hasNext())
591    {
592  31 forwardRef ref = nextFref.next();
593  31 if (ref.isResolvable())
594    {
595  31 try
596    {
597  31 if (ref.resolve())
598    {
599  31 nextFref.remove();
600    }
601    else
602    {
603  0 failedtoresolve++;
604    }
605    } catch (Exception x)
606    {
607  0 jalview.bin.Console.errPrintln(
608    "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
609    + ref.getSref());
610  0 x.printStackTrace();
611  0 failedtoresolve++;
612    }
613    }
614    else
615    {
616  0 unresolved++;
617    }
618    }
619  42 if (unresolved > 0)
620    {
621  0 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
622    + unresolved
623    + " forward references left unresolved on the stack.");
624    }
625  42 if (failedtoresolve > 0)
626    {
627  0 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
628    + " resolvable forward references failed to resolve.");
629    }
630  42 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
631    {
632  0 jalview.bin.Console.errPrintln(
633    "Jalview Project Import: There are " + incompleteSeqs.size()
634    + " sequences which may have incomplete metadata.");
635  0 if (incompleteSeqs.size() < 10)
636    {
637  0 for (SequenceI s : incompleteSeqs.values())
638    {
639  0 jalview.bin.Console.errPrintln(s.toString());
640    }
641    }
642    else
643    {
644  0 jalview.bin.Console.errPrintln(
645    "Too many to report. Skipping output of incomplete sequences.");
646    }
647    }
648    }
649   
650    /**
651    * This maintains a map of viewports, the key being the seqSetId. Important to
652    * set historyItem and redoList for multiple views
653    */
654    Map<String, AlignViewport> viewportsAdded = new HashMap<>();
655   
656    Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
657   
658    String uniqueSetSuffix = "";
659   
660    /**
661    * List of pdbfiles added to Jar
662    */
663    List<String> pdbfiles = null;
664   
665    // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
 
666  20 toggle public void saveState(File statefile)
667    {
668  20 FileOutputStream fos = null;
669   
670  20 try
671    {
672   
673  20 fos = new FileOutputStream(statefile);
674   
675  20 JarOutputStream jout = new JarOutputStream(fos);
676  20 saveState(jout);
677  20 fos.close();
678   
679    } catch (Exception e)
680    {
681  0 Console.error("Couln't write Jalview state to " + statefile, e);
682    // TODO: inform user of the problem - they need to know if their data was
683    // not saved !
684  0 if (errorMessage == null)
685    {
686  0 errorMessage = "Did't write Jalview Archive to output file '"
687    + statefile + "' - See console error log for details";
688    }
689    else
690    {
691  0 errorMessage += "(Didn't write Jalview Archive to output file '"
692    + statefile + ")";
693    }
694  0 e.printStackTrace();
695    } finally
696    {
697  20 if (fos != null)
698    {
699  20 try
700    {
701  20 fos.close();
702    } catch (IOException e)
703    {
704    // ignore
705    }
706    }
707    }
708  20 reportErrors();
709    }
710   
711    /**
712    * Writes a jalview project archive to the given Jar output stream.
713    *
714    * @param jout
715    */
 
716  20 toggle public void saveState(JarOutputStream jout)
717    {
718  20 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
719   
720  20 setStateSavedUpToDate(true);
721   
722  20 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
723    {
724  2 int n = debugDelaySave;
725  2 int i = 0;
726  15 while (i < n)
727    {
728  13 Console.debug("***** debugging save sleep " + i + "/" + n);
729  13 try
730    {
731  13 Thread.sleep(1000);
732    } catch (InterruptedException e)
733    {
734    // TODO Auto-generated catch block
735  0 e.printStackTrace();
736    }
737  13 i++;
738    }
739    }
740   
741  20 if (frames == null)
742    {
743  0 return;
744    }
745  20 saveAllFrames(Arrays.asList(frames), jout);
746    }
747   
748    /**
749    * core method for storing state for a set of AlignFrames.
750    *
751    * @param frames
752    * - frames involving all data to be exported (including those
753    * contained in splitframes, though not the split frames themselves)
754    * @param jout
755    * - project output stream
756    */
 
757  28 toggle private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
758    {
759  28 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
760   
761    /*
762    * ensure cached data is clear before starting
763    */
764    // todo tidy up seqRefIds, seqsToIds initialisation / reset
765  28 rnaSessions.clear();
766  28 splitFrameCandidates.clear();
767   
768  28 try
769    {
770   
771    // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
772    // //////////////////////////////////////////////////
773   
774  28 List<String> shortNames = new ArrayList<>();
775  28 List<String> viewIds = new ArrayList<>();
776   
777    // REVERSE ORDER
778  60 for (int i = frames.size() - 1; i > -1; i--)
779    {
780  33 AlignFrame af = frames.get(i);
781  33 AlignViewport vp = af.getViewport();
782    // skip ?
783  33 if (skipList != null && skipList.containsKey(vp.getSequenceSetId()))
784    {
785  0 continue;
786    }
787   
788  33 String shortName = makeFilename(af, shortNames);
789   
790  33 AlignmentI alignment = vp.getAlignment();
791  33 List<? extends AlignmentViewPanel> panels = af.getAlignPanels();
792  33 int apSize = panels.size();
793   
794  76 for (int ap = 0; ap < apSize; ap++)
795    {
796  44 AlignmentPanel apanel = (AlignmentPanel) panels.get(ap);
797  44 String fileName = apSize == 1 ? shortName : ap + shortName;
798  44 if (!fileName.endsWith(".xml"))
799    {
800  0 fileName = fileName + ".xml";
801    }
802   
803  44 saveState(apanel, fileName, jout, viewIds);
804   
805    }
806  32 if (apSize > 0)
807    {
808    // BH moved next bit out of inner loop, not that it really matters.
809    // so we are testing to make sure we actually have an alignment,
810    // apparently.
811  32 String dssid = getDatasetIdRef(alignment.getDataset());
812  32 if (!dsses.containsKey(dssid))
813    {
814    // We have not already covered this data by reference from another
815    // frame.
816  32 dsses.put(dssid, af);
817    }
818    }
819    }
820   
821  27 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
822    jout);
823   
824  27 try
825    {
826  27 jout.flush();
827    } catch (Exception foo)
828    {
829    }
830  27 jout.close();
831    } catch (Exception ex)
832    {
833    // TODO: inform user of the problem - they need to know if their data was
834    // not saved !
835  1 if (errorMessage == null)
836    {
837  1 errorMessage = "Couldn't write Jalview Archive - see error output for details";
838    }
839  1 ex.printStackTrace();
840    }
841    }
842   
843    /**
844    * Generates a distinct file name, based on the title of the AlignFrame, by
845    * appending _n for increasing n until an unused name is generated. The new
846    * name (without its extension) is added to the list.
847    *
848    * @param af
849    * @param namesUsed
850    * @return the generated name, with .xml extension
851    */
 
852  33 toggle protected String makeFilename(AlignFrame af, List<String> namesUsed)
853    {
854  33 String shortName = af.getTitle();
855   
856  33 if (shortName.indexOf(File.separatorChar) > -1)
857    {
858  17 shortName = shortName
859    .substring(shortName.lastIndexOf(File.separatorChar) + 1);
860    }
861   
862  33 int count = 1;
863   
864  43 while (namesUsed.contains(shortName))
865    {
866  10 if (shortName.endsWith("_" + (count - 1)))
867    {
868  6 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
869    }
870   
871  10 shortName = shortName.concat("_" + count);
872  10 count++;
873    }
874   
875  33 namesUsed.add(shortName);
876   
877  33 if (!shortName.endsWith(".xml"))
878    {
879  33 shortName = shortName + ".xml";
880    }
881  33 return shortName;
882    }
883   
884    // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
 
885  8 toggle public boolean saveAlignment(AlignFrame af, String jarFile,
886    String fileName)
887    {
888  8 try
889    {
890    // create backupfiles object and get new temp filename destination
891  8 boolean doBackup = BackupFiles.getEnabled();
892  8 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
893  8 FileOutputStream fos = new FileOutputStream(
894  8 doBackup ? backupfiles.getTempFilePath() : jarFile);
895   
896  8 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
897    {
898  0 int n = debugDelaySave;
899  0 int i = 0;
900  0 while (i < n)
901    {
902  0 Console.debug("***** debugging save sleep " + i + "/" + n);
903  0 try
904    {
905  0 Thread.sleep(1000);
906    } catch (InterruptedException e)
907    {
908    // TODO Auto-generated catch block
909  0 e.printStackTrace();
910    }
911  0 i++;
912    }
913    }
914   
915  8 JarOutputStream jout = new JarOutputStream(fos);
916  8 List<AlignFrame> frames = new ArrayList<>();
917   
918    // resolve splitframes
919  8 if (af.getViewport().getCodingComplement() != null)
920    {
921  0 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
922    }
923    else
924    {
925  8 frames.add(af);
926    }
927  8 saveAllFrames(frames, jout);
928  8 try
929    {
930  8 jout.flush();
931    } catch (Exception foo)
932    {
933    }
934  8 jout.close();
935  8 boolean success = true;
936   
937  8 if (doBackup)
938    {
939  6 backupfiles.setWriteSuccess(success);
940  6 success = backupfiles.rollBackupsAndRenameTempFile();
941    }
942   
943  8 return success;
944    } catch (Exception ex)
945    {
946  0 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
947  0 ex.printStackTrace();
948  0 return false;
949    }
950    }
951   
952    /**
953    * Each AlignFrame has a single data set associated with it. Note that none of
954    * these frames are split frames, because Desktop.getAlignFrames() collects
955    * top and bottom separately here.
956    *
957    * @param dsses
958    * @param fileName
959    * @param jout
960    */
 
961  27 toggle private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
962    String fileName, JarOutputStream jout)
963    {
964   
965    // Note that in saveAllFrames we have associated each specific dataset to
966    // ONE of its associated frames.
967  27 for (String dssids : dsses.keySet())
968    {
969  32 AlignFrame _af = dsses.get(dssids);
970  32 String jfileName = fileName + " Dataset for " + _af.getTitle();
971  32 if (!jfileName.endsWith(".xml"))
972    {
973  32 jfileName = jfileName + ".xml";
974    }
975  32 saveState(_af.alignPanel, jfileName, true, jout, null);
976    }
977    }
978   
979    /**
980    * create a JalviewModel from an alignment view and marshall it to a
981    * JarOutputStream
982    *
983    * @param ap
984    * panel to create jalview model for
985    * @param fileName
986    * name of alignment panel written to output stream
987    * @param jout
988    * jar output stream
989    * @param viewIds
990    * @param out
991    * jar entry name
992    */
 
993  56 toggle protected JalviewModel saveState(AlignmentPanel ap, String fileName,
994    JarOutputStream jout, List<String> viewIds)
995    {
996  56 return saveState(ap, fileName, false, jout, viewIds);
997    }
998   
999    /**
1000    * create a JalviewModel from an alignment view and marshall it to a
1001    * JarOutputStream
1002    *
1003    * @param ap
1004    * panel to create jalview model for
1005    * @param fileName
1006    * name of alignment panel written to output stream
1007    * @param storeDS
1008    * when true, only write the dataset for the alignment, not the data
1009    * associated with the view.
1010    * @param jout
1011    * jar output stream
1012    * @param out
1013    * jar entry name
1014    */
 
1015  88 toggle protected JalviewModel saveState(AlignmentPanel ap, String fileName,
1016    boolean storeDS, JarOutputStream jout, List<String> viewIds)
1017    {
1018  88 if (viewIds == null)
1019    {
1020  44 viewIds = new ArrayList<>();
1021    }
1022   
1023  88 initSeqRefs();
1024   
1025  88 List<UserColourScheme> userColours = new ArrayList<>();
1026   
1027  88 AlignViewport av = ap.av;
1028  88 ViewportRanges vpRanges = av.getRanges();
1029   
1030  87 final ObjectFactory objectFactory = new ObjectFactory();
1031  87 JalviewModel object = objectFactory.createJalviewModel();
1032  87 object.setVamsasModel(new VAMSAS());
1033   
1034    // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
1035  87 try
1036    {
1037  87 GregorianCalendar c = new GregorianCalendar();
1038  87 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
1039  87 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
1040  87 object.setCreationDate(now);
1041    } catch (DatatypeConfigurationException e)
1042    {
1043  0 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
1044    }
1045  87 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
1046   
1047    /**
1048    * rjal is full height alignment, jal is actual alignment with full metadata
1049    * but excludes hidden sequences.
1050    */
1051  87 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
1052   
1053  87 if (av.hasHiddenRows())
1054    {
1055  19 rjal = jal.getHiddenSequences().getFullAlignment();
1056    }
1057   
1058  87 SequenceSet vamsasSet = new SequenceSet();
1059  87 Sequence vamsasSeq;
1060    // JalviewModelSequence jms = new JalviewModelSequence();
1061   
1062  87 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1063   
1064  87 if (jal.getDataset() != null)
1065    {
1066    // dataset id is the dataset's hashcode
1067  87 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1068  87 if (storeDS)
1069    {
1070    // switch jal and the dataset
1071  32 jal = jal.getDataset();
1072  32 rjal = jal;
1073    }
1074    }
1075  87 if (jal.getProperties() != null)
1076    {
1077  1 Enumeration en = jal.getProperties().keys();
1078  22 while (en.hasMoreElements())
1079    {
1080  21 String key = en.nextElement().toString();
1081  21 SequenceSetProperties ssp = new SequenceSetProperties();
1082  21 ssp.setKey(key);
1083  21 ssp.setValue(jal.getProperties().get(key).toString());
1084    // vamsasSet.addSequenceSetProperties(ssp);
1085  21 vamsasSet.getSequenceSetProperties().add(ssp);
1086    }
1087    }
1088   
1089  87 JSeq jseq;
1090  87 Set<String> calcIdSet = new HashSet<>();
1091    // record the set of vamsas sequence XML POJO we create.
1092  87 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1093    // SAVE SEQUENCES
1094  87 for (final SequenceI jds : rjal.getSequences())
1095    {
1096  12160 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1097    : jds.getDatasetSequence();
1098  12160 String id = seqHash(jds);
1099  12160 if (vamsasSetIds.get(id) == null)
1100    {
1101  12160 if (seqRefIds.get(id) != null && !storeDS)
1102    {
1103    // This happens for two reasons: 1. multiple views are being
1104    // serialised.
1105    // 2. the hashCode has collided with another sequence's code. This
1106    // DOES
1107    // HAPPEN! (PF00072.15.stk does this)
1108    // JBPNote: Uncomment to debug writing out of files that do not read
1109    // back in due to ArrayOutOfBoundExceptions.
1110    // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1111    // jalview.bin.Console.errPrintln(jds.getName()+"
1112    // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1113    // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1114    // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1115    // jalview.bin.Console.errPrintln(rsq.getName()+"
1116    // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1117    // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1118    }
1119    else
1120    {
1121  11940 vamsasSeq = createVamsasSequence(id, jds);
1122    // vamsasSet.addSequence(vamsasSeq);
1123  11940 vamsasSet.getSequence().add(vamsasSeq);
1124  11940 vamsasSetIds.put(id, vamsasSeq);
1125  11940 seqRefIds.put(id, jds);
1126    }
1127    }
1128  12160 jseq = new JSeq();
1129  12160 jseq.setStart(jds.getStart());
1130  12160 jseq.setEnd(jds.getEnd());
1131  12160 jseq.setColour(av.getSequenceColour(jds).getRGB());
1132   
1133  12160 jseq.setId(id); // jseq id should be a string not a number
1134  12160 if (!storeDS)
1135    {
1136    // Store any sequences this sequence represents
1137  720 if (av.hasHiddenRows())
1138    {
1139    // use rjal, contains the full height alignment
1140  190 jseq.setHidden(
1141    av.getAlignment().getHiddenSequences().isHidden(jds));
1142   
1143  190 if (av.isHiddenRepSequence(jds))
1144    {
1145  2 jalview.datamodel.SequenceI[] reps = av
1146    .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1147   
1148  6 for (int h = 0; h < reps.length; h++)
1149    {
1150  4 if (reps[h] != jds)
1151    {
1152    // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1153  2 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1154    }
1155    }
1156    }
1157    }
1158    // mark sequence as reference - if it is the reference for this view
1159  720 if (jal.hasSeqrep())
1160    {
1161  80 jseq.setViewreference(jds == jal.getSeqrep());
1162    }
1163    }
1164   
1165    // TODO: omit sequence features from each alignment view's XML dump if we
1166    // are storing dataset
1167  12160 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1168  12160 for (SequenceFeature sf : sfs)
1169    {
1170    // Features features = new Features();
1171  24636 Feature features = new Feature();
1172   
1173  24636 features.setBegin(sf.getBegin());
1174  24636 features.setEnd(sf.getEnd());
1175  24636 features.setDescription(sf.getDescription());
1176  24636 features.setType(sf.getType());
1177  24636 features.setFeatureGroup(sf.getFeatureGroup());
1178  24636 features.setScore(sf.getScore());
1179  24636 if (sf.links != null)
1180    {
1181  5344 for (int l = 0; l < sf.links.size(); l++)
1182    {
1183  2672 OtherData keyValue = new OtherData();
1184  2672 keyValue.setKey("LINK_" + l);
1185  2672 keyValue.setValue(sf.links.elementAt(l).toString());
1186    // features.addOtherData(keyValue);
1187  2672 features.getOtherData().add(keyValue);
1188    }
1189    }
1190  24636 if (sf.otherDetails != null)
1191    {
1192    /*
1193    * save feature attributes, which may be simple strings or
1194    * map valued (have sub-attributes)
1195    */
1196  15576 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1197    {
1198  15596 String key = entry.getKey();
1199  15596 Object value = entry.getValue();
1200  15596 if (value instanceof Map<?, ?>)
1201    {
1202  20 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1203    .entrySet())
1204    {
1205  20 OtherData otherData = new OtherData();
1206  20 otherData.setKey(key);
1207  20 otherData.setKey2(subAttribute.getKey());
1208  20 otherData.setValue(subAttribute.getValue().toString());
1209    // features.addOtherData(otherData);
1210  20 features.getOtherData().add(otherData);
1211    }
1212    }
1213    else
1214    {
1215  15576 OtherData otherData = new OtherData();
1216  15576 otherData.setKey(key);
1217  15576 otherData.setValue(value.toString());
1218    // features.addOtherData(otherData);
1219  15576 features.getOtherData().add(otherData);
1220    }
1221    }
1222    }
1223   
1224    // jseq.addFeatures(features);
1225  24636 jseq.getFeatures().add(features);
1226    }
1227   
1228    /*
1229    * save PDB entries for sequence
1230    */
1231  12160 if (jdatasq.getAllPDBEntries() != null)
1232    {
1233  12160 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1234  12428 while (en.hasMoreElements())
1235    {
1236  268 Pdbids pdb = new Pdbids();
1237  268 jalview.datamodel.PDBEntry entry = en.nextElement();
1238   
1239  268 String pdbId = entry.getId();
1240  268 pdb.setId(pdbId);
1241  268 pdb.setType(entry.getType());
1242   
1243    /*
1244    * Store any structure views associated with this sequence. This
1245    * section copes with duplicate entries in the project, so a dataset
1246    * only view *should* be coped with sensibly.
1247    */
1248    // This must have been loaded, is it still visible?
1249  268 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1250  268 if (Desktop.getInstance() != null)
1251    {
1252  268 JInternalFrame[] jifs = Desktop.getInstance().getAllFrames();
1253  268 if (jifs != null)
1254    {
1255  268 for (JInternalFrame jif : jifs)
1256    {
1257  756 if (jif instanceof JalviewStructureDisplayI)
1258    {
1259  54 viewFrames.add((JalviewStructureDisplayI) jif);
1260    }
1261    }
1262    }
1263    }
1264  0 else if (Jalview.isHeadlessMode()
1265    && Jalview.getInstance().getCommands() != null)
1266    {
1267  0 viewFrames.addAll(
1268    StructureViewerBase.getAllStructureViewerBases());
1269    }
1270   
1271  268 String matchedFile = null;
1272  268 for (JalviewStructureDisplayI viewFrame : viewFrames)
1273    {
1274  54 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1275    matchedFile, viewFrame);
1276    /*
1277    * Only store each structure viewer's state once in the project
1278    * jar. First time through only (storeDS==false)
1279    */
1280  54 String viewId = viewFrame.getViewId();
1281  54 String viewerType = viewFrame.getViewerType().toString();
1282  54 if (!storeDS && !viewIds.contains(viewId))
1283    {
1284  3 viewIds.add(viewId);
1285  3 File viewerState = viewFrame.saveSession();
1286  3 if (viewerState != null)
1287    {
1288  3 if (viewerState.length() == 0)
1289    {
1290  0 addErrorMessage(
1291    "Dataloss warning: structure viewer session file was zero length.");
1292    }
1293  3 copyFileToJar(jout, viewerState.getPath(),
1294    getViewerJarEntryName(viewId), viewerType);
1295    }
1296    else
1297    {
1298  0 Console.error(
1299    "Failed to save viewer state for " + viewerType);
1300    }
1301    }
1302    }
1303   
1304  268 if (matchedFile != null || entry.getFile() != null)
1305    {
1306  172 if (entry.getFile() != null)
1307    {
1308    // use entry's file
1309  172 matchedFile = entry.getFile();
1310    }
1311  172 pdb.setFile(matchedFile); // entry.getFile());
1312  172 if (pdbfiles == null)
1313    {
1314  9 pdbfiles = new ArrayList<>();
1315    }
1316   
1317  172 if (!pdbfiles.contains(pdbId))
1318    {
1319  67 pdbfiles.add(pdbId);
1320  67 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1321    }
1322    }
1323   
1324  268 Enumeration<String> props = entry.getProperties();
1325  268 if (props.hasMoreElements())
1326    {
1327    // PdbentryItem item = new PdbentryItem();
1328  782 while (props.hasMoreElements())
1329    {
1330  610 Property prop = new Property();
1331  610 String key = props.nextElement();
1332  610 prop.setName(key);
1333  610 prop.setValue(entry.getProperty(key).toString());
1334    // item.addProperty(prop);
1335  610 pdb.getProperty().add(prop);
1336    }
1337    // pdb.addPdbentryItem(item);
1338    }
1339   
1340    // jseq.addPdbids(pdb);
1341  268 jseq.getPdbids().add(pdb);
1342    }
1343    }
1344   
1345  12160 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1346   
1347  12160 if (jds.hasHMMProfile())
1348    {
1349  2 saveHmmerProfile(jout, jseq, jds);
1350    }
1351    // jms.addJSeq(jseq);
1352  12160 object.getJSeq().add(jseq);
1353    }
1354   
1355  87 if (!storeDS && av.hasHiddenRows())
1356    {
1357  12 jal = av.getAlignment();
1358    }
1359    // SAVE MAPPINGS
1360    // FOR DATASET
1361  87 if (storeDS && jal.getCodonFrames() != null)
1362    {
1363  32 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1364  32 for (AlignedCodonFrame acf : jac)
1365    {
1366  0 AlcodonFrame alc = new AlcodonFrame();
1367  0 if (acf.getProtMappings() != null
1368    && acf.getProtMappings().length > 0)
1369    {
1370  0 boolean hasMap = false;
1371  0 SequenceI[] dnas = acf.getdnaSeqs();
1372  0 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1373  0 for (int m = 0; m < pmaps.length; m++)
1374    {
1375  0 AlcodMap alcmap = new AlcodMap();
1376  0 alcmap.setDnasq(seqHash(dnas[m]));
1377  0 alcmap.setMapping(
1378    createVamsasMapping(pmaps[m], dnas[m], null, false));
1379    // alc.addAlcodMap(alcmap);
1380  0 alc.getAlcodMap().add(alcmap);
1381  0 hasMap = true;
1382    }
1383  0 if (hasMap)
1384    {
1385    // vamsasSet.addAlcodonFrame(alc);
1386  0 vamsasSet.getAlcodonFrame().add(alc);
1387    }
1388    }
1389    // TODO: delete this ? dead code from 2.8.3->2.9 ?
1390    // {
1391    // AlcodonFrame alc = new AlcodonFrame();
1392    // vamsasSet.addAlcodonFrame(alc);
1393    // for (int p = 0; p < acf.aaWidth; p++)
1394    // {
1395    // Alcodon cmap = new Alcodon();
1396    // if (acf.codons[p] != null)
1397    // {
1398    // // Null codons indicate a gapped column in the translated peptide
1399    // // alignment.
1400    // cmap.setPos1(acf.codons[p][0]);
1401    // cmap.setPos2(acf.codons[p][1]);
1402    // cmap.setPos3(acf.codons[p][2]);
1403    // }
1404    // alc.addAlcodon(cmap);
1405    // }
1406    // if (acf.getProtMappings() != null
1407    // && acf.getProtMappings().length > 0)
1408    // {
1409    // SequenceI[] dnas = acf.getdnaSeqs();
1410    // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1411    // for (int m = 0; m < pmaps.length; m++)
1412    // {
1413    // AlcodMap alcmap = new AlcodMap();
1414    // alcmap.setDnasq(seqHash(dnas[m]));
1415    // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1416    // false));
1417    // alc.addAlcodMap(alcmap);
1418    // }
1419    // }
1420    }
1421    }
1422   
1423    // SAVE TREES
1424    // /////////////////////////////////
1425  87 if (!storeDS && av.getCurrentTree() != null)
1426    {
1427    // FIND ANY ASSOCIATED TREES
1428    // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1429  6 if (Desktop.getDesktopPane() != null)
1430    {
1431  6 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1432   
1433  31 for (int t = 0; t < frames.length; t++)
1434    {
1435  25 if (frames[t] instanceof TreePanel)
1436    {
1437  6 TreePanel tp = (TreePanel) frames[t];
1438   
1439  6 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1440    {
1441  6 JalviewModel.Tree tree = new JalviewModel.Tree();
1442  6 tree.setTitle(tp.getTitle());
1443  6 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1444   
1445    // Injecting annotation ids into the newick file
1446  6 if (tp.isAnnotationBased())
1447    {
1448    // inject annotationids
1449  2 NewickFile annTreeExporter = new NewickFile(
1450    tp.getTree().getTopNode())
1451    {
 
1452  121 toggle @Override
1453    public String getNodenameFor(
1454    jalview.datamodel.BinaryNode c)
1455    {
1456  121 if (c == null)
1457    {
1458  0 return null;
1459    }
1460    // If no annotation linked to the node
1461  121 if (!c.hasAlignmentAnnotation())
1462    {
1463  81 return c.getName();
1464    }
1465   
1466    // Inject annotation id
1467  40 AlignmentAnnotation nodeAnn = c
1468    .getAlignmentAnnotation();
1469    // this will already have been generated when the dataset
1470    // was saved
1471  40 return nodeAnn.annotationId;
1472    };
1473    };
1474  2 tree.setNewick(annTreeExporter.print(false, true));
1475   
1476    // for color map
1477  2 JalviewModel.Tree.TreeColorMap treeColorMap = new JalviewModel.Tree.TreeColorMap();
1478  2 Map<String, Color> colorMap = tp
1479    .getSecondaryStructureProviderColorMap();
1480  2 if (colorMap != null)
1481    {
1482  2 for (Map.Entry<String, Color> col : colorMap.entrySet())
1483    {
1484  7 JalviewModel.Tree.TreeColorMap.ColorEntry colorEntry = new JalviewModel.Tree.TreeColorMap.ColorEntry();
1485  7 colorEntry.setColor(col.getValue().getRGB());
1486  7 colorEntry.setLabel(col.getKey());
1487  7 treeColorMap.getColorEntry().add(colorEntry);
1488    }
1489    }
1490  2 tree.setTreeColorMap(treeColorMap);
1491   
1492    }
1493    else
1494    {
1495    // tree leaf nodes are named correctly
1496  4 tree.setNewick(tp.getTree().print());
1497    }
1498  6 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1499   
1500  6 tree.setFitToWindow(tp.fitToWindow.getState());
1501  6 tree.setFontName(tp.getTreeFont().getName());
1502  6 tree.setFontSize(tp.getTreeFont().getSize());
1503  6 tree.setFontStyle(tp.getTreeFont().getStyle());
1504  6 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1505   
1506  6 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1507  6 tree.setShowDistances(tp.distanceMenu.getState());
1508   
1509  6 tree.setHeight(tp.getHeight());
1510  6 tree.setWidth(tp.getWidth());
1511  6 tree.setXpos(tp.getX());
1512  6 tree.setYpos(tp.getY());
1513  6 tree.setId(makeHashCode(tp, null));
1514  6 tree.setLinkToAllViews(
1515    tp.getTreeCanvas().isApplyToAllViews());
1516   
1517    // columnWiseTree
1518  6 if (tp.isColumnWise())
1519    {
1520  0 tree.setColumnWise(true);
1521  0 String annId = tp.getAssocAnnotation().annotationId;
1522  0 tree.setColumnReference(annId);
1523    }
1524   
1525    // annotation based tree
1526  6 if (tp.isAnnotationBased())
1527    {
1528  2 tree.setAnnotationBased(true);
1529  2 String viewName = tp.getShowAnnotationAs();
1530  2 tree.setShowAnnotationAs(viewName);
1531    }
1532    // jms.addTree(tree);
1533  6 object.getTree().add(tree);
1534    }
1535    }
1536    }
1537    }
1538    }
1539   
1540    /*
1541    * save PCA viewers
1542    */
1543  87 if (!storeDS && Desktop.getDesktopPane() != null)
1544    {
1545  53 for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames())
1546    {
1547  181 if (frame instanceof PCAPanel)
1548    {
1549  6 PCAPanel panel = (PCAPanel) frame;
1550  6 if (panel.getAlignViewport().getAlignment() == jal)
1551    {
1552  2 savePCA(panel, object);
1553    }
1554    }
1555  181 if (frame instanceof PaSiMapPanel)
1556    {
1557  0 PaSiMapPanel panel = (PaSiMapPanel) frame;
1558  0 if (panel.getAlignViewport().getAlignment() == jal)
1559    {
1560  0 savePaSiMap(panel, object);
1561    }
1562    }
1563    }
1564    }
1565   
1566    // SAVE ANNOTATIONS
1567    /**
1568    * store forward refs from an annotationRow to any groups
1569    */
1570  87 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1571  87 if (storeDS)
1572    {
1573  32 for (SequenceI sq : jal.getSequences())
1574    {
1575    // Store annotation on dataset sequences only
1576  11440 AlignmentAnnotation[] aa = sq.getAnnotation();
1577  11440 if (aa != null && aa.length > 0)
1578    {
1579  125 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1580    vamsasSet);
1581    }
1582    }
1583    }
1584    else
1585    {
1586  55 if (jal.getAlignmentAnnotation() != null)
1587    {
1588    // Store the annotation shown on the alignment.
1589  55 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1590  55 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1591    vamsasSet);
1592    }
1593    }
1594    // SAVE GROUPS
1595  87 if (jal.getGroups() != null)
1596    {
1597  87 JGroup[] groups = new JGroup[jal.getGroups().size()];
1598  87 int i = -1;
1599  87 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1600    {
1601  22 JGroup jGroup = new JGroup();
1602  22 groups[++i] = jGroup;
1603   
1604  22 jGroup.setStart(sg.getStartRes());
1605  22 jGroup.setEnd(sg.getEndRes());
1606  22 jGroup.setName(sg.getName());
1607  22 if (groupRefs.containsKey(sg))
1608    {
1609    // group has references so set its ID field
1610  6 jGroup.setId(groupRefs.get(sg));
1611    }
1612   
1613  22 List<String> groupSecondaryStructureSources = sg
1614    .getSecondaryStructureSources();
1615  22 if (groupSecondaryStructureSources != null
1616    && groupSecondaryStructureSources.size() > 0)
1617    {
1618  0 jGroup.getSecStrProvider().addAll(groupSecondaryStructureSources);
1619    }
1620   
1621  22 ColourSchemeI colourScheme = sg.getColourScheme();
1622  22 if (colourScheme != null)
1623    {
1624  14 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1625  14 if (groupColourScheme.conservationApplied())
1626    {
1627  2 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1628   
1629  2 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1630    {
1631  0 jGroup.setColour(setUserColourScheme(colourScheme,
1632    userColours, object));
1633    }
1634    else
1635    {
1636  2 jGroup.setColour(colourScheme.getSchemeName());
1637    }
1638    }
1639  12 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1640    {
1641  1 jGroup.setColour("AnnotationColourGradient");
1642  1 jGroup.setAnnotationColours(constructAnnotationColours(
1643    (jalview.schemes.AnnotationColourGradient) colourScheme,
1644    userColours, object));
1645    }
1646  11 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1647    {
1648  0 jGroup.setColour(
1649    setUserColourScheme(colourScheme, userColours, object));
1650    }
1651    else
1652    {
1653  11 jGroup.setColour(colourScheme.getSchemeName());
1654    }
1655   
1656  14 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1657   
1658  14 if (groupColourScheme.isConsensusSecondaryStructureColouring())
1659    {
1660  5 jGroup.setSecstrSelected(groupColourScheme
1661    .isConsensusSecondaryStructureColouring());
1662  5 jGroup.setSecstrThreshold(groupColourScheme
1663    .getConsensusSecondaryStructureThreshold());
1664    }
1665    }
1666  22 if (sg.getIdColour() != null)
1667    {
1668  19 jGroup.setIdColour(sg.getIdColour().getRGB());
1669    }
1670  22 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1671  22 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1672  22 jGroup.setDisplayText(sg.getDisplayText());
1673  22 jGroup.setColourText(sg.getColourText());
1674  22 jGroup.setTextCol1(sg.textColour.getRGB());
1675  22 jGroup.setTextCol2(sg.textColour2.getRGB());
1676  22 jGroup.setTextColThreshold(sg.thresholdTextColour);
1677  22 jGroup.setShowUnconserved(sg.getShowNonconserved());
1678  22 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1679  22 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1680  22 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1681  22 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1682  22 for (SequenceI seq : sg.getSequences())
1683    {
1684    // jGroup.addSeq(seqHash(seq));
1685  148 jGroup.getSeq().add(seqHash(seq));
1686    }
1687   
1688    // Save annotations from annotation based tree for groups created
1689    // by splitting the tree
1690  22 if (sg.getAnnotationsFromTree() != null)
1691    {
1692  22 for (AlignmentAnnotation annot : sg.getAnnotationsFromTree())
1693    {
1694  20 jGroup.getAnnotationFromTree().add(annot.annotationId);
1695    }
1696    }
1697    }
1698   
1699    // jms.setJGroup(groups);
1700  87 Object group;
1701  87 for (JGroup grp : groups)
1702    {
1703  22 object.getJGroup().add(grp);
1704    }
1705    }
1706  87 if (!storeDS)
1707    {
1708    // /////////SAVE VIEWPORT
1709  55 Viewport view = new Viewport();
1710  55 view.setTitle(ap.alignFrame.getTitle());
1711  55 view.setSequenceSetId(
1712    makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1713  55 view.setId(av.getViewId());
1714  55 if (av.getCodingComplement() != null)
1715    {
1716  0 view.setComplementId(av.getCodingComplement().getViewId());
1717    }
1718  55 view.setViewName(av.getViewName());
1719  55 view.setGatheredViews(av.isGatherViewsHere());
1720   
1721  55 Rectangle size = ap.av.getExplodedGeometry();
1722  55 Rectangle position = size;
1723  55 if (size == null)
1724    {
1725  45 size = ap.alignFrame.getBounds();
1726  45 if (av.getCodingComplement() != null)
1727    {
1728  0 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1729    .getBounds();
1730    }
1731    else
1732    {
1733  45 position = size;
1734    }
1735    }
1736  55 view.setXpos(position.x);
1737  55 view.setYpos(position.y);
1738   
1739  55 view.setWidth(size.width);
1740  55 view.setHeight(size.height);
1741   
1742  55 view.setStartRes(vpRanges.getStartRes());
1743  55 view.setStartSeq(vpRanges.getStartSeq());
1744   
1745  55 OverviewPanel ov = ap.getOverviewPanel();
1746  55 if (ov != null)
1747    {
1748  14 Overview overview = new Overview();
1749  14 overview.setTitle(ov.getTitle());
1750  14 Rectangle bounds = ov.getFrameBounds();
1751  14 overview.setXpos(bounds.x);
1752  14 overview.setYpos(bounds.y);
1753  14 overview.setWidth(bounds.width);
1754  14 overview.setHeight(bounds.height);
1755  14 overview.setShowHidden(ov.isShowHiddenRegions());
1756  14 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1757  14 overview.setResidueColour(
1758    ov.getCanvas().getResidueColour().getRGB());
1759  14 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1760  14 view.setOverview(overview);
1761    }
1762  55 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1763    {
1764  0 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1765    userColours, object));
1766    }
1767  55 else if (av
1768    .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1769    {
1770  2 AnnotationColourScheme ac = constructAnnotationColours(
1771    (jalview.schemes.AnnotationColourGradient) av
1772    .getGlobalColourScheme(),
1773    userColours, object);
1774   
1775  2 view.setAnnotationColours(ac);
1776  2 view.setBgColour("AnnotationColourGradient");
1777    }
1778    else
1779    {
1780  53 view.setBgColour(ColourSchemeProperty
1781    .getColourName(av.getGlobalColourScheme()));
1782    }
1783   
1784  55 ResidueShaderI vcs = av.getResidueShading();
1785  55 ColourSchemeI cs = av.getGlobalColourScheme();
1786   
1787  55 if (cs != null)
1788    {
1789  9 if (vcs.conservationApplied())
1790    {
1791  2 view.setConsThreshold(vcs.getConservationInc());
1792  2 if (cs instanceof jalview.schemes.UserColourScheme)
1793    {
1794  0 view.setBgColour(setUserColourScheme(cs, userColours, object));
1795    }
1796    }
1797  9 view.setPidThreshold(vcs.getThreshold());
1798   
1799  9 if (vcs.isConsensusSecondaryStructureColouring())
1800    {
1801  0 view.setSecstrThreshold(
1802    vcs.getConsensusSecondaryStructureThreshold());
1803    }
1804    }
1805   
1806  55 view.setConservationSelected(av.getConservationSelected());
1807  55 view.setPidSelected(av.getAbovePIDThreshold());
1808  55 view.setSecstrSelected(av.getByConsensusSecondaryStructureSelected());
1809  55 view.setCharHeight(av.getCharHeight());
1810  55 view.setCharWidth(av.getCharWidth());
1811  55 final Font font = av.getFont();
1812  55 view.setFontName(font.getName());
1813  55 view.setFontSize(font.getSize());
1814  55 view.setFontStyle(font.getStyle());
1815  55 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1816  55 view.setRenderGaps(av.isRenderGaps());
1817  55 view.setShowAnnotation(av.isShowAnnotation());
1818  55 view.setShowStructureProviders(av.isShowStructureProvider());
1819  55 view.setShowBoxes(av.getShowBoxes());
1820  55 view.setShowColourText(av.getColourText());
1821  55 view.setShowFullId(av.getShowJVSuffix());
1822  55 view.setRightAlignIds(av.isRightAlignIds());
1823  55 view.setIdWidth(av.getIdWidth());
1824  55 view.setIdWidthManuallyAdjusted(
1825    ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1826   
1827  55 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1828  55 view.setShowText(av.getShowText());
1829  55 view.setShowUnconserved(av.getShowUnconserved());
1830  55 view.setWrapAlignment(av.getWrapAlignment());
1831  55 view.setTextCol1(av.getTextColour().getRGB());
1832  55 view.setTextCol2(av.getTextColour2().getRGB());
1833  55 view.setTextColThreshold(av.getThresholdTextColour());
1834  55 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1835  55 view.setShowSequenceLogo(av.isShowSequenceLogo());
1836  55 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1837  55 view.setShowGroupConsensus(av.isShowGroupConsensus());
1838  55 view.setShowGroupSecStrConsensus(av.isShowGroupSSConsensus());
1839  55 view.setShowGroupConservation(av.isShowGroupConservation());
1840  55 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1841  55 view.setShowDbRefTooltip(av.isShowDBRefs());
1842  55 view.setFollowHighlight(av.isFollowHighlight());
1843  55 view.setFollowSelection(av.followSelection);
1844  55 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1845  55 view.setShowComplementFeatures(av.isShowComplementFeatures());
1846  55 view.setShowComplementFeaturesOnTop(
1847    av.isShowComplementFeaturesOnTop());
1848  55 if (av.getFeaturesDisplayed() != null)
1849    {
1850  18 FeatureSettings fs = new FeatureSettings();
1851   
1852  18 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1853    .getFeatureRenderer();
1854  18 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1855   
1856  18 Vector<String> settingsAdded = new Vector<>();
1857  18 if (renderOrder != null)
1858    {
1859  18 for (String featureType : renderOrder)
1860    {
1861  267 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1862  267 setting.setType(featureType);
1863   
1864    /*
1865    * save any filter for the feature type
1866    */
1867  267 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1868  267 if (filter != null)
1869    {
1870  3 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1871    .iterator();
1872  3 FeatureMatcherI firstFilter = filters.next();
1873  3 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1874    filters, filter.isAnded()));
1875    }
1876   
1877    /*
1878    * save colour scheme for the feature type
1879    */
1880  267 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1881  267 if (!fcol.isSimpleColour())
1882    {
1883  4 setting.setColour(fcol.getMaxColour().getRGB());
1884  4 setting.setMincolour(fcol.getMinColour().getRGB());
1885  4 setting.setMin(fcol.getMin());
1886  4 setting.setMax(fcol.getMax());
1887  4 setting.setColourByLabel(fcol.isColourByLabel());
1888  4 if (fcol.isColourByAttribute())
1889    {
1890  2 String[] attName = fcol.getAttributeName();
1891  2 setting.getAttributeName().add(attName[0]);
1892  2 if (attName.length > 1)
1893    {
1894  1 setting.getAttributeName().add(attName[1]);
1895    }
1896    }
1897  4 setting.setAutoScale(fcol.isAutoScaled());
1898  4 setting.setThreshold(fcol.getThreshold());
1899  4 Color noColour = fcol.getNoColour();
1900  4 if (noColour == null)
1901    {
1902  4 setting.setNoValueColour(NoValueColour.NONE);
1903    }
1904  0 else if (noColour.equals(fcol.getMaxColour()))
1905    {
1906  0 setting.setNoValueColour(NoValueColour.MAX);
1907    }
1908    else
1909    {
1910  0 setting.setNoValueColour(NoValueColour.MIN);
1911    }
1912    // -1 = No threshold, 0 = Below, 1 = Above
1913  4 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1914  3 : (fcol.isBelowThreshold() ? 0 : -1));
1915    }
1916    else
1917    {
1918  263 setting.setColour(fcol.getColour().getRGB());
1919    }
1920   
1921  267 setting.setDisplay(
1922    av.getFeaturesDisplayed().isVisible(featureType));
1923  267 float rorder = fr.getOrder(featureType);
1924  267 if (rorder > -1)
1925    {
1926  267 setting.setOrder(rorder);
1927    }
1928    /// fs.addSetting(setting);
1929  267 fs.getSetting().add(setting);
1930  267 settingsAdded.addElement(featureType);
1931    }
1932    }
1933   
1934    // is groups actually supposed to be a map here ?
1935  18 Iterator<String> en = fr.getFeatureGroups().iterator();
1936  18 Vector<String> groupsAdded = new Vector<>();
1937  147 while (en.hasNext())
1938    {
1939  129 String grp = en.next();
1940  129 if (groupsAdded.contains(grp))
1941    {
1942  0 continue;
1943    }
1944  129 Group g = new Group();
1945  129 g.setName(grp);
1946  129 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1947    .booleanValue());
1948    // fs.addGroup(g);
1949  129 fs.getGroup().add(g);
1950  129 groupsAdded.addElement(grp);
1951    }
1952    // jms.setFeatureSettings(fs);
1953  18 object.setFeatureSettings(fs);
1954    }
1955   
1956  55 if (av.hasHiddenColumns())
1957    {
1958  4 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1959    .getHiddenColumns();
1960  4 if (hidden == null)
1961    {
1962  0 Console.warn(
1963    "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1964    }
1965    else
1966    {
1967  4 Iterator<int[]> hiddenRegions = hidden.iterator();
1968  10 while (hiddenRegions.hasNext())
1969    {
1970  6 int[] region = hiddenRegions.next();
1971  6 HiddenColumns hc = new HiddenColumns();
1972  6 hc.setStart(region[0]);
1973  6 hc.setEnd(region[1]);
1974    // view.addHiddenColumns(hc);
1975  6 view.getHiddenColumns().add(hc);
1976    }
1977    }
1978    }
1979  55 if (calcIdSet.size() > 0)
1980    {
1981  55 for (String calcId : calcIdSet)
1982    {
1983  86 if (calcId.trim().length() > 0)
1984    {
1985  31 CalcIdParam cidp = createCalcIdParam(calcId, av);
1986    // Some calcIds have no parameters.
1987  31 if (cidp != null)
1988    {
1989    // view.addCalcIdParam(cidp);
1990  0 view.getCalcIdParam().add(cidp);
1991    }
1992    }
1993    }
1994    }
1995   
1996    // jms.addViewport(view);
1997  55 object.getViewport().add(view);
1998    }
1999   
2000  87 if (storeDS)
2001    {
2002    // store matrices referenced by any views or annotation in this dataset
2003  32 if (xmlMatrices != null && xmlMatrices.size() > 0)
2004    {
2005  5 Console.debug(
2006    "Adding " + xmlMatrices.size() + " matrices to dataset.");
2007  5 vamsasSet.getMatrix().addAll(xmlMatrices);
2008  5 xmlMatrices.clear();
2009    }
2010    }
2011   
2012    // object.setJalviewModelSequence(jms);
2013    // object.getVamsasModel().addSequenceSet(vamsasSet);
2014  87 object.getVamsasModel().getSequenceSet().add(vamsasSet);
2015   
2016  87 if (jout != null && fileName != null)
2017    {
2018    // We may not want to write the object to disk,
2019    // eg we can copy the alignViewport to a new view object
2020    // using save and then load
2021  75 try
2022    {
2023  75 fileName = fileName.replace('\\', '/');
2024  75 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
2025  75 JarEntry entry = new JarEntry(fileName);
2026  75 jout.putNextEntry(entry);
2027  71 PrintWriter pout = new PrintWriter(
2028    new OutputStreamWriter(jout, UTF_8));
2029  71 JAXBContext jaxbContext = JAXBContext
2030    .newInstance(JalviewModel.class);
2031  71 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
2032   
2033    // output pretty printed
2034    // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
2035  71 jaxbMarshaller.marshal(
2036    new ObjectFactory().createJalviewModel(object), pout);
2037   
2038    // jaxbMarshaller.marshal(object, pout);
2039    // marshaller.marshal(object);
2040  71 pout.flush();
2041  71 jout.closeEntry();
2042    } catch (Exception ex)
2043    {
2044    // TODO: raise error in GUI if marshalling failed.
2045  4 jalview.bin.Console.errPrintln("Error writing Jalview project");
2046  4 ex.printStackTrace();
2047    }
2048    }
2049  87 return object;
2050    }
2051   
 
2052  0 toggle private void addErrorMessage(String string)
2053    {
2054  0 if (errorMessage == null)
2055    {
2056  0 errorMessage = "";
2057    }
2058  0 errorMessage += string + "\n";
2059    }
2060   
2061    /**
2062    * Saves the HMMER profile associated with the sequence as a file in the jar,
2063    * in HMMER format, and saves the name of the file as a child element of the
2064    * XML sequence element
2065    *
2066    * @param jout
2067    * @param xmlSeq
2068    * @param seq
2069    */
 
2070  2 toggle protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
2071    SequenceI seq)
2072    {
2073  2 HiddenMarkovModel profile = seq.getHMM();
2074  2 if (profile == null)
2075    {
2076  0 Console.warn("Want to save HMM profile for " + seq.getName()
2077    + " but none found");
2078  0 return;
2079    }
2080  2 HMMFile hmmFile = new HMMFile(profile);
2081  2 String hmmAsString = hmmFile.print();
2082  2 String jarEntryName = HMMER_PREFIX + nextCounter();
2083  2 try
2084    {
2085  2 writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
2086  2 xmlSeq.setHmmerProfile(jarEntryName);
2087    } catch (IOException e)
2088    {
2089  0 Console.warn("Error saving HMM profile: " + e.getMessage());
2090    }
2091    }
2092   
2093    /**
2094    * Writes PCA viewer attributes and computed values to an XML model object and
2095    * adds it to the JalviewModel. Any exceptions are reported by logging.
2096    */
 
2097  2 toggle protected void savePCA(PCAPanel panel, JalviewModel object)
2098    {
2099  2 try
2100    {
2101  2 PcaViewer viewer = new PcaViewer();
2102  2 viewer.setHeight(panel.getHeight());
2103  2 viewer.setWidth(panel.getWidth());
2104  2 viewer.setXpos(panel.getX());
2105  2 viewer.setYpos(panel.getY());
2106  2 viewer.setTitle(panel.getTitle());
2107  2 PCAModel pcaModel = panel.getPcaModel();
2108  2 viewer.setScoreModelName(pcaModel.getScoreModelName());
2109  2 viewer.setXDim(panel.getSelectedDimensionIndex(X));
2110  2 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
2111  2 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
2112  2 viewer.setBgColour(
2113    panel.getRotatableCanvas().getBackgroundColour().getRGB());
2114  2 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
2115  2 float[] spMin = panel.getRotatableCanvas().getSeqMin();
2116  2 SeqPointMin spmin = new SeqPointMin();
2117  2 spmin.setXPos(spMin[0]);
2118  2 spmin.setYPos(spMin[1]);
2119  2 spmin.setZPos(spMin[2]);
2120  2 viewer.setSeqPointMin(spmin);
2121  2 float[] spMax = panel.getRotatableCanvas().getSeqMax();
2122  2 SeqPointMax spmax = new SeqPointMax();
2123  2 spmax.setXPos(spMax[0]);
2124  2 spmax.setYPos(spMax[1]);
2125  2 spmax.setZPos(spMax[2]);
2126  2 viewer.setSeqPointMax(spmax);
2127  2 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
2128  2 viewer.setLinkToAllViews(
2129    panel.getRotatableCanvas().isApplyToAllViews());
2130  2 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
2131  2 viewer.setIncludeGaps(sp.includeGaps());
2132  2 viewer.setMatchGaps(sp.matchGaps());
2133  2 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
2134  2 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
2135   
2136    /*
2137    * sequence points on display
2138    */
2139  2 for (jalview.datamodel.SequencePoint spt : pcaModel
2140    .getSequencePoints())
2141    {
2142  37 SequencePoint point = new SequencePoint();
2143  37 point.setSequenceRef(seqHash(spt.getSequence()));
2144  37 point.setXPos(spt.coord.x);
2145  37 point.setYPos(spt.coord.y);
2146  37 point.setZPos(spt.coord.z);
2147  37 AlignmentAnnotation alignAnnot = spt.getAlignmentAnnotation();
2148  37 if( alignAnnot != null )
2149    {
2150  16 point.setAnnotationId(alignAnnot.annotationId);
2151    }
2152  37 point.setSeqPointAnnotDet(spt.getAnnotationDetails());
2153  37 point.setSeqPointLabel(spt.getLabel());
2154  37 viewer.getSequencePoint().add(point);
2155    }
2156   
2157    /*
2158    * (end points of) axes on display
2159    */
2160  2 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
2161    {
2162   
2163  6 Axis axis = new Axis();
2164  6 axis.setXPos(p.x);
2165  6 axis.setYPos(p.y);
2166  6 axis.setZPos(p.z);
2167  6 viewer.getAxis().add(axis);
2168    }
2169   
2170    /*
2171    * raw PCA data (note we are not restoring PCA inputs here -
2172    * alignment view, score model, similarity parameters)
2173    */
2174  2 PcaDataType data = new PcaDataType();
2175  2 viewer.setPcaData(data);
2176  2 PCA pca = pcaModel.getPcaData();
2177   
2178  2 DoubleMatrix pm = new DoubleMatrix();
2179  2 saveDoubleMatrix(pca.getPairwiseScores(), pm);
2180  2 data.setPairwiseMatrix(pm);
2181   
2182  2 DoubleMatrix tm = new DoubleMatrix();
2183  2 saveDoubleMatrix(pca.getTridiagonal(), tm);
2184  2 data.setTridiagonalMatrix(tm);
2185   
2186  2 DoubleMatrix eigenMatrix = new DoubleMatrix();
2187  2 data.setEigenMatrix(eigenMatrix);
2188  2 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
2189   
2190  2 object.getPcaViewer().add(viewer);
2191    } catch (Throwable t)
2192    {
2193  0 Console.error("Error saving PCA: " + t.getMessage());
2194    }
2195    }
2196   
2197    /**
2198    * Writes PaSiMap viewer attributes and computed values to an XML model object
2199    * and adds it to the JalviewModel. Any exceptions are reported by logging.
2200    * uses the functions from PCA
2201    */
 
2202  0 toggle protected void savePaSiMap(PaSiMapPanel panel, JalviewModel object)
2203    {
2204    // TODO: this should be merged with above savePCAPanel - otherwise it is
2205    // essentially redundant code
2206  0 try
2207    {
2208  0 PcaViewer viewer = new PcaViewer();
2209  0 viewer.setHeight(panel.getHeight());
2210  0 viewer.setWidth(panel.getWidth());
2211  0 viewer.setXpos(panel.getX());
2212  0 viewer.setYpos(panel.getY());
2213  0 viewer.setTitle(panel.getTitle());
2214  0 PaSiMapModel pasimapModel = panel.getPasimapModel();
2215  0 viewer.setScoreModelName(pasimapModel.getScoreModelName());
2216  0 viewer.setXDim(panel.getSelectedDimensionIndex(X));
2217  0 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
2218  0 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
2219  0 viewer.setBgColour(
2220    panel.getRotatableCanvas().getBackgroundColour().getRGB());
2221  0 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
2222  0 float[] spMin = panel.getRotatableCanvas().getSeqMin();
2223  0 SeqPointMin spmin = new SeqPointMin();
2224  0 spmin.setXPos(spMin[0]);
2225  0 spmin.setYPos(spMin[1]);
2226  0 spmin.setZPos(spMin[2]);
2227  0 viewer.setSeqPointMin(spmin);
2228  0 float[] spMax = panel.getRotatableCanvas().getSeqMax();
2229  0 SeqPointMax spmax = new SeqPointMax();
2230  0 spmax.setXPos(spMax[0]);
2231  0 spmax.setYPos(spMax[1]);
2232  0 spmax.setZPos(spMax[2]);
2233  0 viewer.setSeqPointMax(spmax);
2234  0 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
2235  0 viewer.setLinkToAllViews(
2236    panel.getRotatableCanvas().isApplyToAllViews());
2237    /* NOT FOR PASIMAP CALCULATIONS
2238    *
2239    SimilarityParamsI sp = pasimapModel.getSimilarityParameters();
2240    viewer.setIncludeGaps(sp.includeGaps());
2241    viewer.setMatchGaps(sp.matchGaps());
2242    viewer.setIncludeGappedColumns(sp.includeGappedColumns());
2243    viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
2244    */
2245   
2246    /*
2247    * sequence points on display
2248    */
2249  0 for (jalview.datamodel.SequencePoint spt : pasimapModel
2250    .getSequencePoints())
2251    {
2252  0 SequencePoint point = new SequencePoint();
2253  0 point.setSequenceRef(seqHash(spt.getSequence()));
2254  0 point.setXPos(spt.coord.x);
2255  0 point.setYPos(spt.coord.y);
2256  0 point.setZPos(spt.coord.z);
2257  0 viewer.getSequencePoint().add(point);
2258    }
2259   
2260    /*
2261    * (end points of) axes on display
2262    */
2263  0 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
2264    {
2265   
2266  0 Axis axis = new Axis();
2267  0 axis.setXPos(p.x);
2268  0 axis.setYPos(p.y);
2269  0 axis.setZPos(p.z);
2270  0 viewer.getAxis().add(axis);
2271    }
2272   
2273    /*
2274    * raw PaSiMap data (note we are not restoring PaSiMap inputs here -
2275    * alignment view, score model, similarity parameters)
2276    */
2277  0 PcaDataType data = new PcaDataType();
2278  0 viewer.setPcaData(data);
2279  0 PaSiMap pasimap = pasimapModel.getPasimapData();
2280   
2281  0 DoubleMatrix pm = new DoubleMatrix();
2282  0 saveDoubleMatrix(pasimap.getPairwiseScores(), pm);
2283  0 data.setPairwiseMatrix(pm);
2284   
2285  0 DoubleMatrix eigenMatrix = new DoubleMatrix();
2286  0 data.setEigenMatrix(eigenMatrix);
2287  0 saveDoubleMatrix(pasimap.getEigenmatrix(), eigenMatrix);
2288   
2289  0 object.getPcaViewer().add(viewer);
2290    } catch (Throwable t)
2291    {
2292  0 Console.error("Error saving PaSiMap: " + t.getMessage());
2293    }
2294    }
2295   
2296    /**
2297    * Stores values from a matrix into an XML element, including (if present) the
2298    * D or E vectors
2299    *
2300    * @param m
2301    * @param xmlMatrix
2302    * @see #loadDoubleMatrix(DoubleMatrix)
2303    */
 
2304  6 toggle protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
2305    {
2306  6 xmlMatrix.setRows(m.height());
2307  6 xmlMatrix.setColumns(m.width());
2308  117 for (int i = 0; i < m.height(); i++)
2309    {
2310  111 DoubleVector row = new DoubleVector();
2311  2238 for (int j = 0; j < m.width(); j++)
2312    {
2313  2127 row.getV().add(m.getValue(i, j));
2314    }
2315  111 xmlMatrix.getRow().add(row);
2316    }
2317  6 if (m.getD() != null)
2318    {
2319  4 DoubleVector dVector = new DoubleVector();
2320  4 for (double d : m.getD())
2321    {
2322  74 dVector.getV().add(d);
2323    }
2324  4 xmlMatrix.setD(dVector);
2325    }
2326  6 if (m.getE() != null)
2327    {
2328  4 DoubleVector eVector = new DoubleVector();
2329  4 for (double e : m.getE())
2330    {
2331  74 eVector.getV().add(e);
2332    }
2333  4 xmlMatrix.setE(eVector);
2334    }
2335    }
2336   
2337    /**
2338    * Loads XML matrix data into a new Matrix object, including the D and/or E
2339    * vectors (if present)
2340    *
2341    * @param mData
2342    * @return
2343    * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2344    */
 
2345  6 toggle protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2346    {
2347  6 int rows = mData.getRows();
2348  6 double[][] vals = new double[rows][];
2349   
2350  117 for (int i = 0; i < rows; i++)
2351    {
2352  111 List<Double> dVector = mData.getRow().get(i).getV();
2353  111 vals[i] = new double[dVector.size()];
2354  111 int dvi = 0;
2355  111 for (Double d : dVector)
2356    {
2357  2127 vals[i][dvi++] = d;
2358    }
2359    }
2360   
2361  6 MatrixI m = new Matrix(vals);
2362   
2363  6 if (mData.getD() != null)
2364    {
2365  4 List<Double> dVector = mData.getD().getV();
2366  4 double[] vec = new double[dVector.size()];
2367  4 int dvi = 0;
2368  4 for (Double d : dVector)
2369    {
2370  74 vec[dvi++] = d;
2371    }
2372  4 m.setD(vec);
2373    }
2374  6 if (mData.getE() != null)
2375    {
2376  4 List<Double> dVector = mData.getE().getV();
2377  4 double[] vec = new double[dVector.size()];
2378  4 int dvi = 0;
2379  4 for (Double d : dVector)
2380    {
2381  74 vec[dvi++] = d;
2382    }
2383  4 m.setE(vec);
2384    }
2385   
2386  6 return m;
2387    }
2388   
2389    /**
2390    * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2391    * for each viewer, with
2392    * <ul>
2393    * <li>viewer geometry (position, size, split pane divider location)</li>
2394    * <li>index of the selected structure in the viewer (currently shows gapped
2395    * or ungapped)</li>
2396    * <li>the id of the annotation holding RNA secondary structure</li>
2397    * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2398    * </ul>
2399    * Varna viewer state is also written out (in native Varna XML) to separate
2400    * project jar entries. A separate entry is written for each RNA structure
2401    * displayed, with the naming convention
2402    * <ul>
2403    * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2404    * </ul>
2405    *
2406    * @param jout
2407    * @param jseq
2408    * @param jds
2409    * @param viewIds
2410    * @param ap
2411    * @param storeDataset
2412    */
 
2413  12160 toggle protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2414    final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2415    boolean storeDataset)
2416    {
2417  12160 if (Desktop.getDesktopPane() == null)
2418    {
2419  60 return;
2420    }
2421  12100 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2422  37963 for (int f = frames.length - 1; f > -1; f--)
2423    {
2424  25863 if (frames[f] instanceof AppVarna)
2425    {
2426  0 AppVarna varna = (AppVarna) frames[f];
2427    /*
2428    * link the sequence to every viewer that is showing it and is linked to
2429    * its alignment panel
2430    */
2431  0 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2432    {
2433  0 String viewId = varna.getViewId();
2434  0 RnaViewer rna = new RnaViewer();
2435  0 rna.setViewId(viewId);
2436  0 rna.setTitle(varna.getTitle());
2437  0 rna.setXpos(varna.getX());
2438  0 rna.setYpos(varna.getY());
2439  0 rna.setWidth(varna.getWidth());
2440  0 rna.setHeight(varna.getHeight());
2441  0 rna.setDividerLocation(varna.getDividerLocation());
2442  0 rna.setSelectedRna(varna.getSelectedIndex());
2443    // jseq.addRnaViewer(rna);
2444  0 jseq.getRnaViewer().add(rna);
2445   
2446    /*
2447    * Store each Varna panel's state once in the project per sequence.
2448    * First time through only (storeDataset==false)
2449    */
2450    // boolean storeSessions = false;
2451    // String sequenceViewId = viewId + seqsToIds.get(jds);
2452    // if (!storeDataset && !viewIds.contains(sequenceViewId))
2453    // {
2454    // viewIds.add(sequenceViewId);
2455    // storeSessions = true;
2456    // }
2457  0 for (RnaModel model : varna.getModels())
2458    {
2459  0 if (model.seq == jds)
2460    {
2461    /*
2462    * VARNA saves each view (sequence or alignment secondary
2463    * structure, gapped or trimmed) as a separate XML file
2464    */
2465  0 String jarEntryName = rnaSessions.get(model);
2466  0 if (jarEntryName == null)
2467    {
2468   
2469  0 String varnaStateFile = varna.getStateInfo(model.rna);
2470  0 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2471  0 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2472  0 rnaSessions.put(model, jarEntryName);
2473    }
2474  0 SecondaryStructure ss = new SecondaryStructure();
2475  0 String annotationId = varna.getAnnotation(jds).annotationId;
2476  0 ss.setAnnotationId(annotationId);
2477  0 ss.setViewerState(jarEntryName);
2478  0 ss.setGapped(model.gapped);
2479  0 ss.setTitle(model.title);
2480    // rna.addSecondaryStructure(ss);
2481  0 rna.getSecondaryStructure().add(ss);
2482    }
2483    }
2484    }
2485    }
2486    }
2487    }
2488   
2489    /**
2490    * Copy the contents of a file to a new entry added to the output jar
2491    *
2492    * @param jout
2493    * @param infilePath
2494    * @param jarEntryName
2495    * @param msg
2496    * additional identifying info to log to the console
2497    */
 
2498  70 toggle protected void copyFileToJar(JarOutputStream jout, String infilePath,
2499    String jarEntryName, String msg)
2500    {
2501  70 try (InputStream is = new FileInputStream(infilePath))
2502    {
2503  70 File file = new File(infilePath);
2504  70 if (file.exists() && jout != null)
2505    {
2506  44 jalview.bin.Console.outPrintln(
2507    "Writing jar entry " + jarEntryName + " (" + msg + ")");
2508  44 jout.putNextEntry(new JarEntry(jarEntryName));
2509  44 copyAll(is, jout);
2510  44 jout.closeEntry();
2511    // dis = new DataInputStream(new FileInputStream(file));
2512    // byte[] data = new byte[(int) file.length()];
2513    // dis.readFully(data);
2514    // writeJarEntry(jout, jarEntryName, data);
2515    }
2516    } catch (Exception ex)
2517    {
2518  0 ex.printStackTrace();
2519    }
2520    }
2521   
2522    /**
2523    * Write the data to a new entry of given name in the output jar file
2524    *
2525    * @param jout
2526    * @param jarEntryName
2527    * @param data
2528    * @throws IOException
2529    */
 
2530  2 toggle protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2531    byte[] data) throws IOException
2532    {
2533  2 if (jout != null)
2534    {
2535  2 jarEntryName = jarEntryName.replace('\\', '/');
2536  2 jalview.bin.Console.outPrintln("Writing jar entry " + jarEntryName);
2537  2 jout.putNextEntry(new JarEntry(jarEntryName));
2538  2 DataOutputStream dout = new DataOutputStream(jout);
2539  2 dout.write(data, 0, data.length);
2540  2 dout.flush();
2541  2 jout.closeEntry();
2542    }
2543    }
2544   
2545    /**
2546    * Copies input to output, in 4K buffers; handles any data (text or binary)
2547    *
2548    * @param in
2549    * @param out
2550    * @throws IOException
2551    */
 
2552  141 toggle protected void copyAll(InputStream in, OutputStream out)
2553    throws IOException
2554    {
2555  141 byte[] buffer = new byte[4096];
2556  141 int bytesRead = 0;
2557  ? while ((bytesRead = in.read(buffer)) != -1)
2558    {
2559  28369 out.write(buffer, 0, bytesRead);
2560    }
2561    }
2562   
2563    /**
2564    * Save the state of a structure viewer
2565    *
2566    * @param ap
2567    * @param jds
2568    * @param pdb
2569    * the archive XML element under which to save the state
2570    * @param entry
2571    * @param viewIds
2572    * @param matchedFile
2573    * @param viewFrame
2574    * @return
2575    */
 
2576  54 toggle protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2577    Pdbids pdb, PDBEntry entry, List<String> viewIds,
2578    String matchedFile, JalviewStructureDisplayI viewFrame)
2579    {
2580  54 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2581   
2582    /*
2583    * Look for any bindings for this viewer to the PDB file of interest
2584    * (including part matches excluding chain id)
2585    */
2586  108 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2587    {
2588  54 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2589  54 final String pdbId = pdbentry.getId();
2590  54 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2591    && entry.getId().toLowerCase(Locale.ROOT)
2592    .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2593    {
2594    /*
2595    * not interested in a binding to a different PDB entry here
2596    */
2597  22 continue;
2598    }
2599  32 if (matchedFile == null)
2600    {
2601  32 matchedFile = pdbentry.getFile();
2602    }
2603  0 else if (!matchedFile.equals(pdbentry.getFile()))
2604    {
2605  0 Console.warn(
2606    "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2607    + pdbentry.getFile());
2608    }
2609    // record the
2610    // file so we
2611    // can get at it if the ID
2612    // match is ambiguous (e.g.
2613    // 1QIP==1qipA)
2614   
2615  96 for (int smap = 0; smap < viewFrame.getBinding()
2616    .getSequence()[peid].length; smap++)
2617    {
2618    // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2619  64 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2620    {
2621  20 StructureState state = new StructureState();
2622  20 state.setVisible(true);
2623  20 state.setXpos(viewFrame.getX()); // from 2.12
2624  20 state.setYpos(viewFrame.getY());
2625  20 state.setWidth(viewFrame.getWidth());
2626  20 state.setHeight(viewFrame.getHeight());
2627  20 final String viewId = viewFrame.getViewId();
2628  20 state.setViewId(viewId);
2629  20 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2630  20 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2631  20 state.setColourByJmol(viewFrame.isColouredByViewer());
2632  20 state.setType(viewFrame.getViewerType().toString());
2633    // pdb.addStructureState(state);
2634  20 pdb.getStructureState().add(state);
2635    }
2636    }
2637    }
2638  54 return matchedFile;
2639    }
2640   
2641    /**
2642    * Populates the AnnotationColourScheme xml for save. This captures the
2643    * settings of the options in the 'Colour by Annotation' dialog.
2644    *
2645    * @param acg
2646    * @param userColours
2647    * @param jm
2648    * @return
2649    */
 
2650  3 toggle private AnnotationColourScheme constructAnnotationColours(
2651    AnnotationColourGradient acg, List<UserColourScheme> userColours,
2652    JalviewModel jm)
2653    {
2654  3 AnnotationColourScheme ac = new AnnotationColourScheme();
2655  3 ac.setAboveThreshold(acg.getAboveThreshold());
2656  3 ac.setThreshold(acg.getAnnotationThreshold());
2657    // 2.10.2 save annotationId (unique) not annotation label
2658  3 ac.setAnnotation(acg.getAnnotation().annotationId);
2659  3 if (acg.getBaseColour() instanceof UserColourScheme)
2660    {
2661  0 ac.setColourScheme(
2662    setUserColourScheme(acg.getBaseColour(), userColours, jm));
2663    }
2664    else
2665    {
2666  3 ac.setColourScheme(
2667    ColourSchemeProperty.getColourName(acg.getBaseColour()));
2668    }
2669   
2670  3 ac.setMaxColour(acg.getMaxColour().getRGB());
2671  3 ac.setMinColour(acg.getMinColour().getRGB());
2672  3 ac.setPerSequence(acg.isSeqAssociated());
2673  3 ac.setPredefinedColours(acg.isPredefinedColours());
2674  3 return ac;
2675    }
2676   
 
2677  180 toggle private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2678    IdentityHashMap<SequenceGroup, String> groupRefs,
2679    AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2680    SequenceSet vamsasSet)
2681    {
2682   
2683  1346 for (int i = 0; i < aa.length; i++)
2684    {
2685  1166 Annotation an = new Annotation();
2686   
2687  1166 AlignmentAnnotation annotation = aa[i];
2688  1166 if (annotation.annotationId != null)
2689    {
2690  1166 annotationIds.put(annotation.annotationId, annotation);
2691    }
2692   
2693  1166 an.setId(annotation.annotationId);
2694   
2695  1166 an.setVisible(annotation.visible);
2696   
2697  1166 an.setDescription(annotation.description);
2698   
2699  1166 if (annotation.sequenceRef != null)
2700    {
2701    // 2.9 JAL-1781 xref on sequence id rather than name
2702  918 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2703    }
2704  1166 if (annotation.groupRef != null)
2705    {
2706  6 String groupIdr = groupRefs.get(annotation.groupRef);
2707  6 if (groupIdr == null)
2708    {
2709    // make a locally unique String
2710  6 groupRefs.put(annotation.groupRef,
2711    groupIdr = ("" + System.currentTimeMillis()
2712    + annotation.groupRef.getName()
2713    + groupRefs.size()));
2714    }
2715  6 an.setGroupRef(groupIdr.toString());
2716    }
2717   
2718    // store all visualization attributes for annotation
2719  1166 an.setGraphHeight(annotation.graphHeight);
2720  1166 an.setCentreColLabels(annotation.centreColLabels);
2721  1166 an.setScaleColLabels(annotation.scaleColLabel);
2722  1166 an.setShowAllColLabels(annotation.showAllColLabels);
2723  1166 an.setBelowAlignment(annotation.belowAlignment);
2724  1166 if (annotation.getAnnotationGroupColour() != null)
2725    {
2726  26 an.setAnnotationGroupColour(
2727    annotation.getAnnotationGroupColour().getRGB());
2728    }
2729   
2730  1166 if (annotation.graph > 0)
2731    {
2732  600 an.setGraph(true);
2733  600 an.setGraphType(annotation.graph);
2734  600 an.setGraphGroup(annotation.graphGroup);
2735  600 if (annotation.getThreshold() != null)
2736    {
2737  0 ThresholdLine line = new ThresholdLine();
2738  0 line.setLabel(annotation.getThreshold().label);
2739  0 line.setValue(annotation.getThreshold().value);
2740  0 line.setColour(annotation.getThreshold().colour.getRGB());
2741  0 an.setThresholdLine(line);
2742    }
2743  600 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2744    {
2745  57 if (annotation.sequenceRef.getContactMaps() != null)
2746    {
2747  57 ContactMatrixI cm = annotation.sequenceRef
2748    .getContactMatrixFor(annotation);
2749  57 if (cm != null)
2750    {
2751  57 storeMatrixFor(vamsasSet, an, annotation, cm);
2752    }
2753    }
2754    }
2755    }
2756    else
2757    {
2758  566 an.setGraph(false);
2759    }
2760   
2761  1166 an.setLabel(annotation.label);
2762   
2763  1166 if (annotation == av.getAlignmentQualityAnnot()
2764    || annotation == av.getAlignmentConservationAnnotation()
2765    || annotation == av.getAlignmentConsensusAnnotation()
2766    || annotation.autoCalculated)
2767    {
2768    // new way of indicating autocalculated annotation -
2769  223 an.setAutoCalculated(annotation.autoCalculated);
2770    }
2771  1166 if (annotation.hasScore())
2772    {
2773  139 an.setScore(annotation.getScore());
2774    }
2775   
2776  1166 if (annotation.getCalcId() != null)
2777    {
2778  1142 calcIdSet.add(annotation.getCalcId());
2779  1142 an.setCalcId(annotation.getCalcId());
2780    }
2781  1166 if (annotation.hasProperties())
2782    {
2783  276 for (String pr : annotation.getProperties())
2784    {
2785  420 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2786  420 prop.setName(pr);
2787  420 prop.setValue(annotation.getProperty(pr));
2788  420 an.getProperty().add(prop);
2789    }
2790    }
2791   
2792  1166 AnnotationElement ae;
2793  1166 if (annotation.annotations != null)
2794    {
2795  1166 an.setScoreOnly(false);
2796  163051 for (int a = 0; a < annotation.annotations.length; a++)
2797    {
2798  161885 if ((annotation == null) || (annotation.annotations[a] == null))
2799    {
2800  39746 continue;
2801    }
2802   
2803  122139 ae = new AnnotationElement();
2804  122139 if (annotation.annotations[a].description != null)
2805    {
2806  117643 ae.setDescription(annotation.annotations[a].description);
2807    }
2808  122139 if (annotation.annotations[a].displayCharacter != null)
2809    {
2810  117973 ae.setDisplayCharacter(
2811    annotation.annotations[a].displayCharacter);
2812    }
2813   
2814  122139 if (!Float.isNaN(annotation.annotations[a].value))
2815    {
2816  120427 ae.setValue(annotation.annotations[a].value);
2817    }
2818   
2819  122139 ae.setPosition(a);
2820  122139 if (annotation.annotations[a].secondaryStructure > ' ')
2821    {
2822  32898 ae.setSecondaryStructure(
2823    annotation.annotations[a].secondaryStructure + "");
2824    }
2825   
2826  122139 if (annotation.annotations[a].colour != null
2827    && annotation.annotations[a].colour != java.awt.Color.black)
2828    {
2829  101541 ae.setColour(annotation.annotations[a].colour.getRGB());
2830    }
2831   
2832    // an.addAnnotationElement(ae);
2833  122139 an.getAnnotationElement().add(ae);
2834  122139 if (annotation.autoCalculated)
2835    {
2836    // only write one non-null entry into the annotation row -
2837    // sufficient to get the visualization attributes necessary to
2838    // display data
2839  25327 continue;
2840    }
2841    }
2842    }
2843    else
2844    {
2845  0 an.setScoreOnly(true);
2846    }
2847  1166 if (!storeDS || (storeDS && !annotation.autoCalculated))
2848    {
2849    // skip autocalculated annotation - these are only provided for
2850    // alignments
2851    // vamsasSet.addAnnotation(an);
2852  1166 vamsasSet.getAnnotation().add(an);
2853    }
2854    }
2855   
2856    }
2857   
 
2858  57 toggle private void storeMatrixFor(SequenceSet root, Annotation an,
2859    AlignmentAnnotation annotation, ContactMatrixI cm)
2860    {
2861  57 String cmId = contactMatrices.get(cm);
2862  57 MatrixType xmlmat = null;
2863   
2864    // first create an xml ref for the matrix data, if none exist
2865  57 if (cmId == null)
2866    {
2867  27 xmlmat = new MatrixType();
2868  27 xmlmat.setType(cm.getType());
2869  27 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2870  27 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2871    // consider using an opaque to/from -> allow instance to control
2872    // its representation ?
2873  27 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2874  27 if (cm.hasGroups())
2875    {
2876  27 for (BitSet gp : cm.getGroups())
2877    {
2878  9 xmlmat.getGroups().add(stringifyBitset(gp));
2879    }
2880    }
2881  27 if (cm.hasTree())
2882    {
2883    // provenance object for tree ?
2884  3 xmlmat.getNewick().add(cm.getNewick());
2885  3 xmlmat.setTreeMethod(cm.getTreeMethod());
2886    }
2887  27 if (cm.hasCutHeight())
2888    {
2889  3 xmlmat.setCutHeight(cm.getCutHeight());
2890    }
2891  27 xmlmat.setId(cmId = "m" + contactMatrices.size()
2892    + System.currentTimeMillis());
2893  27 Console.trace("Matrix data stored :" + cmId);
2894  27 contactMatrices.put(cm, cmId);
2895  27 contactMatrixRefs.put(cmId, cm);
2896  27 xmlMatrices.add(xmlmat);
2897    }
2898    else
2899    {
2900  30 Console.trace("Existing Matrix stored :" + cmId);
2901    }
2902   
2903    // now store mapping
2904   
2905  57 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2906  57 xmlmatmapping.setMatrix(cmId);
2907   
2908    // Pretty much all matrices currently managed in this way are
2909    // mappableContactMatrixI implementations - but check anyway
2910  57 if (cm instanceof MappableContactMatrixI)
2911    {
2912  57 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2913    .getMapFor(annotation.sequenceRef);
2914  57 if (mlst != null)
2915    {
2916  57 MapListType mp = new MapListType();
2917  57 List<int[]> r = mlst.getFromRanges();
2918  57 for (int[] range : r)
2919    {
2920  57 MapListFrom mfrom = new MapListFrom();
2921  57 mfrom.setStart(range[0]);
2922  57 mfrom.setEnd(range[1]);
2923    // mp.addMapListFrom(mfrom);
2924  57 mp.getMapListFrom().add(mfrom);
2925    }
2926  57 r = mlst.getToRanges();
2927  57 for (int[] range : r)
2928    {
2929  57 MapListTo mto = new MapListTo();
2930  57 mto.setStart(range[0]);
2931  57 mto.setEnd(range[1]);
2932    // mp.addMapListTo(mto);
2933  57 mp.getMapListTo().add(mto);
2934    }
2935  57 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2936  57 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2937  57 xmlmatmapping.setMapping(mp);
2938    }
2939    }
2940    // and add to model
2941  57 an.getContactmatrix().add(xmlmatmapping);
2942    }
2943   
 
2944  9 toggle private String stringifyBitset(BitSet gp)
2945    {
2946  9 StringBuilder sb = new StringBuilder();
2947  9 for (long val : gp.toLongArray())
2948    {
2949  9 if (sb.length() > 0)
2950    {
2951  0 sb.append(",");
2952    }
2953  9 sb.append(val);
2954    }
2955  9 return sb.toString();
2956    }
2957   
 
2958  6 toggle private BitSet deStringifyBitset(String stringified)
2959    {
2960  6 if ("".equals(stringified) || stringified == null)
2961    {
2962  0 return new BitSet();
2963    }
2964  6 String[] longvals = stringified.split(",");
2965  6 long[] newlongvals = new long[longvals.length];
2966  12 for (int lv = 0; lv < longvals.length; lv++)
2967    {
2968  6 try
2969    {
2970  6 newlongvals[lv] = Long.valueOf(longvals[lv]);
2971    } catch (Exception x)
2972    {
2973  0 errorMessage += "Couldn't destringify bitset from: '" + stringified
2974    + "'";
2975  0 newlongvals[lv] = 0;
2976    }
2977    }
2978  6 return BitSet.valueOf(newlongvals);
2979   
2980    }
2981   
 
2982  31 toggle private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2983    {
2984  31 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2985  31 if (settings != null)
2986    {
2987  0 CalcIdParam vCalcIdParam = new CalcIdParam();
2988  0 vCalcIdParam.setCalcId(calcId);
2989    // vCalcIdParam.addServiceURL(settings.getServiceURI());
2990  0 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2991    // generic URI allowing a third party to resolve another instance of the
2992    // service used for this calculation
2993  0 for (String url : settings.getServiceURLs())
2994    {
2995    // vCalcIdParam.addServiceURL(urls);
2996  0 vCalcIdParam.getServiceURL().add(url);
2997    }
2998  0 vCalcIdParam.setVersion("1.0");
2999  0 if (settings.getPreset() != null)
3000    {
3001  0 WsParamSetI setting = settings.getPreset();
3002  0 vCalcIdParam.setName(setting.getName());
3003  0 vCalcIdParam.setDescription(setting.getDescription());
3004    }
3005    else
3006    {
3007  0 vCalcIdParam.setName("");
3008  0 vCalcIdParam.setDescription("Last used parameters");
3009    }
3010    // need to be able to recover 1) settings 2) user-defined presets or
3011    // recreate settings from preset 3) predefined settings provided by
3012    // service - or settings that can be transferred (or discarded)
3013  0 vCalcIdParam.setParameters(
3014    settings.getWsParamFile().replace("\n", "|\\n|"));
3015  0 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
3016    // todo - decide if updateImmediately is needed for any projects.
3017   
3018  0 return vCalcIdParam;
3019    }
3020  31 return null;
3021    }
3022   
 
3023  0 toggle private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
3024    AlignViewport av)
3025    {
3026  0 if (calcIdParam.getVersion().equals("1.0"))
3027    {
3028  0 final String[] calcIds = calcIdParam.getServiceURL()
3029    .toArray(new String[0]);
3030  0 ServiceWithParameters service = PreferredServiceRegistry.getRegistry()
3031    .getPreferredServiceFor(calcIds);
3032  0 if (service != null)
3033    {
3034  0 WsParamSetI parmSet = null;
3035  0 try
3036    {
3037  0 parmSet = service.getParamStore().parseServiceParameterFile(
3038    calcIdParam.getName(), calcIdParam.getDescription(),
3039    calcIds,
3040    calcIdParam.getParameters().replace("|\\n|", "\n"));
3041    } catch (IOException x)
3042    {
3043  0 Console.warn("Couldn't parse parameter data for "
3044    + calcIdParam.getCalcId(), x);
3045  0 return false;
3046    }
3047  0 List<ArgumentI> argList = null;
3048  0 if (calcIdParam.getName().length() > 0)
3049    {
3050  0 parmSet = service.getParamStore()
3051    .getPreset(calcIdParam.getName());
3052  0 if (parmSet != null)
3053    {
3054    // TODO : check we have a good match with settings in AACon -
3055    // otherwise we'll need to create a new preset
3056    }
3057    }
3058    else
3059    {
3060  0 argList = parmSet.getArguments();
3061  0 parmSet = null;
3062    }
3063  0 AutoCalcSetting settings = new AAConSettings(
3064    calcIdParam.isAutoUpdate(), service, parmSet, argList);
3065  0 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
3066    calcIdParam.isNeedsUpdate());
3067  0 return true;
3068    }
3069    else
3070    {
3071  0 Console.warn(
3072    "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
3073  0 return false;
3074    }
3075    }
3076  0 throw new Error(MessageManager.formatMessage(
3077    "error.unsupported_version_calcIdparam", new Object[]
3078    { calcIdParam.toString() }));
3079    }
3080   
3081    /**
3082    * External mapping between jalview objects and objects yielding a valid and
3083    * unique object ID string. This is null for normal Jalview project IO, but
3084    * non-null when a jalview project is being read or written as part of a
3085    * vamsas session.
3086    */
3087    IdentityHashMap jv2vobj = null;
3088   
3089    /**
3090    * Construct a unique ID for jvobj using either existing bindings or if none
3091    * exist, the result of the hashcode call for the object.
3092    *
3093    * @param jvobj
3094    * jalview data object
3095    * @return unique ID for referring to jvobj
3096    */
 
3097  12208 toggle private String makeHashCode(Object jvobj, String altCode)
3098    {
3099  12208 if (jv2vobj != null)
3100    {
3101  0 Object id = jv2vobj.get(jvobj);
3102  0 if (id != null)
3103    {
3104  0 return id.toString();
3105    }
3106    // check string ID mappings
3107  0 if (jvids2vobj != null && jvobj instanceof String)
3108    {
3109  0 id = jvids2vobj.get(jvobj);
3110    }
3111  0 if (id != null)
3112    {
3113  0 return id.toString();
3114    }
3115    // give up and warn that something has gone wrong
3116  0 Console.warn(
3117    "Cannot find ID for object in external mapping : " + jvobj);
3118    }
3119  12208 return altCode;
3120    }
3121   
3122    /**
3123    * return local jalview object mapped to ID, if it exists
3124    *
3125    * @param idcode
3126    * (may be null)
3127    * @return null or object bound to idcode
3128    */
 
3129  15 toggle private Object retrieveExistingObj(String idcode)
3130    {
3131  15 if (idcode != null && vobj2jv != null)
3132    {
3133  0 return vobj2jv.get(idcode);
3134    }
3135  15 return null;
3136    }
3137   
3138    /**
3139    * binding from ID strings from external mapping table to jalview data model
3140    * objects.
3141    */
3142    private Hashtable vobj2jv;
3143   
 
3144  11940 toggle private Sequence createVamsasSequence(String id, SequenceI jds)
3145    {
3146  11940 return createVamsasSequence(true, id, jds, null);
3147    }
3148   
 
3149  11940 toggle private Sequence createVamsasSequence(boolean recurse, String id,
3150    SequenceI jds, SequenceI parentseq)
3151    {
3152  11940 Sequence vamsasSeq = new Sequence();
3153  11940 vamsasSeq.setId(id);
3154  11940 vamsasSeq.setName(jds.getName());
3155  11940 vamsasSeq.setSequence(jds.getSequenceAsString());
3156  11940 vamsasSeq.setDescription(jds.getDescription());
3157  11940 List<DBRefEntry> dbrefs = null;
3158  11940 if (jds.getDatasetSequence() != null)
3159    {
3160  500 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
3161    }
3162    else
3163    {
3164    // seqId==dsseqid so we can tell which sequences really are
3165    // dataset sequences only
3166  11440 vamsasSeq.setDsseqid(id);
3167  11440 dbrefs = jds.getDBRefs();
3168  11440 if (parentseq == null)
3169    {
3170  11440 parentseq = jds;
3171    }
3172    }
3173   
3174    /*
3175    * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
3176    */
3177  11940 if (dbrefs != null)
3178    {
3179  1792 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
3180    {
3181  1597 DBRef dbref = new DBRef();
3182  1597 DBRefEntry ref = dbrefs.get(d);
3183  1597 dbref.setSource(ref.getSource());
3184  1597 dbref.setVersion(ref.getVersion());
3185  1597 dbref.setAccessionId(ref.getAccessionId());
3186  1597 dbref.setCanonical(ref.isCanonical());
3187  1597 if (ref instanceof GeneLocus)
3188    {
3189  1 dbref.setLocus(true);
3190    }
3191  1597 if (ref.hasMap())
3192    {
3193  2 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
3194    recurse);
3195  2 dbref.setMapping(mp);
3196    }
3197  1597 vamsasSeq.getDBRef().add(dbref);
3198    }
3199    }
3200  11940 return vamsasSeq;
3201    }
3202   
 
3203  2 toggle private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
3204    SequenceI parentseq, SequenceI jds, boolean recurse)
3205    {
3206  2 Mapping mp = null;
3207  2 if (jmp.getMap() != null)
3208    {
3209  2 mp = new Mapping();
3210   
3211  2 jalview.util.MapList mlst = jmp.getMap();
3212  2 List<int[]> r = mlst.getFromRanges();
3213  2 for (int[] range : r)
3214    {
3215  2 MapListFrom mfrom = new MapListFrom();
3216  2 mfrom.setStart(range[0]);
3217  2 mfrom.setEnd(range[1]);
3218    // mp.addMapListFrom(mfrom);
3219  2 mp.getMapListFrom().add(mfrom);
3220    }
3221  2 r = mlst.getToRanges();
3222  2 for (int[] range : r)
3223    {
3224  2 MapListTo mto = new MapListTo();
3225  2 mto.setStart(range[0]);
3226  2 mto.setEnd(range[1]);
3227    // mp.addMapListTo(mto);
3228  2 mp.getMapListTo().add(mto);
3229    }
3230  2 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
3231  2 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
3232  2 if (jmp.getTo() != null)
3233    {
3234    // MappingChoice mpc = new MappingChoice();
3235   
3236    // check/create ID for the sequence referenced by getTo()
3237   
3238  1 String jmpid = "";
3239  1 SequenceI ps = null;
3240  1 if (parentseq != jmp.getTo()
3241    && parentseq.getDatasetSequence() != jmp.getTo())
3242    {
3243    // chaining dbref rather than a handshaking one
3244  1 jmpid = seqHash(ps = jmp.getTo());
3245    }
3246    else
3247    {
3248  0 jmpid = seqHash(ps = parentseq);
3249    }
3250    // mpc.setDseqFor(jmpid);
3251  1 mp.setDseqFor(jmpid);
3252  1 if (!seqRefIds.containsKey(jmpid))
3253    {
3254  0 Console.debug("creatign new DseqFor ID");
3255  0 seqRefIds.put(jmpid, ps);
3256    }
3257    else
3258    {
3259  1 Console.debug("reusing DseqFor ID");
3260    }
3261   
3262    // mp.setMappingChoice(mpc);
3263    }
3264    }
3265  2 return mp;
3266    }
3267   
 
3268  0 toggle String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
3269    List<UserColourScheme> userColours, JalviewModel jm)
3270    {
3271  0 String id = null;
3272  0 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
3273  0 boolean newucs = false;
3274  0 if (!userColours.contains(ucs))
3275    {
3276  0 userColours.add(ucs);
3277  0 newucs = true;
3278    }
3279  0 id = "ucs" + userColours.indexOf(ucs);
3280  0 if (newucs)
3281    {
3282    // actually create the scheme's entry in the XML model
3283  0 java.awt.Color[] colours = ucs.getColours();
3284  0 UserColours uc = new UserColours();
3285    // UserColourScheme jbucs = new UserColourScheme();
3286  0 JalviewUserColours jbucs = new JalviewUserColours();
3287   
3288  0 for (int i = 0; i < colours.length; i++)
3289    {
3290  0 Colour col = new Colour();
3291  0 col.setName(ResidueProperties.aa[i]);
3292  0 col.setRGB(jalview.util.Format.getHexString(colours[i]));
3293    // jbucs.addColour(col);
3294  0 jbucs.getColour().add(col);
3295    }
3296  0 if (ucs.getLowerCaseColours() != null)
3297    {
3298  0 colours = ucs.getLowerCaseColours();
3299  0 for (int i = 0; i < colours.length; i++)
3300    {
3301  0 Colour col = new Colour();
3302  0 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
3303  0 col.setRGB(jalview.util.Format.getHexString(colours[i]));
3304    // jbucs.addColour(col);
3305  0 jbucs.getColour().add(col);
3306    }
3307    }
3308   
3309  0 uc.setId(id);
3310  0 uc.setUserColourScheme(jbucs);
3311    // jm.addUserColours(uc);
3312  0 jm.getUserColours().add(uc);
3313    }
3314   
3315  0 return id;
3316    }
3317   
 
3318  0 toggle jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
3319    String id)
3320    {
3321  0 List<UserColours> uc = jm.getUserColours();
3322  0 UserColours colours = null;
3323    /*
3324    for (int i = 0; i < uc.length; i++)
3325    {
3326    if (uc[i].getId().equals(id))
3327    {
3328    colours = uc[i];
3329    break;
3330    }
3331    }
3332    */
3333  0 for (UserColours c : uc)
3334    {
3335  0 if (c.getId().equals(id))
3336    {
3337  0 colours = c;
3338  0 break;
3339    }
3340    }
3341   
3342  0 java.awt.Color[] newColours = new java.awt.Color[24];
3343   
3344  0 for (int i = 0; i < 24; i++)
3345    {
3346  0 newColours[i] = new java.awt.Color(Integer.parseInt(
3347    // colours.getUserColourScheme().getColour(i).getRGB(), 16));
3348    colours.getUserColourScheme().getColour().get(i).getRGB(),
3349    16));
3350    }
3351   
3352  0 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
3353    newColours);
3354   
3355  0 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3356    {
3357  0 newColours = new java.awt.Color[23];
3358  0 for (int i = 0; i < 23; i++)
3359    {
3360  0 newColours[i] = new java.awt.Color(
3361    Integer.parseInt(colours.getUserColourScheme().getColour()
3362    .get(i + 24).getRGB(), 16));
3363    }
3364  0 ucs.setLowerCaseColours(newColours);
3365    }
3366   
3367  0 return ucs;
3368    }
3369   
3370    /**
3371    * Load a jalview project archive from a jar file
3372    *
3373    * @param file
3374    * - HTTP URL or filename
3375    */
 
3376  42 toggle public AlignFrame loadJalviewAlign(final Object file)
3377    {
3378   
3379  42 jalview.gui.AlignFrame af = null;
3380   
3381  42 try
3382    {
3383    // create list to store references for any new Jmol viewers created
3384  42 newStructureViewers = new Vector<>();
3385    // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3386    // Workaround is to make sure caller implements the JarInputStreamProvider
3387    // interface
3388    // so we can re-open the jar input stream for each entry.
3389   
3390  42 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3391  42 af = loadJalviewAlign(jprovider);
3392  42 if (af != null)
3393    {
3394  42 af.setMenusForViewport();
3395    }
3396    } catch (MalformedURLException e)
3397    {
3398  0 errorMessage = "Invalid URL format for '" + file + "'";
3399  0 reportErrors();
3400    } finally
3401    {
3402  42 try
3403    {
3404  42 if (Platform.isJS())
3405    {
3406  0 setLoadingFinishedForNewStructureViewers();
3407    }
3408    else
3409    {
3410  42 SwingUtilities.invokeAndWait(new Runnable()
3411    {
 
3412  42 toggle @Override
3413    public void run()
3414    {
3415  42 setLoadingFinishedForNewStructureViewers();
3416    }
3417    });
3418    }
3419    } catch (Exception x)
3420    {
3421  0 jalview.bin.Console
3422    .errPrintln("Error loading alignment: " + x.getMessage());
3423    }
3424    }
3425  42 this.jarFile = null;
3426  42 return af;
3427    }
3428   
 
3429  42 toggle @SuppressWarnings("unused")
3430    private jarInputStreamProvider createjarInputStreamProvider(
3431    final Object ofile) throws MalformedURLException
3432    {
3433   
3434  42 try
3435    {
3436  42 String file = (ofile instanceof File
3437    ? ((File) ofile).getCanonicalPath()
3438    : ofile.toString());
3439  42 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3440    : null;
3441  42 if (bytes != null)
3442    {
3443  0 this.jarFile = (File) ofile;
3444    }
3445  42 URL url;
3446  42 errorMessage = null;
3447  42 uniqueSetSuffix = null;
3448  42 seqRefIds = null;
3449  42 viewportsAdded.clear();
3450  42 frefedSequence = null;
3451   
3452  42 if (HttpUtils.startsWithHttpOrHttps(file))
3453    {
3454  0 url = new URL(file);
3455    }
3456    else
3457    {
3458  42 url = null;
3459    }
3460  42 return new jarInputStreamProvider()
3461    {
3462   
 
3463  346 toggle @Override
3464    public JarInputStream getJarInputStream() throws IOException
3465    {
3466  346 InputStream is = bytes != null ? new ByteArrayInputStream(bytes)
3467  346 : (url != null ? url.openStream()
3468    : new FileInputStream(file));
3469  346 return new JarInputStream(is);
3470    }
3471   
 
3472  42 toggle @Override
3473    public File getFile()
3474    {
3475  42 return jarFile;
3476    }
3477   
 
3478  42 toggle @Override
3479    public String getFilename()
3480    {
3481  42 return file;
3482    }
3483    };
3484    } catch (IOException e)
3485    {
3486  0 e.printStackTrace();
3487  0 return null;
3488    }
3489    }
3490   
3491    /**
3492    * Recover jalview session from a jalview project archive. Caller may
3493    * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3494    * themselves. Any null fields will be initialised with default values,
3495    * non-null fields are left alone.
3496    *
3497    * @param jprovider
3498    * @return
3499    */
 
3500  42 toggle public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3501    {
3502  42 errorMessage = null;
3503  42 if (uniqueSetSuffix == null)
3504    {
3505  42 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3506    }
3507  42 if (seqRefIds == null)
3508    {
3509  42 initSeqRefs();
3510    }
3511  42 AlignFrame af = null, _af = null;
3512  42 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3513  42 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3514  42 String fileName = jprovider.getFilename();
3515  42 File file = jprovider.getFile();
3516  42 List<AlignFrame> alignFrames = new ArrayList<>();
3517  42 try
3518    {
3519  42 JarInputStream jin = null;
3520  42 JarEntry jarentry = null;
3521  42 int entryCount = 1;
3522   
3523    // Look for all the entry names ending with ".xml"
3524    // This includes all panels and at least one frame.
3525    // Platform.timeCheck(null, Platform.TIME_MARK);
3526  42 do
3527    {
3528  259 jin = jprovider.getJarInputStream();
3529  1594 for (int i = 0; i < entryCount; i++)
3530    {
3531  1335 jarentry = jin.getNextJarEntry();
3532    }
3533  259 String name = (jarentry == null ? null : jarentry.getName());
3534   
3535    // System.out.println("Jalview2XML opening " + name);
3536  259 if (name != null && name.endsWith(".xml"))
3537    {
3538    // DataSet for.... is read last.
3539   
3540    // The question here is what to do with the two
3541    // .xml files in the jvp file.
3542    // Some number of them, "...Dataset for...", will be the
3543    // Only AlignPanels and will have Viewport.
3544    // One or more will be the source data, with the DBRefs.
3545    //
3546    // JVP file writing (above) ensures tha the AlignPanels are written
3547    // first, then all relevant datasets (which are
3548    // Jalview.datamodel.Alignment).
3549    //
3550   
3551    // Platform.timeCheck("Jalview2XML JAXB " + name, Platform.TIME_MARK);
3552  128 JAXBContext jc = JAXBContext
3553    .newInstance("jalview.xml.binding.jalview");
3554  128 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3555    .createXMLStreamReader(jin);
3556  128 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3557  128 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3558    JalviewModel.class);
3559  128 JalviewModel model = jbe.getValue();
3560   
3561  128 if (true) // !skipViewport(object))
3562    {
3563    // Q: Do we have to load from the model, even if it
3564    // does not have a viewport, could we discover that early on?
3565    // Q: Do we need to load this object?
3566  128 _af = loadFromObject(model, fileName, file, true, jprovider);
3567    // Platform.timeCheck("Jalview2XML.loadFromObject",
3568    // Platform.TIME_MARK);
3569   
3570  128 if (_af != null)
3571    {
3572  90 alignFrames.add(_af);
3573    }
3574  128 if (_af != null && model.getViewport().size() > 0)
3575    {
3576   
3577  90 if (af == null)
3578    {
3579    // store a reference to the first view
3580  42 af = _af;
3581    }
3582  90 if (_af.getViewport().isGatherViewsHere())
3583    {
3584    // if this is a gathered view, keep its reference since
3585    // after gathering views, only this frame will remain
3586  15 af = _af;
3587  15 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3588    _af);
3589    }
3590    // Save dataset to register mappings once all resolved
3591  90 importedDatasets.put(
3592    af.getViewport().getAlignment().getDataset(),
3593    af.getViewport().getAlignment().getDataset());
3594    }
3595    }
3596  128 entryCount++;
3597    }
3598  131 else if (jarentry != null)
3599    {
3600    // Some other file here.
3601  89 entryCount++;
3602    }
3603  259 } while (jarentry != null);
3604  42 jin.close();
3605  42 resolveFrefedSequences();
3606    } catch (IOException ex)
3607    {
3608  0 ex.printStackTrace();
3609  0 errorMessage = "Couldn't locate Jalview XML file : " + fileName;
3610  0 jalview.bin.Console.errPrintln(
3611    "Exception whilst loading jalview XML file : " + ex + "\n");
3612    } catch (Exception ex)
3613    {
3614  0 jalview.bin.Console
3615    .errPrintln("Parsing as Jalview Version 2 file failed.");
3616  0 ex.printStackTrace(System.err);
3617  0 if (attemptversion1parse)
3618    {
3619    // used to attempt to parse as V1 castor-generated xml
3620    }
3621  0 if (Desktop.getInstance() != null)
3622    {
3623  0 Desktop.getInstance().stopLoading();
3624    }
3625  0 if (af != null)
3626    {
3627  0 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3628  0 return af;
3629    }
3630  0 ex.printStackTrace();
3631   
3632  0 jalview.bin.Console.errPrintln(
3633    "Exception whilst loading jalview XML file : " + ex + "\n");
3634    } catch (OutOfMemoryError e)
3635    {
3636    // Don't use the OOM Window here
3637  0 errorMessage = "Out of memory loading jalview XML file";
3638  0 jalview.bin.Console
3639    .errPrintln("Out of memory whilst loading jalview XML file");
3640  0 e.printStackTrace();
3641    } finally
3642    {
3643  42 for (AlignFrame alf : alignFrames)
3644    {
3645  90 alf.alignPanel.setHoldRepaint(false);
3646    }
3647    }
3648   
3649    /*
3650    * Regather multiple views (with the same sequence set id) to the frame (if
3651    * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3652    * views instead of separate frames. Note this doesn't restore a state where
3653    * some expanded views in turn have tabbed views - the last "first tab" read
3654    * in will play the role of gatherer for all.
3655    */
3656  42 if (Desktop.getInstance() != null)
3657    {
3658  42 for (AlignFrame fr : gatherToThisFrame.values())
3659    {
3660  15 Desktop.getInstance().gatherViews(fr);
3661    }
3662    }
3663   
3664  42 restoreSplitFrames();
3665  42 for (AlignmentI ds : importedDatasets.keySet())
3666    {
3667  42 if (ds.getCodonFrames() != null)
3668    {
3669  42 Desktop.getStructureSelectionManager()
3670    .registerMappings(ds.getCodonFrames());
3671    }
3672    }
3673  42 if (errorMessage != null)
3674    {
3675  0 reportErrors();
3676    }
3677   
3678  42 if (Desktop.getInstance() != null)
3679    {
3680  42 Desktop.getInstance().stopLoading();
3681    }
3682   
3683  42 return af;
3684    }
3685   
3686    /**
3687    * Try to reconstruct and display SplitFrame windows, where each contains
3688    * complementary dna and protein alignments. Done by pairing up AlignFrame
3689    * objects (created earlier) which have complementary viewport ids associated.
3690    */
 
3691  42 toggle protected void restoreSplitFrames()
3692    {
3693  42 List<SplitFrame> gatherTo = new ArrayList<>();
3694  42 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3695  42 Map<String, AlignFrame> dna = new HashMap<>();
3696   
3697    /*
3698    * Identify the DNA alignments
3699    */
3700  42 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3701    .entrySet())
3702    {
3703  0 AlignFrame af = candidate.getValue();
3704  0 if (af.getViewport().getAlignment().isNucleotide())
3705    {
3706  0 dna.put(candidate.getKey().getId(), af);
3707    }
3708    }
3709   
3710    /*
3711    * Try to match up the protein complements
3712    */
3713  42 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3714    .entrySet())
3715    {
3716  0 AlignFrame af = candidate.getValue();
3717  0 if (!af.getViewport().getAlignment().isNucleotide())
3718    {
3719  0 String complementId = candidate.getKey().getComplementId();
3720    // only non-null complements should be in the Map
3721  0 if (complementId != null && dna.containsKey(complementId))
3722    {
3723  0 final AlignFrame dnaFrame = dna.get(complementId);
3724  0 SplitFrame sf = createSplitFrame(dnaFrame, af);
3725  0 addedToSplitFrames.add(dnaFrame);
3726  0 addedToSplitFrames.add(af);
3727  0 dnaFrame.setMenusForViewport();
3728  0 af.setMenusForViewport();
3729  0 if (af.getViewport().isGatherViewsHere())
3730    {
3731  0 gatherTo.add(sf);
3732    }
3733    }
3734    }
3735    }
3736   
3737    /*
3738    * Open any that we failed to pair up (which shouldn't happen!) as
3739    * standalone AlignFrame's.
3740    */
3741  42 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3742    .entrySet())
3743    {
3744  0 AlignFrame af = candidate.getValue();
3745  0 if (!addedToSplitFrames.contains(af))
3746    {
3747  0 Viewport view = candidate.getKey();
3748  0 Desktop.addInternalFrame(af, view.getTitle(),
3749    safeInt(view.getWidth()), safeInt(view.getHeight()));
3750  0 af.setMenusForViewport();
3751  0 jalview.bin.Console.errPrintln("Failed to restore view "
3752    + view.getTitle() + " to split frame");
3753    }
3754    }
3755   
3756    /*
3757    * Gather back into tabbed views as flagged.
3758    */
3759  42 for (SplitFrame sf : gatherTo)
3760    {
3761  0 Desktop.getInstance().gatherViews(sf);
3762    }
3763   
3764  42 splitFrameCandidates.clear();
3765    }
3766   
3767    /**
3768    * Construct and display one SplitFrame holding DNA and protein alignments.
3769    *
3770    * @param dnaFrame
3771    * @param proteinFrame
3772    * @return
3773    */
 
3774  0 toggle protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3775    AlignFrame proteinFrame)
3776    {
3777  0 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3778  0 String title = MessageManager.getString("label.linked_view_title");
3779  0 int width = (int) dnaFrame.getBounds().getWidth();
3780  0 int height = (int) (dnaFrame.getBounds().getHeight()
3781    + proteinFrame.getBounds().getHeight() + 50);
3782   
3783    /*
3784    * SplitFrame location is saved to both enclosed frames
3785    */
3786  0 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3787  0 Desktop.addInternalFrame(splitFrame, title, width, height);
3788   
3789    /*
3790    * And compute cDNA consensus (couldn't do earlier with consensus as
3791    * mappings were not yet present)
3792    */
3793  0 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3794   
3795  0 return splitFrame;
3796    }
3797   
3798    /**
3799    * check errorMessage for a valid error message and raise an error box in the
3800    * GUI or write the current errorMessage to stderr and then clear the error
3801    * state.
3802    */
 
3803  20 toggle protected void reportErrors()
3804    {
3805  20 reportErrors(false);
3806    }
3807   
 
3808  20 toggle protected void reportErrors(final boolean saving)
3809    {
3810  20 if (errorMessage != null)
3811    {
3812  1 final String finalErrorMessage = errorMessage;
3813  1 if (raiseGUI)
3814    {
3815  1 javax.swing.SwingUtilities.invokeLater(new Runnable()
3816    {
 
3817  1 toggle @Override
3818    public void run()
3819    {
3820  1 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3821    finalErrorMessage,
3822  1 "Error " + (saving ? "saving" : "loading")
3823    + " Jalview file",
3824    JvOptionPane.WARNING_MESSAGE);
3825    }
3826    });
3827    }
3828    else
3829    {
3830  0 jalview.bin.Console.errPrintln(
3831    "Problem loading Jalview file: " + errorMessage);
3832    }
3833    }
3834  20 errorMessage = null;
3835    }
3836   
3837    Map<String, String> alreadyLoadedPDB = new HashMap<>();
3838   
3839    /**
3840    * when set, local views will be updated from view stored in JalviewXML
3841    * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3842    * sync if this is set to true.
3843    */
3844    private final boolean updateLocalViews = false;
3845   
3846    /**
3847    * Returns the path to a temporary file holding the PDB file for the given PDB
3848    * id. The first time of asking, searches for a file of that name in the
3849    * Jalview project jar, and copies it to a new temporary file. Any repeat
3850    * requests just return the path to the file previously created.
3851    *
3852    * @param jprovider
3853    * @param pdbId
3854    * @return
3855    */
 
3856  342 toggle String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3857    String origFile)
3858    {
3859  342 if (alreadyLoadedPDB.containsKey(pdbId))
3860    {
3861  258 return alreadyLoadedPDB.get(pdbId).toString();
3862    }
3863   
3864  84 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3865    origFile);
3866  84 if (tempFile != null)
3867    {
3868  84 alreadyLoadedPDB.put(pdbId, tempFile);
3869    }
3870  84 return tempFile;
3871    }
3872   
3873    /**
3874    * Copies the jar entry of given name to a new temporary file and returns the
3875    * path to the file, or null if the entry is not found.
3876    *
3877    * @param jprovider
3878    * @param jarEntryName
3879    * @param prefix
3880    * a prefix for the temporary file name, must be at least three
3881    * characters long
3882    * @param suffixModel
3883    * null or original file - so new file can be given the same suffix
3884    * as the old one
3885    * @return
3886    */
 
3887  85 toggle protected String copyJarEntry(jarInputStreamProvider jprovider,
3888    String jarEntryName, String prefix, String suffixModel)
3889    {
3890  85 BufferedReader in = null;
3891  85 PrintWriter out = null;
3892  85 String suffix = ".tmp";
3893  85 if (suffixModel == null)
3894    {
3895  1 suffixModel = jarEntryName;
3896    }
3897  85 int sfpos = suffixModel.lastIndexOf(".");
3898  85 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3899    {
3900  84 suffix = "." + suffixModel.substring(sfpos + 1);
3901    }
3902   
3903  85 try (JarInputStream jin = jprovider.getJarInputStream())
3904    {
3905  85 JarEntry entry = null;
3906  85 do
3907    {
3908  510 entry = jin.getNextJarEntry();
3909  510 } while (entry != null && !entry.getName().equals(jarEntryName));
3910   
3911  85 if (entry != null)
3912    {
3913    // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3914  85 File outFile = File.createTempFile(prefix, suffix);
3915  85 outFile.deleteOnExit();
3916  85 try (OutputStream os = new FileOutputStream(outFile))
3917    {
3918  85 copyAll(jin, os);
3919    }
3920  85 String t = outFile.getAbsolutePath();
3921  85 Console.trace("Successfully extracted " + jarEntryName
3922    + " as local temporary file: " + outFile.getCanonicalPath()
3923    + " (using template " + suffixModel + ")");
3924   
3925  85 return t;
3926    }
3927    else
3928    {
3929  0 Console.warn(
3930    "Couldn't find entry in Jalview Jar for " + jarEntryName);
3931    }
3932    } catch (Exception ex)
3933    {
3934  0 ex.printStackTrace();
3935    }
3936   
3937  0 return null;
3938    }
3939   
 
3940    private class JvAnnotRow
3941    {
 
3942  766 toggle public JvAnnotRow(int i, AlignmentAnnotation jaa)
3943    {
3944  766 order = i;
3945  766 template = jaa;
3946    }
3947   
3948    /**
3949    * persisted version of annotation row from which to take vis properties
3950    */
3951    public jalview.datamodel.AlignmentAnnotation template;
3952   
3953    /**
3954    * original position of the annotation row in the alignment
3955    */
3956    public int order;
3957    }
3958   
3959    /**
3960    * Load alignment frame from jalview XML DOM object. For a DOM object that
3961    * includes one or more Viewport elements (one with a title that does NOT
3962    * contain "Dataset for"), create the frame.
3963    *
3964    * @param jalviewModel
3965    * DOM
3966    * @param fileName
3967    * filename source string
3968    * @param file
3969    * @param loadTreesAndStructures
3970    * when false only create Viewport
3971    * @param jprovider
3972    * data source provider
3973    * @return alignment frame created from view stored in DOM
3974    */
 
3975  140 toggle AlignFrame loadFromObject(JalviewModel jalviewModel, String fileName,
3976    File file, boolean loadTreesAndStructures,
3977    jarInputStreamProvider jprovider)
3978    {
3979  140 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3980    .get(0);
3981  140 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3982   
3983    // JalviewModelSequence jms = object.getJalviewModelSequence();
3984   
3985    // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3986    // : null;
3987  140 Viewport view = (jalviewModel.getViewport().size() > 0)
3988    ? jalviewModel.getViewport().get(0)
3989    : null;
3990   
3991    // ////////////////////////////////
3992    // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3993    //
3994    //
3995    // If we just load in the same jar file again, the sequenceSetId
3996    // will be the same, and we end up with multiple references
3997    // to the same sequenceSet. We must modify this id on load
3998    // so that each load of the file gives a unique id
3999   
4000    /**
4001    * used to resolve correct alignment dataset for alignments with multiple
4002    * views
4003    */
4004  140 String uniqueSeqSetId = null;
4005  140 String viewId = null;
4006  140 if (view != null)
4007    {
4008  102 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
4009  102 viewId = (view.getId() == null ? null
4010    : view.getId() + uniqueSetSuffix);
4011    }
4012   
4013    // ////////////////////////////////
4014    // LOAD MATRICES (IF ANY)
4015   
4016  140 if (vamsasSet.getMatrix() != null && vamsasSet.getMatrix().size() > 0)
4017    {
4018  8 importMatrixData(vamsasSet.getMatrix());
4019    }
4020   
4021    // ////////////////////////////////
4022    // LOAD SEQUENCES
4023   
4024  140 List<SequenceI> hiddenSeqs = null;
4025   
4026  140 List<SequenceI> tmpseqs = new ArrayList<>();
4027   
4028  140 boolean multipleView = false;
4029  140 SequenceI referenceseqForView = null;
4030    // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
4031  140 List<JSeq> jseqs = jalviewModel.getJSeq();
4032  140 int vi = 0; // counter in vamsasSeq array
4033  23999 for (int i = 0; i < jseqs.size(); i++)
4034    {
4035  23859 JSeq jseq = jseqs.get(i);
4036  23859 String seqId = jseq.getId();
4037   
4038  23859 SequenceI tmpSeq = seqRefIds.get(seqId);
4039  23859 if (tmpSeq != null)
4040    {
4041  1260 if (!incompleteSeqs.containsKey(seqId))
4042    {
4043    // may not need this check, but keep it for at least 2.9,1 release
4044  1260 if (tmpSeq.getStart() != jseq.getStart()
4045    || tmpSeq.getEnd() != jseq.getEnd())
4046    {
4047  0 jalview.bin.Console.errPrintln(String.format(
4048    "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
4049    tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
4050    jseq.getStart(), jseq.getEnd()));
4051    }
4052    }
4053    else
4054    {
4055  0 incompleteSeqs.remove(seqId);
4056    }
4057  1260 if (vamsasSeqs.size() > vi
4058    && vamsasSeqs.get(vi).getId().equals(seqId))
4059    {
4060    // most likely we are reading a dataset XML document so
4061    // update from vamsasSeq section of XML for this sequence
4062  580 tmpSeq.setName(vamsasSeqs.get(vi).getName());
4063  580 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
4064  580 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
4065  580 vi++;
4066    }
4067    else
4068    {
4069    // reading multiple views, so vamsasSeq set is a subset of JSeq
4070  680 multipleView = true;
4071    }
4072  1260 tmpSeq.setStart(jseq.getStart());
4073  1260 tmpSeq.setEnd(jseq.getEnd());
4074  1260 tmpseqs.add(tmpSeq);
4075    }
4076    else
4077    {
4078  22599 Sequence vamsasSeq = vamsasSeqs.get(vi);
4079  22599 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
4080    vamsasSeq.getSequence());
4081  22599 tmpSeq.setDescription(vamsasSeq.getDescription());
4082  22599 tmpSeq.setStart(jseq.getStart());
4083  22599 tmpSeq.setEnd(jseq.getEnd());
4084  22599 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
4085  22599 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
4086  22599 tmpseqs.add(tmpSeq);
4087  22599 vi++;
4088    }
4089   
4090  23859 if (safeBoolean(jseq.isViewreference()))
4091    {
4092  5 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
4093    }
4094   
4095  23859 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
4096    {
4097  186 if (hiddenSeqs == null)
4098    {
4099  42 hiddenSeqs = new ArrayList<>();
4100    }
4101   
4102  186 hiddenSeqs.add(tmpSeq);
4103    }
4104    }
4105   
4106    // /
4107    // Create the alignment object from the sequence set
4108    // ///////////////////////////////
4109  140 SequenceI[] orderedSeqs = tmpseqs
4110    .toArray(new SequenceI[tmpseqs.size()]);
4111   
4112  140 AlignmentI al = null;
4113    // so we must create or recover the dataset alignment before going further
4114    // ///////////////////////////////
4115  140 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
4116    {
4117    // older jalview projects do not have a dataset - so creat alignment and
4118    // dataset
4119  30 al = new Alignment(orderedSeqs);
4120  30 al.setDataset(null);
4121    }
4122    else
4123    {
4124  110 boolean isdsal = jalviewModel.getViewport().isEmpty();
4125  110 if (isdsal)
4126    {
4127    // we are importing a dataset record, so
4128    // recover reference to an alignment already materialsed as dataset
4129  38 al = getDatasetFor(vamsasSet.getDatasetId());
4130    }
4131  110 if (al == null)
4132    {
4133    // materialse the alignment
4134  72 al = new Alignment(orderedSeqs);
4135    }
4136  110 if (isdsal)
4137    {
4138  38 addDatasetRef(vamsasSet.getDatasetId(), al);
4139    }
4140   
4141    // finally, verify all data in vamsasSet is actually present in al
4142    // passing on flag indicating if it is actually a stored dataset
4143  110 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
4144    }
4145   
4146  140 if (referenceseqForView != null)
4147    {
4148  5 al.setSeqrep(referenceseqForView);
4149    }
4150    // / Add the alignment properties
4151  161 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
4152    {
4153  21 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
4154    .get(i);
4155  21 al.setProperty(ssp.getKey(), ssp.getValue());
4156    }
4157   
4158    // ///////////////////////////////
4159   
4160  140 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
4161  140 if (!multipleView)
4162    {
4163    // load sequence features, database references and any associated PDB
4164    // structures for the alignment
4165    //
4166    // prior to 2.10, this part would only be executed the first time a
4167    // sequence was encountered, but not afterwards.
4168    // now, for 2.10 projects, this is also done if the xml doc includes
4169    // dataset sequences not actually present in any particular view.
4170    //
4171  23258 for (int i = 0; i < vamsasSeqs.size(); i++)
4172    {
4173  23164 JSeq jseq = jseqs.get(i);
4174  23164 if (jseq.getFeatures().size() > 0)
4175    {
4176  413 List<Feature> features = jseq.getFeatures();
4177  155546 for (int f = 0; f < features.size(); f++)
4178    {
4179  155133 Feature feat = features.get(f);
4180  155133 SequenceFeature sf = new SequenceFeature(feat.getType(),
4181    feat.getDescription(), feat.getBegin(), feat.getEnd(),
4182    safeFloat(feat.getScore()), feat.getFeatureGroup());
4183  155133 sf.setStatus(feat.getStatus());
4184   
4185    /*
4186    * load any feature attributes - include map-valued attributes
4187    */
4188  155133 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
4189  690111 for (int od = 0; od < feat.getOtherData().size(); od++)
4190    {
4191  534978 OtherData keyValue = feat.getOtherData().get(od);
4192  534978 String attributeName = keyValue.getKey();
4193  534978 String attributeValue = keyValue.getValue();
4194  534978 if (attributeName.startsWith("LINK"))
4195    {
4196  6725 sf.addLink(attributeValue);
4197    }
4198    else
4199    {
4200  528253 String subAttribute = keyValue.getKey2();
4201  528253 if (subAttribute == null)
4202    {
4203    // simple string-valued attribute
4204  528233 sf.setValue(attributeName, attributeValue);
4205    }
4206    else
4207    {
4208    // attribute 'key' has sub-attribute 'key2'
4209  20 if (!mapAttributes.containsKey(attributeName))
4210    {
4211  20 mapAttributes.put(attributeName, new HashMap<>());
4212    }
4213  20 mapAttributes.get(attributeName).put(subAttribute,
4214    attributeValue);
4215    }
4216    }
4217    }
4218  155133 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
4219    .entrySet())
4220    {
4221  20 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
4222    }
4223   
4224    // adds feature to datasequence's feature set (since Jalview 2.10)
4225  155133 al.getSequenceAt(i).addSequenceFeature(sf);
4226    }
4227    }
4228  23164 if (vamsasSeqs.get(i).getDBRef().size() > 0)
4229    {
4230    // adds dbrefs to datasequence's set (since Jalview 2.10)
4231  299 addDBRefs(
4232  299 al.getSequenceAt(i).getDatasetSequence() == null
4233    ? al.getSequenceAt(i)
4234    : al.getSequenceAt(i).getDatasetSequence(),
4235    vamsasSeqs.get(i));
4236    }
4237  23164 if (jseq.getPdbids().size() > 0)
4238    {
4239  179 List<Pdbids> ids = jseq.getPdbids();
4240  713 for (int p = 0; p < ids.size(); p++)
4241    {
4242  534 Pdbids pdbid = ids.get(p);
4243  534 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
4244  534 entry.setId(pdbid.getId());
4245  534 if (pdbid.getType() != null)
4246    {
4247  212 if (PDBEntry.Type.getType(pdbid.getType()) != null)
4248    {
4249  212 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
4250    }
4251    else
4252    {
4253  0 entry.setType(PDBEntry.Type.FILE);
4254    }
4255    }
4256    // jprovider is null when executing 'New View'
4257  534 if (pdbid.getFile() != null && jprovider != null)
4258    {
4259  182 if (!pdbloaded.containsKey(pdbid.getFile()))
4260    {
4261  182 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
4262    pdbid.getFile()));
4263    }
4264    else
4265    {
4266  0 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
4267    }
4268    }
4269    /*
4270    if (pdbid.getPdbentryItem() != null)
4271    {
4272    for (PdbentryItem item : pdbid.getPdbentryItem())
4273    {
4274    for (Property pr : item.getProperty())
4275    {
4276    entry.setProperty(pr.getName(), pr.getValue());
4277    }
4278    }
4279    }
4280    */
4281  534 for (Property prop : pdbid.getProperty())
4282    {
4283  832 entry.setProperty(prop.getName(), prop.getValue());
4284    }
4285  534 Desktop.getStructureSelectionManager().registerPDBEntry(entry);
4286    // adds PDBEntry to datasequence's set (since Jalview 2.10)
4287  534 if (al.getSequenceAt(i).getDatasetSequence() != null)
4288    {
4289  263 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
4290    }
4291    else
4292    {
4293  271 al.getSequenceAt(i).addPDBId(entry);
4294    }
4295    }
4296    }
4297    /*
4298    * load any HMMER profile
4299    */
4300    // TODO fix this
4301   
4302  23164 String hmmJarFile = jseqs.get(i).getHmmerProfile();
4303  23164 if (hmmJarFile != null && jprovider != null)
4304    {
4305  1 loadHmmerProfile(jprovider, hmmJarFile, al.getSequenceAt(i));
4306    }
4307    }
4308    } // end !multipleview
4309   
4310    // ///////////////////////////////
4311    // LOAD SEQUENCE MAPPINGS
4312   
4313  140 if (vamsasSet.getAlcodonFrame().size() > 0)
4314    {
4315    // TODO Potentially this should only be done once for all views of an
4316    // alignment
4317  0 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
4318  0 for (int i = 0; i < alc.size(); i++)
4319    {
4320  0 AlignedCodonFrame cf = new AlignedCodonFrame();
4321  0 if (alc.get(i).getAlcodMap().size() > 0)
4322    {
4323  0 List<AlcodMap> maps = alc.get(i).getAlcodMap();
4324  0 for (int m = 0; m < maps.size(); m++)
4325    {
4326  0 AlcodMap map = maps.get(m);
4327  0 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
4328    // Load Mapping
4329  0 jalview.datamodel.Mapping mapping = null;
4330    // attach to dna sequence reference.
4331  0 if (map.getMapping() != null)
4332    {
4333  0 mapping = addMapping(map.getMapping());
4334  0 if (dnaseq != null && mapping.getTo() != null)
4335    {
4336  0 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
4337    }
4338    else
4339    {
4340    // defer to later
4341  0 frefedSequence
4342    .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
4343    }
4344    }
4345    }
4346  0 al.addCodonFrame(cf);
4347    }
4348    }
4349    }
4350   
4351    // ////////////////////////////////
4352    // LOAD ANNOTATIONS
4353  140 List<JvAnnotRow> autoAlan = new ArrayList<>();
4354   
4355    /*
4356    * store any annotations which forward reference a group's ID
4357    */
4358  140 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
4359   
4360  140 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
4361    {
4362  116 List<Annotation> an = vamsasSet.getAnnotation();
4363   
4364  1878 for (int i = 0; i < an.size(); i++)
4365    {
4366  1762 Annotation annotation = an.get(i);
4367   
4368    /**
4369    * test if annotation is automatically calculated for this view only
4370    */
4371  1762 boolean autoForView = false;
4372  1762 if (annotation.getLabel().equals("Quality")
4373    || annotation.getLabel().equals("Conservation")
4374    || annotation.getLabel().equals("Consensus"))
4375    {
4376    // Kludge for pre 2.5 projects which lacked the autocalculated flag
4377  280 autoForView = true;
4378    // JAXB has no has() test; schema defaults value to false
4379    // if (!annotation.hasAutoCalculated())
4380    // {
4381    // annotation.setAutoCalculated(true);
4382    // }
4383    }
4384  1762 if (autoForView || annotation.isAutoCalculated())
4385    {
4386    // remove ID - we don't recover annotation from other views for
4387    // view-specific annotation
4388  379 annotation.setId(null);
4389    }
4390   
4391    // set visibility for other annotation in this view
4392  1762 String annotationId = annotation.getId();
4393  1762 if (annotationId != null && annotationIds.containsKey(annotationId))
4394    {
4395  266 AlignmentAnnotation jda = annotationIds.get(annotationId);
4396    // in principle Visible should always be true for annotation displayed
4397    // in multiple views
4398  266 if (annotation.isVisible() != null)
4399    {
4400  266 jda.visible = annotation.isVisible();
4401    }
4402   
4403  266 al.addAnnotation(jda);
4404   
4405  266 continue;
4406    }
4407    // Construct new annotation from model.
4408  1496 List<AnnotationElement> ae = annotation.getAnnotationElement();
4409  1496 jalview.datamodel.Annotation[] anot = null;
4410  1496 java.awt.Color firstColour = null;
4411  1496 int anpos;
4412  1496 if (!annotation.isScoreOnly())
4413    {
4414  1496 anot = new jalview.datamodel.Annotation[al.getWidth()];
4415  381569 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4416    {
4417  380073 AnnotationElement annElement = ae.get(aa);
4418  380073 anpos = annElement.getPosition();
4419   
4420  380073 if (anpos >= anot.length)
4421    {
4422  0 continue;
4423    }
4424   
4425  380073 float value = safeFloat(annElement.getValue());
4426  380073 anot[anpos] = new jalview.datamodel.Annotation(
4427    annElement.getDisplayCharacter(),
4428    annElement.getDescription(),
4429  380073 (annElement.getSecondaryStructure() == null
4430    || annElement.getSecondaryStructure()
4431    .length() == 0)
4432    ? ' '
4433    : annElement
4434    .getSecondaryStructure()
4435    .charAt(0),
4436    value);
4437  380073 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4438  380073 if (firstColour == null)
4439    {
4440  1463 firstColour = anot[anpos].colour;
4441    }
4442    }
4443    }
4444    // create the new AlignmentAnnotation
4445  1496 jalview.datamodel.AlignmentAnnotation jaa = null;
4446   
4447  1496 if (annotation.isGraph())
4448    {
4449  828 float llim = 0, hlim = 0;
4450    // if (autoForView || an[i].isAutoCalculated()) {
4451    // hlim=11f;
4452    // }
4453  828 jaa = new jalview.datamodel.AlignmentAnnotation(
4454    annotation.getLabel(), annotation.getDescription(), anot,
4455    llim, hlim, safeInt(annotation.getGraphType()));
4456   
4457  828 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4458  828 jaa._linecolour = firstColour;
4459  828 if (annotation.getThresholdLine() != null)
4460    {
4461  0 jaa.setThreshold(new jalview.datamodel.GraphLine(
4462    safeFloat(annotation.getThresholdLine().getValue()),
4463    annotation.getThresholdLine().getLabel(),
4464    new java.awt.Color(safeInt(
4465    annotation.getThresholdLine().getColour()))));
4466    }
4467  828 if (autoForView || annotation.isAutoCalculated())
4468    {
4469    // Hardwire the symbol display line to ensure that labels for
4470    // histograms are displayed
4471  379 jaa.hasText = true;
4472    }
4473    }
4474    else
4475    {
4476  668 jaa = new jalview.datamodel.AlignmentAnnotation(
4477    annotation.getLabel(), annotation.getDescription(), anot);
4478  668 jaa._linecolour = firstColour;
4479    }
4480    // register new annotation
4481    // Annotation graphs such as Conservation will not have id.
4482  1496 if (annotation.getId() != null)
4483    {
4484  1117 annotationIds.put(annotation.getId(), jaa);
4485  1117 jaa.annotationId = annotation.getId();
4486    }
4487    // recover sequence association
4488  1496 String sequenceRef = annotation.getSequenceRef();
4489  1496 if (sequenceRef != null)
4490    {
4491    // from 2.9 sequenceRef is to sequence id (JAL-1781)
4492  1034 SequenceI sequence = seqRefIds.get(sequenceRef);
4493  1034 if (sequence == null)
4494    {
4495    // in pre-2.9 projects sequence ref is to sequence name
4496  0 sequence = al.findName(sequenceRef);
4497    }
4498  1034 if (sequence != null)
4499    {
4500  1034 jaa.createSequenceMapping(sequence, 1, true);
4501  1034 sequence.addAlignmentAnnotation(jaa);
4502    }
4503    }
4504    // and make a note of any group association
4505  1496 if (annotation.getGroupRef() != null
4506    && annotation.getGroupRef().length() > 0)
4507    {
4508  24 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4509    .get(annotation.getGroupRef());
4510  24 if (aal == null)
4511    {
4512  24 aal = new ArrayList<>();
4513  24 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4514    }
4515  24 aal.add(jaa);
4516    }
4517   
4518  1496 if (annotation.getScore() != null)
4519    {
4520  139 jaa.setScore(annotation.getScore().doubleValue());
4521    }
4522  1496 if (annotation.isVisible() != null)
4523    {
4524  1496 jaa.visible = annotation.isVisible().booleanValue();
4525    }
4526   
4527  1496 if (annotation.isCentreColLabels() != null)
4528    {
4529  1496 jaa.centreColLabels = annotation.isCentreColLabels()
4530    .booleanValue();
4531    }
4532   
4533  1496 if (annotation.isScaleColLabels() != null)
4534    {
4535  1496 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4536    }
4537  1496 if (autoForView || annotation.isAutoCalculated())
4538    {
4539    // newer files have an 'autoCalculated' flag and store calculation
4540    // state in viewport properties
4541  379 jaa.autoCalculated = true; // means annotation will be marked for
4542    // update at end of load.
4543    }
4544  1496 if (annotation.getGraphHeight() != null)
4545    {
4546  1496 jaa.graphHeight = annotation.getGraphHeight().intValue();
4547    }
4548  1496 jaa.belowAlignment = annotation.isBelowAlignment();
4549  1496 jaa.setCalcId(annotation.getCalcId());
4550  1496 if (annotation.getAnnotationGroupColour() != null)
4551    {
4552  42 jaa.setAnnotationGroupColour(
4553    new Color(annotation.getAnnotationGroupColour()));
4554    }
4555  1496 if (annotation.getProperty().size() > 0)
4556    {
4557  262 for (jalview.xml.binding.jalview.Property prop : annotation
4558    .getProperty())
4559    {
4560  468 jaa.setProperty(prop.getName(), prop.getValue());
4561    }
4562    }
4563  1496 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4564    {
4565  59 if (annotation.getContactmatrix() != null
4566    && annotation.getContactmatrix().size() > 0)
4567    {
4568  59 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4569    {
4570  59 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4571    }
4572    }
4573    }
4574   
4575  1496 if (jaa.autoCalculated)
4576    {
4577  379 autoAlan.add(new JvAnnotRow(i, jaa));
4578    }
4579    else
4580    // if (!autoForView)
4581    {
4582    // add autocalculated group annotation and any user created annotation
4583    // for the view
4584  1117 al.addAnnotation(jaa);
4585    }
4586    }
4587    }
4588    // ///////////////////////
4589    // LOAD GROUPS
4590    // Create alignment markup and styles for this view
4591  140 if (jalviewModel.getJGroup().size() > 0)
4592    {
4593  34 List<JGroup> groups = jalviewModel.getJGroup();
4594  34 boolean addAnnotSchemeGroup = false;
4595  93 for (int i = 0; i < groups.size(); i++)
4596    {
4597  59 JGroup jGroup = groups.get(i);
4598  59 ColourSchemeI cs = null;
4599  59 if (jGroup.getColour() != null)
4600    {
4601  33 if (jGroup.getColour().startsWith("ucs"))
4602    {
4603  0 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4604    }
4605  33 else if (jGroup.getColour().equals("AnnotationColourGradient")
4606    && jGroup.getAnnotationColours() != null)
4607    {
4608  1 addAnnotSchemeGroup = true;
4609    }
4610    else
4611    {
4612  32 cs = ColourSchemeProperty.getColourScheme(null, al,
4613    jGroup.getColour());
4614    }
4615    }
4616  59 int pidThreshold = safeInt(jGroup.getPidThreshold());
4617   
4618  59 Vector<SequenceI> seqs = new Vector<>();
4619   
4620  496 for (int s = 0; s < jGroup.getSeq().size(); s++)
4621    {
4622  437 String seqId = jGroup.getSeq().get(s);
4623  437 SequenceI ts = seqRefIds.get(seqId);
4624   
4625  437 if (ts != null)
4626    {
4627  437 seqs.addElement(ts);
4628    }
4629    }
4630   
4631  59 if (seqs.size() < 1)
4632    {
4633  0 continue;
4634    }
4635   
4636  59 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4637    safeBoolean(jGroup.isDisplayBoxes()),
4638    safeBoolean(jGroup.isDisplayText()),
4639    safeBoolean(jGroup.isColourText()),
4640    safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4641  59 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4642  59 sg.getGroupColourScheme().setConsensusSecondaryStructureColouring(
4643    safeBoolean(jGroup.isSecstrSelected()));
4644  59 sg.getGroupColourScheme()
4645    .setConservationInc(safeInt(jGroup.getConsThreshold()));
4646  59 sg.getGroupColourScheme().setConsensusSecondaryStructureThreshold(
4647    safeInt(jGroup.getSecstrThreshold()));
4648  59 sg.setIdColour(new Color(safeInt(jGroup.getIdColour())));
4649  59 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4650   
4651  59 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4652  59 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4653  59 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4654  59 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4655    // attributes with a default in the schema are never null
4656  59 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4657  59 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4658  59 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4659  59 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4660  59 sg.setSecondaryStructureSources(jGroup.getSecStrProvider());
4661   
4662    // Restore annotations from annotation based tree for groups created
4663    // by splitting the tree
4664  59 if (jGroup.getAnnotationFromTree() != null)
4665    {
4666  59 for (String annot : jGroup.getAnnotationFromTree())
4667    {
4668  36 if (annotationIds.get(annot) != null)
4669    {
4670  36 sg.addAnnotationFromTree(annotationIds.get(annot));
4671    }
4672    }
4673    }
4674   
4675  59 if (jGroup.getConsThreshold() != null
4676    && jGroup.getConsThreshold().intValue() != 0)
4677    {
4678  2 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4679    sg.getWidth() - 1);
4680  2 c.calculate();
4681  2 c.verdict(false, 25);
4682  2 sg.cs.setConservation(c);
4683    }
4684   
4685  59 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4686    {
4687    // re-instate unique group/annotation row reference
4688  24 List<AlignmentAnnotation> jaal = groupAnnotRefs
4689    .get(jGroup.getId());
4690  24 if (jaal != null)
4691    {
4692  24 for (AlignmentAnnotation jaa : jaal)
4693    {
4694  24 jaa.groupRef = sg;
4695  24 if (jaa.autoCalculated)
4696    {
4697    // match up and try to set group autocalc alignment row for this
4698    // annotation
4699  24 if (jaa.label.startsWith("Consensus for "))
4700    {
4701  24 sg.setConsensus(jaa);
4702    }
4703    // match up and try to set group autocalc alignment row for this
4704    // annotation
4705  24 if (jaa.label.startsWith("Conservation for "))
4706    {
4707  0 sg.setConservationRow(jaa);
4708    }
4709  24 if (jaa.label.startsWith("Secondary Structure Consensus"))
4710    {
4711  0 sg.setSSConsensusRow(jaa);
4712    }
4713    }
4714    }
4715    }
4716    }
4717  59 al.addGroup(sg);
4718  59 if (addAnnotSchemeGroup)
4719    {
4720    // reconstruct the annotation colourscheme
4721  1 sg.setColourScheme(
4722    constructAnnotationColour(jGroup.getAnnotationColours(),
4723    null, al, jalviewModel, false));
4724    }
4725    }
4726    }
4727  140 if (view == null)
4728    {
4729    // only dataset in this model, so just return.
4730  38 return null;
4731    }
4732    // ///////////////////////////////
4733    // LOAD VIEWPORT
4734   
4735    // now check to see if we really need to create a new viewport.
4736  102 if (multipleView && viewportsAdded.size() == 0)
4737    {
4738    // We recovered an alignment for which a viewport already exists.
4739    // TODO: fix up any settings necessary for overlaying stored state onto
4740    // state recovered from another document. (may not be necessary).
4741    // we may need a binding from a viewport in memory to one recovered from
4742    // XML.
4743    // and then recover its containing af to allow the settings to be applied.
4744    // TODO: fix for vamsas demo
4745  0 jalview.bin.Console.errPrintln(
4746    "About to recover a viewport for existing alignment: Sequence set ID is "
4747    + uniqueSeqSetId);
4748  0 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4749  0 if (seqsetobj != null)
4750    {
4751  0 if (seqsetobj instanceof String)
4752    {
4753  0 uniqueSeqSetId = (String) seqsetobj;
4754  0 jalview.bin.Console.errPrintln(
4755    "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4756    + uniqueSeqSetId);
4757    }
4758    else
4759    {
4760  0 jalview.bin.Console.errPrintln(
4761    "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4762    }
4763   
4764    }
4765    }
4766    /**
4767    * indicate that annotation colours are applied across all groups (pre
4768    * Jalview 2.8.1 behaviour)
4769    */
4770  102 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4771    jalviewModel.getVersion());
4772   
4773  102 AlignFrame af = null;
4774  102 AlignmentPanel ap = null;
4775  102 AlignViewport av = null;
4776  102 if (viewId != null)
4777    {
4778    // Check to see if this alignment already has a view id == viewId
4779  90 jalview.gui.AlignmentPanel views[] = (jalview.gui.AlignmentPanel[]) Desktop
4780    .getAlignmentPanels(uniqueSeqSetId);
4781  90 if (views != null && views.length > 0)
4782    {
4783  144 for (int v = 0; v < views.length; v++)
4784    {
4785  99 ap = views[v];
4786  99 av = ap.av;
4787  99 if (av.getViewId().equalsIgnoreCase(viewId))
4788    {
4789    // recover the existing alignpanel, alignframe, viewport
4790  0 af = ap.alignFrame;
4791  0 break;
4792    // TODO: could even skip resetting view settings if we don't want to
4793    // change the local settings from other jalview processes
4794    }
4795    }
4796    }
4797    }
4798   
4799  102 if (af == null)
4800    {
4801  102 af = loadViewport(fileName, file, jseqs, hiddenSeqs, al, jalviewModel,
4802    view, uniqueSeqSetId, viewId, autoAlan);
4803  102 av = af.getViewport();
4804    // note that this only retrieves the most recently accessed
4805    // tab of an AlignFrame.
4806  102 ap = af.alignPanel;
4807    }
4808   
4809    /*
4810    * Load any trees, PDB structures and viewers, Overview
4811    *
4812    * Not done if flag is false (when this method is used for New View)
4813    */
4814  102 final AlignFrame af0 = af;
4815  102 final AlignViewport av0 = av;
4816  102 final AlignmentPanel ap0 = ap;
4817    // Platform.timeCheck("Jalview2XML.loadFromObject-beforetree",
4818    // Platform.TIME_MARK);
4819  102 if (loadTreesAndStructures)
4820    {
4821  90 if (!jalviewModel.getTree().isEmpty())
4822    {
4823  15 SwingUtilities.invokeLater(new Runnable()
4824    {
 
4825  15 toggle @Override
4826    public void run()
4827    {
4828    // Platform.timeCheck(null, Platform.TIME_MARK);
4829  15 loadTrees(jalviewModel, view, af0, av0, ap0);
4830    // Platform.timeCheck("Jalview2XML.loadTrees", Platform.TIME_MARK);
4831    }
4832    });
4833    }
4834  90 if (!jalviewModel.getPcaViewer().isEmpty())
4835    {
4836  2 SwingUtilities.invokeLater(new Runnable()
4837    {
 
4838  2 toggle @Override
4839    public void run()
4840    {
4841    // Platform.timeCheck(null, Platform.TIME_MARK);
4842  2 loadPCAViewers(jalviewModel, ap0);
4843  2 loadPaSiMapViewers(jalviewModel, ap0);
4844    // Platform.timeCheck("Jalview2XML.loadPCA", Platform.TIME_MARK);
4845    }
4846    });
4847    }
4848  90 SwingUtilities.invokeLater(new Runnable()
4849    {
 
4850  90 toggle @Override
4851    public void run()
4852    {
4853    // Platform.timeCheck(null, Platform.TIME_MARK);
4854  90 loadPDBStructures(jprovider, jseqs, af0, ap0);
4855    // Platform.timeCheck("Jalview2XML.loadPDB", Platform.TIME_MARK);
4856    }
4857    });
4858  90 SwingUtilities.invokeLater(new Runnable()
4859    {
 
4860  90 toggle @Override
4861    public void run()
4862    {
4863  90 loadRnaViewers(jprovider, jseqs, ap0);
4864    }
4865    });
4866  90 loadOverview(view, jalviewModel.getVersion(), af);
4867    }
4868    // and finally return.
4869    // but do not set holdRepaint true just yet, because this could be the
4870    // initial frame with just its dataset.
4871  102 return af;
4872    }
4873   
 
4874  8 toggle private void importMatrixData(List<MatrixType> xmlmatrices)
4875    {
4876  8 for (MatrixType xmlmat : xmlmatrices)
4877    {
4878  30 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4879    {
4880  0 Console.error("Ignoring matrix '" + xmlmat.getId() + "' of type '"
4881    + xmlmat.getType());
4882  0 continue;
4883    }
4884   
4885  30 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4886    {
4887  0 Console.error("Can't handle non square matrices");
4888  0 continue;
4889    }
4890   
4891  30 float[][] elements = ContactMatrix.fromFloatStringToContacts(
4892    xmlmat.getElements(), xmlmat.getCols().intValue(),
4893    xmlmat.getRows().intValue());
4894   
4895  30 List<BitSet> newgroups = new ArrayList<BitSet>();
4896  30 if (xmlmat.getGroups().size() > 0)
4897    {
4898  2 for (String sgroup : xmlmat.getGroups())
4899    {
4900  6 newgroups.add(deStringifyBitset(sgroup));
4901    }
4902    }
4903  30 String nwk = xmlmat.getNewick().size() > 0 ? xmlmat.getNewick().get(0)
4904    : null;
4905  30 if (xmlmat.getNewick().size() > 1)
4906    {
4907  0 Console.log
4908    .info("Ignoring additional clusterings for contact matrix");
4909    }
4910  30 String treeMethod = xmlmat.getTreeMethod();
4911  30 double thresh = xmlmat.getCutHeight() != null ? xmlmat.getCutHeight()
4912    : 0;
4913  30 GroupSet grpset = new GroupSet();
4914  30 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4915   
4916  30 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4917  30 contactMatrixRefs.put(xmlmat.getId(), newcm);
4918  30 Console.trace("Restored base contact matrix " + xmlmat.getId());
4919    }
4920    }
4921   
 
4922  59 toggle private void restoreMatrixFor(SequenceI sequenceRef,
4923    AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4924    {
4925    // restore mapping data to matrix data
4926  59 jalview.util.MapList mapping = null;
4927  59 if (xmlmatmapping.getMapping() != null)
4928    {
4929  59 MapListType m = xmlmatmapping.getMapping();
4930    // Mapping m = dr.getMapping();
4931  59 int fr[] = new int[m.getMapListFrom().size() * 2];
4932  59 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4933  118 for (int _i = 0; from.hasNext(); _i += 2)
4934    {
4935  59 MapListFrom mf = from.next();
4936  59 fr[_i] = mf.getStart();
4937  59 fr[_i + 1] = mf.getEnd();
4938    }
4939  59 int fto[] = new int[m.getMapListTo().size() * 2];
4940  59 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4941  118 for (int _i = 0; to.hasNext(); _i += 2)
4942    {
4943  59 MapListTo mf = to.next();
4944  59 fto[_i] = mf.getStart();
4945  59 fto[_i + 1] = mf.getEnd();
4946    }
4947   
4948  59 mapping = new jalview.util.MapList(fr, fto,
4949    m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4950    }
4951   
4952    // locate matrix data in project XML and import
4953  59 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4954  59 if (cm == null)
4955    {
4956  31 frefedSequence
4957    .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4958    }
4959    else
4960    {
4961    // create the PAEMatrix now
4962  28 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4963    mapping, cm);
4964   
4965  28 jaa.sequenceRef.addContactListFor(jaa, newpae);
4966    }
4967   
4968  59 return;
4969    }
4970   
4971    /**
4972    * Load Overview window, restoring colours, 'show hidden regions' flag, title
4973    * and geometry as saved
4974    *
4975    * @param view
4976    * @param af
4977    */
 
4978  90 toggle protected void loadOverview(Viewport view, String version, AlignFrame af)
4979    {
4980  90 if (!isVersionStringLaterThan("2.11.3", version)
4981    && view.getOverview() == null)
4982    {
4983  43 return;
4984    }
4985    /*
4986    * first close any Overview that was opened automatically
4987    * (if so configured in Preferences) so that the view is
4988    * restored in the same state as saved
4989    */
4990  47 af.alignPanel.closeOverviewPanel();
4991   
4992  47 Overview overview = view.getOverview();
4993  47 if (overview != null)
4994    {
4995  11 OverviewPanel overviewPanel = af
4996    .openOverviewPanel(overview.isShowHidden());
4997  11 overviewPanel.setTitle(overview.getTitle());
4998  11 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4999    overview.getWidth(), overview.getHeight());
5000  11 Color gap = new Color(overview.getGapColour());
5001  11 Color residue = new Color(overview.getResidueColour());
5002  11 Color hidden = new Color(overview.getHiddenColour());
5003  11 overviewPanel.getCanvas().setColours(gap, residue, hidden);
5004    }
5005    }
5006   
5007    /**
5008    * Loads a HMMER profile from a file stored in the project, and associates it
5009    * with the specified sequence
5010    *
5011    * @param jprovider
5012    * @param hmmJarFile
5013    * @param seq
5014    */
 
5015  1 toggle protected void loadHmmerProfile(jarInputStreamProvider jprovider,
5016    String hmmJarFile, SequenceI seq)
5017    {
5018  1 try
5019    {
5020  1 String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
5021  1 HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
5022  1 HiddenMarkovModel hmmModel = parser.getHMM();
5023  1 hmmModel = new HiddenMarkovModel(hmmModel, seq);
5024  1 seq.setHMM(hmmModel);
5025    } catch (IOException e)
5026    {
5027  0 Console.warn("Error loading HMM profile for " + seq.getName() + ": "
5028    + e.getMessage());
5029    }
5030    }
5031   
5032    /**
5033    * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
5034    * panel is restored from separate jar entries, two (gapped and trimmed) per
5035    * sequence and secondary structure.
5036    *
5037    * Currently each viewer shows just one sequence and structure (gapped and
5038    * trimmed), however this method is designed to support multiple sequences or
5039    * structures in viewers if wanted in future.
5040    *
5041    * @param jprovider
5042    * @param jseqs
5043    * @param ap
5044    */
 
5045  90 toggle protected void loadRnaViewers(jarInputStreamProvider jprovider,
5046    List<JSeq> jseqs, AlignmentPanel ap)
5047    {
5048    /*
5049    * scan the sequences for references to viewers; create each one the first
5050    * time it is referenced, add Rna models to existing viewers
5051    */
5052  90 for (JSeq jseq : jseqs)
5053    {
5054  1212 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
5055    {
5056  0 RnaViewer viewer = jseq.getRnaViewer().get(i);
5057  0 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
5058    ap);
5059   
5060  0 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
5061    {
5062  0 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
5063  0 SequenceI seq = seqRefIds.get(jseq.getId());
5064  0 AlignmentAnnotation ann = this.annotationIds
5065    .get(ss.getAnnotationId());
5066   
5067    /*
5068    * add the structure to the Varna display (with session state copied
5069    * from the jar to a temporary file)
5070    */
5071  0 boolean gapped = safeBoolean(ss.isGapped());
5072  0 String rnaTitle = ss.getTitle();
5073  0 String sessionState = ss.getViewerState();
5074  0 String tempStateFile = copyJarEntry(jprovider, sessionState,
5075    "varna", null);
5076  0 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
5077  0 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
5078    }
5079  0 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
5080    }
5081    }
5082    }
5083   
5084    /**
5085    * Locate and return an already instantiated matching AppVarna, or create one
5086    * if not found
5087    *
5088    * @param viewer
5089    * @param viewIdSuffix
5090    * @param ap
5091    * @return
5092    */
 
5093  0 toggle protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
5094    String viewIdSuffix, AlignmentPanel ap)
5095    {
5096    /*
5097    * on each load a suffix is appended to the saved viewId, to avoid conflicts
5098    * if load is repeated
5099    */
5100  0 String postLoadId = viewer.getViewId() + viewIdSuffix;
5101  0 for (JInternalFrame frame : getAllFrames())
5102    {
5103  0 if (frame instanceof AppVarna)
5104    {
5105  0 AppVarna varna = (AppVarna) frame;
5106  0 if (postLoadId.equals(varna.getViewId()))
5107    {
5108    // this viewer is already instantiated
5109    // could in future here add ap as another 'parent' of the
5110    // AppVarna window; currently just 1-to-many
5111  0 return varna;
5112    }
5113    }
5114    }
5115   
5116    /*
5117    * viewer not found - make it
5118    */
5119  0 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
5120    safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
5121    safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
5122    safeInt(viewer.getDividerLocation()));
5123  0 AppVarna varna = new AppVarna(model, ap);
5124   
5125  0 return varna;
5126    }
5127   
5128    /**
5129    * Load any saved trees
5130    *
5131    * @param jm
5132    * @param view
5133    * @param af
5134    * @param av
5135    * @param ap
5136    */
 
5137  15 toggle protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
5138    AlignViewport av, AlignmentPanel ap)
5139    {
5140    // TODO result of automated refactoring - are all these parameters needed?
5141  15 try
5142    {
5143  18 for (int t = 0; t < jm.getTree().size(); t++)
5144    {
5145   
5146  15 Tree tree = jm.getTree().get(t);
5147   
5148  15 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
5149  15 if (tp == null)
5150    {
5151  15 if (tree.isColumnWise())
5152    {
5153  0 AlignmentAnnotation aa = annotationIds
5154    .get(tree.getColumnReference());
5155  0 if (aa == null)
5156    {
5157  0 Console.warn(
5158    "Null alignment annotation when restoring columnwise tree");
5159    }
5160  0 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
5161    tree.getTitle(), safeInt(tree.getWidth()),
5162    safeInt(tree.getHeight()), safeInt(tree.getXpos()),
5163    safeInt(tree.getYpos()));
5164   
5165    }
5166    else
5167    {
5168  15 if (tree.isAnnotationBased())
5169    {
5170    // Invoke showNewickTreeForAnnotation() if tree is annotation
5171    // based
5172  3 tp = af.showNewickTreeForAnnotation(
5173    new NewickFile(tree.getNewick()), annotationIds,
5174    tree.getTitle(), null, safeInt(tree.getWidth()),
5175    safeInt(tree.getHeight()), safeInt(tree.getXpos()),
5176    safeInt(tree.getYpos()));
5177    }
5178    else
5179    {
5180  12 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
5181    tree.getTitle(), safeInt(tree.getWidth()),
5182    safeInt(tree.getHeight()), safeInt(tree.getXpos()),
5183    safeInt(tree.getYpos()));
5184    }
5185    }
5186  15 if (tp == null)
5187    {
5188  0 Console.warn(
5189    "There was a problem recovering stored Newick tree: \n"
5190    + tree.getNewick());
5191  0 continue;
5192    }
5193  15 if (tree.getId() != null)
5194    {
5195    // perhaps bind the tree id to something ?
5196    }
5197    }
5198    else
5199    {
5200    // update local tree attributes ?
5201    // TODO: should check if tp has been manipulated by user - if so its
5202    // settings shouldn't be modified
5203  0 tp.setTitle(tree.getTitle());
5204  0 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
5205    safeInt(tree.getYpos()), safeInt(tree.getWidth()),
5206    safeInt(tree.getHeight())));
5207  0 tp.setViewport(av); // af.viewport;
5208    // TODO: verify 'associate with all views' works still
5209  0 tp.getTreeCanvas().setViewport(av); // af.viewport;
5210  0 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
5211    }
5212  15 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
5213   
5214  15 tp.setAnnotationBased(safeBoolean(tree.isAnnotationBased()));
5215   
5216  15 if (tree.getTreeColorMap() == null)
5217    {
5218  12 return; // No color data saved
5219    }
5220   
5221  3 Map<String, Color> colorMap = new HashMap<>();
5222  3 for (JalviewModel.Tree.TreeColorMap.ColorEntry colorEntry : tree
5223    .getTreeColorMap().getColorEntry())
5224    {
5225  12 String label = colorEntry.getLabel();
5226  12 int rgb = colorEntry.getColor(); // Retrieve stored integer color
5227  12 Color color = new Color(rgb, true); // Convert back to Color object
5228  12 colorMap.put(label, color);
5229    }
5230   
5231    // Set the restored colors to the TreePanel
5232  3 tp.restoreSecondaryStructureProviderColorMap(colorMap);
5233   
5234  3 tp.setShowAnnotationAs(Optional
5235    .ofNullable(tree.getShowAnnotationAs()).orElse("None"));
5236   
5237  3 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
5238  3 tp.fitToWindow_actionPerformed(null);
5239   
5240  3 if (tree.getFontName() != null)
5241    {
5242  3 tp.setTreeFont(
5243    new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
5244    safeInt(tree.getFontSize())));
5245    }
5246    else
5247    {
5248  0 tp.setTreeFont(
5249    new Font(view.getFontName(), safeInt(view.getFontStyle()),
5250    safeInt(view.getFontSize())));
5251    }
5252   
5253  3 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
5254  3 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
5255  3 tp.showDistances(safeBoolean(tree.isShowDistances()));
5256   
5257  3 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
5258   
5259  3 if (safeBoolean(tree.isCurrentTree()))
5260    {
5261  3 af.getViewport().setCurrentTree(tp.getTree());
5262    }
5263    }
5264   
5265    } catch (Exception ex)
5266    {
5267  0 ex.printStackTrace();
5268    }
5269    }
5270   
5271    /**
5272    * Load and link any saved structure viewers.
5273    *
5274    * @param jprovider
5275    * @param jseqs
5276    * @param af
5277    * @param ap
5278    */
 
5279  90 toggle protected void loadPDBStructures(jarInputStreamProvider jprovider,
5280    List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
5281    {
5282    /*
5283    * Run through all PDB ids on the alignment, and collect mappings between
5284    * distinct view ids and all sequences referring to that view.
5285    */
5286  90 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
5287   
5288  1302 for (int i = 0; i < jseqs.size(); i++)
5289    {
5290  1212 JSeq jseq = jseqs.get(i);
5291  1212 if (jseq.getPdbids().size() > 0)
5292    {
5293  204 List<Pdbids> ids = jseq.getPdbids();
5294  563 for (int p = 0; p < ids.size(); p++)
5295    {
5296  359 Pdbids pdbid = ids.get(p);
5297  359 final int structureStateCount = pdbid.getStructureState().size();
5298  439 for (int s = 0; s < structureStateCount; s++)
5299    {
5300    // check to see if we haven't already created this structure view
5301  80 final StructureState structureState = pdbid.getStructureState()
5302    .get(s);
5303  80 String sviewid = (structureState.getViewId() == null) ? null
5304    : structureState.getViewId() + uniqueSetSuffix;
5305  80 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
5306    // Originally : pdbid.getFile()
5307    // : TODO: verify external PDB file recovery still works in normal
5308    // jalview project load
5309  80 jpdb.setFile(
5310    loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
5311  80 jpdb.setId(pdbid.getId());
5312   
5313  80 int x = safeInt(structureState.getXpos());
5314  80 int y = safeInt(structureState.getYpos());
5315  80 int width = safeInt(structureState.getWidth());
5316  80 int height = safeInt(structureState.getHeight());
5317   
5318    // Probably don't need to do this anymore...
5319    // Desktop.getDesktop().getComponentAt(x, y);
5320    // TODO: NOW: check that this recovers the PDB file correctly.
5321  80 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
5322    pdbid.getFile());
5323  80 jalview.datamodel.SequenceI seq = seqRefIds
5324    .get(jseq.getId() + "");
5325  80 if (sviewid == null)
5326    {
5327  0 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
5328    + height;
5329    }
5330  80 if (!structureViewers.containsKey(sviewid))
5331    {
5332  40 String viewerType = structureState.getType();
5333  40 if (viewerType == null) // pre Jalview 2.9
5334    {
5335  30 viewerType = ViewerType.JMOL.toString();
5336    }
5337  40 structureViewers.put(sviewid,
5338    new StructureViewerModel(x, y, width, height, false,
5339    false, true, structureState.getViewId(),
5340    viewerType));
5341    // Legacy pre-2.7 conversion JAL-823 :
5342    // do not assume any view has to be linked for colour by
5343    // sequence
5344    }
5345   
5346    // assemble String[] { pdb files }, String[] { id for each
5347    // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
5348    // seqs_file 2}, boolean[] {
5349    // linkAlignPanel,superposeWithAlignpanel}} from hash
5350  80 StructureViewerModel jmoldat = structureViewers.get(sviewid);
5351  80 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
5352    || structureState.isAlignwithAlignPanel());
5353   
5354    /*
5355    * Default colour by linked panel to false if not specified (e.g.
5356    * for pre-2.7 projects)
5357    */
5358  80 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
5359  80 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
5360  80 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
5361   
5362    /*
5363    * Default colour by viewer to true if not specified (e.g. for
5364    * pre-2.7 projects)
5365    */
5366  80 boolean colourByViewer = jmoldat.isColourByViewer();
5367  80 colourByViewer &= structureState.isColourByJmol();
5368  80 jmoldat.setColourByViewer(colourByViewer);
5369   
5370  80 if (jmoldat.getStateData().length() < structureState.getValue()
5371    /*Content()*/.length())
5372    {
5373  30 jmoldat.setStateData(structureState.getValue());// Content());
5374    }
5375  80 if (pdbid.getFile() != null)
5376    {
5377  80 File mapkey = new File(pdbid.getFile());
5378  80 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
5379  80 if (seqstrmaps == null)
5380    {
5381  40 jmoldat.getFileData().put(mapkey,
5382    seqstrmaps = jmoldat.new StructureData(pdbFile,
5383    pdbid.getId()));
5384    }
5385  80 if (!seqstrmaps.getSeqList().contains(seq))
5386    {
5387  80 seqstrmaps.getSeqList().add(seq);
5388    // TODO and chains?
5389    }
5390    }
5391    else
5392    {
5393  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");
5394  0 Console.warn(errorMessage);
5395    }
5396    }
5397    }
5398    }
5399    }
5400    // Instantiate the associated structure views
5401  90 for (Entry<String, StructureViewerModel> entry : structureViewers
5402    .entrySet())
5403    {
5404  40 try
5405    {
5406  40 createOrLinkStructureViewer(entry, af, ap, jprovider);
5407    } catch (Exception e)
5408    {
5409  0 jalview.bin.Console.errPrintln(
5410    "Error loading structure viewer: " + e.getMessage());
5411    // failed - try the next one
5412    }
5413    }
5414    }
5415   
5416    /**
5417    *
5418    * @param viewerData
5419    * @param af
5420    * @param ap
5421    * @param jprovider
5422    */
 
5423  40 toggle protected void createOrLinkStructureViewer(
5424    Entry<String, StructureViewerModel> viewerData, AlignFrame af,
5425    AlignmentPanel ap, jarInputStreamProvider jprovider)
5426    {
5427  40 final StructureViewerModel stateData = viewerData.getValue();
5428   
5429    /*
5430    * Search for any viewer windows already open from other alignment views
5431    * that exactly match the stored structure state
5432    */
5433  40 StructureViewerBase comp = findMatchingViewer(viewerData);
5434   
5435  40 if (comp != null)
5436    {
5437  28 linkStructureViewer(ap, comp, stateData);
5438  28 return;
5439    }
5440   
5441  12 String type = stateData.getType();
5442  12 try
5443    {
5444  12 ViewerType viewerType = ViewerType.valueOf(type);
5445  12 createStructureViewer(viewerType, viewerData, af, jprovider);
5446    } catch (IllegalArgumentException | NullPointerException e)
5447    {
5448    // TODO JAL-3619 show error dialog / offer an alternative viewer
5449  0 Console.error("Invalid structure viewer type: " + type);
5450    }
5451    }
5452   
5453    /**
5454    * Generates a name for the entry in the project jar file to hold state
5455    * information for a structure viewer
5456    *
5457    * @param viewId
5458    * @return
5459    */
 
5460  5 toggle protected String getViewerJarEntryName(String viewId)
5461    {
5462  5 return VIEWER_PREFIX + viewId;
5463    }
5464   
5465    /**
5466    * Returns any open frame that matches given structure viewer data. The match
5467    * is based on the unique viewId, or (for older project versions) the frame's
5468    * geometry.
5469    *
5470    * @param viewerData
5471    * @return
5472    */
 
5473  40 toggle protected StructureViewerBase findMatchingViewer(
5474    Entry<String, StructureViewerModel> viewerData)
5475    {
5476  40 final String sviewid = viewerData.getKey();
5477  40 final StructureViewerModel svattrib = viewerData.getValue();
5478  40 StructureViewerBase comp = null;
5479  40 JInternalFrame[] frames = getAllFrames();
5480  40 for (JInternalFrame frame : frames)
5481    {
5482  161 if (frame instanceof StructureViewerBase)
5483    {
5484    /*
5485    * Post jalview 2.4 schema includes structure view id
5486    */
5487  28 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
5488    .equals(sviewid))
5489    {
5490  28 comp = (StructureViewerBase) frame;
5491  28 break; // break added in 2.9
5492    }
5493    /*
5494    * Otherwise test for matching position and size of viewer frame
5495    */
5496  0 else if (frame.getX() == svattrib.getX()
5497    && frame.getY() == svattrib.getY()
5498    && frame.getHeight() == svattrib.getHeight()
5499    && frame.getWidth() == svattrib.getWidth())
5500    {
5501  0 comp = (StructureViewerBase) frame;
5502    // no break in faint hope of an exact match on viewId
5503    }
5504    }
5505    }
5506  40 return comp;
5507    }
5508   
5509    /**
5510    * Link an AlignmentPanel to an existing structure viewer.
5511    *
5512    * @param ap
5513    * @param viewer
5514    * @param oldFiles
5515    * @param useinViewerSuperpos
5516    * @param usetoColourbyseq
5517    * @param viewerColouring
5518    */
 
5519  28 toggle protected void linkStructureViewer(AlignmentPanel ap,
5520    StructureViewerBase viewer, StructureViewerModel stateData)
5521    {
5522    // NOTE: if the jalview project is part of a shared session then
5523    // view synchronization should/could be done here.
5524   
5525  28 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
5526  28 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
5527  28 final boolean viewerColouring = stateData.isColourByViewer();
5528  28 Map<File, StructureData> oldFiles = stateData.getFileData();
5529   
5530    /*
5531    * Add mapping for sequences in this view to an already open viewer
5532    */
5533  28 final AAStructureBindingModel binding = viewer.getBinding();
5534  28 for (File id : oldFiles.keySet())
5535    {
5536    // add this and any other pdb files that should be present in the
5537    // viewer
5538  28 StructureData filedat = oldFiles.get(id);
5539  28 String pdbFile = filedat.getFilePath();
5540  28 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5541  28 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5542    null);
5543  28 binding.addSequenceForStructFile(pdbFile, seq);
5544    }
5545    // and add the AlignmentPanel's reference to the view panel
5546  28 viewer.addAlignmentPanel(ap);
5547  28 if (useinViewerSuperpos)
5548    {
5549  0 viewer.useAlignmentPanelForSuperposition(ap);
5550    }
5551    else
5552    {
5553  28 viewer.excludeAlignmentPanelForSuperposition(ap);
5554    }
5555  28 if (usetoColourbyseq)
5556    {
5557  7 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5558    }
5559    else
5560    {
5561  21 viewer.excludeAlignmentPanelForColourbyseq(ap);
5562    }
5563    }
5564   
5565    /**
5566    * Get all frames within the Desktop.
5567    *
5568    * @return
5569    */
 
5570  40 toggle protected JInternalFrame[] getAllFrames()
5571    {
5572  40 JInternalFrame[] frames = null;
5573    // TODO is this necessary - is it safe - risk of hanging?
5574  40 do
5575    {
5576  40 try
5577    {
5578  40 frames = Desktop.getDesktopPane().getAllFrames();
5579    } catch (ArrayIndexOutOfBoundsException e)
5580    {
5581    // occasional No such child exceptions are thrown here...
5582  0 try
5583    {
5584  0 Thread.sleep(10);
5585    } catch (InterruptedException f)
5586    {
5587    }
5588    }
5589  40 } while (frames == null);
5590  40 return frames;
5591    }
5592   
5593    /**
5594    * Answers true if 'version' is equal to or later than 'supported', where each
5595    * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5596    * changes. Development and test values for 'version' are leniently treated
5597    * i.e. answer true.
5598    *
5599    * @param supported
5600    * - minimum version we are comparing against
5601    * @param version
5602    * - version of data being processsed
5603    * @return true if version is equal to or later than supported
5604    */
 
5605  266 toggle public static boolean isVersionStringLaterThan(String supported,
5606    String version)
5607    {
5608  266 if (supported == null || version == null
5609    || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5610    || version.equalsIgnoreCase("Test")
5611    || version.equalsIgnoreCase("AUTOMATED BUILD"))
5612    {
5613  108 jalview.bin.Console.errPrintln("Assuming project file with "
5614  108 + (version == null ? "null" : version)
5615    + " is compatible with Jalview version " + supported);
5616  108 return true;
5617    }
5618    else
5619    {
5620  158 return StringUtils.compareVersions(version, supported, "b") >= 0;
5621    }
5622    }
5623   
5624    Vector<JalviewStructureDisplayI> newStructureViewers = null;
5625   
 
5626  7 toggle protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5627    {
5628  7 if (newStructureViewers != null)
5629    {
5630  7 sview.getBinding().setFinishedLoadingFromArchive(false);
5631  7 newStructureViewers.add(sview);
5632    }
5633    }
5634   
 
5635  42 toggle protected void setLoadingFinishedForNewStructureViewers()
5636    {
5637  42 if (newStructureViewers != null)
5638    {
5639  42 for (JalviewStructureDisplayI sview : newStructureViewers)
5640    {
5641  7 sview.getBinding().setFinishedLoadingFromArchive(true);
5642    }
5643  42 newStructureViewers.clear();
5644  42 newStructureViewers = null;
5645    }
5646    }
5647   
 
5648  102 toggle AlignFrame loadViewport(String fileName, File file, List<JSeq> JSEQ,
5649    List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5650    Viewport view, String uniqueSeqSetId, String viewId,
5651    List<JvAnnotRow> autoAlan)
5652    {
5653  102 AlignFrame af = null;
5654  102 af = new AlignFrame(al, safeInt(view.getWidth()),
5655    safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5656    // {
5657    //
5658    // @Override
5659    // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5660    // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5661    // super.processKeyEvent(e);
5662    //
5663    // }
5664    //
5665    // }
5666    ;
5667   
5668  102 af.alignPanel.setHoldRepaint(true);
5669  102 af.setFile(fileName, file, null, FileFormat.Jalview);
5670  102 af.setFileObject(jarFile); // BH 2019 JAL-3436
5671   
5672  102 final AlignViewport viewport = af.getViewport();
5673  1466 for (int i = 0; i < JSEQ.size(); i++)
5674    {
5675  1364 int colour = safeInt(JSEQ.get(i).getColour());
5676  1364 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5677    new Color(colour));
5678  1364 viewport.updateAnnotationColours();
5679    }
5680   
5681  102 if (al.hasSeqrep())
5682    {
5683  5 viewport.setColourByReferenceSeq(true);
5684  5 viewport.setDisplayReferenceSeq(true);
5685    }
5686   
5687  102 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5688   
5689  102 if (view.getSequenceSetId() != null)
5690    {
5691  102 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5692   
5693  102 viewport.setSequenceSetId(uniqueSeqSetId);
5694  102 if (av != null)
5695    {
5696    // propagate shared settings to this new view
5697  45 viewport.setHistoryList(av.getHistoryList());
5698  45 viewport.setRedoList(av.getRedoList());
5699    }
5700    else
5701    {
5702  57 viewportsAdded.put(uniqueSeqSetId, viewport);
5703    }
5704    // TODO: check if this method can be called repeatedly without
5705    // side-effects if alignpanel already registered.
5706  102 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5707    }
5708    // apply Hidden regions to view.
5709  102 if (hiddenSeqs != null)
5710    {
5711  712 for (int s = 0; s < JSEQ.size(); s++)
5712    {
5713  670 SequenceGroup hidden = new SequenceGroup();
5714  670 boolean isRepresentative = false;
5715  672 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5716    {
5717  2 isRepresentative = true;
5718  2 SequenceI sequenceToHide = al
5719    .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5720  2 hidden.addSequence(sequenceToHide, false);
5721    // remove from hiddenSeqs list so we don't try to hide it twice
5722  2 hiddenSeqs.remove(sequenceToHide);
5723    }
5724  670 if (isRepresentative)
5725    {
5726  2 SequenceI representativeSequence = al.getSequenceAt(s);
5727  2 hidden.addSequence(representativeSequence, false);
5728  2 viewport.hideRepSequences(representativeSequence, hidden);
5729    }
5730    }
5731   
5732  42 SequenceI[] hseqs = hiddenSeqs
5733    .toArray(new SequenceI[hiddenSeqs.size()]);
5734  42 viewport.hideSequence(hseqs);
5735   
5736    }
5737    // recover view properties and display parameters
5738   
5739  102 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5740  102 viewport.setShowStructureProvider(
5741    safeBoolean(view.isShowStructureProviders()));
5742  102 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5743  102 final int pidThreshold = safeInt(view.getPidThreshold());
5744  102 viewport.setThreshold(pidThreshold);
5745   
5746  102 viewport.setColourText(safeBoolean(view.isShowColourText()));
5747   
5748  102 viewport.setConservationSelected(
5749    safeBoolean(view.isConservationSelected()));
5750  102 viewport.setIncrement(safeInt(view.getConsThreshold()));
5751  102 viewport.setByConsensusSecondaryStructureSelected(
5752    safeBoolean(view.isSecstrSelected()));
5753  102 viewport.setConsensusSecondaryStructureThreshold(
5754    safeInt(view.getSecstrThreshold()));
5755  102 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5756  102 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5757  102 viewport.setFont(
5758    new Font(view.getFontName(), safeInt(view.getFontStyle()),
5759    safeInt(view.getFontSize())),
5760  102 (view.getCharWidth() != null) ? false : true);
5761  102 if (view.getCharWidth() != null)
5762    {
5763  59 viewport.setCharWidth(view.getCharWidth());
5764  59 viewport.setCharHeight(view.getCharHeight());
5765    }
5766  102 ViewStyleI vs = viewport.getViewStyle();
5767  102 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5768  102 viewport.setViewStyle(vs);
5769    // TODO: allow custom charWidth/Heights to be restored by updating them
5770    // after setting font - which means set above to false
5771  102 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5772  102 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5773  102 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5774   
5775  102 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5776   
5777  102 viewport.setShowText(safeBoolean(view.isShowText()));
5778   
5779  102 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5780  102 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5781  102 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5782  102 viewport.setShowUnconserved(view.isShowUnconserved());
5783  102 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5784   
5785  102 if (view.getViewName() != null)
5786    {
5787  63 viewport.setViewName(view.getViewName());
5788  63 af.setInitialTabVisible();
5789    }
5790  102 int x = safeInt(view.getXpos());
5791  102 int y = safeInt(view.getYpos());
5792  102 int w = safeInt(view.getWidth());
5793  102 int h = safeInt(view.getHeight());
5794    // // BH we cannot let the title bar go off the top
5795    // if (Platform.isJS())
5796    // {
5797    // x = Math.max(50 - w, x);
5798    // y = Math.max(0, y);
5799    // }
5800   
5801  102 af.setBounds(x, y, w, h);
5802   
5803  102 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID
5804    // width
5805  102 if (view.getIdWidth() == null)
5806    {
5807  43 if (!isVersionStringLaterThan("2.11.3", jm.getVersion()))
5808    {
5809    // Pre 2.11.3 jalview projects do not store the id width
5810    // idWidth was also calculated in a different way.
5811  43 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5812  43 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5813    }
5814    }
5815    else
5816    {
5817  59 viewport.setIdWidth(view.getIdWidth());
5818  59 af.alignPanel.getIdPanel().getIdCanvas()
5819    .setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5820    }
5821   
5822    // startSeq set in af.alignPanel.updateLayout below
5823  102 af.alignPanel.updateLayout();
5824  102 ColourSchemeI cs = null;
5825    // apply colourschemes
5826  102 if (view.getBgColour() != null)
5827    {
5828  102 if (view.getBgColour().startsWith("ucs"))
5829    {
5830  0 cs = getUserColourScheme(jm, view.getBgColour());
5831    }
5832  102 else if (view.getBgColour().startsWith("Annotation"))
5833    {
5834  2 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5835  2 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5836   
5837    // annpos
5838   
5839    }
5840    else
5841    {
5842  100 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5843    view.getBgColour());
5844    }
5845    }
5846   
5847    /*
5848    * turn off 'alignment colour applies to all groups'
5849    * while restoring global colour scheme
5850    */
5851  102 viewport.setColourAppliesToAllGroups(false);
5852  102 viewport.setGlobalColourScheme(cs);
5853  102 viewport.getResidueShading().setThreshold(pidThreshold,
5854    view.isIgnoreGapsinConsensus());
5855  102 viewport.getResidueShading()
5856    .setConsensus(viewport.getSequenceConsensusHash());
5857  102 viewport.getResidueShading().setSSConsensusProfileMap(
5858    viewport.getSequenceSSConsensusHash());
5859   
5860  102 if (safeBoolean(view.isConservationSelected()) && cs != null)
5861    {
5862  2 viewport.getResidueShading()
5863    .setConservationInc(safeInt(view.getConsThreshold()));
5864    }
5865  102 if (safeBoolean(view.isSecstrSelected()) && cs != null)
5866    {
5867  2 viewport.getResidueShading().setConsensusSecondaryStructureThreshold(
5868    safeInt(view.getSecstrThreshold()));
5869    }
5870  102 af.changeColour(cs);
5871    // initialise any per-group shading - e.g. IdColour
5872  102 for (SequenceGroup sg : viewport.getAlignment().getGroups())
5873    {
5874  59 cs = sg.getColourScheme();
5875  59 if (cs != null)
5876    {
5877  33 cs = cs.getInstance(viewport, sg);
5878  33 sg.setColourScheme(cs);
5879    }
5880    }
5881   
5882  102 viewport.setColourAppliesToAllGroups(true);
5883   
5884  102 viewport.setShowSequenceFeatures(
5885    safeBoolean(view.isShowSequenceFeatures()));
5886   
5887  102 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5888  102 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5889  102 viewport.setFollowHighlight(view.isFollowHighlight());
5890  102 viewport.followSelection = view.isFollowSelection();
5891  102 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5892  102 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5893  102 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5894  102 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5895  102 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5896  102 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5897  102 viewport.setShowGroupSSConsensus(view.isShowGroupSecStrConsensus());
5898  102 viewport.setShowGroupConservation(view.isShowGroupConservation());
5899  102 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5900  102 viewport.setShowComplementFeaturesOnTop(
5901    view.isShowComplementFeaturesOnTop());
5902   
5903    // recover feature settings
5904  102 if (jm.getFeatureSettings() != null)
5905    {
5906  51 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5907    .getFeatureRenderer();
5908  51 FeaturesDisplayed fdi;
5909  51 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5910  51 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5911    .size()];
5912  51 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5913  51 Map<String, Float> featureOrder = new Hashtable<>();
5914   
5915  986 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5916    .size(); fs++)
5917    {
5918  935 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5919  935 String featureType = setting.getType();
5920   
5921    /*
5922    * restore feature filters (if any)
5923    */
5924  935 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5925    .getMatcherSet();
5926  935 if (filters != null)
5927    {
5928  3 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5929    filters);
5930  3 if (!filter.isEmpty())
5931    {
5932  3 fr.setFeatureFilter(featureType, filter);
5933    }
5934    }
5935   
5936    /*
5937    * restore feature colour scheme
5938    */
5939  935 Color maxColour = new Color(setting.getColour());
5940  935 if (setting.getMincolour() != null)
5941    {
5942    /*
5943    * minColour is always set unless a simple colour
5944    * (including for colour by label though it doesn't use it)
5945    */
5946  5 Color minColour = new Color(setting.getMincolour().intValue());
5947  5 Color noValueColour = minColour;
5948  5 NoValueColour noColour = setting.getNoValueColour();
5949  5 if (noColour == NoValueColour.NONE)
5950    {
5951  5 noValueColour = null;
5952    }
5953  0 else if (noColour == NoValueColour.MAX)
5954    {
5955  0 noValueColour = maxColour;
5956    }
5957  5 float min = safeFloat(safeFloat(setting.getMin()));
5958  5 float max = setting.getMax() == null ? 1f
5959    : setting.getMax().floatValue();
5960  5 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5961    maxColour, noValueColour, min, max);
5962  5 if (setting.getAttributeName().size() > 0)
5963    {
5964  2 gc.setAttributeName(setting.getAttributeName().toArray(
5965    new String[setting.getAttributeName().size()]));
5966    }
5967  5 if (setting.getThreshold() != null)
5968    {
5969  5 gc.setThreshold(setting.getThreshold().floatValue());
5970  5 int threshstate = safeInt(setting.getThreshstate());
5971    // -1 = None, 0 = Below, 1 = Above threshold
5972  5 if (threshstate == 0)
5973    {
5974  1 gc.setBelowThreshold(true);
5975    }
5976  4 else if (threshstate == 1)
5977    {
5978  1 gc.setAboveThreshold(true);
5979    }
5980    }
5981  5 gc.setAutoScaled(true); // default
5982  5 if (setting.isAutoScale() != null)
5983    {
5984  5 gc.setAutoScaled(setting.isAutoScale());
5985    }
5986  5 if (setting.isColourByLabel() != null)
5987    {
5988  5 gc.setColourByLabel(setting.isColourByLabel());
5989    }
5990    // and put in the feature colour table.
5991  5 featureColours.put(featureType, gc);
5992    }
5993    else
5994    {
5995  930 featureColours.put(featureType, new FeatureColour(maxColour));
5996    }
5997  935 renderOrder[fs] = featureType;
5998  935 if (setting.getOrder() != null)
5999    {
6000  935 featureOrder.put(featureType, setting.getOrder().floatValue());
6001    }
6002    else
6003    {
6004  0 featureOrder.put(featureType, Float.valueOf(
6005    fs / jm.getFeatureSettings().getSetting().size()));
6006    }
6007  935 if (safeBoolean(setting.isDisplay()))
6008    {
6009  350 fdi.setVisible(featureType);
6010    }
6011    }
6012  51 Map<String, Boolean> fgtable = new Hashtable<>();
6013  319 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
6014    {
6015  268 Group grp = jm.getFeatureSettings().getGroup().get(gs);
6016  268 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
6017    }
6018    // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
6019    // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
6020    // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
6021  51 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
6022    fgtable, featureColours, 1.0f, featureOrder);
6023  51 fr.transferSettings(frs);
6024    }
6025   
6026  102 if (view.getHiddenColumns().size() > 0)
6027    {
6028  76 for (int c = 0; c < view.getHiddenColumns().size(); c++)
6029    {
6030  54 final HiddenColumns hc = view.getHiddenColumns().get(c);
6031  54 viewport.hideColumns(safeInt(hc.getStart()),
6032    safeInt(hc.getEnd()) /* +1 */);
6033    }
6034    }
6035  102 if (view.getCalcIdParam() != null)
6036    {
6037  102 for (CalcIdParam calcIdParam : view.getCalcIdParam())
6038    {
6039  0 if (calcIdParam != null)
6040    {
6041  0 if (recoverCalcIdParam(calcIdParam, viewport))
6042    {
6043    }
6044    else
6045    {
6046  0 Console.warn("Couldn't recover parameters for "
6047    + calcIdParam.getCalcId());
6048    }
6049    }
6050    }
6051    }
6052  102 af.setMenusFromViewport(viewport);
6053  102 af.setTitle(view.getTitle());
6054    // TODO: we don't need to do this if the viewport is aready visible.
6055    /*
6056    * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
6057    * has a 'cdna/protein complement' view, in which case save it in order to
6058    * populate a SplitFrame once all views have been read in.
6059    */
6060  102 String complementaryViewId = view.getComplementId();
6061   
6062  102 if (complementaryViewId == null)
6063    {
6064  102 Dimension dim = Platform.getDimIfEmbedded(af,
6065    safeInt(view.getWidth()), safeInt(view.getHeight()));
6066  102 Desktop.addInternalFrame(af, view.getTitle(), dim.width, dim.height);
6067    // recompute any autoannotation
6068  102 af.alignPanel.updateAnnotation(false, true);
6069  102 reorderAutoannotation(af, al, autoAlan);
6070  102 af.alignPanel.alignmentChanged();
6071    }
6072    else
6073    {
6074  0 splitFrameCandidates.put(view, af);
6075    }
6076   
6077  102 return af;
6078    }
6079   
6080    /**
6081    * Reads saved data to restore Colour by Annotation settings
6082    *
6083    * @param viewAnnColour
6084    * @param af
6085    * @param al
6086    * @param model
6087    * @param checkGroupAnnColour
6088    * @return
6089    */
 
6090  3 toggle private ColourSchemeI constructAnnotationColour(
6091    AnnotationColourScheme viewAnnColour, AlignFrame af,
6092    AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
6093    {
6094  3 boolean propagateAnnColour = false;
6095  3 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
6096    : al;
6097  3 if (checkGroupAnnColour && al.getGroups() != null
6098    && al.getGroups().size() > 0)
6099    {
6100    // pre 2.8.1 behaviour
6101    // check to see if we should transfer annotation colours
6102  1 propagateAnnColour = true;
6103  1 for (SequenceGroup sg : al.getGroups())
6104    {
6105  1 if (sg.getColourScheme() instanceof AnnotationColourGradient)
6106    {
6107  1 propagateAnnColour = false;
6108    }
6109    }
6110    }
6111   
6112    /*
6113    * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
6114    */
6115  3 String annotationId = viewAnnColour.getAnnotation();
6116  3 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
6117   
6118    /*
6119    * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
6120    */
6121  3 if (matchedAnnotation == null
6122    && annAlignment.getAlignmentAnnotation() != null)
6123    {
6124  0 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
6125    {
6126  0 if (annotationId
6127    .equals(annAlignment.getAlignmentAnnotation()[i].label))
6128    {
6129  0 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
6130  0 break;
6131    }
6132    }
6133    }
6134  3 if (matchedAnnotation == null)
6135    {
6136  0 jalview.bin.Console
6137    .errPrintln("Failed to match annotation colour scheme for "
6138    + annotationId);
6139  0 return null;
6140    }
6141    // belt-and-braces create a threshold line if the
6142    // colourscheme needs one but the matchedAnnotation doesn't have one
6143  3 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
6144    && matchedAnnotation.getThreshold() == null)
6145    {
6146  1 matchedAnnotation.setThreshold(
6147    new GraphLine(safeFloat(viewAnnColour.getThreshold()),
6148    "Threshold", Color.black));
6149    }
6150   
6151  3 AnnotationColourGradient cs = null;
6152  3 if (viewAnnColour.getColourScheme().equals("None"))
6153    {
6154  3 cs = new AnnotationColourGradient(matchedAnnotation,
6155    new Color(safeInt(viewAnnColour.getMinColour())),
6156    new Color(safeInt(viewAnnColour.getMaxColour())),
6157    safeInt(viewAnnColour.getAboveThreshold()));
6158    }
6159  0 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
6160    {
6161  0 cs = new AnnotationColourGradient(matchedAnnotation,
6162    getUserColourScheme(model, viewAnnColour.getColourScheme()),
6163    safeInt(viewAnnColour.getAboveThreshold()));
6164    }
6165    else
6166    {
6167  0 cs = new AnnotationColourGradient(matchedAnnotation,
6168    ColourSchemeProperty.getColourScheme(af.getViewport(), al,
6169    viewAnnColour.getColourScheme()),
6170    safeInt(viewAnnColour.getAboveThreshold()));
6171    }
6172   
6173  3 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
6174  3 boolean useOriginalColours = safeBoolean(
6175    viewAnnColour.isPredefinedColours());
6176  3 cs.setSeqAssociated(perSequenceOnly);
6177  3 cs.setPredefinedColours(useOriginalColours);
6178   
6179  3 if (propagateAnnColour && al.getGroups() != null)
6180    {
6181    // Also use these settings for all the groups
6182  0 for (int g = 0; g < al.getGroups().size(); g++)
6183    {
6184  0 SequenceGroup sg = al.getGroups().get(g);
6185  0 if (sg.getGroupColourScheme() == null)
6186    {
6187  0 continue;
6188    }
6189   
6190  0 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
6191    matchedAnnotation, sg.getColourScheme(),
6192    safeInt(viewAnnColour.getAboveThreshold()));
6193  0 sg.setColourScheme(groupScheme);
6194  0 groupScheme.setSeqAssociated(perSequenceOnly);
6195  0 groupScheme.setPredefinedColours(useOriginalColours);
6196    }
6197    }
6198  3 return cs;
6199    }
6200   
 
6201  102 toggle private void reorderAutoannotation(AlignFrame af, AlignmentI al,
6202    List<JvAnnotRow> autoAlan)
6203    {
6204    // copy over visualization settings for autocalculated annotation in the
6205    // view
6206  102 if (al.getAlignmentAnnotation() != null)
6207    {
6208    /**
6209    * Kludge for magic autoannotation names (see JAL-811)
6210    */
6211  102 String[] magicNames = new String[] { "Consensus", "Quality",
6212    "Conservation", "cDNA Consensus" };
6213  102 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
6214  102 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
6215  102 for (String nm : magicNames)
6216    {
6217  408 visan.put(nm, nullAnnot);
6218    }
6219  102 for (JvAnnotRow auan : autoAlan)
6220    {
6221  379 visan.put(auan.template.label
6222  379 + (auan.template.getCalcId() == null ? ""
6223    : "\t" + auan.template.getCalcId()),
6224    auan);
6225    }
6226  102 int hSize = al.getAlignmentAnnotation().length;
6227  102 List<JvAnnotRow> reorder = new ArrayList<>();
6228    // work through any autoCalculated annotation already on the view
6229    // removing it if it should be placed in a different location on the
6230    // annotation panel.
6231  102 List<String> remains = new ArrayList<>(visan.keySet());
6232  1395 for (int h = 0; h < hSize; h++)
6233    {
6234  1293 jalview.datamodel.AlignmentAnnotation jalan = al
6235    .getAlignmentAnnotation()[h];
6236  1293 if (jalan.autoCalculated)
6237    {
6238  427 String k;
6239  427 JvAnnotRow valan = visan.get(k = jalan.label);
6240  427 if (jalan.getCalcId() != null)
6241    {
6242  403 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
6243    }
6244   
6245  427 if (valan != null)
6246    {
6247    // delete the auto calculated row from the alignment
6248  285 al.deleteAnnotation(jalan, false);
6249  285 remains.remove(k);
6250  285 hSize--;
6251  285 h--;
6252  285 if (valan != nullAnnot)
6253    {
6254  285 if (jalan != valan.template)
6255    {
6256    // newly created autoannotation row instance
6257    // so keep a reference to the visible annotation row
6258    // and copy over all relevant attributes
6259  261 if (valan.template.graphHeight >= 0)
6260   
6261    {
6262  261 jalan.graphHeight = valan.template.graphHeight;
6263    }
6264  261 jalan.visible = valan.template.visible;
6265    }
6266  285 reorder.add(new JvAnnotRow(valan.order, jalan));
6267    }
6268    }
6269    }
6270    }
6271    // Add any (possibly stale) autocalculated rows that were not appended to
6272    // the view during construction
6273  102 for (String other : remains)
6274    {
6275  430 JvAnnotRow othera = visan.get(other);
6276  430 if (othera != nullAnnot && othera.template.getCalcId() != null
6277    && othera.template.getCalcId().length() > 0)
6278    {
6279  0 reorder.add(othera);
6280    }
6281    }
6282    // now put the automatic annotation in its correct place
6283  102 int s = 0, srt[] = new int[reorder.size()];
6284  102 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
6285  102 for (JvAnnotRow jvar : reorder)
6286    {
6287  285 rws[s] = jvar;
6288  285 srt[s++] = jvar.order;
6289    }
6290  102 reorder.clear();
6291  102 jalview.util.QuickSort.sort(srt, rws);
6292    // and re-insert the annotation at its correct position
6293  102 for (JvAnnotRow jvar : rws)
6294    {
6295  285 al.addAnnotation(jvar.template, jvar.order);
6296    }
6297  102 af.alignPanel.adjustAnnotationHeight();
6298    }
6299    }
6300   
6301    Hashtable skipList = null;
6302   
6303    /**
6304    * TODO remove this method
6305    *
6306    * @param view
6307    * @return AlignFrame bound to sequenceSetId from view, if one exists. private
6308    * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
6309    * throw new Error("Implementation Error. No skipList defined for this
6310    * Jalview2XML instance."); } return (AlignFrame)
6311    * skipList.get(view.getSequenceSetId()); }
6312    */
6313   
6314    /**
6315    * Check if the Jalview view contained in object should be skipped or not.
6316    *
6317    * @param object
6318    * @return true if view's sequenceSetId is a key in skipList
6319    */
 
6320  0 toggle private boolean skipViewport(JalviewModel object)
6321    {
6322  0 if (skipList == null)
6323    {
6324  0 return false;
6325    }
6326  0 String id = object.getViewport().get(0).getSequenceSetId();
6327  0 if (skipList.containsKey(id))
6328    {
6329  0 Console.debug("Skipping seuqence set id " + id);
6330  0 return true;
6331    }
6332  0 return false;
6333    }
6334   
 
6335  0 toggle protected void addToSkipList(AlignFrame af)
6336    {
6337  0 if (skipList == null)
6338    {
6339  0 skipList = new Hashtable();
6340    }
6341  0 skipList.put(af.getViewport().getSequenceSetId(), af);
6342    }
6343   
 
6344  0 toggle protected void clearSkipList()
6345    {
6346  0 if (skipList != null)
6347    {
6348  0 skipList.clear();
6349  0 skipList = null;
6350    }
6351    }
6352   
 
6353  110 toggle private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
6354    boolean ignoreUnrefed, String uniqueSeqSetId)
6355    {
6356  110 jalview.datamodel.AlignmentI ds = getDatasetFor(
6357    vamsasSet.getDatasetId());
6358  110 AlignmentI xtant_ds = ds;
6359  110 if (xtant_ds == null)
6360    {
6361    // good chance we are about to create a new dataset, but check if we've
6362    // seen some of the dataset sequence IDs before.
6363    // TODO: skip this check if we are working with project generated by
6364    // version 2.11 or later
6365  51 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
6366  51 if (xtant_ds != null)
6367    {
6368  2 ds = xtant_ds;
6369  2 addDatasetRef(vamsasSet.getDatasetId(), ds);
6370    }
6371    }
6372  110 Vector<SequenceI> dseqs = null;
6373  110 if (!ignoreUnrefed)
6374    {
6375    // recovering an alignment View
6376  72 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
6377  72 if (seqSetDS != null)
6378    {
6379  21 if (ds != null && ds != seqSetDS)
6380    {
6381  0 Console.warn(
6382    "JAL-3171 regression: Overwriting a dataset reference for an alignment"
6383    + " - CDS/Protein crossreference data may be lost");
6384  0 if (xtant_ds != null)
6385    {
6386    // This can only happen if the unique sequence set ID was bound to a
6387    // dataset that did not contain any of the sequences in the view
6388    // currently being restored.
6389  0 Console.warn(
6390    "JAL-3171 SERIOUS! TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed.");
6391    }
6392    }
6393  21 ds = seqSetDS;
6394  21 addDatasetRef(vamsasSet.getDatasetId(), ds);
6395    }
6396    }
6397  110 if (ds == null)
6398    {
6399    // try even harder to restore dataset
6400  37 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
6401    // create a list of new dataset sequences
6402  37 dseqs = new Vector<>();
6403    }
6404  23193 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
6405    {
6406  23083 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
6407  23083 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
6408    }
6409    // create a new dataset
6410  110 if (ds == null)
6411    {
6412  37 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
6413  37 dseqs.copyInto(dsseqs);
6414  37 ds = new jalview.datamodel.Alignment(dsseqs);
6415    // Console.debug("Jalview2XML Created new dataset " +
6416    // vamsasSet.getDatasetId()
6417    // + " for alignment " + System.identityHashCode(al));
6418  37 addDatasetRef(vamsasSet.getDatasetId(), ds);
6419    }
6420    // set the dataset for the newly imported alignment.
6421  110 if (al.getDataset() == null && !ignoreUnrefed)
6422    {
6423  72 al.setDataset(ds);
6424    // register dataset for the alignment's uniqueSeqSetId for legacy projects
6425  72 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
6426    }
6427  110 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
6428    }
6429   
6430    /**
6431    * XML dataset sequence ID to materialised dataset reference
6432    */
6433    HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
6434   
6435    /**
6436    * @return the first materialised dataset reference containing a dataset
6437    * sequence referenced in the given view
6438    * @param list
6439    * - sequences from the view
6440    */
 
6441  88 toggle AlignmentI checkIfHasDataset(List<Sequence> list)
6442    {
6443  88 for (Sequence restoredSeq : list)
6444    {
6445  830 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
6446  830 if (datasetFor != null)
6447    {
6448  2 return datasetFor;
6449    }
6450    }
6451  86 return null;
6452    }
6453   
6454    /**
6455    * Register ds as the containing dataset for the dataset sequences referenced
6456    * by sequences in list
6457    *
6458    * @param list
6459    * - sequences in a view
6460    * @param ds
6461    */
 
6462  110 toggle void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
6463    {
6464  110 for (Sequence restoredSeq : list)
6465    {
6466  23083 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
6467  23083 if (prevDS != null && prevDS != ds)
6468    {
6469  0 Console.warn("Dataset sequence appears in many datasets: "
6470    + restoredSeq.getDsseqid());
6471    // TODO: try to merge!
6472    }
6473    }
6474    }
6475   
6476    /**
6477    *
6478    * @param vamsasSeq
6479    * sequence definition to create/merge dataset sequence for
6480    * @param ds
6481    * dataset alignment
6482    * @param dseqs
6483    * vector to add new dataset sequence to
6484    * @param ignoreUnrefed
6485    * - when true, don't create new sequences from vamsasSeq if it's id
6486    * doesn't already have an asssociated Jalview sequence.
6487    * @param vseqpos
6488    * - used to reorder the sequence in the alignment according to the
6489    * vamsasSeq array ordering, to preserve ordering of dataset
6490    */
 
6491  23083 toggle private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
6492    AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
6493    int vseqpos)
6494    {
6495    // JBP TODO: Check this is called for AlCodonFrames to support recovery of
6496    // xRef Codon Maps
6497  23083 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
6498  23083 boolean reorder = false;
6499  23083 SequenceI dsq = null;
6500  23083 if (sq != null && sq.getDatasetSequence() != null)
6501    {
6502  152 dsq = sq.getDatasetSequence();
6503    }
6504    else
6505    {
6506  22931 reorder = true;
6507    }
6508  23083 if (sq == null && ignoreUnrefed)
6509    {
6510  0 return;
6511    }
6512  23083 String sqid = vamsasSeq.getDsseqid();
6513  23083 if (dsq == null)
6514    {
6515    // need to create or add a new dataset sequence reference to this sequence
6516  22931 if (sqid != null)
6517    {
6518  22931 dsq = seqRefIds.get(sqid);
6519    }
6520    // check again
6521  22931 if (dsq == null)
6522    {
6523    // make a new dataset sequence
6524  420 dsq = sq.createDatasetSequence();
6525  420 if (sqid == null)
6526    {
6527    // make up a new dataset reference for this sequence
6528  0 sqid = seqHash(dsq);
6529    }
6530  420 dsq.setVamsasId(uniqueSetSuffix + sqid);
6531  420 seqRefIds.put(sqid, dsq);
6532  420 if (ds == null)
6533    {
6534  413 if (dseqs != null)
6535    {
6536  413 dseqs.addElement(dsq);
6537    }
6538    }
6539    else
6540    {
6541  7 ds.addSequence(dsq);
6542    }
6543    }
6544    else
6545    {
6546  22511 if (sq != dsq)
6547    { // make this dataset sequence sq's dataset sequence
6548  16 sq.setDatasetSequence(dsq);
6549    // and update the current dataset alignment
6550  16 if (ds == null)
6551    {
6552  0 if (dseqs != null)
6553    {
6554  0 if (!dseqs.contains(dsq))
6555    {
6556  0 dseqs.add(dsq);
6557    }
6558    }
6559    else
6560    {
6561  0 if (ds.findIndex(dsq) < 0)
6562    {
6563  0 ds.addSequence(dsq);
6564    }
6565    }
6566    }
6567    }
6568    }
6569    }
6570    // TODO: refactor this as a merge dataset sequence function
6571    // now check that sq (the dataset sequence) sequence really is the union of
6572    // all references to it
6573    // boolean pre = sq.getStart() < dsq.getStart();
6574    // boolean post = sq.getEnd() > dsq.getEnd();
6575    // if (pre || post)
6576  23083 if (sq != dsq)
6577    {
6578    // StringBuffer sb = new StringBuffer();
6579  588 String newres = jalview.analysis.AlignSeq.extractGaps(
6580    jalview.util.Comparison.GapChars, sq.getSequenceAsString());
6581  588 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
6582    && newres.length() > dsq.getLength())
6583    {
6584    // Update with the longer sequence.
6585  8 synchronized (dsq)
6586    {
6587    /*
6588    * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
6589    * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
6590    * sb.append(newres.substring(newres.length() - sq.getEnd() -
6591    * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
6592    */
6593  8 dsq.setSequence(newres);
6594    }
6595    // TODO: merges will never happen if we 'know' we have the real dataset
6596    // sequence - this should be detected when id==dssid
6597  8 jalview.bin.Console.errPrintln(
6598    "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
6599    // + (pre ? "prepended" : "") + " "
6600    // + (post ? "appended" : ""));
6601    }
6602    }
6603    else
6604    {
6605    // sequence refs are identical. We may need to update the existing dataset
6606    // alignment with this one, though.
6607  22495 if (ds != null && dseqs == null)
6608    {
6609  22495 int opos = ds.findIndex(dsq);
6610  22495 SequenceI tseq = null;
6611  22495 if (opos != -1 && vseqpos != opos)
6612    {
6613    // remove from old position
6614  65 ds.deleteSequence(dsq);
6615    }
6616  22495 if (vseqpos < ds.getHeight())
6617    {
6618  439 if (vseqpos != opos)
6619    {
6620    // save sequence at destination position
6621  76 tseq = ds.getSequenceAt(vseqpos);
6622  76 ds.replaceSequenceAt(vseqpos, dsq);
6623  76 ds.addSequence(tseq);
6624    }
6625    }
6626    else
6627    {
6628  22056 ds.addSequence(dsq);
6629    }
6630    }
6631    }
6632    }
6633   
6634    /*
6635    * TODO use AlignmentI here and in related methods - needs
6636    * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6637    */
6638    Hashtable<String, AlignmentI> datasetIds = null;
6639   
6640    IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6641   
 
6642  220 toggle private AlignmentI getDatasetFor(String datasetId)
6643    {
6644  220 if (datasetIds == null)
6645    {
6646  36 datasetIds = new Hashtable<>();
6647  36 return null;
6648    }
6649  184 if (datasetIds.containsKey(datasetId))
6650    {
6651  118 return datasetIds.get(datasetId);
6652    }
6653  66 return null;
6654    }
6655   
 
6656  182 toggle private void addDatasetRef(String datasetId, AlignmentI dataset)
6657    {
6658  182 if (datasetIds == null)
6659    {
6660  12 datasetIds = new Hashtable<>();
6661    }
6662  182 datasetIds.put(datasetId, dataset);
6663    }
6664   
6665    /**
6666    * make a new dataset ID for this jalview dataset alignment
6667    *
6668    * @param dataset
6669    * @return
6670    */
 
6671  119 toggle private String getDatasetIdRef(AlignmentI dataset)
6672    {
6673  119 if (dataset.getDataset() != null)
6674    {
6675  0 Console.warn(
6676    "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6677    }
6678  119 String datasetId = makeHashCode(dataset, null);
6679  119 if (datasetId == null)
6680    {
6681    // make a new datasetId and record it
6682  119 if (dataset2Ids == null)
6683    {
6684  39 dataset2Ids = new IdentityHashMap<>();
6685    }
6686    else
6687    {
6688  80 datasetId = dataset2Ids.get(dataset);
6689    }
6690  119 if (datasetId == null)
6691    {
6692  48 datasetId = "ds" + dataset2Ids.size() + 1;
6693  48 dataset2Ids.put(dataset, datasetId);
6694    }
6695    }
6696  119 return datasetId;
6697    }
6698   
6699    /**
6700    * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6701    * constructed as a special subclass GeneLocus.
6702    *
6703    * @param datasetSequence
6704    * @param sequence
6705    */
 
6706  299 toggle private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6707    {
6708  4206 for (int d = 0; d < sequence.getDBRef().size(); d++)
6709    {
6710  3907 DBRef dr = sequence.getDBRef().get(d);
6711  3907 DBRefEntry entry;
6712  3907 if (dr.isLocus())
6713    {
6714  23 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6715    dr.getAccessionId());
6716    }
6717    else
6718    {
6719  3884 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6720    dr.getAccessionId());
6721    }
6722  3907 if (dr.getMapping() != null)
6723    {
6724  46 entry.setMap(addMapping(dr.getMapping()));
6725    }
6726  3907 entry.setCanonical(dr.isCanonical());
6727  3907 datasetSequence.addDBRef(entry);
6728    }
6729    }
6730   
 
6731  46 toggle private jalview.datamodel.Mapping addMapping(Mapping m)
6732    {
6733  46 SequenceI dsto = null;
6734    // Mapping m = dr.getMapping();
6735  46 int fr[] = new int[m.getMapListFrom().size() * 2];
6736  46 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6737  92 for (int _i = 0; from.hasNext(); _i += 2)
6738    {
6739  46 MapListFrom mf = from.next();
6740  46 fr[_i] = mf.getStart();
6741  46 fr[_i + 1] = mf.getEnd();
6742    }
6743  46 int fto[] = new int[m.getMapListTo().size() * 2];
6744  46 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6745  313 for (int _i = 0; to.hasNext(); _i += 2)
6746    {
6747  267 MapListTo mf = to.next();
6748  267 fto[_i] = mf.getStart();
6749  267 fto[_i + 1] = mf.getEnd();
6750    }
6751  46 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6752    fto, m.getMapFromUnit().intValue(),
6753    m.getMapToUnit().intValue());
6754   
6755    /*
6756    * (optional) choice of dseqFor or Sequence
6757    */
6758  46 if (m.getDseqFor() != null)
6759    {
6760  23 String dsfor = m.getDseqFor();
6761  23 if (seqRefIds.containsKey(dsfor))
6762    {
6763    /*
6764    * recover from hash
6765    */
6766  23 jmap.setTo(seqRefIds.get(dsfor));
6767    }
6768    else
6769    {
6770  0 frefedSequence.add(newMappingRef(dsfor, jmap));
6771    }
6772    }
6773  23 else if (m.getSequence() != null)
6774    {
6775    /*
6776    * local sequence definition
6777    */
6778  0 Sequence ms = m.getSequence();
6779  0 SequenceI djs = null;
6780  0 String sqid = ms.getDsseqid();
6781  0 if (sqid != null && sqid.length() > 0)
6782    {
6783    /*
6784    * recover dataset sequence
6785    */
6786  0 djs = seqRefIds.get(sqid);
6787    }
6788    else
6789    {
6790  0 jalview.bin.Console.errPrintln(
6791    "Warning - making up dataset sequence id for DbRef sequence map reference");
6792  0 sqid = ms.toString(); // make up a new hascode for
6793    // undefined dataset sequence hash
6794    // (unlikely to happen)
6795    }
6796   
6797  0 if (djs == null)
6798    {
6799    /**
6800    * make a new dataset sequence and add it to refIds hash
6801    */
6802  0 djs = new jalview.datamodel.Sequence(ms.getName(),
6803    ms.getSequence());
6804  0 djs.setStart(jmap.getMap().getToLowest());
6805  0 djs.setEnd(jmap.getMap().getToHighest());
6806  0 djs.setVamsasId(uniqueSetSuffix + sqid);
6807  0 jmap.setTo(djs);
6808  0 incompleteSeqs.put(sqid, djs);
6809  0 seqRefIds.put(sqid, djs);
6810   
6811    }
6812  0 Console.debug("about to recurse on addDBRefs.");
6813  0 addDBRefs(djs, ms);
6814   
6815    }
6816   
6817  46 return jmap;
6818    }
6819   
6820    /**
6821    * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6822    * view as XML (but not to file), and then reloading it
6823    *
6824    * @param ap
6825    * @return
6826    */
 
6827  12 toggle public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6828    {
6829  12 initSeqRefs();
6830  12 JalviewModel jm = saveState(ap, null, null, null);
6831   
6832  12 addDatasetRef(
6833    jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6834    ap.getAlignment().getDataset());
6835   
6836  12 uniqueSetSuffix = "";
6837    // jm.getJalviewModelSequence().getViewport(0).setId(null);
6838  12 jm.getViewport().get(0).setId(null);
6839    // we don't overwrite the view we just copied
6840   
6841  12 if (this.frefedSequence == null)
6842    {
6843  0 frefedSequence = new Vector<>();
6844    }
6845   
6846  12 viewportsAdded.clear();
6847   
6848  12 AlignFrame af = loadFromObject(jm, null, null, false, null);
6849  12 af.getAlignPanels().clear();
6850  12 af.closeMenuItem_actionPerformed(true);
6851  12 af.alignPanel.setHoldRepaint(false);
6852  12 this.jarFile = null;
6853   
6854    /*
6855    * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6856    * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6857    * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6858    * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6859    * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6860    */
6861   
6862  12 return af.alignPanel;
6863    }
6864   
6865    private Hashtable jvids2vobj;
6866   
6867    /**
6868    * set the object to ID mapping tables used to write/recover objects and XML
6869    * ID strings for the jalview project. If external tables are provided then
6870    * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6871    * object goes out of scope. - also populates the datasetIds hashtable with
6872    * alignment objects containing dataset sequences
6873    *
6874    * @param vobj2jv
6875    * Map from ID strings to jalview datamodel
6876    * @param jv2vobj
6877    * Map from jalview datamodel to ID strings
6878    *
6879    *
6880    */
 
6881  0 toggle public void setObjectMappingTables(Hashtable vobj2jv,
6882    IdentityHashMap jv2vobj)
6883    {
6884  0 this.jv2vobj = jv2vobj;
6885  0 this.vobj2jv = vobj2jv;
6886  0 Iterator ds = jv2vobj.keySet().iterator();
6887  0 String id;
6888  0 while (ds.hasNext())
6889    {
6890  0 Object jvobj = ds.next();
6891  0 id = jv2vobj.get(jvobj).toString();
6892  0 if (jvobj instanceof jalview.datamodel.Alignment)
6893    {
6894  0 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6895    {
6896  0 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6897    }
6898    }
6899  0 else if (jvobj instanceof jalview.datamodel.Sequence)
6900    {
6901    // register sequence object so the XML parser can recover it.
6902  0 if (seqRefIds == null)
6903    {
6904  0 seqRefIds = new HashMap<>();
6905    }
6906  0 if (seqsToIds == null)
6907    {
6908  0 seqsToIds = new IdentityHashMap<>();
6909    }
6910  0 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6911  0 seqsToIds.put((SequenceI) jvobj, id);
6912    }
6913  0 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6914    {
6915  0 String anid;
6916  0 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6917  0 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6918  0 if (jvann.annotationId == null)
6919    {
6920  0 jvann.annotationId = anid;
6921    }
6922  0 if (!jvann.annotationId.equals(anid))
6923    {
6924    // TODO verify that this is the correct behaviour
6925  0 Console.warn("Overriding Annotation ID for " + anid
6926    + " from different id : " + jvann.annotationId);
6927  0 jvann.annotationId = anid;
6928    }
6929    }
6930  0 else if (jvobj instanceof String)
6931    {
6932  0 if (jvids2vobj == null)
6933    {
6934  0 jvids2vobj = new Hashtable();
6935  0 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6936    }
6937    }
6938    else
6939    {
6940  0 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6941    }
6942    }
6943    }
6944   
6945    /**
6946    * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6947    * objects created from the project archive. If string is null (default for
6948    * construction) then suffix will be set automatically.
6949    *
6950    * @param string
6951    */
 
6952  0 toggle public void setUniqueSetSuffix(String string)
6953    {
6954  0 uniqueSetSuffix = string;
6955   
6956    }
6957   
6958    /**
6959    * uses skipList2 as the skipList for skipping views on sequence sets
6960    * associated with keys in the skipList
6961    *
6962    * @param skipList2
6963    */
 
6964  0 toggle public void setSkipList(Hashtable skipList2)
6965    {
6966  0 skipList = skipList2;
6967    }
6968   
6969    /**
6970    * Reads the jar entry of given name and returns its contents, or null if the
6971    * entry is not found.
6972    *
6973    * @param jprovider
6974    * @param jarEntryName
6975    * @return
6976    */
 
6977  2 toggle protected String readJarEntry(jarInputStreamProvider jprovider,
6978    String jarEntryName)
6979    {
6980  2 String result = null;
6981  2 BufferedReader in = null;
6982   
6983  2 try
6984    {
6985    /*
6986    * Reopen the jar input stream and traverse its entries to find a matching
6987    * name
6988    */
6989  2 JarInputStream jin = jprovider.getJarInputStream();
6990  2 JarEntry entry = null;
6991  2 do
6992    {
6993  2 entry = jin.getNextJarEntry();
6994  2 } while (entry != null && !entry.getName().equals(jarEntryName));
6995   
6996  2 if (entry != null)
6997    {
6998  2 StringBuilder out = new StringBuilder(256);
6999  2 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
7000  2 String data;
7001   
7002  ? while ((data = in.readLine()) != null)
7003    {
7004  674 out.append(data);
7005    }
7006  2 result = out.toString();
7007    }
7008    else
7009    {
7010  0 Console.warn(
7011    "Couldn't find entry in Jalview Jar for " + jarEntryName);
7012    }
7013    } catch (Exception ex)
7014    {
7015  0 ex.printStackTrace();
7016    } finally
7017    {
7018  2 if (in != null)
7019    {
7020  2 try
7021    {
7022  2 in.close();
7023    } catch (IOException e)
7024    {
7025    // ignore
7026    }
7027    }
7028    }
7029   
7030  2 return result;
7031    }
7032   
7033    /**
7034    * Returns an incrementing counter (0, 1, 2...)
7035    *
7036    * @return
7037    */
 
7038  2 toggle private synchronized int nextCounter()
7039    {
7040  2 return counter++;
7041    }
7042   
7043    /**
7044    * Loads any saved PCA viewers
7045    *
7046    * @param jms
7047    * @param ap
7048    */
 
7049  2 toggle protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
7050    {
7051  2 try
7052    {
7053  2 List<PcaViewer> pcaviewers = model.getPcaViewer();
7054  2 for (PcaViewer viewer : pcaviewers)
7055    {
7056  2 if (isPasimap(viewer))
7057    {
7058  0 continue;
7059    }
7060  2 String modelName = viewer.getScoreModelName();
7061  2 SimilarityParamsI params = new SimilarityParams(
7062    viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
7063    viewer.isIncludeGaps(),
7064    viewer.isDenominateByShortestLength());
7065   
7066    /*
7067    * create the panel (without computing the PCA)
7068    */
7069  2 PCAPanel panel = new PCAPanel(ap, modelName, params);
7070   
7071  2 panel.setTitle(viewer.getTitle());
7072  2 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
7073    viewer.getWidth(), viewer.getHeight()));
7074   
7075  2 boolean showLabels = viewer.isShowLabels();
7076  2 panel.setShowLabels(showLabels);
7077  2 panel.getRotatableCanvas().setShowLabels(showLabels);
7078  2 panel.getRotatableCanvas()
7079    .setBgColour(new Color(viewer.getBgColour()));
7080  2 panel.getRotatableCanvas()
7081    .setApplyToAllViews(viewer.isLinkToAllViews());
7082   
7083    /*
7084    * load PCA output data
7085    */
7086  2 ScoreModelI scoreModel = ScoreModels.getInstance()
7087    .getScoreModel(modelName, ap);
7088  2 PCA pca = new PCA(null, scoreModel, params);
7089  2 PcaDataType pcaData = viewer.getPcaData();
7090   
7091  2 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
7092  2 pca.setPairwiseScores(pairwise);
7093   
7094  2 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
7095  2 pca.setTridiagonal(triDiag);
7096   
7097  2 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
7098  2 pca.setEigenmatrix(result);
7099   
7100  2 panel.getPcaModel().setPCA(pca);
7101   
7102    /*
7103    * we haven't saved the input data! (JAL-2647 to do)
7104    */
7105  2 panel.setInputData(null);
7106   
7107    /*
7108    * add the sequence points for the PCA display
7109    */
7110  2 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
7111  2 for (SequencePoint sp : viewer.getSequencePoint())
7112    {
7113  37 String seqId = sp.getSequenceRef();
7114  37 SequenceI seq = seqRefIds.get(seqId);
7115  37 if (seq == null)
7116    {
7117  0 throw new IllegalStateException(
7118    "Unmatched seqref for PCA: " + seqId);
7119    }
7120  37 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
7121  37 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
7122    seq, pt);
7123  37 String annotId = sp.getAnnotationId();
7124  37 if ( annotId != null && annotationIds != null)
7125    {
7126  16 AlignmentAnnotation annot = annotationIds.get(annotId);
7127  16 if (annot != null)
7128    {
7129  16 seqPoint.setAlignmentAnnotation(annot);
7130    }
7131    }
7132  37 seqPoint.setLabel(sp.getSeqPointLabel());
7133  37 seqPoint.setAnnotationDetails(sp.getSeqPointAnnotDet());
7134   
7135  37 seqPoints.add(seqPoint);
7136    }
7137  2 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
7138   
7139    /*
7140    * set min-max ranges and scale after setPoints (which recomputes them)
7141    */
7142  2 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
7143  2 SeqPointMin spMin = viewer.getSeqPointMin();
7144  2 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
7145    spMin.getZPos() };
7146  2 SeqPointMax spMax = viewer.getSeqPointMax();
7147  2 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
7148    spMax.getZPos() };
7149  2 panel.getRotatableCanvas().setSeqMinMax(min, max);
7150   
7151    // todo: hold points list in PCAModel only
7152  2 panel.getPcaModel().setSequencePoints(seqPoints);
7153   
7154  2 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
7155  2 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
7156  2 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
7157   
7158    // is this duplication needed?
7159  2 panel.setTop(seqPoints.size() - 1);
7160  2 panel.getPcaModel().setTop(seqPoints.size() - 1);
7161   
7162    /*
7163    * add the axes' end points for the display
7164    */
7165  8 for (int i = 0; i < 3; i++)
7166    {
7167  6 Axis axis = viewer.getAxis().get(i);
7168  6 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
7169    axis.getXPos(), axis.getYPos(), axis.getZPos());
7170    }
7171   
7172  2 Dimension dim = Platform.getDimIfEmbedded(panel, 475, 450);
7173  2 Desktop.addInternalFrame(panel, MessageManager
7174    .formatMessage("label.calc_title", "PCA", modelName),
7175    dim.width, dim.height);
7176    }
7177    } catch (Exception ex)
7178    {
7179  0 Console.error("Error loading PCA: " + ex.toString());
7180    }
7181    }
7182   
 
7183  4 toggle private boolean isPasimap(PcaViewer viewer)
7184    {
7185  4 return viewer.getTitle().toLowerCase(Locale.ROOT).startsWith("pasimap");
7186    }
7187   
7188    /**
7189    * Loads any saved PaSiMAp viewers using the function from PCA
7190    *
7191    * @param jms
7192    * @param ap
7193    */
 
7194  2 toggle protected void loadPaSiMapViewers(JalviewModel model, AlignmentPanel ap)
7195    {
7196  2 try
7197    {
7198  2 List<PcaViewer> pcaviewers = model.getPcaViewer();
7199  2 for (PcaViewer viewer : pcaviewers)
7200    {
7201  2 if (!isPasimap(viewer))
7202    {
7203  2 continue;
7204    }
7205  0 String modelName = viewer.getScoreModelName();
7206    /*
7207    SimilarityParamsI params = new SimilarityParams(
7208    viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
7209    viewer.isIncludeGaps(),
7210    viewer.isDenominateByShortestLength());
7211    */
7212   
7213    /*
7214    * create the panel (without computing the PaSiMAp)
7215    */
7216  0 PaSiMapPanel panel = new PaSiMapPanel(ap, modelName);
7217   
7218  0 panel.setTitle(viewer.getTitle());
7219  0 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
7220    viewer.getWidth(), viewer.getHeight()));
7221   
7222  0 boolean showLabels = viewer.isShowLabels();
7223  0 panel.setShowLabels(showLabels);
7224  0 panel.getRotatableCanvas().setShowLabels(showLabels);
7225  0 panel.getRotatableCanvas()
7226    .setBgColour(new Color(viewer.getBgColour()));
7227  0 panel.getRotatableCanvas()
7228    .setApplyToAllViews(viewer.isLinkToAllViews());
7229   
7230    /*
7231    * load PaSiMap output data
7232    */
7233  0 ScoreModelI scoreModel = ScoreModels.getInstance()
7234    .getScoreModel(modelName, ap);
7235  0 PaSiMap pasimap = new PaSiMap(null, scoreModel, null);
7236  0 PcaDataType pasimapData = viewer.getPcaData();
7237   
7238  0 MatrixI pairwise = loadDoubleMatrix(
7239    pasimapData.getPairwiseMatrix());
7240  0 pasimap.setPairwiseScores(pairwise);
7241   
7242  0 MatrixI result = loadDoubleMatrix(pasimapData.getEigenMatrix());
7243  0 pasimap.setEigenmatrix(result);
7244   
7245  0 panel.getPasimapModel().setPaSiMap(pasimap);
7246   
7247    /*
7248    * we haven't saved the input data! (JAL-2647 to do)
7249    */
7250  0 panel.setInputData(null);
7251   
7252    /*
7253    * add the sequence points for the PCA display
7254    */
7255  0 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
7256  0 for (SequencePoint sp : viewer.getSequencePoint())
7257    {
7258  0 String seqId = sp.getSequenceRef();
7259  0 SequenceI seq = seqRefIds.get(seqId);
7260  0 if (seq == null)
7261    {
7262  0 throw new IllegalStateException(
7263    "Unmatched seqref for PaSiMap: " + seqId);
7264    }
7265  0 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
7266  0 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
7267    seq, pt);
7268  0 seqPoints.add(seqPoint);
7269    }
7270  0 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
7271   
7272    /*
7273    * set min-max ranges and scale after setPoints (which recomputes them)
7274    */
7275  0 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
7276  0 SeqPointMin spMin = viewer.getSeqPointMin();
7277  0 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
7278    spMin.getZPos() };
7279  0 SeqPointMax spMax = viewer.getSeqPointMax();
7280  0 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
7281    spMax.getZPos() };
7282  0 panel.getRotatableCanvas().setSeqMinMax(min, max);
7283   
7284    // todo: hold points list in PCAModel only
7285  0 panel.getPasimapModel().setSequencePoints(seqPoints);
7286   
7287  0 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
7288  0 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
7289  0 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
7290   
7291    // is this duplication needed?
7292  0 panel.setTop(seqPoints.size() - 1);
7293  0 panel.getPasimapModel().setTop(seqPoints.size() - 1);
7294   
7295    /*
7296    * add the axes' end points for the display
7297    */
7298  0 for (int i = 0; i < 3; i++)
7299    {
7300  0 Axis axis = viewer.getAxis().get(i);
7301  0 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
7302    axis.getXPos(), axis.getYPos(), axis.getZPos());
7303    }
7304   
7305  0 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
7306    "label.calc_title", "PaSiMap", modelName), 475, 450);
7307    }
7308    } catch (Exception ex)
7309    {
7310  0 Console.error("Error loading PaSiMap: " + ex.toString());
7311    }
7312    }
7313   
7314    /**
7315    * Creates a new structure viewer window
7316    *
7317    * @param viewerType
7318    * @param viewerData
7319    * @param af
7320    * @param jprovider
7321    */
 
7322  12 toggle protected void createStructureViewer(ViewerType viewerType,
7323    final Entry<String, StructureViewerModel> viewerData,
7324    AlignFrame af, jarInputStreamProvider jprovider)
7325    {
7326  12 final StructureViewerModel viewerModel = viewerData.getValue();
7327  12 String sessionFilePath = null;
7328   
7329  12 if (viewerType == ViewerType.JMOL)
7330    {
7331  12 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
7332    }
7333    else
7334    {
7335  0 String viewerJarEntryName = getViewerJarEntryName(
7336    viewerModel.getViewId());
7337  0 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
7338    "viewerSession", ".tmp");
7339    }
7340  12 final String sessionPath = sessionFilePath;
7341  12 final String sviewid = viewerData.getKey();
7342    // BH again was invokeAndWait
7343    // try
7344    // {
7345  12 javax.swing.SwingUtilities.invokeLater(new Runnable()
7346    {
 
7347  12 toggle @Override
7348    public void run()
7349    {
7350  12 JalviewStructureDisplayI sview = null;
7351  12 try
7352    {
7353  12 sview = StructureViewer.createView(viewerType, af.alignPanel,
7354    viewerModel, sessionPath, sviewid);
7355  7 addNewStructureViewer(sview);
7356    } catch (OutOfMemoryError ex)
7357    {
7358  0 new OOMWarning("Restoring structure view for " + viewerType,
7359    (OutOfMemoryError) ex.getCause());
7360  0 if (sview != null && sview.isVisible())
7361    {
7362  0 sview.closeViewer(false);
7363  0 sview.setVisible(false);
7364  0 sview.dispose();
7365    }
7366    }
7367    }
7368    });
7369    // } catch (InvocationTargetException | InterruptedException ex)
7370    // {
7371    // Console.warn("Unexpected error when opening " + viewerType
7372    // + " structure viewer", ex);
7373    // }
7374    }
7375   
7376    /**
7377    * Rewrites a Jmol session script, saves it to a temporary file, and returns
7378    * the path of the file. "load file" commands are rewritten to change the
7379    * original PDB file names to those created as the Jalview project is loaded.
7380    *
7381    * @param svattrib
7382    * @param jprovider
7383    * @return
7384    */
 
7385  12 toggle private String rewriteJmolSession(StructureViewerModel svattrib,
7386    jarInputStreamProvider jprovider)
7387    {
7388  12 String state = svattrib.getStateData(); // Jalview < 2.9
7389  12 if (state == null || state.isEmpty()) // Jalview >= 2.9
7390    {
7391  2 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
7392  2 state = readJarEntry(jprovider, jarEntryName);
7393    }
7394    // TODO or simpler? for each key in oldFiles,
7395    // replace key.getPath() in state with oldFiles.get(key).getFilePath()
7396    // (allowing for different path escapings)
7397  12 StringBuilder rewritten = new StringBuilder(state.length());
7398  12 int cp = 0, ncp, ecp;
7399  12 Map<File, StructureData> oldFiles = svattrib.getFileData();
7400  ? while ((ncp = state.indexOf("load ", cp)) > -1)
7401    {
7402  12 do
7403    {
7404    // look for next filename in load statement
7405  12 rewritten.append(state.substring(cp,
7406    ncp = (state.indexOf("\"", ncp + 1) + 1)));
7407  12 String oldfilenam = state.substring(ncp,
7408    ecp = state.indexOf("\"", ncp));
7409    // recover the new mapping data for this old filename
7410    // have to normalize filename - since Jmol and jalview do
7411    // filename translation differently.
7412  12 StructureData filedat = oldFiles.get(new File(oldfilenam));
7413  12 if (filedat == null)
7414    {
7415  0 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
7416  0 filedat = oldFiles.get(new File(reformatedOldFilename));
7417    }
7418  12 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
7419  12 rewritten.append("\"");
7420  12 cp = ecp + 1; // advance beyond last \" and set cursor so we can
7421    // look for next file statement.
7422  ? } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
7423    }
7424  12 if (cp > 0)
7425    {
7426    // just append rest of state
7427  12 rewritten.append(state.substring(cp));
7428    }
7429    else
7430    {
7431  0 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
7432  0 rewritten = new StringBuilder(state);
7433  0 rewritten.append("; load append ");
7434  0 for (File id : oldFiles.keySet())
7435    {
7436    // add pdb files that should be present in the viewer
7437  0 StructureData filedat = oldFiles.get(id);
7438  0 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
7439    }
7440  0 rewritten.append(";");
7441    }
7442   
7443  12 if (rewritten.length() == 0)
7444    {
7445  0 return null;
7446    }
7447  12 final String history = "history = ";
7448  12 int historyIndex = rewritten.indexOf(history);
7449  12 if (historyIndex > -1)
7450    {
7451    /*
7452    * change "history = [true|false];" to "history = [1|0];"
7453    */
7454  0 historyIndex += history.length();
7455  0 String val = rewritten.substring(historyIndex, historyIndex + 5);
7456  0 if (val.startsWith("true"))
7457    {
7458  0 rewritten.replace(historyIndex, historyIndex + 4, "1");
7459    }
7460  0 else if (val.startsWith("false"))
7461    {
7462  0 rewritten.replace(historyIndex, historyIndex + 5, "0");
7463    }
7464    }
7465   
7466  12 try
7467    {
7468  12 File tmp = File.createTempFile("viewerSession", ".tmp");
7469  12 try (OutputStream os = new FileOutputStream(tmp))
7470    {
7471  12 InputStream is = new ByteArrayInputStream(
7472    rewritten.toString().getBytes());
7473  12 copyAll(is, os);
7474  12 return tmp.getAbsolutePath();
7475    }
7476    } catch (IOException e)
7477    {
7478  0 Console.error("Error restoring Jmol session: " + e.toString());
7479    }
7480  0 return null;
7481    }
7482   
7483    /**
7484    * Populates an XML model of the feature colour scheme for one feature type
7485    *
7486    * @param featureType
7487    * @param fcol
7488    * @return
7489    */
 
7490  5 toggle public static Colour marshalColour(String featureType,
7491    FeatureColourI fcol)
7492    {
7493  5 Colour col = new Colour();
7494  5 if (fcol.isSimpleColour())
7495    {
7496  1 col.setRGB(Format.getHexString(fcol.getColour()));
7497    }
7498    else
7499    {
7500  4 col.setRGB(Format.getHexString(fcol.getMaxColour()));
7501  4 col.setMin(fcol.getMin());
7502  4 col.setMax(fcol.getMax());
7503  4 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
7504  4 col.setAutoScale(fcol.isAutoScaled());
7505  4 col.setThreshold(fcol.getThreshold());
7506  4 col.setColourByLabel(fcol.isColourByLabel());
7507  4 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
7508  3 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
7509    : ThresholdType.NONE));
7510  4 if (fcol.isColourByAttribute())
7511    {
7512  2 final String[] attName = fcol.getAttributeName();
7513  2 col.getAttributeName().add(attName[0]);
7514  2 if (attName.length > 1)
7515    {
7516  1 col.getAttributeName().add(attName[1]);
7517    }
7518    }
7519  4 Color noColour = fcol.getNoColour();
7520  4 if (noColour == null)
7521    {
7522  4 col.setNoValueColour(NoValueColour.NONE);
7523    }
7524  0 else if (noColour == fcol.getMaxColour())
7525    {
7526  0 col.setNoValueColour(NoValueColour.MAX);
7527    }
7528    else
7529    {
7530  0 col.setNoValueColour(NoValueColour.MIN);
7531    }
7532    }
7533  5 col.setName(featureType);
7534  5 return col;
7535    }
7536   
7537    /**
7538    * Populates an XML model of the feature filter(s) for one feature type
7539    *
7540    * @param firstMatcher
7541    * the first (or only) match condition)
7542    * @param filter
7543    * remaining match conditions (if any)
7544    * @param and
7545    * if true, conditions are and-ed, else or-ed
7546    */
 
7547  14 toggle public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
7548    FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
7549    boolean and)
7550    {
7551  14 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
7552   
7553  14 if (filters.hasNext())
7554    {
7555    /*
7556    * compound matcher
7557    */
7558  4 CompoundMatcher compound = new CompoundMatcher();
7559  4 compound.setAnd(and);
7560  4 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
7561    firstMatcher, Collections.emptyIterator(), and);
7562    // compound.addMatcherSet(matcher1);
7563  4 compound.getMatcherSet().add(matcher1);
7564  4 FeatureMatcherI nextMatcher = filters.next();
7565  4 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
7566    nextMatcher, filters, and);
7567    // compound.addMatcherSet(matcher2);
7568  4 compound.getMatcherSet().add(matcher2);
7569  4 result.setCompoundMatcher(compound);
7570    }
7571    else
7572    {
7573    /*
7574    * single condition matcher
7575    */
7576    // MatchCondition matcherModel = new MatchCondition();
7577  10 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
7578  10 matcherModel.setCondition(
7579    firstMatcher.getMatcher().getCondition().getStableName());
7580  10 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
7581  10 if (firstMatcher.isByAttribute())
7582    {
7583  4 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
7584    // matcherModel.setAttributeName(firstMatcher.getAttribute());
7585  4 String[] attName = firstMatcher.getAttribute();
7586  4 matcherModel.getAttributeName().add(attName[0]); // attribute
7587  4 if (attName.length > 1)
7588    {
7589  2 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
7590    }
7591    }
7592  6 else if (firstMatcher.isByLabel())
7593    {
7594  2 matcherModel.setBy(FilterBy.BY_LABEL);
7595    }
7596  4 else if (firstMatcher.isByScore())
7597    {
7598  4 matcherModel.setBy(FilterBy.BY_SCORE);
7599    }
7600  10 result.setMatchCondition(matcherModel);
7601    }
7602   
7603  14 return result;
7604    }
7605   
7606    /**
7607    * Loads one XML model of a feature filter to a Jalview object
7608    *
7609    * @param featureType
7610    * @param matcherSetModel
7611    * @return
7612    */
 
7613  6 toggle public static FeatureMatcherSetI parseFilter(String featureType,
7614    jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
7615    {
7616  6 FeatureMatcherSetI result = new FeatureMatcherSet();
7617  6 try
7618    {
7619  6 parseFilterConditions(result, matcherSetModel, true);
7620    } catch (IllegalStateException e)
7621    {
7622    // mixing AND and OR conditions perhaps
7623  0 jalview.bin.Console.errPrintln(
7624    String.format("Error reading filter conditions for '%s': %s",
7625    featureType, e.getMessage()));
7626    // return as much as was parsed up to the error
7627    }
7628   
7629  6 return result;
7630    }
7631   
7632    /**
7633    * Adds feature match conditions to matcherSet as unmarshalled from XML
7634    * (possibly recursively for compound conditions)
7635    *
7636    * @param matcherSet
7637    * @param matcherSetModel
7638    * @param and
7639    * if true, multiple conditions are AND-ed, else they are OR-ed
7640    * @throws IllegalStateException
7641    * if AND and OR conditions are mixed
7642    */
 
7643  14 toggle protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
7644    jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
7645    boolean and)
7646    {
7647  14 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
7648    .getMatchCondition();
7649  14 if (mc != null)
7650    {
7651    /*
7652    * single condition
7653    */
7654  10 FilterBy filterBy = mc.getBy();
7655  10 Condition cond = Condition.fromString(mc.getCondition());
7656  10 String pattern = mc.getValue();
7657  10 FeatureMatcherI matchCondition = null;
7658  10 if (filterBy == FilterBy.BY_LABEL)
7659    {
7660  2 matchCondition = FeatureMatcher.byLabel(cond, pattern);
7661    }
7662  8 else if (filterBy == FilterBy.BY_SCORE)
7663    {
7664  4 matchCondition = FeatureMatcher.byScore(cond, pattern);
7665   
7666    }
7667  4 else if (filterBy == FilterBy.BY_ATTRIBUTE)
7668    {
7669  4 final List<String> attributeName = mc.getAttributeName();
7670  4 String[] attNames = attributeName
7671    .toArray(new String[attributeName.size()]);
7672  4 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
7673    attNames);
7674    }
7675   
7676    /*
7677    * note this throws IllegalStateException if AND-ing to a
7678    * previously OR-ed compound condition, or vice versa
7679    */
7680  10 if (and)
7681    {
7682  6 matcherSet.and(matchCondition);
7683    }
7684    else
7685    {
7686  4 matcherSet.or(matchCondition);
7687    }
7688    }
7689    else
7690    {
7691    /*
7692    * compound condition
7693    */
7694  4 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
7695    .getCompoundMatcher().getMatcherSet();
7696  4 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
7697  4 if (matchers.size() == 2)
7698    {
7699  4 parseFilterConditions(matcherSet, matchers.get(0), anded);
7700  4 parseFilterConditions(matcherSet, matchers.get(1), anded);
7701    }
7702    else
7703    {
7704  0 jalview.bin.Console
7705    .errPrintln("Malformed compound filter condition");
7706    }
7707    }
7708    }
7709   
7710    /**
7711    * Loads one XML model of a feature colour to a Jalview object
7712    *
7713    * @param colourModel
7714    * @return
7715    */
 
7716  5 toggle public static FeatureColourI parseColour(Colour colourModel)
7717    {
7718  5 FeatureColourI colour = null;
7719   
7720  5 if (colourModel.getMax() != null)
7721    {
7722  4 Color mincol = null;
7723  4 Color maxcol = null;
7724  4 Color noValueColour = null;
7725   
7726  4 try
7727    {
7728  4 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
7729  4 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7730    } catch (Exception e)
7731    {
7732  0 Console.warn("Couldn't parse out graduated feature color.", e);
7733    }
7734   
7735  4 NoValueColour noCol = colourModel.getNoValueColour();
7736  4 if (noCol == NoValueColour.MIN)
7737    {
7738  0 noValueColour = mincol;
7739    }
7740  4 else if (noCol == NoValueColour.MAX)
7741    {
7742  0 noValueColour = maxcol;
7743    }
7744   
7745  4 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
7746    safeFloat(colourModel.getMin()),
7747    safeFloat(colourModel.getMax()));
7748  4 final List<String> attributeName = colourModel.getAttributeName();
7749  4 String[] attributes = attributeName
7750    .toArray(new String[attributeName.size()]);
7751  4 if (attributes != null && attributes.length > 0)
7752    {
7753  2 colour.setAttributeName(attributes);
7754    }
7755  4 if (colourModel.isAutoScale() != null)
7756    {
7757  4 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7758    }
7759  4 if (colourModel.isColourByLabel() != null)
7760    {
7761  4 colour.setColourByLabel(
7762    colourModel.isColourByLabel().booleanValue());
7763    }
7764  4 if (colourModel.getThreshold() != null)
7765    {
7766  4 colour.setThreshold(colourModel.getThreshold().floatValue());
7767    }
7768  4 ThresholdType ttyp = colourModel.getThreshType();
7769  4 if (ttyp == ThresholdType.ABOVE)
7770    {
7771  1 colour.setAboveThreshold(true);
7772    }
7773  3 else if (ttyp == ThresholdType.BELOW)
7774    {
7775  1 colour.setBelowThreshold(true);
7776    }
7777    }
7778    else
7779    {
7780  1 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7781  1 colour = new FeatureColour(color);
7782    }
7783   
7784  5 return colour;
7785    }
7786   
 
7787  25 toggle public static void setStateSavedUpToDate(boolean s)
7788    {
7789  25 Console.debug("Setting overall stateSavedUpToDate to " + s);
7790  25 stateSavedUpToDate = s;
7791    }
7792   
 
7793  6 toggle public static boolean stateSavedUpToDate()
7794    {
7795  6 Console.debug("Returning overall stateSavedUpToDate value: "
7796    + stateSavedUpToDate);
7797  6 return stateSavedUpToDate;
7798    }
7799   
 
7800  6 toggle public static boolean allSavedUpToDate()
7801    {
7802  6 if (stateSavedUpToDate()) // nothing happened since last project save
7803  2 return true;
7804   
7805  4 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7806  4 if (frames != null)
7807    {
7808  7 for (int i = 0; i < frames.length; i++)
7809    {
7810  4 if (frames[i] == null)
7811  0 continue;
7812  4 if (!frames[i].getViewport().savedUpToDate())
7813  1 return false; // at least one alignment is not individually saved
7814    }
7815    }
7816  3 return true;
7817    }
7818   
7819    // used for debugging and tests
7820    private static int debugDelaySave = 20;
7821   
 
7822  12 toggle public static void setDebugDelaySave(int n)
7823    {
7824  12 debugDelaySave = n;
7825    }
7826    }