2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import jalview.analysis.Conservation;
28 import jalview.analysis.PCA;
29 import jalview.analysis.scoremodels.ScoreModels;
30 import jalview.analysis.scoremodels.SimilarityParams;
31 import jalview.api.AlignmentViewPanel;
32 import jalview.api.FeatureColourI;
33 import jalview.api.ViewStyleI;
34 import jalview.api.analysis.ScoreModelI;
35 import jalview.api.analysis.SimilarityParamsI;
36 import jalview.api.structures.JalviewStructureDisplayI;
37 import jalview.bin.Cache;
38 import jalview.datamodel.AlignedCodonFrame;
39 import jalview.datamodel.Alignment;
40 import jalview.datamodel.AlignmentAnnotation;
41 import jalview.datamodel.AlignmentI;
42 import jalview.datamodel.DBRefEntry;
43 import jalview.datamodel.GeneLocus;
44 import jalview.datamodel.GraphLine;
45 import jalview.datamodel.HiddenMarkovModel;
46 import jalview.datamodel.PDBEntry;
47 import jalview.datamodel.Point;
48 import jalview.datamodel.RnaViewerModel;
49 import jalview.datamodel.SequenceFeature;
50 import jalview.datamodel.SequenceGroup;
51 import jalview.datamodel.SequenceI;
52 import jalview.datamodel.StructureViewerModel;
53 import jalview.datamodel.StructureViewerModel.StructureData;
54 import jalview.datamodel.features.FeatureMatcher;
55 import jalview.datamodel.features.FeatureMatcherI;
56 import jalview.datamodel.features.FeatureMatcherSet;
57 import jalview.datamodel.features.FeatureMatcherSetI;
58 import jalview.ext.varna.RnaModel;
59 import jalview.gui.AlignFrame;
60 import jalview.gui.AlignViewport;
61 import jalview.gui.AlignmentPanel;
62 import jalview.gui.AppVarna;
63 import jalview.gui.ChimeraViewFrame;
64 import jalview.gui.Desktop;
65 import jalview.gui.FeatureRenderer;
66 import jalview.gui.JvOptionPane;
67 import jalview.gui.OOMWarning;
68 import jalview.gui.PCAPanel;
69 import jalview.gui.PaintRefresher;
70 import jalview.gui.SplitFrame;
71 import jalview.gui.StructureViewer;
72 import jalview.gui.StructureViewer.ViewerType;
73 import jalview.gui.StructureViewerBase;
74 import jalview.gui.TreePanel;
75 import jalview.io.BackupFiles;
76 import jalview.io.DataSourceType;
77 import jalview.io.FileFormat;
78 import jalview.io.HMMFile;
79 import jalview.io.NewickFile;
80 import jalview.math.Matrix;
81 import jalview.math.MatrixI;
82 import jalview.renderer.ResidueShaderI;
83 import jalview.schemes.AnnotationColourGradient;
84 import jalview.schemes.ColourSchemeI;
85 import jalview.schemes.ColourSchemeProperty;
86 import jalview.schemes.FeatureColour;
87 import jalview.schemes.ResidueProperties;
88 import jalview.schemes.UserColourScheme;
89 import jalview.structures.models.AAStructureBindingModel;
90 import jalview.util.Format;
91 import jalview.util.MessageManager;
92 import jalview.util.Platform;
93 import jalview.util.StringUtils;
94 import jalview.util.jarInputStreamProvider;
95 import jalview.util.matcher.Condition;
96 import jalview.viewmodel.AlignmentViewport;
97 import jalview.viewmodel.PCAModel;
98 import jalview.viewmodel.ViewportRanges;
99 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
100 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
101 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
102 import jalview.ws.api.ServiceWithParameters;
103 import jalview.ws.jws2.PreferredServiceRegistry;
104 import jalview.ws.jws2.dm.AAConSettings;
105 import jalview.ws.params.ArgumentI;
106 import jalview.ws.params.AutoCalcSetting;
107 import jalview.ws.params.WsParamSetI;
108 import jalview.xml.binding.jalview.AlcodonFrame;
109 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
110 import jalview.xml.binding.jalview.Annotation;
111 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
112 import jalview.xml.binding.jalview.AnnotationColourScheme;
113 import jalview.xml.binding.jalview.AnnotationElement;
114 import jalview.xml.binding.jalview.DoubleMatrix;
115 import jalview.xml.binding.jalview.DoubleVector;
116 import jalview.xml.binding.jalview.Feature;
117 import jalview.xml.binding.jalview.Feature.OtherData;
118 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
119 import jalview.xml.binding.jalview.FilterBy;
120 import jalview.xml.binding.jalview.JalviewModel;
121 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
122 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
123 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
124 import jalview.xml.binding.jalview.JalviewModel.JGroup;
125 import jalview.xml.binding.jalview.JalviewModel.JSeq;
126 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
127 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
128 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
129 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
130 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
131 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
132 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
133 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
134 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
135 import jalview.xml.binding.jalview.JalviewModel.Tree;
136 import jalview.xml.binding.jalview.JalviewModel.UserColours;
137 import jalview.xml.binding.jalview.JalviewModel.Viewport;
138 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
139 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
140 import jalview.xml.binding.jalview.JalviewUserColours;
141 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
142 import jalview.xml.binding.jalview.MapListType.MapListFrom;
143 import jalview.xml.binding.jalview.MapListType.MapListTo;
144 import jalview.xml.binding.jalview.Mapping;
145 import jalview.xml.binding.jalview.NoValueColour;
146 import jalview.xml.binding.jalview.ObjectFactory;
147 import jalview.xml.binding.jalview.PcaDataType;
148 import jalview.xml.binding.jalview.Pdbentry.Property;
149 import jalview.xml.binding.jalview.Sequence;
150 import jalview.xml.binding.jalview.Sequence.DBRef;
151 import jalview.xml.binding.jalview.SequenceSet;
152 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
153 import jalview.xml.binding.jalview.ThresholdType;
154 import jalview.xml.binding.jalview.VAMSAS;
156 import java.awt.Color;
157 import java.awt.Dimension;
158 import java.awt.Font;
159 import java.awt.Rectangle;
160 import java.io.BufferedReader;
161 import java.io.ByteArrayInputStream;
162 import java.io.DataInputStream;
163 import java.io.DataOutputStream;
165 import java.io.FileInputStream;
166 import java.io.FileOutputStream;
167 import java.io.IOException;
168 import java.io.InputStream;
169 import java.io.InputStreamReader;
170 import java.io.OutputStreamWriter;
171 import java.io.PrintWriter;
172 import java.math.BigInteger;
173 import java.net.MalformedURLException;
175 import java.util.ArrayList;
176 import java.util.Arrays;
177 import java.util.Collections;
178 import java.util.Enumeration;
179 import java.util.GregorianCalendar;
180 import java.util.HashMap;
181 import java.util.HashSet;
182 import java.util.Hashtable;
183 import java.util.IdentityHashMap;
184 import java.util.Iterator;
185 import java.util.LinkedHashMap;
186 import java.util.List;
187 import java.util.Map;
188 import java.util.Map.Entry;
189 import java.util.Set;
190 import java.util.Vector;
191 import java.util.jar.JarEntry;
192 import java.util.jar.JarInputStream;
193 import java.util.jar.JarOutputStream;
195 import javax.swing.JInternalFrame;
196 import javax.swing.SwingUtilities;
197 import javax.xml.bind.JAXBContext;
198 import javax.xml.bind.JAXBElement;
199 import javax.xml.bind.Marshaller;
200 import javax.xml.datatype.DatatypeConfigurationException;
201 import javax.xml.datatype.DatatypeFactory;
202 import javax.xml.datatype.XMLGregorianCalendar;
203 import javax.xml.stream.XMLInputFactory;
204 import javax.xml.stream.XMLStreamReader;
207 * Write out the current jalview desktop state as a Jalview XML stream.
209 * Note: the vamsas objects referred to here are primitive versions of the
210 * VAMSAS project schema elements - they are not the same and most likely never
214 * @version $Revision: 1.134 $
216 public class Jalview2XML
219 // BH 2018 we add the .jvp binary extension to J2S so that
220 // it will declare that binary when we do the file save from the browser
224 Platform.addJ2SBinaryType(".jvp?");
227 private static final String VIEWER_PREFIX = "viewer_";
229 private static final String RNA_PREFIX = "rna_";
231 private static final String HMMER_PREFIX = "hmmer_";
233 private static final String UTF_8 = "UTF-8";
236 * prefix for recovering datasets for alignments with multiple views where
237 * non-existent dataset IDs were written for some views
239 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
241 // use this with nextCounter() to make unique names for entities
242 private int counter = 0;
245 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
246 * of sequence objects are created.
248 IdentityHashMap<SequenceI, String> seqsToIds = null;
251 * jalview XML Sequence ID to jalview sequence object reference (both dataset
252 * and alignment sequences. Populated as XML reps of sequence objects are
255 Map<String, SequenceI> seqRefIds = null;
257 Map<String, SequenceI> incompleteSeqs = null;
259 List<SeqFref> frefedSequence = null;
261 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
264 * Map of reconstructed AlignFrame objects that appear to have come from
265 * SplitFrame objects (have a dna/protein complement view).
267 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
270 * Map from displayed rna structure models to their saved session state jar
273 private Map<RnaModel, String> rnaSessions = new HashMap<>();
276 * contains last error message (if any) encountered by XML loader.
278 String errorMessage = null;
281 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
282 * exceptions are raised during project XML parsing
284 public boolean attemptversion1parse = false;
287 * JalviewJS only -- to allow read file bytes to be saved in the
288 * created AlignFrame, allowing File | Reload of a project file to work
292 private File jarFile;
295 * A helper method for safely using the value of an optional attribute that
296 * may be null if not present in the XML. Answers the boolean value, or false
302 public static boolean safeBoolean(Boolean b)
304 return b == null ? false : b.booleanValue();
308 * A helper method for safely using the value of an optional attribute that
309 * may be null if not present in the XML. Answers the integer value, or zero
315 public static int safeInt(Integer i)
317 return i == null ? 0 : i.intValue();
321 * A helper method for safely using the value of an optional attribute that
322 * may be null if not present in the XML. Answers the float value, or zero if
328 public static float safeFloat(Float f)
330 return f == null ? 0f : f.floatValue();
334 * create/return unique hash string for sq
337 * @return new or existing unique string for sq
339 String seqHash(SequenceI sq)
341 if (seqsToIds == null)
345 if (seqsToIds.containsKey(sq))
347 return seqsToIds.get(sq);
351 // create sequential key
352 String key = "sq" + (seqsToIds.size() + 1);
353 key = makeHashCode(sq, key); // check we don't have an external reference
355 seqsToIds.put(sq, key);
362 if (seqsToIds == null)
364 seqsToIds = new IdentityHashMap<>();
366 if (seqRefIds == null)
368 seqRefIds = new HashMap<>();
370 if (incompleteSeqs == null)
372 incompleteSeqs = new HashMap<>();
374 if (frefedSequence == null)
376 frefedSequence = new ArrayList<>();
384 public Jalview2XML(boolean raiseGUI)
386 this.raiseGUI = raiseGUI;
390 * base class for resolving forward references to sequences by their ID
395 abstract class SeqFref
401 public SeqFref(String _sref, String type)
407 public String getSref()
412 public SequenceI getSrefSeq()
414 return seqRefIds.get(sref);
417 public boolean isResolvable()
419 return seqRefIds.get(sref) != null;
422 public SequenceI getSrefDatasetSeq()
424 SequenceI sq = seqRefIds.get(sref);
427 while (sq.getDatasetSequence() != null)
429 sq = sq.getDatasetSequence();
436 * @return true if the forward reference was fully resolved
438 abstract boolean resolve();
441 public String toString()
443 return type + " reference to " + sref;
448 * create forward reference for a mapping
454 protected SeqFref newMappingRef(final String sref,
455 final jalview.datamodel.Mapping _jmap)
457 SeqFref fref = new SeqFref(sref, "Mapping")
459 public jalview.datamodel.Mapping jmap = _jmap;
464 SequenceI seq = getSrefDatasetSeq();
476 protected SeqFref newAlcodMapRef(final String sref,
477 final AlignedCodonFrame _cf,
478 final jalview.datamodel.Mapping _jmap)
481 SeqFref fref = new SeqFref(sref, "Codon Frame")
483 AlignedCodonFrame cf = _cf;
485 public jalview.datamodel.Mapping mp = _jmap;
488 public boolean isResolvable()
490 return super.isResolvable() && mp.getTo() != null;
496 SequenceI seq = getSrefDatasetSeq();
501 cf.addMap(seq, mp.getTo(), mp.getMap());
508 protected void resolveFrefedSequences()
510 Iterator<SeqFref> nextFref = frefedSequence.iterator();
511 int toresolve = frefedSequence.size();
512 int unresolved = 0, failedtoresolve = 0;
513 while (nextFref.hasNext())
515 SeqFref ref = nextFref.next();
516 if (ref.isResolvable())
528 } catch (Exception x)
531 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
544 System.err.println("Jalview Project Import: There were " + unresolved
545 + " forward references left unresolved on the stack.");
547 if (failedtoresolve > 0)
549 System.err.println("SERIOUS! " + failedtoresolve
550 + " resolvable forward references failed to resolve.");
552 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
555 "Jalview Project Import: There are " + incompleteSeqs.size()
556 + " sequences which may have incomplete metadata.");
557 if (incompleteSeqs.size() < 10)
559 for (SequenceI s : incompleteSeqs.values())
561 System.err.println(s.toString());
567 "Too many to report. Skipping output of incomplete sequences.");
573 * This maintains a map of viewports, the key being the seqSetId. Important to
574 * set historyItem and redoList for multiple views
576 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
578 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
580 String uniqueSetSuffix = "";
583 * List of pdbfiles added to Jar
585 List<String> pdbfiles = null;
587 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
588 public void saveState(File statefile)
590 FileOutputStream fos = null;
595 fos = new FileOutputStream(statefile);
597 JarOutputStream jout = new JarOutputStream(fos);
601 } catch (Exception e)
603 Cache.log.error("Couln't write Jalview state to " + statefile, e);
604 // TODO: inform user of the problem - they need to know if their data was
606 if (errorMessage == null)
608 errorMessage = "Did't write Jalview Archive to output file '"
609 + statefile + "' - See console error log for details";
613 errorMessage += "(Didn't write Jalview Archive to output file '"
624 } catch (IOException e)
634 * Writes a jalview project archive to the given Jar output stream.
638 public void saveState(JarOutputStream jout)
640 AlignFrame[] frames = Desktop.getAlignFrames();
646 saveAllFrames(Arrays.asList(frames), jout);
650 * core method for storing state for a set of AlignFrames.
653 * - frames involving all data to be exported (including those
654 * contained in splitframes, though not the split frames themselves)
656 * - project output stream
658 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
661 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
664 * ensure cached data is clear before starting
666 // todo tidy up seqRefIds, seqsToIds initialisation / reset
668 splitFrameCandidates.clear();
673 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
674 // //////////////////////////////////////////////////
676 List<String> shortNames = new ArrayList<>();
677 List<String> viewIds = new ArrayList<>();
680 for (int i = frames.size() - 1; i > -1; i--)
682 AlignFrame af = frames.get(i);
683 AlignViewport vp = af.getViewport();
685 if (skipList != null && skipList
686 .containsKey(vp.getSequenceSetId()))
691 String shortName = makeFilename(af, shortNames);
693 AlignmentI alignment = vp.getAlignment();
694 List<? extends AlignmentViewPanel> panels = af.getAlignPanels();
695 int apSize = panels.size();
696 for (int ap = 0; ap < apSize; ap++)
698 AlignmentPanel apanel = (AlignmentPanel) panels.get(ap);
699 String fileName = apSize == 1 ? shortName : ap + shortName;
700 if (!fileName.endsWith(".xml"))
702 fileName = fileName + ".xml";
705 saveState(apanel, fileName, jout, viewIds);
709 // BH moved next bit out of inner loop, not that it really matters.
710 // so we are testing to make sure we actually have an alignment,
712 String dssid = getDatasetIdRef(alignment.getDataset());
713 if (!dsses.containsKey(dssid))
715 // We have not already covered this data by reference from another
717 dsses.put(dssid, af);
722 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
728 } catch (Exception foo)
732 } catch (Exception ex)
734 // TODO: inform user of the problem - they need to know if their data was
736 if (errorMessage == null)
738 errorMessage = "Couldn't write Jalview Archive - see error output for details";
740 ex.printStackTrace();
745 * Generates a distinct file name, based on the title of the AlignFrame, by
746 * appending _n for increasing n until an unused name is generated. The new
747 * name (without its extension) is added to the list.
751 * @return the generated name, with .xml extension
753 protected String makeFilename(AlignFrame af, List<String> namesUsed)
755 String shortName = af.getTitle();
757 if (shortName.indexOf(File.separatorChar) > -1)
759 shortName = shortName
760 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
765 while (namesUsed.contains(shortName))
767 if (shortName.endsWith("_" + (count - 1)))
769 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
772 shortName = shortName.concat("_" + count);
776 namesUsed.add(shortName);
778 if (!shortName.endsWith(".xml"))
780 shortName = shortName + ".xml";
785 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
786 public boolean saveAlignment(AlignFrame af, String jarFile,
791 // create backupfiles object and get new temp filename destination
792 boolean doBackup = BackupFiles.getEnabled();
793 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
794 FileOutputStream fos = new FileOutputStream(doBackup ?
795 backupfiles.getTempFilePath() : jarFile);
797 JarOutputStream jout = new JarOutputStream(fos);
798 List<AlignFrame> frames = new ArrayList<>();
800 // resolve splitframes
801 if (af.getViewport().getCodingComplement() != null)
803 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
809 saveAllFrames(frames, jout);
813 } catch (Exception foo)
817 boolean success = true;
821 backupfiles.setWriteSuccess(success);
822 success = backupfiles.rollBackupsAndRenameTempFile();
826 } catch (Exception ex)
828 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
829 ex.printStackTrace();
835 * Each AlignFrame has a single data set associated with it. Note that none of
836 * these frames are split frames, because Desktop.getAlignFrames() collects
837 * top and bottom separately here.
843 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
844 String fileName, JarOutputStream jout)
847 // Note that in saveAllFrames we have associated each specific dataset to
848 // ONE of its associated frames.
850 for (String dssids : dsses.keySet())
852 AlignFrame _af = dsses.get(dssids);
853 String jfileName = fileName + " Dataset for " + _af.getTitle();
854 if (!jfileName.endsWith(".xml"))
856 jfileName = jfileName + ".xml";
858 saveState(_af.alignPanel, jfileName, true, jout, null);
863 * create a JalviewModel from an alignment view and marshall it to a
867 * panel to create jalview model for
869 * name of alignment panel written to output stream
876 protected JalviewModel saveState(AlignmentPanel ap, String fileName,
877 JarOutputStream jout, List<String> viewIds)
879 return saveState(ap, fileName, false, jout, viewIds);
883 * create a JalviewModel from an alignment view and marshall it to a
887 * panel to create jalview model for
889 * name of alignment panel written to output stream
891 * when true, only write the dataset for the alignment, not the data
892 * associated with the view.
898 protected JalviewModel saveState(AlignmentPanel ap, String fileName,
899 boolean storeDS, JarOutputStream jout, List<String> viewIds)
903 viewIds = new ArrayList<>();
908 List<UserColourScheme> userColours = new ArrayList<>();
910 AlignViewport av = ap.av;
911 ViewportRanges vpRanges = av.getRanges();
913 final ObjectFactory objectFactory = new ObjectFactory();
914 JalviewModel object = objectFactory.createJalviewModel();
915 object.setVamsasModel(new VAMSAS());
917 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
920 GregorianCalendar c = new GregorianCalendar();
921 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
922 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
923 object.setCreationDate(now);
924 } catch (DatatypeConfigurationException e)
926 System.err.println("error writing date: " + e.toString());
929 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
932 * rjal is full height alignment, jal is actual alignment with full metadata
933 * but excludes hidden sequences.
935 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
937 if (av.hasHiddenRows())
939 rjal = jal.getHiddenSequences().getFullAlignment();
942 SequenceSet vamsasSet = new SequenceSet();
944 // JalviewModelSequence jms = new JalviewModelSequence();
946 vamsasSet.setGapChar(jal.getGapCharacter() + "");
948 if (jal.getDataset() != null)
950 // dataset id is the dataset's hashcode
951 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
954 // switch jal and the dataset
955 jal = jal.getDataset();
959 if (jal.getProperties() != null)
961 Enumeration en = jal.getProperties().keys();
962 while (en.hasMoreElements())
964 String key = en.nextElement().toString();
965 SequenceSetProperties ssp = new SequenceSetProperties();
967 ssp.setValue(jal.getProperties().get(key).toString());
968 // vamsasSet.addSequenceSetProperties(ssp);
969 vamsasSet.getSequenceSetProperties().add(ssp);
974 Set<String> calcIdSet = new HashSet<>();
975 // record the set of vamsas sequence XML POJO we create.
976 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
978 for (final SequenceI jds : rjal.getSequences())
980 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
981 : jds.getDatasetSequence();
982 String id = seqHash(jds);
983 if (vamsasSetIds.get(id) == null)
985 if (seqRefIds.get(id) != null && !storeDS)
987 // This happens for two reasons: 1. multiple views are being
989 // 2. the hashCode has collided with another sequence's code. This
991 // HAPPEN! (PF00072.15.stk does this)
992 // JBPNote: Uncomment to debug writing out of files that do not read
993 // back in due to ArrayOutOfBoundExceptions.
994 // System.err.println("vamsasSeq backref: "+id+"");
995 // System.err.println(jds.getName()+"
996 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
997 // System.err.println("Hashcode: "+seqHash(jds));
998 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
999 // System.err.println(rsq.getName()+"
1000 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1001 // System.err.println("Hashcode: "+seqHash(rsq));
1005 vamsasSeq = createVamsasSequence(id, jds);
1006 // vamsasSet.addSequence(vamsasSeq);
1007 vamsasSet.getSequence().add(vamsasSeq);
1008 vamsasSetIds.put(id, vamsasSeq);
1009 seqRefIds.put(id, jds);
1013 jseq.setStart(jds.getStart());
1014 jseq.setEnd(jds.getEnd());
1015 jseq.setColour(av.getSequenceColour(jds).getRGB());
1017 jseq.setId(id); // jseq id should be a string not a number
1020 // Store any sequences this sequence represents
1021 if (av.hasHiddenRows())
1023 // use rjal, contains the full height alignment
1025 av.getAlignment().getHiddenSequences().isHidden(jds));
1027 if (av.isHiddenRepSequence(jds))
1029 jalview.datamodel.SequenceI[] reps = av
1030 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1032 for (int h = 0; h < reps.length; h++)
1036 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1037 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1042 // mark sequence as reference - if it is the reference for this view
1043 if (jal.hasSeqrep())
1045 jseq.setViewreference(jds == jal.getSeqrep());
1049 // TODO: omit sequence features from each alignment view's XML dump if we
1050 // are storing dataset
1051 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1052 for (SequenceFeature sf : sfs)
1054 // Features features = new Features();
1055 Feature features = new Feature();
1057 features.setBegin(sf.getBegin());
1058 features.setEnd(sf.getEnd());
1059 features.setDescription(sf.getDescription());
1060 features.setType(sf.getType());
1061 features.setFeatureGroup(sf.getFeatureGroup());
1062 features.setScore(sf.getScore());
1063 if (sf.links != null)
1065 for (int l = 0; l < sf.links.size(); l++)
1067 OtherData keyValue = new OtherData();
1068 keyValue.setKey("LINK_" + l);
1069 keyValue.setValue(sf.links.elementAt(l).toString());
1070 // features.addOtherData(keyValue);
1071 features.getOtherData().add(keyValue);
1074 if (sf.otherDetails != null)
1077 * save feature attributes, which may be simple strings or
1078 * map valued (have sub-attributes)
1080 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1082 String key = entry.getKey();
1083 Object value = entry.getValue();
1084 if (value instanceof Map<?, ?>)
1086 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1089 OtherData otherData = new OtherData();
1090 otherData.setKey(key);
1091 otherData.setKey2(subAttribute.getKey());
1092 otherData.setValue(subAttribute.getValue().toString());
1093 // features.addOtherData(otherData);
1094 features.getOtherData().add(otherData);
1099 OtherData otherData = new OtherData();
1100 otherData.setKey(key);
1101 otherData.setValue(value.toString());
1102 // features.addOtherData(otherData);
1103 features.getOtherData().add(otherData);
1108 // jseq.addFeatures(features);
1109 jseq.getFeatures().add(features);
1113 * save PDB entries for sequence
1115 if (jdatasq.getAllPDBEntries() != null)
1117 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1118 while (en.hasMoreElements())
1120 Pdbids pdb = new Pdbids();
1121 jalview.datamodel.PDBEntry entry = en.nextElement();
1123 String pdbId = entry.getId();
1125 pdb.setType(entry.getType());
1128 * Store any structure views associated with this sequence. This
1129 * section copes with duplicate entries in the project, so a dataset
1130 * only view *should* be coped with sensibly.
1132 // This must have been loaded, is it still visible?
1133 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1134 String matchedFile = null;
1135 for (int f = frames.length - 1; f > -1; f--)
1137 if (frames[f] instanceof StructureViewerBase)
1139 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1140 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1141 matchedFile, viewFrame);
1143 * Only store each structure viewer's state once in the project
1144 * jar. First time through only (storeDS==false)
1146 String viewId = viewFrame.getViewId();
1147 if (!storeDS && !viewIds.contains(viewId))
1149 viewIds.add(viewId);
1152 String viewerState = viewFrame.getStateInfo();
1153 writeJarEntry(jout, getViewerJarEntryName(viewId),
1154 viewerState.getBytes());
1155 } catch (IOException e)
1158 "Error saving viewer state: " + e.getMessage());
1164 if (matchedFile != null || entry.getFile() != null)
1166 if (entry.getFile() != null)
1169 matchedFile = entry.getFile();
1171 pdb.setFile(matchedFile); // entry.getFile());
1172 if (pdbfiles == null)
1174 pdbfiles = new ArrayList<>();
1177 if (!pdbfiles.contains(pdbId))
1179 pdbfiles.add(pdbId);
1180 copyFileToJar(jout, matchedFile, pdbId);
1184 Enumeration<String> props = entry.getProperties();
1185 if (props.hasMoreElements())
1187 // PdbentryItem item = new PdbentryItem();
1188 while (props.hasMoreElements())
1190 Property prop = new Property();
1191 String key = props.nextElement();
1193 prop.setValue(entry.getProperty(key).toString());
1194 // item.addProperty(prop);
1195 pdb.getProperty().add(prop);
1197 // pdb.addPdbentryItem(item);
1200 // jseq.addPdbids(pdb);
1201 jseq.getPdbids().add(pdb);
1205 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1207 if (jds.hasHMMProfile())
1209 saveHmmerProfile(jout, jseq, jds);
1212 // jms.addJSeq(jseq);
1213 object.getJSeq().add(jseq);
1216 if (!storeDS && av.hasHiddenRows())
1218 jal = av.getAlignment();
1222 if (storeDS && jal.getCodonFrames() != null)
1224 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1225 for (AlignedCodonFrame acf : jac)
1227 AlcodonFrame alc = new AlcodonFrame();
1228 if (acf.getProtMappings() != null
1229 && acf.getProtMappings().length > 0)
1231 boolean hasMap = false;
1232 SequenceI[] dnas = acf.getdnaSeqs();
1233 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1234 for (int m = 0; m < pmaps.length; m++)
1236 AlcodMap alcmap = new AlcodMap();
1237 alcmap.setDnasq(seqHash(dnas[m]));
1239 createVamsasMapping(pmaps[m], dnas[m], null, false));
1240 // alc.addAlcodMap(alcmap);
1241 alc.getAlcodMap().add(alcmap);
1246 // vamsasSet.addAlcodonFrame(alc);
1247 vamsasSet.getAlcodonFrame().add(alc);
1250 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1252 // AlcodonFrame alc = new AlcodonFrame();
1253 // vamsasSet.addAlcodonFrame(alc);
1254 // for (int p = 0; p < acf.aaWidth; p++)
1256 // Alcodon cmap = new Alcodon();
1257 // if (acf.codons[p] != null)
1259 // // Null codons indicate a gapped column in the translated peptide
1261 // cmap.setPos1(acf.codons[p][0]);
1262 // cmap.setPos2(acf.codons[p][1]);
1263 // cmap.setPos3(acf.codons[p][2]);
1265 // alc.addAlcodon(cmap);
1267 // if (acf.getProtMappings() != null
1268 // && acf.getProtMappings().length > 0)
1270 // SequenceI[] dnas = acf.getdnaSeqs();
1271 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1272 // for (int m = 0; m < pmaps.length; m++)
1274 // AlcodMap alcmap = new AlcodMap();
1275 // alcmap.setDnasq(seqHash(dnas[m]));
1276 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1278 // alc.addAlcodMap(alcmap);
1285 // /////////////////////////////////
1286 if (!storeDS && av.getCurrentTree() != null)
1288 // FIND ANY ASSOCIATED TREES
1289 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1290 if (Desktop.getDesktopPane() != null)
1292 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1294 for (int t = 0; t < frames.length; t++)
1296 if (frames[t] instanceof TreePanel)
1298 TreePanel tp = (TreePanel) frames[t];
1300 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1302 JalviewModel.Tree tree = new JalviewModel.Tree();
1303 tree.setTitle(tp.getTitle());
1304 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1305 tree.setNewick(tp.getTree().print());
1306 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1308 tree.setFitToWindow(tp.fitToWindow.getState());
1309 tree.setFontName(tp.getTreeFont().getName());
1310 tree.setFontSize(tp.getTreeFont().getSize());
1311 tree.setFontStyle(tp.getTreeFont().getStyle());
1312 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1314 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1315 tree.setShowDistances(tp.distanceMenu.getState());
1317 tree.setHeight(tp.getHeight());
1318 tree.setWidth(tp.getWidth());
1319 tree.setXpos(tp.getX());
1320 tree.setYpos(tp.getY());
1321 tree.setId(makeHashCode(tp, null));
1322 tree.setLinkToAllViews(
1323 tp.getTreeCanvas().isApplyToAllViews());
1325 // jms.addTree(tree);
1326 object.getTree().add(tree);
1336 if (!storeDS && Desktop.getDesktopPane() != null)
1338 for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames())
1340 if (frame instanceof PCAPanel)
1342 PCAPanel panel = (PCAPanel) frame;
1343 if (panel.getAlignViewport().getAlignment() == jal)
1345 savePCA(panel, object);
1353 * store forward refs from an annotationRow to any groups
1355 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1358 for (SequenceI sq : jal.getSequences())
1360 // Store annotation on dataset sequences only
1361 AlignmentAnnotation[] aa = sq.getAnnotation();
1362 if (aa != null && aa.length > 0)
1364 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1371 if (jal.getAlignmentAnnotation() != null)
1373 // Store the annotation shown on the alignment.
1374 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1375 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1380 if (jal.getGroups() != null)
1382 JGroup[] groups = new JGroup[jal.getGroups().size()];
1384 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1386 JGroup jGroup = new JGroup();
1387 groups[++i] = jGroup;
1389 jGroup.setStart(sg.getStartRes());
1390 jGroup.setEnd(sg.getEndRes());
1391 jGroup.setName(sg.getName());
1392 if (groupRefs.containsKey(sg))
1394 // group has references so set its ID field
1395 jGroup.setId(groupRefs.get(sg));
1397 ColourSchemeI colourScheme = sg.getColourScheme();
1398 if (colourScheme != null)
1400 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1401 if (groupColourScheme.conservationApplied())
1403 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1405 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1408 setUserColourScheme(colourScheme, userColours,
1413 jGroup.setColour(colourScheme.getSchemeName());
1416 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1418 jGroup.setColour("AnnotationColourGradient");
1419 jGroup.setAnnotationColours(constructAnnotationColours(
1420 (jalview.schemes.AnnotationColourGradient) colourScheme,
1421 userColours, object));
1423 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1426 setUserColourScheme(colourScheme, userColours, object));
1430 jGroup.setColour(colourScheme.getSchemeName());
1433 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1436 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1437 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1438 jGroup.setDisplayText(sg.getDisplayText());
1439 jGroup.setColourText(sg.getColourText());
1440 jGroup.setTextCol1(sg.textColour.getRGB());
1441 jGroup.setTextCol2(sg.textColour2.getRGB());
1442 jGroup.setTextColThreshold(sg.thresholdTextColour);
1443 jGroup.setShowUnconserved(sg.getShowNonconserved());
1444 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1445 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1446 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1447 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1448 for (SequenceI seq : sg.getSequences())
1450 // jGroup.addSeq(seqHash(seq));
1451 jGroup.getSeq().add(seqHash(seq));
1455 //jms.setJGroup(groups);
1457 for (JGroup grp : groups)
1459 object.getJGroup().add(grp);
1464 // /////////SAVE VIEWPORT
1465 Viewport view = new Viewport();
1466 view.setTitle(ap.alignFrame.getTitle());
1467 view.setSequenceSetId(
1468 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1469 view.setId(av.getViewId());
1470 if (av.getCodingComplement() != null)
1472 view.setComplementId(av.getCodingComplement().getViewId());
1474 view.setViewName(av.getViewName());
1475 view.setGatheredViews(av.isGatherViewsHere());
1477 Rectangle size = ap.av.getExplodedGeometry();
1478 Rectangle position = size;
1481 size = ap.alignFrame.getBounds();
1482 if (av.getCodingComplement() != null)
1484 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1492 view.setXpos(position.x);
1493 view.setYpos(position.y);
1495 view.setWidth(size.width);
1496 view.setHeight(size.height);
1498 view.setStartRes(vpRanges.getStartRes());
1499 view.setStartSeq(vpRanges.getStartSeq());
1501 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1503 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1504 userColours, object));
1507 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1509 AnnotationColourScheme ac = constructAnnotationColours(
1510 (jalview.schemes.AnnotationColourGradient) av
1511 .getGlobalColourScheme(),
1512 userColours, object);
1514 view.setAnnotationColours(ac);
1515 view.setBgColour("AnnotationColourGradient");
1519 view.setBgColour(ColourSchemeProperty
1520 .getColourName(av.getGlobalColourScheme()));
1523 ResidueShaderI vcs = av.getResidueShading();
1524 ColourSchemeI cs = av.getGlobalColourScheme();
1528 if (vcs.conservationApplied())
1530 view.setConsThreshold(vcs.getConservationInc());
1531 if (cs instanceof jalview.schemes.UserColourScheme)
1533 view.setBgColour(setUserColourScheme(cs, userColours, object));
1536 view.setPidThreshold(vcs.getThreshold());
1539 view.setConservationSelected(av.getConservationSelected());
1540 view.setPidSelected(av.getAbovePIDThreshold());
1541 final Font font = av.getFont();
1542 view.setFontName(font.getName());
1543 view.setFontSize(font.getSize());
1544 view.setFontStyle(font.getStyle());
1545 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1546 view.setRenderGaps(av.isRenderGaps());
1547 view.setShowAnnotation(av.isShowAnnotation());
1548 view.setShowBoxes(av.getShowBoxes());
1549 view.setShowColourText(av.getColourText());
1550 view.setShowFullId(av.getShowJVSuffix());
1551 view.setRightAlignIds(av.isRightAlignIds());
1552 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1553 view.setShowText(av.getShowText());
1554 view.setShowUnconserved(av.getShowUnconserved());
1555 view.setWrapAlignment(av.getWrapAlignment());
1556 view.setTextCol1(av.getTextColour().getRGB());
1557 view.setTextCol2(av.getTextColour2().getRGB());
1558 view.setTextColThreshold(av.getThresholdTextColour());
1559 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1560 view.setShowSequenceLogo(av.isShowSequenceLogo());
1561 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1562 view.setShowGroupConsensus(av.isShowGroupConsensus());
1563 view.setShowGroupConservation(av.isShowGroupConservation());
1564 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1565 view.setShowDbRefTooltip(av.isShowDBRefs());
1566 view.setFollowHighlight(av.isFollowHighlight());
1567 view.setFollowSelection(av.followSelection);
1568 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1569 view.setShowComplementFeatures(av.isShowComplementFeatures());
1570 view.setShowComplementFeaturesOnTop(
1571 av.isShowComplementFeaturesOnTop());
1572 if (av.getFeaturesDisplayed() != null)
1574 FeatureSettings fs = new FeatureSettings();
1576 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1577 .getFeatureRenderer();
1578 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1580 Vector<String> settingsAdded = new Vector<>();
1581 if (renderOrder != null)
1583 for (String featureType : renderOrder)
1585 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1586 setting.setType(featureType);
1589 * save any filter for the feature type
1591 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1592 if (filter != null) {
1593 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1594 FeatureMatcherI firstFilter = filters.next();
1595 setting.setMatcherSet(Jalview2XML.marshalFilter(
1596 firstFilter, filters, filter.isAnded()));
1600 * save colour scheme for the feature type
1602 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1603 if (!fcol.isSimpleColour())
1605 setting.setColour(fcol.getMaxColour().getRGB());
1606 setting.setMincolour(fcol.getMinColour().getRGB());
1607 setting.setMin(fcol.getMin());
1608 setting.setMax(fcol.getMax());
1609 setting.setColourByLabel(fcol.isColourByLabel());
1610 if (fcol.isColourByAttribute())
1612 String[] attName = fcol.getAttributeName();
1613 setting.getAttributeName().add(attName[0]);
1614 if (attName.length > 1)
1616 setting.getAttributeName().add(attName[1]);
1619 setting.setAutoScale(fcol.isAutoScaled());
1620 setting.setThreshold(fcol.getThreshold());
1621 Color noColour = fcol.getNoColour();
1622 if (noColour == null)
1624 setting.setNoValueColour(NoValueColour.NONE);
1626 else if (noColour.equals(fcol.getMaxColour()))
1628 setting.setNoValueColour(NoValueColour.MAX);
1632 setting.setNoValueColour(NoValueColour.MIN);
1634 // -1 = No threshold, 0 = Below, 1 = Above
1635 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1636 : (fcol.isBelowThreshold() ? 0 : -1));
1640 setting.setColour(fcol.getColour().getRGB());
1644 av.getFeaturesDisplayed().isVisible(featureType));
1646 .getOrder(featureType);
1649 setting.setOrder(rorder);
1651 /// fs.addSetting(setting);
1652 fs.getSetting().add(setting);
1653 settingsAdded.addElement(featureType);
1657 // is groups actually supposed to be a map here ?
1658 Iterator<String> en = fr.getFeatureGroups().iterator();
1659 Vector<String> groupsAdded = new Vector<>();
1660 while (en.hasNext())
1662 String grp = en.next();
1663 if (groupsAdded.contains(grp))
1667 Group g = new Group();
1669 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1672 fs.getGroup().add(g);
1673 groupsAdded.addElement(grp);
1675 // jms.setFeatureSettings(fs);
1676 object.setFeatureSettings(fs);
1679 if (av.hasHiddenColumns())
1681 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1682 .getHiddenColumns();
1685 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1689 Iterator<int[]> hiddenRegions = hidden.iterator();
1690 while (hiddenRegions.hasNext())
1692 int[] region = hiddenRegions.next();
1693 HiddenColumns hc = new HiddenColumns();
1694 hc.setStart(region[0]);
1695 hc.setEnd(region[1]);
1696 // view.addHiddenColumns(hc);
1697 view.getHiddenColumns().add(hc);
1701 if (calcIdSet.size() > 0)
1703 for (String calcId : calcIdSet)
1705 if (calcId.trim().length() > 0)
1707 CalcIdParam cidp = createCalcIdParam(calcId, av);
1708 // Some calcIds have no parameters.
1711 // view.addCalcIdParam(cidp);
1712 view.getCalcIdParam().add(cidp);
1718 // jms.addViewport(view);
1719 object.getViewport().add(view);
1721 // object.setJalviewModelSequence(jms);
1722 // object.getVamsasModel().addSequenceSet(vamsasSet);
1723 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1725 if (jout != null && fileName != null)
1727 // We may not want to write the object to disk,
1728 // eg we can copy the alignViewport to a new view object
1729 // using save and then load
1732 fileName = fileName.replace('\\', '/');
1733 System.out.println("Writing jar entry " + fileName);
1734 JarEntry entry = new JarEntry(fileName);
1735 jout.putNextEntry(entry);
1736 PrintWriter pout = new PrintWriter(
1737 new OutputStreamWriter(jout, UTF_8));
1738 JAXBContext jaxbContext = JAXBContext
1739 .newInstance(JalviewModel.class);
1740 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1742 // output pretty printed
1743 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1744 jaxbMarshaller.marshal(
1745 new ObjectFactory().createJalviewModel(object), pout);
1747 // jaxbMarshaller.marshal(object, pout);
1748 // marshaller.marshal(object);
1751 } catch (Exception ex)
1753 // TODO: raise error in GUI if marshalling failed.
1754 System.err.println("Error writing Jalview project");
1755 ex.printStackTrace();
1761 * Saves the HMMER profile associated with the sequence as a file in the jar,
1762 * in HMMER format, and saves the name of the file as a child element of the
1763 * XML sequence element
1769 protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
1772 HiddenMarkovModel profile = seq.getHMM();
1773 if (profile == null)
1775 warn("Want to save HMM profile for " + seq.getName()
1776 + " but none found");
1779 HMMFile hmmFile = new HMMFile(profile);
1780 String hmmAsString = hmmFile.print();
1781 String jarEntryName = HMMER_PREFIX + nextCounter();
1784 writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
1785 xmlSeq.setHmmerProfile(jarEntryName);
1786 } catch (IOException e)
1788 warn("Error saving HMM profile: " + e.getMessage());
1794 * Writes PCA viewer attributes and computed values to an XML model object and
1795 * adds it to the JalviewModel. Any exceptions are reported by logging.
1797 protected void savePCA(PCAPanel panel, JalviewModel object)
1801 PcaViewer viewer = new PcaViewer();
1802 viewer.setHeight(panel.getHeight());
1803 viewer.setWidth(panel.getWidth());
1804 viewer.setXpos(panel.getX());
1805 viewer.setYpos(panel.getY());
1806 viewer.setTitle(panel.getTitle());
1807 PCAModel pcaModel = panel.getPcaModel();
1808 viewer.setScoreModelName(pcaModel.getScoreModelName());
1809 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1810 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1811 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1813 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1814 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1815 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1816 SeqPointMin spmin = new SeqPointMin();
1817 spmin.setXPos(spMin[0]);
1818 spmin.setYPos(spMin[1]);
1819 spmin.setZPos(spMin[2]);
1820 viewer.setSeqPointMin(spmin);
1821 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1822 SeqPointMax spmax = new SeqPointMax();
1823 spmax.setXPos(spMax[0]);
1824 spmax.setYPos(spMax[1]);
1825 spmax.setZPos(spMax[2]);
1826 viewer.setSeqPointMax(spmax);
1827 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1828 viewer.setLinkToAllViews(
1829 panel.getRotatableCanvas().isApplyToAllViews());
1830 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1831 viewer.setIncludeGaps(sp.includeGaps());
1832 viewer.setMatchGaps(sp.matchGaps());
1833 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1834 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1837 * sequence points on display
1839 for (jalview.datamodel.SequencePoint spt : pcaModel
1840 .getSequencePoints())
1842 SequencePoint point = new SequencePoint();
1843 point.setSequenceRef(seqHash(spt.getSequence()));
1844 point.setXPos(spt.coord.x);
1845 point.setYPos(spt.coord.y);
1846 point.setZPos(spt.coord.z);
1847 viewer.getSequencePoint().add(point);
1851 * (end points of) axes on display
1853 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1856 Axis axis = new Axis();
1860 viewer.getAxis().add(axis);
1864 * raw PCA data (note we are not restoring PCA inputs here -
1865 * alignment view, score model, similarity parameters)
1867 PcaDataType data = new PcaDataType();
1868 viewer.setPcaData(data);
1869 PCA pca = pcaModel.getPcaData();
1871 DoubleMatrix pm = new DoubleMatrix();
1872 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1873 data.setPairwiseMatrix(pm);
1875 DoubleMatrix tm = new DoubleMatrix();
1876 saveDoubleMatrix(pca.getTridiagonal(), tm);
1877 data.setTridiagonalMatrix(tm);
1879 DoubleMatrix eigenMatrix = new DoubleMatrix();
1880 data.setEigenMatrix(eigenMatrix);
1881 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1883 object.getPcaViewer().add(viewer);
1884 } catch (Throwable t)
1886 Cache.log.error("Error saving PCA: " + t.getMessage());
1891 * Stores values from a matrix into an XML element, including (if present) the
1896 * @see #loadDoubleMatrix(DoubleMatrix)
1898 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1900 xmlMatrix.setRows(m.height());
1901 xmlMatrix.setColumns(m.width());
1902 for (int i = 0; i < m.height(); i++)
1904 DoubleVector row = new DoubleVector();
1905 for (int j = 0; j < m.width(); j++)
1907 row.getV().add(m.getValue(i, j));
1909 xmlMatrix.getRow().add(row);
1911 if (m.getD() != null)
1913 DoubleVector dVector = new DoubleVector();
1914 for (double d : m.getD())
1916 dVector.getV().add(d);
1918 xmlMatrix.setD(dVector);
1920 if (m.getE() != null)
1922 DoubleVector eVector = new DoubleVector();
1923 for (double e : m.getE())
1925 eVector.getV().add(e);
1927 xmlMatrix.setE(eVector);
1932 * Loads XML matrix data into a new Matrix object, including the D and/or E
1933 * vectors (if present)
1937 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1939 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1941 int rows = mData.getRows();
1942 double[][] vals = new double[rows][];
1944 for (int i = 0; i < rows; i++)
1946 List<Double> dVector = mData.getRow().get(i).getV();
1947 vals[i] = new double[dVector.size()];
1949 for (Double d : dVector)
1955 MatrixI m = new Matrix(vals);
1957 if (mData.getD() != null)
1959 List<Double> dVector = mData.getD().getV();
1960 double[] vec = new double[dVector.size()];
1962 for (Double d : dVector)
1968 if (mData.getE() != null)
1970 List<Double> dVector = mData.getE().getV();
1971 double[] vec = new double[dVector.size()];
1973 for (Double d : dVector)
1984 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1985 * for each viewer, with
1987 * <li>viewer geometry (position, size, split pane divider location)</li>
1988 * <li>index of the selected structure in the viewer (currently shows gapped
1990 * <li>the id of the annotation holding RNA secondary structure</li>
1991 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1993 * Varna viewer state is also written out (in native Varna XML) to separate
1994 * project jar entries. A separate entry is written for each RNA structure
1995 * displayed, with the naming convention
1997 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2005 * @param storeDataset
2007 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2008 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2009 boolean storeDataset)
2011 if (Desktop.getDesktopPane() == null)
2015 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2016 for (int f = frames.length - 1; f > -1; f--)
2018 if (frames[f] instanceof AppVarna)
2020 AppVarna varna = (AppVarna) frames[f];
2022 * link the sequence to every viewer that is showing it and is linked to
2023 * its alignment panel
2025 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2027 String viewId = varna.getViewId();
2028 RnaViewer rna = new RnaViewer();
2029 rna.setViewId(viewId);
2030 rna.setTitle(varna.getTitle());
2031 rna.setXpos(varna.getX());
2032 rna.setYpos(varna.getY());
2033 rna.setWidth(varna.getWidth());
2034 rna.setHeight(varna.getHeight());
2035 rna.setDividerLocation(varna.getDividerLocation());
2036 rna.setSelectedRna(varna.getSelectedIndex());
2037 // jseq.addRnaViewer(rna);
2038 jseq.getRnaViewer().add(rna);
2041 * Store each Varna panel's state once in the project per sequence.
2042 * First time through only (storeDataset==false)
2044 // boolean storeSessions = false;
2045 // String sequenceViewId = viewId + seqsToIds.get(jds);
2046 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2048 // viewIds.add(sequenceViewId);
2049 // storeSessions = true;
2051 for (RnaModel model : varna.getModels())
2053 if (model.seq == jds)
2056 * VARNA saves each view (sequence or alignment secondary
2057 * structure, gapped or trimmed) as a separate XML file
2059 String jarEntryName = rnaSessions.get(model);
2060 if (jarEntryName == null)
2063 String varnaStateFile = varna.getStateInfo(model.rna);
2064 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2065 copyFileToJar(jout, varnaStateFile, jarEntryName);
2066 rnaSessions.put(model, jarEntryName);
2068 SecondaryStructure ss = new SecondaryStructure();
2069 String annotationId = varna.getAnnotation(jds).annotationId;
2070 ss.setAnnotationId(annotationId);
2071 ss.setViewerState(jarEntryName);
2072 ss.setGapped(model.gapped);
2073 ss.setTitle(model.title);
2074 // rna.addSecondaryStructure(ss);
2075 rna.getSecondaryStructure().add(ss);
2084 * Copy the contents of a file to a new entry added to the output jar
2088 * @param jarEntryName
2090 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2091 String jarEntryName)
2093 DataInputStream dis = null;
2096 File file = new File(infilePath);
2097 if (file.exists() && jout != null)
2099 dis = new DataInputStream(new FileInputStream(file));
2100 byte[] data = new byte[(int) file.length()];
2101 dis.readFully(data);
2102 writeJarEntry(jout, jarEntryName, data);
2104 } catch (Exception ex)
2106 ex.printStackTrace();
2114 } catch (IOException e)
2123 * Write the data to a new entry of given name in the output jar file
2126 * @param jarEntryName
2128 * @throws IOException
2130 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2131 byte[] data) throws IOException
2135 jarEntryName = jarEntryName.replace('\\','/');
2136 System.out.println("Writing jar entry " + jarEntryName);
2137 jout.putNextEntry(new JarEntry(jarEntryName));
2138 DataOutputStream dout = new DataOutputStream(jout);
2139 dout.write(data, 0, data.length);
2146 * Save the state of a structure viewer
2151 * the archive XML element under which to save the state
2154 * @param matchedFile
2158 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2159 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2160 String matchedFile, StructureViewerBase viewFrame)
2162 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2165 * Look for any bindings for this viewer to the PDB file of interest
2166 * (including part matches excluding chain id)
2168 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2170 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2171 final String pdbId = pdbentry.getId();
2172 if (!pdbId.equals(entry.getId())
2173 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2174 .startsWith(pdbId.toLowerCase())))
2177 * not interested in a binding to a different PDB entry here
2181 if (matchedFile == null)
2183 matchedFile = pdbentry.getFile();
2185 else if (!matchedFile.equals(pdbentry.getFile()))
2188 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2189 + pdbentry.getFile());
2193 // can get at it if the ID
2194 // match is ambiguous (e.g.
2197 for (int smap = 0; smap < viewFrame.getBinding()
2198 .getSequence()[peid].length; smap++)
2200 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2201 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2203 StructureState state = new StructureState();
2204 state.setVisible(true);
2205 state.setXpos(viewFrame.getX());
2206 state.setYpos(viewFrame.getY());
2207 state.setWidth(viewFrame.getWidth());
2208 state.setHeight(viewFrame.getHeight());
2209 final String viewId = viewFrame.getViewId();
2210 state.setViewId(viewId);
2211 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2212 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2213 state.setColourByJmol(viewFrame.isColouredByViewer());
2214 state.setType(viewFrame.getViewerType().toString());
2215 // pdb.addStructureState(state);
2216 pdb.getStructureState().add(state);
2224 * Populates the AnnotationColourScheme xml for save. This captures the
2225 * settings of the options in the 'Colour by Annotation' dialog.
2228 * @param userColours
2232 private AnnotationColourScheme constructAnnotationColours(
2233 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2236 AnnotationColourScheme ac = new AnnotationColourScheme();
2237 ac.setAboveThreshold(acg.getAboveThreshold());
2238 ac.setThreshold(acg.getAnnotationThreshold());
2239 // 2.10.2 save annotationId (unique) not annotation label
2240 ac.setAnnotation(acg.getAnnotation().annotationId);
2241 if (acg.getBaseColour() instanceof UserColourScheme)
2244 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2249 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2252 ac.setMaxColour(acg.getMaxColour().getRGB());
2253 ac.setMinColour(acg.getMinColour().getRGB());
2254 ac.setPerSequence(acg.isSeqAssociated());
2255 ac.setPredefinedColours(acg.isPredefinedColours());
2259 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2260 IdentityHashMap<SequenceGroup, String> groupRefs,
2261 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2262 SequenceSet vamsasSet)
2265 for (int i = 0; i < aa.length; i++)
2267 Annotation an = new Annotation();
2269 AlignmentAnnotation annotation = aa[i];
2270 if (annotation.annotationId != null)
2272 annotationIds.put(annotation.annotationId, annotation);
2275 an.setId(annotation.annotationId);
2277 an.setVisible(annotation.visible);
2279 an.setDescription(annotation.description);
2281 if (annotation.sequenceRef != null)
2283 // 2.9 JAL-1781 xref on sequence id rather than name
2284 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2286 if (annotation.groupRef != null)
2288 String groupIdr = groupRefs.get(annotation.groupRef);
2289 if (groupIdr == null)
2291 // make a locally unique String
2292 groupRefs.put(annotation.groupRef,
2293 groupIdr = ("" + System.currentTimeMillis()
2294 + annotation.groupRef.getName()
2295 + groupRefs.size()));
2297 an.setGroupRef(groupIdr.toString());
2300 // store all visualization attributes for annotation
2301 an.setGraphHeight(annotation.graphHeight);
2302 an.setCentreColLabels(annotation.centreColLabels);
2303 an.setScaleColLabels(annotation.scaleColLabel);
2304 an.setShowAllColLabels(annotation.showAllColLabels);
2305 an.setBelowAlignment(annotation.belowAlignment);
2307 if (annotation.graph > 0)
2310 an.setGraphType(annotation.graph);
2311 an.setGraphGroup(annotation.graphGroup);
2312 if (annotation.getThreshold() != null)
2314 ThresholdLine line = new ThresholdLine();
2315 line.setLabel(annotation.getThreshold().label);
2316 line.setValue(annotation.getThreshold().value);
2317 line.setColour(annotation.getThreshold().colour.getRGB());
2318 an.setThresholdLine(line);
2326 an.setLabel(annotation.label);
2328 if (annotation == av.getAlignmentQualityAnnot()
2329 || annotation == av.getAlignmentConservationAnnotation()
2330 || annotation == av.getAlignmentConsensusAnnotation()
2331 || annotation.autoCalculated)
2333 // new way of indicating autocalculated annotation -
2334 an.setAutoCalculated(annotation.autoCalculated);
2336 if (annotation.hasScore())
2338 an.setScore(annotation.getScore());
2341 if (annotation.getCalcId() != null)
2343 calcIdSet.add(annotation.getCalcId());
2344 an.setCalcId(annotation.getCalcId());
2346 if (annotation.hasProperties())
2348 for (String pr : annotation.getProperties())
2350 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2352 prop.setValue(annotation.getProperty(pr));
2353 // an.addProperty(prop);
2354 an.getProperty().add(prop);
2358 AnnotationElement ae;
2359 if (annotation.annotations != null)
2361 an.setScoreOnly(false);
2362 for (int a = 0; a < annotation.annotations.length; a++)
2364 if ((annotation == null) || (annotation.annotations[a] == null))
2369 ae = new AnnotationElement();
2370 if (annotation.annotations[a].description != null)
2372 ae.setDescription(annotation.annotations[a].description);
2374 if (annotation.annotations[a].displayCharacter != null)
2376 ae.setDisplayCharacter(
2377 annotation.annotations[a].displayCharacter);
2380 if (!Float.isNaN(annotation.annotations[a].value))
2382 ae.setValue(annotation.annotations[a].value);
2386 if (annotation.annotations[a].secondaryStructure > ' ')
2388 ae.setSecondaryStructure(
2389 annotation.annotations[a].secondaryStructure + "");
2392 if (annotation.annotations[a].colour != null
2393 && annotation.annotations[a].colour != java.awt.Color.black)
2395 ae.setColour(annotation.annotations[a].colour.getRGB());
2398 // an.addAnnotationElement(ae);
2399 an.getAnnotationElement().add(ae);
2400 if (annotation.autoCalculated)
2402 // only write one non-null entry into the annotation row -
2403 // sufficient to get the visualization attributes necessary to
2411 an.setScoreOnly(true);
2413 if (!storeDS || (storeDS && !annotation.autoCalculated))
2415 // skip autocalculated annotation - these are only provided for
2417 // vamsasSet.addAnnotation(an);
2418 vamsasSet.getAnnotation().add(an);
2424 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2426 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2427 if (settings != null)
2429 CalcIdParam vCalcIdParam = new CalcIdParam();
2430 vCalcIdParam.setCalcId(calcId);
2431 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2432 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2433 // generic URI allowing a third party to resolve another instance of the
2434 // service used for this calculation
2435 for (String url : settings.getServiceURLs())
2437 // vCalcIdParam.addServiceURL(urls);
2438 vCalcIdParam.getServiceURL().add(url);
2440 vCalcIdParam.setVersion("1.0");
2441 if (settings.getPreset() != null)
2443 WsParamSetI setting = settings.getPreset();
2444 vCalcIdParam.setName(setting.getName());
2445 vCalcIdParam.setDescription(setting.getDescription());
2449 vCalcIdParam.setName("");
2450 vCalcIdParam.setDescription("Last used parameters");
2452 // need to be able to recover 1) settings 2) user-defined presets or
2453 // recreate settings from preset 3) predefined settings provided by
2454 // service - or settings that can be transferred (or discarded)
2455 vCalcIdParam.setParameters(
2456 settings.getWsParamFile().replace("\n", "|\\n|"));
2457 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2458 // todo - decide if updateImmediately is needed for any projects.
2460 return vCalcIdParam;
2465 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2468 if (calcIdParam.getVersion().equals("1.0"))
2470 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2471 ServiceWithParameters service = PreferredServiceRegistry.getRegistry()
2472 .getPreferredServiceFor(calcIds);
2473 if (service != null)
2475 WsParamSetI parmSet = null;
2478 parmSet = service.getParamStore().parseServiceParameterFile(
2479 calcIdParam.getName(), calcIdParam.getDescription(),
2481 calcIdParam.getParameters().replace("|\\n|", "\n"));
2482 } catch (IOException x)
2484 warn("Couldn't parse parameter data for "
2485 + calcIdParam.getCalcId(), x);
2488 List<ArgumentI> argList = null;
2489 if (calcIdParam.getName().length() > 0)
2491 parmSet = service.getParamStore()
2492 .getPreset(calcIdParam.getName());
2493 if (parmSet != null)
2495 // TODO : check we have a good match with settings in AACon -
2496 // otherwise we'll need to create a new preset
2501 argList = parmSet.getArguments();
2504 AutoCalcSetting settings = new AAConSettings(
2505 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2506 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2507 calcIdParam.isNeedsUpdate());
2512 warn("Cannot resolve a service for the parameters used in this project. Try configuring a server in the Web Services preferences tab.");
2516 throw new Error(MessageManager.formatMessage(
2517 "error.unsupported_version_calcIdparam", new Object[]
2518 { calcIdParam.toString() }));
2522 * External mapping between jalview objects and objects yielding a valid and
2523 * unique object ID string. This is null for normal Jalview project IO, but
2524 * non-null when a jalview project is being read or written as part of a
2527 IdentityHashMap jv2vobj = null;
2530 * Construct a unique ID for jvobj using either existing bindings or if none
2531 * exist, the result of the hashcode call for the object.
2534 * jalview data object
2535 * @return unique ID for referring to jvobj
2537 private String makeHashCode(Object jvobj, String altCode)
2539 if (jv2vobj != null)
2541 Object id = jv2vobj.get(jvobj);
2544 return id.toString();
2546 // check string ID mappings
2547 if (jvids2vobj != null && jvobj instanceof String)
2549 id = jvids2vobj.get(jvobj);
2553 return id.toString();
2555 // give up and warn that something has gone wrong
2556 warn("Cannot find ID for object in external mapping : " + jvobj);
2562 * return local jalview object mapped to ID, if it exists
2566 * @return null or object bound to idcode
2568 private Object retrieveExistingObj(String idcode)
2570 if (idcode != null && vobj2jv != null)
2572 return vobj2jv.get(idcode);
2578 * binding from ID strings from external mapping table to jalview data model
2581 private Hashtable vobj2jv;
2583 private Sequence createVamsasSequence(String id, SequenceI jds)
2585 return createVamsasSequence(true, id, jds, null);
2588 private Sequence createVamsasSequence(boolean recurse, String id,
2589 SequenceI jds, SequenceI parentseq)
2591 Sequence vamsasSeq = new Sequence();
2592 vamsasSeq.setId(id);
2593 vamsasSeq.setName(jds.getName());
2594 vamsasSeq.setSequence(jds.getSequenceAsString());
2595 vamsasSeq.setDescription(jds.getDescription());
2596 List<DBRefEntry> dbrefs = null;
2597 if (jds.getDatasetSequence() != null)
2599 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2603 // seqId==dsseqid so we can tell which sequences really are
2604 // dataset sequences only
2605 vamsasSeq.setDsseqid(id);
2606 dbrefs = jds.getDBRefs();
2607 if (parentseq == null)
2614 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2618 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2620 DBRef dbref = new DBRef();
2621 DBRefEntry ref = dbrefs.get(d);
2622 dbref.setSource(ref.getSource());
2623 dbref.setVersion(ref.getVersion());
2624 dbref.setAccessionId(ref.getAccessionId());
2625 if (ref instanceof GeneLocus)
2627 dbref.setLocus(true);
2631 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2633 dbref.setMapping(mp);
2635 vamsasSeq.getDBRef().add(dbref);
2641 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2642 SequenceI parentseq, SequenceI jds, boolean recurse)
2645 if (jmp.getMap() != null)
2649 jalview.util.MapList mlst = jmp.getMap();
2650 List<int[]> r = mlst.getFromRanges();
2651 for (int[] range : r)
2653 MapListFrom mfrom = new MapListFrom();
2654 mfrom.setStart(range[0]);
2655 mfrom.setEnd(range[1]);
2656 // mp.addMapListFrom(mfrom);
2657 mp.getMapListFrom().add(mfrom);
2659 r = mlst.getToRanges();
2660 for (int[] range : r)
2662 MapListTo mto = new MapListTo();
2663 mto.setStart(range[0]);
2664 mto.setEnd(range[1]);
2665 // mp.addMapListTo(mto);
2666 mp.getMapListTo().add(mto);
2668 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2669 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2670 if (jmp.getTo() != null)
2672 // MappingChoice mpc = new MappingChoice();
2674 // check/create ID for the sequence referenced by getTo()
2677 SequenceI ps = null;
2678 if (parentseq != jmp.getTo()
2679 && parentseq.getDatasetSequence() != jmp.getTo())
2681 // chaining dbref rather than a handshaking one
2682 jmpid = seqHash(ps = jmp.getTo());
2686 jmpid = seqHash(ps = parentseq);
2688 // mpc.setDseqFor(jmpid);
2689 mp.setDseqFor(jmpid);
2690 if (!seqRefIds.containsKey(jmpid))
2692 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2693 seqRefIds.put(jmpid, ps);
2697 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2700 // mp.setMappingChoice(mpc);
2706 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2707 List<UserColourScheme> userColours, JalviewModel jm)
2710 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2711 boolean newucs = false;
2712 if (!userColours.contains(ucs))
2714 userColours.add(ucs);
2717 id = "ucs" + userColours.indexOf(ucs);
2720 // actually create the scheme's entry in the XML model
2721 java.awt.Color[] colours = ucs.getColours();
2722 UserColours uc = new UserColours();
2723 // UserColourScheme jbucs = new UserColourScheme();
2724 JalviewUserColours jbucs = new JalviewUserColours();
2726 for (int i = 0; i < colours.length; i++)
2728 Colour col = new Colour();
2729 col.setName(ResidueProperties.aa[i]);
2730 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2731 // jbucs.addColour(col);
2732 jbucs.getColour().add(col);
2734 if (ucs.getLowerCaseColours() != null)
2736 colours = ucs.getLowerCaseColours();
2737 for (int i = 0; i < colours.length; i++)
2739 Colour col = new Colour();
2740 col.setName(ResidueProperties.aa[i].toLowerCase());
2741 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2742 // jbucs.addColour(col);
2743 jbucs.getColour().add(col);
2748 uc.setUserColourScheme(jbucs);
2749 // jm.addUserColours(uc);
2750 jm.getUserColours().add(uc);
2756 jalview.schemes.UserColourScheme getUserColourScheme(
2757 JalviewModel jm, String id)
2759 List<UserColours> uc = jm.getUserColours();
2760 UserColours colours = null;
2762 for (int i = 0; i < uc.length; i++)
2764 if (uc[i].getId().equals(id))
2771 for (UserColours c : uc)
2773 if (c.getId().equals(id))
2780 java.awt.Color[] newColours = new java.awt.Color[24];
2782 for (int i = 0; i < 24; i++)
2784 newColours[i] = new java.awt.Color(Integer.parseInt(
2785 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2786 colours.getUserColourScheme().getColour().get(i).getRGB(),
2790 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2793 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2795 newColours = new java.awt.Color[23];
2796 for (int i = 0; i < 23; i++)
2798 newColours[i] = new java.awt.Color(Integer.parseInt(
2799 colours.getUserColourScheme().getColour().get(i + 24)
2803 ucs.setLowerCaseColours(newColours);
2810 * Load a jalview project archive from a jar file
2813 * - HTTP URL or filename
2815 public AlignFrame loadJalviewAlign(final Object file)
2818 jalview.gui.AlignFrame af = null;
2822 // create list to store references for any new Jmol viewers created
2823 newStructureViewers = new Vector<>();
2824 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2825 // Workaround is to make sure caller implements the JarInputStreamProvider
2827 // so we can re-open the jar input stream for each entry.
2829 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2830 af = loadJalviewAlign(jprovider);
2833 af.setMenusForViewport();
2835 } catch (MalformedURLException e)
2837 errorMessage = "Invalid URL format for '" + file + "'";
2843 // was invokeAndWait
2845 // BH 2019 -- can't wait
2846 SwingUtilities.invokeLater(new Runnable()
2851 setLoadingFinishedForNewStructureViewers();
2854 } catch (Exception x)
2856 System.err.println("Error loading alignment: " + x.getMessage());
2859 this.jarFile = null;
2863 @SuppressWarnings("unused")
2864 private jarInputStreamProvider createjarInputStreamProvider(
2865 final Object ofile) throws MalformedURLException
2869 String file = (ofile instanceof File
2870 ? ((File) ofile).getCanonicalPath()
2871 : ofile.toString());
2872 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2876 this.jarFile = (File) ofile;
2878 errorMessage = null;
2879 uniqueSetSuffix = null;
2881 viewportsAdded.clear();
2882 frefedSequence = null;
2884 URL url = file.startsWith("http://") ? new URL(file) : null;
2885 return new jarInputStreamProvider()
2888 public JarInputStream getJarInputStream() throws IOException
2890 InputStream is = bytes != null ? new ByteArrayInputStream(bytes)
2891 : (url != null ? url.openStream()
2892 : new FileInputStream(file));
2893 return new JarInputStream(is);
2897 public File getFile()
2903 public String getFilename()
2908 } catch (IOException e)
2910 e.printStackTrace();
2916 * Recover jalview session from a jalview project archive. Caller may
2917 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2918 * themselves. Any null fields will be initialised with default values,
2919 * non-null fields are left alone.
2924 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2926 errorMessage = null;
2927 if (uniqueSetSuffix == null)
2929 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2931 if (seqRefIds == null)
2935 AlignFrame af = null, _af = null;
2936 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2937 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2938 String fileName = jprovider.getFilename();
2939 File file = jprovider.getFile();
2940 List<AlignFrame> alignFrames = new ArrayList<>();
2944 JarInputStream jin = null;
2945 JarEntry jarentry = null;
2949 // Look for all the entry names ending with ".xml"
2950 // This includes all panels and at least one frame.
2951 // Platform.timeCheck(null, Platform.TIME_MARK);
2954 jin = jprovider.getJarInputStream();
2955 for (int i = 0; i < entryCount; i++)
2957 jarentry = jin.getNextJarEntry();
2959 String name = (jarentry == null ? null : jarentry.getName());
2961 // System.out.println("Jalview2XML opening " + name);
2962 if (name != null && name.endsWith(".xml"))
2965 // DataSet for.... is read last.
2968 // The question here is what to do with the two
2969 // .xml files in the jvp file.
2970 // Some number of them, "...Dataset for...", will be the
2971 // Only AlignPanels and will have Viewport.
2972 // One or more will be the source data, with the DBRefs.
2974 // JVP file writing (above) ensures tha the AlignPanels are written
2975 // first, then all relevant datasets (which are
2976 // Jalview.datamodel.Alignment).
2979 // Platform.timeCheck("Jalview2XML JAXB " + name, Platform.TIME_MARK);
2980 JAXBContext jc = JAXBContext
2981 .newInstance("jalview.xml.binding.jalview");
2982 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2983 .createXMLStreamReader(jin);
2984 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2985 JAXBElement<JalviewModel> jbe = um
2986 .unmarshal(streamReader, JalviewModel.class);
2987 JalviewModel model = jbe.getValue();
2989 if (true) // !skipViewport(object))
2991 // Q: Do we have to load from the model, even if it
2992 // does not have a viewport, could we discover that early on?
2993 // Q: Do we need to load this object?
2994 _af = loadFromObject(model, fileName, file, true, jprovider);
2995 // Platform.timeCheck("Jalview2XML.loadFromObject",
2996 // Platform.TIME_MARK);
3000 alignFrames.add(_af);
3002 if (_af != null && model.getViewport().size() > 0)
3005 // That is, this is one of the AlignmentPanel models
3008 // store a reference to the first view
3011 if (_af.getViewport().isGatherViewsHere())
3013 // if this is a gathered view, keep its reference since
3014 // after gathering views, only this frame will remain
3016 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3019 // Save dataset to register mappings once all resolved
3020 importedDatasets.put(
3021 af.getViewport().getAlignment().getDataset(),
3022 af.getViewport().getAlignment().getDataset());
3027 else if (jarentry != null)
3029 // Some other file here.
3032 } while (jarentry != null);
3033 resolveFrefedSequences();
3034 } catch (IOException ex)
3036 ex.printStackTrace();
3037 errorMessage = "Couldn't locate Jalview XML file : " + fileName;
3039 "Exception whilst loading jalview XML file : " + ex + "\n");
3040 } catch (Exception ex)
3042 System.err.println("Parsing as Jalview Version 2 file failed.");
3043 ex.printStackTrace(System.err);
3044 if (attemptversion1parse)
3046 // used to attempt to parse as V1 castor-generated xml
3048 if (Desktop.getInstance() != null)
3050 Desktop.getInstance().stopLoading();
3054 System.out.println("Successfully loaded archive file");
3057 ex.printStackTrace();
3060 "Exception whilst loading jalview XML file : " + ex + "\n");
3061 } catch (OutOfMemoryError e)
3063 // Don't use the OOM Window here
3064 errorMessage = "Out of memory loading jalview XML file";
3065 System.err.println("Out of memory whilst loading jalview XML file");
3066 e.printStackTrace();
3069 for (AlignFrame alf : alignFrames)
3071 alf.alignPanel.setHoldRepaint(false);
3077 * Regather multiple views (with the same sequence set id) to the frame (if
3078 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3079 * views instead of separate frames. Note this doesn't restore a state where
3080 * some expanded views in turn have tabbed views - the last "first tab" read
3081 * in will play the role of gatherer for all.
3083 for (AlignFrame fr : gatherToThisFrame.values())
3085 Desktop.getInstance().gatherViews(fr);
3088 restoreSplitFrames();
3089 for (AlignmentI ds : importedDatasets.keySet())
3091 if (ds.getCodonFrames() != null)
3093 Desktop.getStructureSelectionManager()
3094 .registerMappings(ds.getCodonFrames());
3097 if (errorMessage != null)
3102 if (Desktop.getInstance() != null)
3104 Desktop.getInstance().stopLoading();
3111 * Try to reconstruct and display SplitFrame windows, where each contains
3112 * complementary dna and protein alignments. Done by pairing up AlignFrame
3113 * objects (created earlier) which have complementary viewport ids associated.
3115 protected void restoreSplitFrames()
3117 List<SplitFrame> gatherTo = new ArrayList<>();
3118 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3119 Map<String, AlignFrame> dna = new HashMap<>();
3122 * Identify the DNA alignments
3124 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3127 AlignFrame af = candidate.getValue();
3128 if (af.getViewport().getAlignment().isNucleotide())
3130 dna.put(candidate.getKey().getId(), af);
3135 * Try to match up the protein complements
3137 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3140 AlignFrame af = candidate.getValue();
3141 if (!af.getViewport().getAlignment().isNucleotide())
3143 String complementId = candidate.getKey().getComplementId();
3144 // only non-null complements should be in the Map
3145 if (complementId != null && dna.containsKey(complementId))
3147 final AlignFrame dnaFrame = dna.get(complementId);
3148 SplitFrame sf = createSplitFrame(dnaFrame, af);
3149 addedToSplitFrames.add(dnaFrame);
3150 addedToSplitFrames.add(af);
3151 dnaFrame.setMenusForViewport();
3152 af.setMenusForViewport();
3153 if (af.getViewport().isGatherViewsHere())
3162 * Open any that we failed to pair up (which shouldn't happen!) as
3163 * standalone AlignFrame's.
3165 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3168 AlignFrame af = candidate.getValue();
3169 if (!addedToSplitFrames.contains(af))
3171 Viewport view = candidate.getKey();
3172 Desktop.addInternalFrame(af, view.getTitle(),
3173 safeInt(view.getWidth()), safeInt(view.getHeight()));
3174 af.setMenusForViewport();
3175 System.err.println("Failed to restore view " + view.getTitle()
3176 + " to split frame");
3181 * Gather back into tabbed views as flagged.
3183 for (SplitFrame sf : gatherTo)
3185 Desktop.getInstance().gatherViews(sf);
3188 splitFrameCandidates.clear();
3192 * Construct and display one SplitFrame holding DNA and protein alignments.
3195 * @param proteinFrame
3198 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3199 AlignFrame proteinFrame)
3201 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3202 String title = MessageManager.getString("label.linked_view_title");
3203 int width = (int) dnaFrame.getBounds().getWidth();
3204 int height = (int) (dnaFrame.getBounds().getHeight()
3205 + proteinFrame.getBounds().getHeight() + 50);
3208 * SplitFrame location is saved to both enclosed frames
3210 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3211 Desktop.addInternalFrame(splitFrame, title, width, height);
3214 * And compute cDNA consensus (couldn't do earlier with consensus as
3215 * mappings were not yet present)
3217 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3223 * check errorMessage for a valid error message and raise an error box in the
3224 * GUI or write the current errorMessage to stderr and then clear the error
3227 protected void reportErrors()
3229 reportErrors(false);
3232 protected void reportErrors(final boolean saving)
3234 if (errorMessage != null)
3236 final String finalErrorMessage = errorMessage;
3239 javax.swing.SwingUtilities.invokeLater(new Runnable()
3244 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3246 "Error " + (saving ? "saving" : "loading")
3248 JvOptionPane.WARNING_MESSAGE);
3254 System.err.println("Problem loading Jalview file: " + errorMessage);
3257 errorMessage = null;
3260 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3263 * when set, local views will be updated from view stored in JalviewXML
3264 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3265 * sync if this is set to true.
3267 private final boolean updateLocalViews = false;
3270 * Returns the path to a temporary file holding the PDB file for the given PDB
3271 * id. The first time of asking, searches for a file of that name in the
3272 * Jalview project jar, and copies it to a new temporary file. Any repeat
3273 * requests just return the path to the file previously created.
3279 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3282 if (alreadyLoadedPDB.containsKey(pdbId))
3284 return alreadyLoadedPDB.get(pdbId).toString();
3287 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3289 if (tempFile != null)
3291 alreadyLoadedPDB.put(pdbId, tempFile);
3297 * Copies the jar entry of given name to a new temporary file and returns the
3298 * path to the file, or null if the entry is not found.
3301 * @param jarEntryName
3303 * a prefix for the temporary file name, must be at least three
3306 * null or original file - so new file can be given the same suffix
3310 protected String copyJarEntry(jarInputStreamProvider jprovider,
3311 String jarEntryName, String prefix, String origFile)
3313 BufferedReader in = null;
3314 PrintWriter out = null;
3315 String suffix = ".tmp";
3316 if (origFile == null)
3318 origFile = jarEntryName;
3320 int sfpos = origFile.lastIndexOf(".");
3321 if (sfpos > -1 && sfpos < (origFile.length() - 3))
3323 suffix = "." + origFile.substring(sfpos + 1);
3327 JarInputStream jin = jprovider.getJarInputStream();
3329 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3330 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3331 * FileInputStream(jprovider)); }
3334 JarEntry entry = null;
3337 entry = jin.getNextJarEntry();
3338 } while (entry != null && !entry.getName().equals(jarEntryName));
3341 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3342 File outFile = File.createTempFile(prefix, suffix);
3343 outFile.deleteOnExit();
3344 out = new PrintWriter(new FileOutputStream(outFile));
3347 while ((data = in.readLine()) != null)
3352 String t = outFile.getAbsolutePath();
3357 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3359 } catch (Exception ex)
3361 ex.printStackTrace();
3369 } catch (IOException e)
3383 private class JvAnnotRow
3385 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3392 * persisted version of annotation row from which to take vis properties
3394 public jalview.datamodel.AlignmentAnnotation template;
3397 * original position of the annotation row in the alignment
3403 * Load alignment frame from jalview XML DOM object. For a DOM object that
3404 * includes one or more Viewport elements (one with a title that does NOT
3405 * contain "Dataset for"), create the frame.
3407 * @param jalviewModel
3410 * filename source string
3412 * @param loadTreesAndStructures
3413 * when false only create Viewport
3415 * data source provider
3416 * @return alignment frame created from view stored in DOM
3418 AlignFrame loadFromObject(JalviewModel jalviewModel, String fileName,
3419 File file, boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3421 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3422 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3425 // JalviewModelSequence jms = object.getJalviewModelSequence();
3427 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3429 Viewport view = (jalviewModel.getViewport().size() > 0)
3430 ? jalviewModel.getViewport().get(0)
3433 // ////////////////////////////////
3434 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3437 // If we just load in the same jar file again, the sequenceSetId
3438 // will be the same, and we end up with multiple references
3439 // to the same sequenceSet. We must modify this id on load
3440 // so that each load of the file gives a unique id
3443 * used to resolve correct alignment dataset for alignments with multiple
3446 String uniqueSeqSetId = null;
3447 String viewId = null;
3450 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3451 viewId = (view.getId() == null ? null
3452 : view.getId() + uniqueSetSuffix);
3455 // ////////////////////////////////
3458 List<SequenceI> hiddenSeqs = null;
3460 List<SequenceI> tmpseqs = new ArrayList<>();
3462 boolean multipleView = false;
3463 SequenceI referenceseqForView = null;
3464 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3465 List<JSeq> jseqs = jalviewModel.getJSeq();
3466 int vi = 0; // counter in vamsasSeq array
3467 for (int i = 0; i < jseqs.size(); i++)
3469 JSeq jseq = jseqs.get(i);
3470 String seqId = jseq.getId();
3472 SequenceI tmpSeq = seqRefIds.get(seqId);
3475 if (!incompleteSeqs.containsKey(seqId))
3477 // may not need this check, but keep it for at least 2.9,1 release
3478 if (tmpSeq.getStart() != jseq.getStart()
3479 || tmpSeq.getEnd() != jseq.getEnd())
3482 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3483 tmpSeq.getName(), tmpSeq.getStart(),
3484 tmpSeq.getEnd(), jseq.getStart(),
3490 incompleteSeqs.remove(seqId);
3492 if (vamsasSeqs.size() > vi
3493 && vamsasSeqs.get(vi).getId().equals(seqId))
3495 // most likely we are reading a dataset XML document so
3496 // update from vamsasSeq section of XML for this sequence
3497 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3498 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3499 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3504 // reading multiple views, so vamsasSeq set is a subset of JSeq
3505 multipleView = true;
3507 tmpSeq.setStart(jseq.getStart());
3508 tmpSeq.setEnd(jseq.getEnd());
3509 tmpseqs.add(tmpSeq);
3513 Sequence vamsasSeq = vamsasSeqs.get(vi);
3514 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3515 vamsasSeq.getSequence());
3516 tmpSeq.setDescription(vamsasSeq.getDescription());
3517 tmpSeq.setStart(jseq.getStart());
3518 tmpSeq.setEnd(jseq.getEnd());
3519 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3520 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3521 tmpseqs.add(tmpSeq);
3525 if (safeBoolean(jseq.isViewreference()))
3527 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3530 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3532 if (hiddenSeqs == null)
3534 hiddenSeqs = new ArrayList<>();
3537 hiddenSeqs.add(tmpSeq);
3542 // Create the alignment object from the sequence set
3543 // ///////////////////////////////
3544 SequenceI[] orderedSeqs = tmpseqs
3545 .toArray(new SequenceI[tmpseqs.size()]);
3547 AlignmentI al = null;
3548 // so we must create or recover the dataset alignment before going further
3549 // ///////////////////////////////
3550 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3552 // older jalview projects do not have a dataset - so creat alignment and
3554 al = new Alignment(orderedSeqs);
3555 al.setDataset(null);
3559 boolean isdsal = jalviewModel.getViewport().isEmpty();
3562 // we are importing a dataset record, so
3563 // recover reference to an alignment already materialsed as dataset
3564 al = getDatasetFor(vamsasSet.getDatasetId());
3568 // materialse the alignment
3569 al = new Alignment(orderedSeqs);
3573 addDatasetRef(vamsasSet.getDatasetId(), al);
3576 // finally, verify all data in vamsasSet is actually present in al
3577 // passing on flag indicating if it is actually a stored dataset
3578 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3581 if (referenceseqForView != null)
3583 al.setSeqrep(referenceseqForView);
3585 // / Add the alignment properties
3586 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3588 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3590 al.setProperty(ssp.getKey(), ssp.getValue());
3593 // ///////////////////////////////
3595 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3598 // load sequence features, database references and any associated PDB
3599 // structures for the alignment
3601 // prior to 2.10, this part would only be executed the first time a
3602 // sequence was encountered, but not afterwards.
3603 // now, for 2.10 projects, this is also done if the xml doc includes
3604 // dataset sequences not actually present in any particular view.
3606 for (int i = 0; i < vamsasSeqs.size(); i++)
3608 JSeq jseq = jseqs.get(i);
3609 if (jseq.getFeatures().size() > 0)
3611 List<Feature> features = jseq.getFeatures();
3612 for (int f = 0; f < features.size(); f++)
3614 Feature feat = features.get(f);
3615 SequenceFeature sf = new SequenceFeature(feat.getType(),
3616 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3617 safeFloat(feat.getScore()), feat.getFeatureGroup());
3618 sf.setStatus(feat.getStatus());
3621 * load any feature attributes - include map-valued attributes
3623 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3624 for (int od = 0; od < feat.getOtherData().size(); od++)
3626 OtherData keyValue = feat.getOtherData().get(od);
3627 String attributeName = keyValue.getKey();
3628 String attributeValue = keyValue.getValue();
3629 if (attributeName.startsWith("LINK"))
3631 sf.addLink(attributeValue);
3635 String subAttribute = keyValue.getKey2();
3636 if (subAttribute == null)
3638 // simple string-valued attribute
3639 sf.setValue(attributeName, attributeValue);
3643 // attribute 'key' has sub-attribute 'key2'
3644 if (!mapAttributes.containsKey(attributeName))
3646 mapAttributes.put(attributeName, new HashMap<>());
3648 mapAttributes.get(attributeName).put(subAttribute,
3653 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3656 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3659 // adds feature to datasequence's feature set (since Jalview 2.10)
3660 al.getSequenceAt(i).addSequenceFeature(sf);
3663 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3665 // adds dbrefs to datasequence's set (since Jalview 2.10)
3667 al.getSequenceAt(i).getDatasetSequence() == null
3668 ? al.getSequenceAt(i)
3669 : al.getSequenceAt(i).getDatasetSequence(),
3672 if (jseq.getPdbids().size() > 0)
3674 List<Pdbids> ids = jseq.getPdbids();
3675 for (int p = 0; p < ids.size(); p++)
3677 Pdbids pdbid = ids.get(p);
3678 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3679 entry.setId(pdbid.getId());
3680 if (pdbid.getType() != null)
3682 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3684 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3688 entry.setType(PDBEntry.Type.FILE);
3691 // jprovider is null when executing 'New View'
3692 if (pdbid.getFile() != null && jprovider != null)
3694 if (!pdbloaded.containsKey(pdbid.getFile()))
3696 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3701 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3705 if (pdbid.getPdbentryItem() != null)
3707 for (PdbentryItem item : pdbid.getPdbentryItem())
3709 for (Property pr : item.getProperty())
3711 entry.setProperty(pr.getName(), pr.getValue());
3716 for (Property prop : pdbid.getProperty())
3718 entry.setProperty(prop.getName(), prop.getValue());
3720 Desktop.getStructureSelectionManager()
3721 .registerPDBEntry(entry);
3722 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3723 if (al.getSequenceAt(i).getDatasetSequence() != null)
3725 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3729 al.getSequenceAt(i).addPDBId(entry);
3735 * load any HMMER profile
3739 String hmmJarFile = jseqs.get(i).getHmmerProfile();
3740 if (hmmJarFile != null && jprovider != null)
3742 loadHmmerProfile(jprovider, hmmJarFile, al.getSequenceAt(i));
3745 } // end !multipleview
3747 // ///////////////////////////////
3748 // LOAD SEQUENCE MAPPINGS
3750 if (vamsasSet.getAlcodonFrame().size() > 0)
3752 // TODO Potentially this should only be done once for all views of an
3754 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3755 for (int i = 0; i < alc.size(); i++)
3757 AlignedCodonFrame cf = new AlignedCodonFrame();
3758 if (alc.get(i).getAlcodMap().size() > 0)
3760 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3761 for (int m = 0; m < maps.size(); m++)
3763 AlcodMap map = maps.get(m);
3764 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3766 jalview.datamodel.Mapping mapping = null;
3767 // attach to dna sequence reference.
3768 if (map.getMapping() != null)
3770 mapping = addMapping(map.getMapping());
3771 if (dnaseq != null && mapping.getTo() != null)
3773 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3779 newAlcodMapRef(map.getDnasq(), cf, mapping));
3783 al.addCodonFrame(cf);
3788 // ////////////////////////////////
3790 List<JvAnnotRow> autoAlan = new ArrayList<>();
3793 * store any annotations which forward reference a group's ID
3795 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3797 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3799 List<Annotation> an = vamsasSet.getAnnotation();
3801 for (int i = 0; i < an.size(); i++)
3803 Annotation annotation = an.get(i);
3806 * test if annotation is automatically calculated for this view only
3808 boolean autoForView = false;
3809 if (annotation.getLabel().equals("Quality")
3810 || annotation.getLabel().equals("Conservation")
3811 || annotation.getLabel().equals("Consensus"))
3813 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3815 // JAXB has no has() test; schema defaults value to false
3816 // if (!annotation.hasAutoCalculated())
3818 // annotation.setAutoCalculated(true);
3821 if (autoForView || annotation.isAutoCalculated())
3823 // remove ID - we don't recover annotation from other views for
3824 // view-specific annotation
3825 annotation.setId(null);
3828 // set visibility for other annotation in this view
3829 String annotationId = annotation.getId();
3830 if (annotationId != null && annotationIds.containsKey(annotationId))
3832 AlignmentAnnotation jda = annotationIds.get(annotationId);
3833 // in principle Visible should always be true for annotation displayed
3834 // in multiple views
3835 if (annotation.isVisible() != null)
3837 jda.visible = annotation.isVisible();
3840 al.addAnnotation(jda);
3844 // Construct new annotation from model.
3845 List<AnnotationElement> ae = annotation.getAnnotationElement();
3846 jalview.datamodel.Annotation[] anot = null;
3847 java.awt.Color firstColour = null;
3849 if (!annotation.isScoreOnly())
3851 anot = new jalview.datamodel.Annotation[al.getWidth()];
3852 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3854 AnnotationElement annElement = ae.get(aa);
3855 anpos = annElement.getPosition();
3857 if (anpos >= anot.length)
3862 float value = safeFloat(annElement.getValue());
3863 anot[anpos] = new jalview.datamodel.Annotation(
3864 annElement.getDisplayCharacter(),
3865 annElement.getDescription(),
3866 (annElement.getSecondaryStructure() == null
3867 || annElement.getSecondaryStructure()
3871 .getSecondaryStructure()
3874 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3875 if (firstColour == null)
3877 firstColour = anot[anpos].colour;
3881 // create the new AlignmentAnnotation
3882 jalview.datamodel.AlignmentAnnotation jaa = null;
3884 if (annotation.isGraph())
3886 float llim = 0, hlim = 0;
3887 // if (autoForView || an[i].isAutoCalculated()) {
3890 jaa = new jalview.datamodel.AlignmentAnnotation(
3891 annotation.getLabel(), annotation.getDescription(), anot,
3892 llim, hlim, safeInt(annotation.getGraphType()));
3894 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3895 jaa._linecolour = firstColour;
3896 if (annotation.getThresholdLine() != null)
3898 jaa.setThreshold(new jalview.datamodel.GraphLine(
3899 safeFloat(annotation.getThresholdLine().getValue()),
3900 annotation.getThresholdLine().getLabel(),
3901 new java.awt.Color(safeInt(
3902 annotation.getThresholdLine().getColour()))));
3904 if (autoForView || annotation.isAutoCalculated())
3906 // Hardwire the symbol display line to ensure that labels for
3907 // histograms are displayed
3913 jaa = new jalview.datamodel.AlignmentAnnotation(
3914 annotation.getLabel(), annotation.getDescription(), anot);
3915 jaa._linecolour = firstColour;
3917 // register new annotation
3918 // Annotation graphs such as Conservation will not have id.
3919 if (annotation.getId() != null)
3921 annotationIds.put(annotation.getId(), jaa);
3922 jaa.annotationId = annotation.getId();
3924 // recover sequence association
3925 String sequenceRef = annotation.getSequenceRef();
3926 if (sequenceRef != null)
3928 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3929 SequenceI sequence = seqRefIds.get(sequenceRef);
3930 if (sequence == null)
3932 // in pre-2.9 projects sequence ref is to sequence name
3933 sequence = al.findName(sequenceRef);
3935 if (sequence != null)
3937 jaa.createSequenceMapping(sequence, 1, true);
3938 sequence.addAlignmentAnnotation(jaa);
3941 // and make a note of any group association
3942 if (annotation.getGroupRef() != null
3943 && annotation.getGroupRef().length() > 0)
3945 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3946 .get(annotation.getGroupRef());
3949 aal = new ArrayList<>();
3950 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3955 if (annotation.getScore() != null)
3957 jaa.setScore(annotation.getScore().doubleValue());
3959 if (annotation.isVisible() != null)
3961 jaa.visible = annotation.isVisible().booleanValue();
3964 if (annotation.isCentreColLabels() != null)
3966 jaa.centreColLabels = annotation.isCentreColLabels()
3970 if (annotation.isScaleColLabels() != null)
3972 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3974 if (annotation.isAutoCalculated())
3976 // newer files have an 'autoCalculated' flag and store calculation
3977 // state in viewport properties
3978 jaa.autoCalculated = true; // means annotation will be marked for
3979 // update at end of load.
3981 if (annotation.getGraphHeight() != null)
3983 jaa.graphHeight = annotation.getGraphHeight().intValue();
3985 jaa.belowAlignment = annotation.isBelowAlignment();
3986 jaa.setCalcId(annotation.getCalcId());
3987 if (annotation.getProperty().size() > 0)
3989 for (Annotation.Property prop : annotation
3992 jaa.setProperty(prop.getName(), prop.getValue());
3995 if (jaa.autoCalculated)
3997 autoAlan.add(new JvAnnotRow(i, jaa));
4000 // if (!autoForView)
4002 // add autocalculated group annotation and any user created annotation
4004 al.addAnnotation(jaa);
4008 // ///////////////////////
4010 // Create alignment markup and styles for this view
4011 if (jalviewModel.getJGroup().size() > 0)
4013 List<JGroup> groups = jalviewModel.getJGroup();
4014 boolean addAnnotSchemeGroup = false;
4015 for (int i = 0; i < groups.size(); i++)
4017 JGroup jGroup = groups.get(i);
4018 ColourSchemeI cs = null;
4019 if (jGroup.getColour() != null)
4021 if (jGroup.getColour().startsWith("ucs"))
4023 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4025 else if (jGroup.getColour().equals("AnnotationColourGradient")
4026 && jGroup.getAnnotationColours() != null)
4028 addAnnotSchemeGroup = true;
4032 cs = ColourSchemeProperty.getColourScheme(null, al,
4033 jGroup.getColour());
4036 int pidThreshold = safeInt(jGroup.getPidThreshold());
4038 Vector<SequenceI> seqs = new Vector<>();
4040 for (int s = 0; s < jGroup.getSeq().size(); s++)
4042 String seqId = jGroup.getSeq().get(s);
4043 SequenceI ts = seqRefIds.get(seqId);
4047 seqs.addElement(ts);
4051 if (seqs.size() < 1)
4056 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4057 safeBoolean(jGroup.isDisplayBoxes()),
4058 safeBoolean(jGroup.isDisplayText()),
4059 safeBoolean(jGroup.isColourText()),
4060 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4061 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4062 sg.getGroupColourScheme()
4063 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4064 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4066 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4067 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4068 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4069 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4070 // attributes with a default in the schema are never null
4071 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4072 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4073 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4074 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4075 if (jGroup.getConsThreshold() != null
4076 && jGroup.getConsThreshold().intValue() != 0)
4078 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4081 c.verdict(false, 25);
4082 sg.cs.setConservation(c);
4085 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4087 // re-instate unique group/annotation row reference
4088 List<AlignmentAnnotation> jaal = groupAnnotRefs
4089 .get(jGroup.getId());
4092 for (AlignmentAnnotation jaa : jaal)
4095 if (jaa.autoCalculated)
4097 // match up and try to set group autocalc alignment row for this
4099 if (jaa.label.startsWith("Consensus for "))
4101 sg.setConsensus(jaa);
4103 // match up and try to set group autocalc alignment row for this
4105 if (jaa.label.startsWith("Conservation for "))
4107 sg.setConservationRow(jaa);
4114 if (addAnnotSchemeGroup)
4116 // reconstruct the annotation colourscheme
4117 sg.setColourScheme(constructAnnotationColour(
4118 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
4124 // only dataset in this model, so just return.
4127 // ///////////////////////////////
4130 // now check to see if we really need to create a new viewport.
4131 if (multipleView && viewportsAdded.size() == 0)
4133 // We recovered an alignment for which a viewport already exists.
4134 // TODO: fix up any settings necessary for overlaying stored state onto
4135 // state recovered from another document. (may not be necessary).
4136 // we may need a binding from a viewport in memory to one recovered from
4138 // and then recover its containing af to allow the settings to be applied.
4139 // TODO: fix for vamsas demo
4141 "About to recover a viewport for existing alignment: Sequence set ID is "
4143 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4144 if (seqsetobj != null)
4146 if (seqsetobj instanceof String)
4148 uniqueSeqSetId = (String) seqsetobj;
4150 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4156 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4162 * indicate that annotation colours are applied across all groups (pre
4163 * Jalview 2.8.1 behaviour)
4165 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4166 jalviewModel.getVersion());
4168 AlignFrame af = null;
4169 AlignmentPanel ap = null;
4170 AlignViewport av = null;
4173 // Check to see if this alignment already has a view id == viewId
4174 jalview.gui.AlignmentPanel views[] = Desktop
4175 .getAlignmentPanels(uniqueSeqSetId);
4176 if (views != null && views.length > 0)
4178 for (int v = 0; v < views.length; v++)
4182 if (av.getViewId().equalsIgnoreCase(viewId))
4184 // recover the existing alignpanel, alignframe, viewport
4187 // TODO: could even skip resetting view settings if we don't want to
4188 // change the local settings from other jalview processes
4196 af = loadViewport(fileName, file, jseqs, hiddenSeqs, al, jalviewModel, view,
4197 uniqueSeqSetId, viewId, autoAlan);
4198 av = af.getViewport();
4199 // note that this only retrieves the most recently accessed
4200 // tab of an AlignFrame.
4205 * Load any trees, PDB structures and viewers
4207 * Not done if flag is false (when this method is used for New View)
4209 final AlignFrame af0 = af;
4210 final AlignViewport av0 = av;
4211 final AlignmentPanel ap0 = ap;
4212 // Platform.timeCheck("Jalview2XML.loadFromObject-beforetree",
4213 // Platform.TIME_MARK);
4214 if (loadTreesAndStructures)
4216 if (!jalviewModel.getTree().isEmpty())
4218 SwingUtilities.invokeLater(new Runnable()
4223 // Platform.timeCheck(null, Platform.TIME_MARK);
4224 loadTrees(jalviewModel, view, af0, av0, ap0);
4225 // Platform.timeCheck("Jalview2XML.loadTrees", Platform.TIME_MARK);
4229 if (!jalviewModel.getPcaViewer().isEmpty())
4231 SwingUtilities.invokeLater(new Runnable()
4236 // Platform.timeCheck(null, Platform.TIME_MARK);
4237 loadPCAViewers(jalviewModel, ap0);
4238 // Platform.timeCheck("Jalview2XML.loadPCA", Platform.TIME_MARK);
4242 SwingUtilities.invokeLater(new Runnable()
4247 // Platform.timeCheck(null, Platform.TIME_MARK);
4248 loadPDBStructures(jprovider, jseqs, af0, ap0);
4249 // Platform.timeCheck("Jalview2XML.loadPDB", Platform.TIME_MARK);
4252 SwingUtilities.invokeLater(new Runnable()
4257 loadRnaViewers(jprovider, jseqs, ap0);
4261 // and finally return.
4262 // but do not set holdRepaint true just yet, because this could be the
4263 // initial frame with just its dataset.
4268 * Loads a HMMER profile from a file stored in the project, and associates it
4269 * with the specified sequence
4275 protected void loadHmmerProfile(jarInputStreamProvider jprovider,
4276 String hmmJarFile, SequenceI seq)
4280 String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
4281 HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
4282 HiddenMarkovModel hmmModel = parser.getHMM();
4283 hmmModel = new HiddenMarkovModel(hmmModel, seq);
4284 seq.setHMM(hmmModel);
4285 } catch (IOException e)
4287 warn("Error loading HMM profile for " + seq.getName() + ": "
4293 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4294 * panel is restored from separate jar entries, two (gapped and trimmed) per
4295 * sequence and secondary structure.
4297 * Currently each viewer shows just one sequence and structure (gapped and
4298 * trimmed), however this method is designed to support multiple sequences or
4299 * structures in viewers if wanted in future.
4305 protected void loadRnaViewers(jarInputStreamProvider jprovider,
4306 List<JSeq> jseqs, AlignmentPanel ap)
4309 * scan the sequences for references to viewers; create each one the first
4310 * time it is referenced, add Rna models to existing viewers
4312 for (JSeq jseq : jseqs)
4314 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4316 RnaViewer viewer = jseq.getRnaViewer().get(i);
4317 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4320 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4322 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4323 SequenceI seq = seqRefIds.get(jseq.getId());
4324 AlignmentAnnotation ann = this.annotationIds
4325 .get(ss.getAnnotationId());
4328 * add the structure to the Varna display (with session state copied
4329 * from the jar to a temporary file)
4331 boolean gapped = safeBoolean(ss.isGapped());
4332 String rnaTitle = ss.getTitle();
4333 String sessionState = ss.getViewerState();
4334 String tempStateFile = copyJarEntry(jprovider, sessionState,
4336 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4337 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4339 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4345 * Locate and return an already instantiated matching AppVarna, or create one
4349 * @param viewIdSuffix
4353 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4354 String viewIdSuffix, AlignmentPanel ap)
4357 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4358 * if load is repeated
4360 String postLoadId = viewer.getViewId() + viewIdSuffix;
4361 for (JInternalFrame frame : getAllFrames())
4363 if (frame instanceof AppVarna)
4365 AppVarna varna = (AppVarna) frame;
4366 if (postLoadId.equals(varna.getViewId()))
4368 // this viewer is already instantiated
4369 // could in future here add ap as another 'parent' of the
4370 // AppVarna window; currently just 1-to-many
4377 * viewer not found - make it
4379 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4380 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4381 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4382 safeInt(viewer.getDividerLocation()));
4383 AppVarna varna = new AppVarna(model, ap);
4389 * Load any saved trees
4397 protected void loadTrees(JalviewModel jm, Viewport view,
4398 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4400 // TODO result of automated refactoring - are all these parameters needed?
4403 for (int t = 0; t < jm.getTree().size(); t++)
4406 Tree tree = jm.getTree().get(t);
4408 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4411 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4412 tree.getTitle(), safeInt(tree.getWidth()),
4413 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4414 safeInt(tree.getYpos()));
4417 warn("There was a problem recovering stored Newick tree: \n"
4418 + tree.getNewick());
4421 if (tree.getId() != null)
4423 // perhaps bind the tree id to something ?
4428 // update local tree attributes ?
4429 // TODO: should check if tp has been manipulated by user - if so its
4430 // settings shouldn't be modified
4431 tp.setTitle(tree.getTitle());
4432 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4433 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4434 safeInt(tree.getHeight())));
4435 tp.setViewport(av); // af.viewport;
4436 // TODO: verify 'associate with all views' works still
4437 tp.getTreeCanvas().setViewport(av); // af.viewport;
4438 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4440 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4441 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4442 tp.fitToWindow_actionPerformed(null);
4444 if (tree.getFontName() != null)
4447 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4448 safeInt(tree.getFontSize())));
4453 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4454 safeInt(view.getFontSize())));
4457 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4458 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4459 tp.showDistances(safeBoolean(tree.isShowDistances()));
4461 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4463 if (safeBoolean(tree.isCurrentTree()))
4465 af.getViewport().setCurrentTree(tp.getTree());
4469 } catch (Exception ex)
4471 ex.printStackTrace();
4476 * Load and link any saved structure viewers.
4483 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4484 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4487 * Run through all PDB ids on the alignment, and collect mappings between
4488 * distinct view ids and all sequences referring to that view.
4490 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4492 for (int i = 0; i < jseqs.size(); i++)
4494 JSeq jseq = jseqs.get(i);
4495 if (jseq.getPdbids().size() > 0)
4497 List<Pdbids> ids = jseq.getPdbids();
4498 for (int p = 0; p < ids.size(); p++)
4500 Pdbids pdbid = ids.get(p);
4501 final int structureStateCount = pdbid.getStructureState().size();
4502 for (int s = 0; s < structureStateCount; s++)
4504 // check to see if we haven't already created this structure view
4505 final StructureState structureState = pdbid
4506 .getStructureState().get(s);
4507 String sviewid = (structureState.getViewId() == null) ? null
4508 : structureState.getViewId() + uniqueSetSuffix;
4509 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4510 // Originally : pdbid.getFile()
4511 // : TODO: verify external PDB file recovery still works in normal
4512 // jalview project load
4514 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4515 jpdb.setId(pdbid.getId());
4517 int x = safeInt(structureState.getXpos());
4518 int y = safeInt(structureState.getYpos());
4519 int width = safeInt(structureState.getWidth());
4520 int height = safeInt(structureState.getHeight());
4522 // Probably don't need to do this anymore...
4523 // Desktop.getDesktop().getComponentAt(x, y);
4524 // TODO: NOW: check that this recovers the PDB file correctly.
4525 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4527 jalview.datamodel.SequenceI seq = seqRefIds
4528 .get(jseq.getId() + "");
4529 if (sviewid == null)
4531 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4534 if (!structureViewers.containsKey(sviewid))
4536 structureViewers.put(sviewid,
4537 new StructureViewerModel(x, y, width, height, false,
4538 false, true, structureState.getViewId(),
4539 structureState.getType()));
4540 // Legacy pre-2.7 conversion JAL-823 :
4541 // do not assume any view has to be linked for colour by
4545 // assemble String[] { pdb files }, String[] { id for each
4546 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4547 // seqs_file 2}, boolean[] {
4548 // linkAlignPanel,superposeWithAlignpanel}} from hash
4549 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4550 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4551 || structureState.isAlignwithAlignPanel());
4554 * Default colour by linked panel to false if not specified (e.g.
4555 * for pre-2.7 projects)
4557 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4558 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4559 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4562 * Default colour by viewer to true if not specified (e.g. for
4565 boolean colourByViewer = jmoldat.isColourByViewer();
4566 colourByViewer &= structureState.isColourByJmol();
4567 jmoldat.setColourByViewer(colourByViewer);
4569 if (jmoldat.getStateData().length() < structureState
4570 .getValue()/*Content()*/.length())
4572 jmoldat.setStateData(structureState.getValue());// Content());
4574 if (pdbid.getFile() != null)
4576 File mapkey = new File(pdbid.getFile());
4577 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4578 if (seqstrmaps == null)
4580 jmoldat.getFileData().put(mapkey,
4581 seqstrmaps = jmoldat.new StructureData(pdbFile,
4584 if (!seqstrmaps.getSeqList().contains(seq))
4586 seqstrmaps.getSeqList().add(seq);
4592 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");
4599 // Instantiate the associated structure views
4600 for (Entry<String, StructureViewerModel> entry : structureViewers
4605 createOrLinkStructureViewer(entry, af, ap, jprovider);
4606 } catch (Exception e)
4609 "Error loading structure viewer: " + e.getMessage());
4610 // failed - try the next one
4622 protected void createOrLinkStructureViewer(
4623 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4624 AlignmentPanel ap, jarInputStreamProvider jprovider)
4626 final StructureViewerModel stateData = viewerData.getValue();
4629 * Search for any viewer windows already open from other alignment views
4630 * that exactly match the stored structure state
4632 StructureViewerBase comp = findMatchingViewer(viewerData);
4636 linkStructureViewer(ap, comp, stateData);
4641 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4642 * "viewer_"+stateData.viewId
4644 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4646 createChimeraViewer(viewerData, af, jprovider);
4651 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4653 createJmolViewer(viewerData, af, jprovider);
4658 * Create a new Chimera viewer.
4664 protected void createChimeraViewer(
4665 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4666 jarInputStreamProvider jprovider)
4668 StructureViewerModel data = viewerData.getValue();
4669 String chimeraSessionFile = data.getStateData();
4672 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4674 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4675 * 'uniquified' sviewid used to reconstruct the viewer here
4677 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4678 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4681 Set<Entry<File, StructureData>> fileData = data.getFileData()
4683 List<PDBEntry> pdbs = new ArrayList<>();
4684 List<SequenceI[]> allseqs = new ArrayList<>();
4685 for (Entry<File, StructureData> pdb : fileData)
4687 String filePath = pdb.getValue().getFilePath();
4688 String pdbId = pdb.getValue().getPdbId();
4689 // pdbs.add(new PDBEntry(filePath, pdbId));
4690 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4691 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4692 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4696 boolean colourByChimera = data.isColourByViewer();
4697 boolean colourBySequence = data.isColourWithAlignPanel();
4699 // TODO use StructureViewer as a factory here, see JAL-1761
4700 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4701 final SequenceI[][] seqsArray = allseqs
4702 .toArray(new SequenceI[allseqs.size()][]);
4703 String newViewId = viewerData.getKey();
4705 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4706 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4707 colourBySequence, newViewId);
4708 cvf.setSize(data.getWidth(), data.getHeight());
4709 cvf.setLocation(data.getX(), data.getY());
4713 * Create a new Jmol window. First parse the Jmol state to translate filenames
4714 * loaded into the view, and record the order in which files are shown in the
4715 * Jmol view, so we can add the sequence mappings in same order.
4721 protected void createJmolViewer(
4722 final Entry<String, StructureViewerModel> viewerData,
4723 AlignFrame af, jarInputStreamProvider jprovider)
4725 final StructureViewerModel svattrib = viewerData.getValue();
4726 String state = svattrib.getStateData();
4729 * Pre-2.9: state element value is the Jmol state string
4731 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4734 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4736 state = readJarEntry(jprovider,
4737 getViewerJarEntryName(svattrib.getViewId()));
4740 List<String> pdbfilenames = new ArrayList<>();
4741 List<SequenceI[]> seqmaps = new ArrayList<>();
4742 List<String> pdbids = new ArrayList<>();
4743 StringBuilder newFileLoc = new StringBuilder(64);
4744 int cp = 0, ncp, ecp;
4745 Map<File, StructureData> oldFiles = svattrib.getFileData();
4746 while ((ncp = state.indexOf("load ", cp)) > -1)
4750 // look for next filename in load statement
4751 newFileLoc.append(state.substring(cp,
4752 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4753 String oldfilenam = state.substring(ncp,
4754 ecp = state.indexOf("\"", ncp));
4755 // recover the new mapping data for this old filename
4756 // have to normalize filename - since Jmol and jalview do
4758 // translation differently.
4759 StructureData filedat = oldFiles.get(new File(oldfilenam));
4760 if (filedat == null)
4762 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4763 filedat = oldFiles.get(new File(reformatedOldFilename));
4766 .append(Platform.escapeBackslashes(filedat.getFilePath()));
4767 pdbfilenames.add(filedat.getFilePath());
4768 pdbids.add(filedat.getPdbId());
4769 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4770 newFileLoc.append("\"");
4771 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4772 // look for next file statement.
4773 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4777 // just append rest of state
4778 newFileLoc.append(state.substring(cp));
4782 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4783 newFileLoc = new StringBuilder(state);
4784 newFileLoc.append("; load append ");
4785 for (File id : oldFiles.keySet())
4787 // add this and any other pdb files that should be present in
4789 StructureData filedat = oldFiles.get(id);
4790 newFileLoc.append(filedat.getFilePath());
4791 pdbfilenames.add(filedat.getFilePath());
4792 pdbids.add(filedat.getPdbId());
4793 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4794 newFileLoc.append(" \"");
4795 newFileLoc.append(filedat.getFilePath());
4796 newFileLoc.append("\"");
4799 newFileLoc.append(";");
4802 if (newFileLoc.length() == 0)
4806 int histbug = newFileLoc.indexOf("history = ");
4810 * change "history = [true|false];" to "history = [1|0];"
4813 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4814 String val = (diff == -1) ? null
4815 : newFileLoc.substring(histbug, diff);
4816 if (val != null && val.length() >= 4)
4818 if (val.contains("e")) // eh? what can it be?
4820 if (val.trim().equals("true"))
4828 newFileLoc.replace(histbug, diff, val);
4833 final String[] pdbf = pdbfilenames
4834 .toArray(new String[pdbfilenames.size()]);
4835 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4836 final SequenceI[][] sq = seqmaps
4837 .toArray(new SequenceI[seqmaps.size()][]);
4838 final String fileloc = newFileLoc.toString();
4839 final String sviewid = viewerData.getKey();
4840 final AlignFrame alf = af;
4841 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4842 svattrib.getWidth(), svattrib.getHeight());
4844 // BH again was invokeAndWait
4847 javax.swing.SwingUtilities.invokeLater(new Runnable()
4852 JalviewStructureDisplayI sview = null;
4855 sview = new StructureViewer(
4856 alf.alignPanel.getStructureSelectionManager())
4857 .createView(StructureViewer.ViewerType.JMOL,
4858 pdbf, id, sq, alf.alignPanel, svattrib,
4859 fileloc, rect, sviewid);
4860 addNewStructureViewer(sview);
4861 } catch (OutOfMemoryError ex)
4863 new OOMWarning("restoring structure view for PDB id " + id,
4864 (OutOfMemoryError) ex.getCause());
4865 if (sview != null && sview.isVisible())
4867 sview.closeViewer(false);
4868 sview.setVisible(false);
4874 // } catch (InvocationTargetException ex)
4876 // warn("Unexpected error when opening Jmol view.", ex);
4878 // } catch (InterruptedException e)
4880 // // e.printStackTrace();
4886 * Generates a name for the entry in the project jar file to hold state
4887 * information for a structure viewer
4892 protected String getViewerJarEntryName(String viewId)
4894 return VIEWER_PREFIX + viewId;
4898 * Returns any open frame that matches given structure viewer data. The match
4899 * is based on the unique viewId, or (for older project versions) the frame's
4905 protected StructureViewerBase findMatchingViewer(
4906 Entry<String, StructureViewerModel> viewerData)
4908 final String sviewid = viewerData.getKey();
4909 final StructureViewerModel svattrib = viewerData.getValue();
4910 StructureViewerBase comp = null;
4911 JInternalFrame[] frames = getAllFrames();
4912 for (JInternalFrame frame : frames)
4914 if (frame instanceof StructureViewerBase)
4917 * Post jalview 2.4 schema includes structure view id
4919 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4922 comp = (StructureViewerBase) frame;
4923 break; // break added in 2.9
4926 * Otherwise test for matching position and size of viewer frame
4928 else if (frame.getX() == svattrib.getX()
4929 && frame.getY() == svattrib.getY()
4930 && frame.getHeight() == svattrib.getHeight()
4931 && frame.getWidth() == svattrib.getWidth())
4933 comp = (StructureViewerBase) frame;
4934 // no break in faint hope of an exact match on viewId
4942 * Link an AlignmentPanel to an existing structure viewer.
4947 * @param useinViewerSuperpos
4948 * @param usetoColourbyseq
4949 * @param viewerColouring
4951 protected void linkStructureViewer(AlignmentPanel ap,
4952 StructureViewerBase viewer, StructureViewerModel stateData)
4954 // NOTE: if the jalview project is part of a shared session then
4955 // view synchronization should/could be done here.
4957 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4958 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4959 final boolean viewerColouring = stateData.isColourByViewer();
4960 Map<File, StructureData> oldFiles = stateData.getFileData();
4963 * Add mapping for sequences in this view to an already open viewer
4965 final AAStructureBindingModel binding = viewer.getBinding();
4966 for (File id : oldFiles.keySet())
4968 // add this and any other pdb files that should be present in the
4970 StructureData filedat = oldFiles.get(id);
4971 String pdbFile = filedat.getFilePath();
4972 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4973 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4975 binding.addSequenceForStructFile(pdbFile, seq);
4977 // and add the AlignmentPanel's reference to the view panel
4978 viewer.addAlignmentPanel(ap);
4979 if (useinViewerSuperpos)
4981 viewer.useAlignmentPanelForSuperposition(ap);
4985 viewer.excludeAlignmentPanelForSuperposition(ap);
4987 if (usetoColourbyseq)
4989 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4993 viewer.excludeAlignmentPanelForColourbyseq(ap);
4998 * Get all frames within the Desktop.
5002 protected JInternalFrame[] getAllFrames()
5004 JInternalFrame[] frames = null;
5005 // TODO is this necessary - is it safe - risk of hanging?
5010 frames = Desktop.getDesktopPane().getAllFrames();
5011 } catch (ArrayIndexOutOfBoundsException e)
5013 // occasional No such child exceptions are thrown here...
5017 } catch (InterruptedException f)
5021 } while (frames == null);
5026 * Answers true if 'version' is equal to or later than 'supported', where each
5027 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5028 * changes. Development and test values for 'version' are leniently treated
5032 * - minimum version we are comparing against
5034 * - version of data being processsed
5037 public static boolean isVersionStringLaterThan(String supported,
5040 if (supported == null || version == null
5041 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5042 || version.equalsIgnoreCase("Test")
5043 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5045 System.err.println("Assuming project file with "
5046 + (version == null ? "null" : version)
5047 + " is compatible with Jalview version " + supported);
5052 return StringUtils.compareVersions(version, supported, "b") >= 0;
5056 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5058 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5060 if (newStructureViewers != null)
5062 sview.getBinding().setFinishedLoadingFromArchive(false);
5063 newStructureViewers.add(sview);
5067 protected void setLoadingFinishedForNewStructureViewers()
5069 if (newStructureViewers != null)
5071 for (JalviewStructureDisplayI sview : newStructureViewers)
5073 sview.getBinding().setFinishedLoadingFromArchive(true);
5075 newStructureViewers.clear();
5076 newStructureViewers = null;
5080 AlignFrame loadViewport(String fileName, File file, List<JSeq> JSEQ,
5081 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5082 Viewport view, String uniqueSeqSetId, String viewId,
5083 List<JvAnnotRow> autoAlan)
5085 AlignFrame af = null;
5086 af = new AlignFrame(al, safeInt(view.getWidth()),
5087 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5091 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5092 // System.out.println("Jalview2XML AF " + e);
5093 // super.processKeyEvent(e);
5099 af.alignPanel.setHoldRepaint(true);
5100 af.setFile(fileName, file, null, FileFormat.Jalview);
5101 af.setFileObject(jarFile); // BH 2019 JAL-3436
5103 final AlignViewport viewport = af.getViewport();
5104 for (int i = 0; i < JSEQ.size(); i++)
5106 int colour = safeInt(JSEQ.get(i).getColour());
5107 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5113 viewport.setColourByReferenceSeq(true);
5114 viewport.setDisplayReferenceSeq(true);
5117 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5119 if (view.getSequenceSetId() != null)
5121 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5123 viewport.setSequenceSetId(uniqueSeqSetId);
5126 // propagate shared settings to this new view
5127 viewport.setHistoryList(av.getHistoryList());
5128 viewport.setRedoList(av.getRedoList());
5132 viewportsAdded.put(uniqueSeqSetId, viewport);
5134 // TODO: check if this method can be called repeatedly without
5135 // side-effects if alignpanel already registered.
5136 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5138 // apply Hidden regions to view.
5139 if (hiddenSeqs != null)
5141 for (int s = 0; s < JSEQ.size(); s++)
5143 SequenceGroup hidden = new SequenceGroup();
5144 boolean isRepresentative = false;
5145 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5147 isRepresentative = true;
5148 SequenceI sequenceToHide = al
5149 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5150 hidden.addSequence(sequenceToHide, false);
5151 // remove from hiddenSeqs list so we don't try to hide it twice
5152 hiddenSeqs.remove(sequenceToHide);
5154 if (isRepresentative)
5156 SequenceI representativeSequence = al.getSequenceAt(s);
5157 hidden.addSequence(representativeSequence, false);
5158 viewport.hideRepSequences(representativeSequence, hidden);
5162 SequenceI[] hseqs = hiddenSeqs
5163 .toArray(new SequenceI[hiddenSeqs.size()]);
5164 viewport.hideSequence(hseqs);
5167 // recover view properties and display parameters
5169 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5170 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5171 final int pidThreshold = safeInt(view.getPidThreshold());
5172 viewport.setThreshold(pidThreshold);
5174 viewport.setColourText(safeBoolean(view.isShowColourText()));
5176 viewport.setConservationSelected(
5177 safeBoolean(view.isConservationSelected()));
5178 viewport.setIncrement(safeInt(view.getConsThreshold()));
5179 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5180 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5181 viewport.setFont(new Font(view.getFontName(),
5182 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
5184 ViewStyleI vs = viewport.getViewStyle();
5185 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5186 viewport.setViewStyle(vs);
5187 // TODO: allow custom charWidth/Heights to be restored by updating them
5188 // after setting font - which means set above to false
5189 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5190 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5191 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5193 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5195 viewport.setShowText(safeBoolean(view.isShowText()));
5197 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5198 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5199 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5200 viewport.setShowUnconserved(view.isShowUnconserved());
5201 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5203 if (view.getViewName() != null)
5205 viewport.setViewName(view.getViewName());
5206 af.setInitialTabVisible();
5208 int x = safeInt(view.getXpos());
5209 int y = safeInt(view.getYpos());
5210 int w = safeInt(view.getWidth());
5211 int h = safeInt(view.getHeight());
5212 // // BH we cannot let the title bar go off the top
5213 // if (Platform.isJS())
5215 // x = Math.max(50 - w, x);
5216 // y = Math.max(0, y);
5219 af.setBounds(x, y, w, h);
5220 // startSeq set in af.alignPanel.updateLayout below
5221 af.alignPanel.updateLayout();
5222 ColourSchemeI cs = null;
5223 // apply colourschemes
5224 if (view.getBgColour() != null)
5226 if (view.getBgColour().startsWith("ucs"))
5228 cs = getUserColourScheme(jm, view.getBgColour());
5230 else if (view.getBgColour().startsWith("Annotation"))
5232 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5233 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5240 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5241 view.getBgColour());
5246 * turn off 'alignment colour applies to all groups'
5247 * while restoring global colour scheme
5249 viewport.setColourAppliesToAllGroups(false);
5250 viewport.setGlobalColourScheme(cs);
5251 viewport.getResidueShading().setThreshold(pidThreshold,
5252 view.isIgnoreGapsinConsensus());
5253 viewport.getResidueShading()
5254 .setConsensus(viewport.getSequenceConsensusHash());
5255 if (safeBoolean(view.isConservationSelected()) && cs != null)
5257 viewport.getResidueShading()
5258 .setConservationInc(safeInt(view.getConsThreshold()));
5260 af.changeColour(cs);
5261 viewport.setColourAppliesToAllGroups(true);
5263 viewport.setShowSequenceFeatures(
5264 safeBoolean(view.isShowSequenceFeatures()));
5266 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5267 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5268 viewport.setFollowHighlight(view.isFollowHighlight());
5269 viewport.followSelection = view.isFollowSelection();
5270 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5271 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5272 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5273 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5274 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5275 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5276 viewport.setShowGroupConservation(view.isShowGroupConservation());
5277 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5278 viewport.setShowComplementFeaturesOnTop(
5279 view.isShowComplementFeaturesOnTop());
5281 // recover feature settings
5282 if (jm.getFeatureSettings() != null)
5284 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
5285 .getFeatureRenderer();
5286 FeaturesDisplayed fdi;
5287 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5288 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5290 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5291 Map<String, Float> featureOrder = new Hashtable<>();
5293 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5296 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5297 String featureType = setting.getType();
5300 * restore feature filters (if any)
5302 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5304 if (filters != null)
5306 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5308 if (!filter.isEmpty())
5310 fr.setFeatureFilter(featureType, filter);
5315 * restore feature colour scheme
5317 Color maxColour = new Color(setting.getColour());
5318 if (setting.getMincolour() != null)
5321 * minColour is always set unless a simple colour
5322 * (including for colour by label though it doesn't use it)
5324 Color minColour = new Color(setting.getMincolour().intValue());
5325 Color noValueColour = minColour;
5326 NoValueColour noColour = setting.getNoValueColour();
5327 if (noColour == NoValueColour.NONE)
5329 noValueColour = null;
5331 else if (noColour == NoValueColour.MAX)
5333 noValueColour = maxColour;
5335 float min = safeFloat(safeFloat(setting.getMin()));
5336 float max = setting.getMax() == null ? 1f
5337 : setting.getMax().floatValue();
5338 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5339 maxColour, noValueColour, min, max);
5340 if (setting.getAttributeName().size() > 0)
5342 gc.setAttributeName(setting.getAttributeName().toArray(
5343 new String[setting.getAttributeName().size()]));
5345 if (setting.getThreshold() != null)
5347 gc.setThreshold(setting.getThreshold().floatValue());
5348 int threshstate = safeInt(setting.getThreshstate());
5349 // -1 = None, 0 = Below, 1 = Above threshold
5350 if (threshstate == 0)
5352 gc.setBelowThreshold(true);
5354 else if (threshstate == 1)
5356 gc.setAboveThreshold(true);
5359 gc.setAutoScaled(true); // default
5360 if (setting.isAutoScale() != null)
5362 gc.setAutoScaled(setting.isAutoScale());
5364 if (setting.isColourByLabel() != null)
5366 gc.setColourByLabel(setting.isColourByLabel());
5368 // and put in the feature colour table.
5369 featureColours.put(featureType, gc);
5373 featureColours.put(featureType, new FeatureColour(maxColour));
5375 renderOrder[fs] = featureType;
5376 if (setting.getOrder() != null)
5378 featureOrder.put(featureType, setting.getOrder().floatValue());
5382 featureOrder.put(featureType, Float.valueOf(
5383 fs / jm.getFeatureSettings().getSetting().size()));
5385 if (safeBoolean(setting.isDisplay()))
5387 fdi.setVisible(featureType);
5390 Map<String, Boolean> fgtable = new Hashtable<>();
5391 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5393 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5394 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5396 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5397 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5398 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5399 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5400 fgtable, featureColours, 1.0f, featureOrder);
5401 fr.transferSettings(frs);
5404 if (view.getHiddenColumns().size() > 0)
5406 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5408 final HiddenColumns hc = view.getHiddenColumns().get(c);
5409 viewport.hideColumns(safeInt(hc.getStart()),
5410 safeInt(hc.getEnd()) /* +1 */);
5413 if (view.getCalcIdParam() != null)
5415 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5417 if (calcIdParam != null)
5419 if (recoverCalcIdParam(calcIdParam, viewport))
5424 warn("Couldn't recover parameters for "
5425 + calcIdParam.getCalcId());
5430 af.setMenusFromViewport(viewport);
5431 af.setTitle(view.getTitle());
5432 // TODO: we don't need to do this if the viewport is aready visible.
5434 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5435 * has a 'cdna/protein complement' view, in which case save it in order to
5436 * populate a SplitFrame once all views have been read in.
5438 String complementaryViewId = view.getComplementId();
5439 if (complementaryViewId == null)
5441 Dimension dim = Platform.getDimIfEmbedded(af,
5442 safeInt(view.getWidth()), safeInt(view.getHeight()));
5443 Desktop.addInternalFrame(af, view.getTitle(), dim.width, dim.height);
5444 // recompute any autoannotation
5445 af.alignPanel.updateAnnotation(false, true);
5446 reorderAutoannotation(af, al, autoAlan);
5447 af.alignPanel.alignmentChanged();
5451 splitFrameCandidates.put(view, af);
5457 * Reads saved data to restore Colour by Annotation settings
5459 * @param viewAnnColour
5463 * @param checkGroupAnnColour
5466 private ColourSchemeI constructAnnotationColour(
5467 AnnotationColourScheme viewAnnColour, AlignFrame af,
5468 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5470 boolean propagateAnnColour = false;
5471 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5473 if (checkGroupAnnColour && al.getGroups() != null
5474 && al.getGroups().size() > 0)
5476 // pre 2.8.1 behaviour
5477 // check to see if we should transfer annotation colours
5478 propagateAnnColour = true;
5479 for (SequenceGroup sg : al.getGroups())
5481 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5483 propagateAnnColour = false;
5489 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5491 String annotationId = viewAnnColour.getAnnotation();
5492 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5495 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5497 if (matchedAnnotation == null
5498 && annAlignment.getAlignmentAnnotation() != null)
5500 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5503 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5505 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5510 if (matchedAnnotation == null)
5512 System.err.println("Failed to match annotation colour scheme for "
5516 if (matchedAnnotation.getThreshold() == null)
5518 matchedAnnotation.setThreshold(
5519 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5520 "Threshold", Color.black));
5523 AnnotationColourGradient cs = null;
5524 if (viewAnnColour.getColourScheme().equals("None"))
5526 cs = new AnnotationColourGradient(matchedAnnotation,
5527 new Color(safeInt(viewAnnColour.getMinColour())),
5528 new Color(safeInt(viewAnnColour.getMaxColour())),
5529 safeInt(viewAnnColour.getAboveThreshold()));
5531 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5533 cs = new AnnotationColourGradient(matchedAnnotation,
5534 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5535 safeInt(viewAnnColour.getAboveThreshold()));
5539 cs = new AnnotationColourGradient(matchedAnnotation,
5540 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5541 viewAnnColour.getColourScheme()),
5542 safeInt(viewAnnColour.getAboveThreshold()));
5545 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5546 boolean useOriginalColours = safeBoolean(
5547 viewAnnColour.isPredefinedColours());
5548 cs.setSeqAssociated(perSequenceOnly);
5549 cs.setPredefinedColours(useOriginalColours);
5551 if (propagateAnnColour && al.getGroups() != null)
5553 // Also use these settings for all the groups
5554 for (int g = 0; g < al.getGroups().size(); g++)
5556 SequenceGroup sg = al.getGroups().get(g);
5557 if (sg.getGroupColourScheme() == null)
5562 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5563 matchedAnnotation, sg.getColourScheme(),
5564 safeInt(viewAnnColour.getAboveThreshold()));
5565 sg.setColourScheme(groupScheme);
5566 groupScheme.setSeqAssociated(perSequenceOnly);
5567 groupScheme.setPredefinedColours(useOriginalColours);
5573 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5574 List<JvAnnotRow> autoAlan)
5576 // copy over visualization settings for autocalculated annotation in the
5578 if (al.getAlignmentAnnotation() != null)
5581 * Kludge for magic autoannotation names (see JAL-811)
5583 String[] magicNames = new String[] { "Consensus", "Quality",
5585 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5586 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5587 for (String nm : magicNames)
5589 visan.put(nm, nullAnnot);
5591 for (JvAnnotRow auan : autoAlan)
5593 visan.put(auan.template.label
5594 + (auan.template.getCalcId() == null ? ""
5595 : "\t" + auan.template.getCalcId()),
5598 int hSize = al.getAlignmentAnnotation().length;
5599 List<JvAnnotRow> reorder = new ArrayList<>();
5600 // work through any autoCalculated annotation already on the view
5601 // removing it if it should be placed in a different location on the
5602 // annotation panel.
5603 List<String> remains = new ArrayList<>(visan.keySet());
5604 for (int h = 0; h < hSize; h++)
5606 jalview.datamodel.AlignmentAnnotation jalan = al
5607 .getAlignmentAnnotation()[h];
5608 if (jalan.autoCalculated)
5611 JvAnnotRow valan = visan.get(k = jalan.label);
5612 if (jalan.getCalcId() != null)
5614 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5619 // delete the auto calculated row from the alignment
5620 al.deleteAnnotation(jalan, false);
5624 if (valan != nullAnnot)
5626 if (jalan != valan.template)
5628 // newly created autoannotation row instance
5629 // so keep a reference to the visible annotation row
5630 // and copy over all relevant attributes
5631 if (valan.template.graphHeight >= 0)
5634 jalan.graphHeight = valan.template.graphHeight;
5636 jalan.visible = valan.template.visible;
5638 reorder.add(new JvAnnotRow(valan.order, jalan));
5643 // Add any (possibly stale) autocalculated rows that were not appended to
5644 // the view during construction
5645 for (String other : remains)
5647 JvAnnotRow othera = visan.get(other);
5648 if (othera != nullAnnot && othera.template.getCalcId() != null
5649 && othera.template.getCalcId().length() > 0)
5651 reorder.add(othera);
5654 // now put the automatic annotation in its correct place
5655 int s = 0, srt[] = new int[reorder.size()];
5656 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5657 for (JvAnnotRow jvar : reorder)
5660 srt[s++] = jvar.order;
5663 jalview.util.QuickSort.sort(srt, rws);
5664 // and re-insert the annotation at its correct position
5665 for (JvAnnotRow jvar : rws)
5667 al.addAnnotation(jvar.template, jvar.order);
5669 af.alignPanel.adjustAnnotationHeight();
5673 Hashtable skipList = null;
5676 * TODO remove this method
5679 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5680 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5681 * throw new Error("Implementation Error. No skipList defined for this
5682 * Jalview2XML instance."); } return (AlignFrame)
5683 * skipList.get(view.getSequenceSetId()); }
5687 * Check if the Jalview view contained in object should be skipped or not.
5690 * @return true if view's sequenceSetId is a key in skipList
5692 private boolean skipViewport(JalviewModel object)
5694 if (skipList == null)
5698 String id = object.getViewport().get(0).getSequenceSetId();
5699 if (skipList.containsKey(id))
5701 if (Cache.log != null && Cache.log.isDebugEnabled())
5703 Cache.log.debug("Skipping seuqence set id " + id);
5710 protected void addToSkipList(AlignFrame af)
5712 if (skipList == null)
5714 skipList = new Hashtable();
5716 skipList.put(af.getViewport().getSequenceSetId(), af);
5719 protected void clearSkipList()
5721 if (skipList != null)
5728 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5729 boolean ignoreUnrefed, String uniqueSeqSetId)
5731 jalview.datamodel.AlignmentI ds = getDatasetFor(
5732 vamsasSet.getDatasetId());
5733 AlignmentI xtant_ds = ds;
5734 if (xtant_ds == null)
5736 // good chance we are about to create a new dataset, but check if we've
5737 // seen some of the dataset sequence IDs before.
5738 // TODO: skip this check if we are working with project generated by
5739 // version 2.11 or later
5740 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5741 if (xtant_ds != null)
5744 addDatasetRef(vamsasSet.getDatasetId(), ds);
5747 Vector dseqs = null;
5750 // recovering an alignment View
5751 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5752 if (seqSetDS != null)
5754 if (ds != null && ds != seqSetDS)
5756 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5757 + " - CDS/Protein crossreference data may be lost");
5758 if (xtant_ds != null)
5760 // This can only happen if the unique sequence set ID was bound to a
5761 // dataset that did not contain any of the sequences in the view
5762 // currently being restored.
5763 warn("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.");
5767 addDatasetRef(vamsasSet.getDatasetId(), ds);
5772 // try even harder to restore dataset
5773 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5774 // create a list of new dataset sequences
5775 dseqs = new Vector();
5777 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5779 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5780 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5782 // create a new dataset
5785 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5786 dseqs.copyInto(dsseqs);
5787 ds = new jalview.datamodel.Alignment(dsseqs);
5788 // debug("Jalview2XML Created new dataset " + vamsasSet.getDatasetId()
5789 // + " for alignment " + System.identityHashCode(al));
5790 addDatasetRef(vamsasSet.getDatasetId(), ds);
5792 // set the dataset for the newly imported alignment.
5793 if (al.getDataset() == null && !ignoreUnrefed)
5796 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5797 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5799 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5803 * XML dataset sequence ID to materialised dataset reference
5805 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5808 * @return the first materialised dataset reference containing a dataset
5809 * sequence referenced in the given view
5811 * - sequences from the view
5813 AlignmentI checkIfHasDataset(List<Sequence> list)
5815 for (Sequence restoredSeq : list)
5817 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5818 if (datasetFor != null)
5827 * Register ds as the containing dataset for the dataset sequences referenced
5828 * by sequences in list
5831 * - sequences in a view
5834 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5836 for (Sequence restoredSeq : list)
5838 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5839 if (prevDS != null && prevDS != ds)
5841 warn("Dataset sequence appears in many datasets: "
5842 + restoredSeq.getDsseqid());
5843 // TODO: try to merge!
5850 * sequence definition to create/merge dataset sequence for
5854 * vector to add new dataset sequence to
5855 * @param ignoreUnrefed
5856 * - when true, don't create new sequences from vamsasSeq if it's id
5857 * doesn't already have an asssociated Jalview sequence.
5859 * - used to reorder the sequence in the alignment according to the
5860 * vamsasSeq array ordering, to preserve ordering of dataset
5862 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5863 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5865 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5867 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5868 boolean reorder = false;
5869 SequenceI dsq = null;
5870 if (sq != null && sq.getDatasetSequence() != null)
5872 dsq = sq.getDatasetSequence();
5878 if (sq == null && ignoreUnrefed)
5882 String sqid = vamsasSeq.getDsseqid();
5885 // need to create or add a new dataset sequence reference to this sequence
5888 dsq = seqRefIds.get(sqid);
5893 // make a new dataset sequence
5894 dsq = sq.createDatasetSequence();
5897 // make up a new dataset reference for this sequence
5898 sqid = seqHash(dsq);
5900 dsq.setVamsasId(uniqueSetSuffix + sqid);
5901 seqRefIds.put(sqid, dsq);
5906 dseqs.addElement(dsq);
5911 ds.addSequence(dsq);
5917 { // make this dataset sequence sq's dataset sequence
5918 sq.setDatasetSequence(dsq);
5919 // and update the current dataset alignment
5924 if (!dseqs.contains(dsq))
5931 if (ds.findIndex(dsq) < 0)
5933 ds.addSequence(dsq);
5940 // TODO: refactor this as a merge dataset sequence function
5941 // now check that sq (the dataset sequence) sequence really is the union of
5942 // all references to it
5943 // boolean pre = sq.getStart() < dsq.getStart();
5944 // boolean post = sq.getEnd() > dsq.getEnd();
5948 // StringBuffer sb = new StringBuffer();
5949 String newres = jalview.analysis.AlignSeq.extractGaps(
5950 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5951 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5952 && newres.length() > dsq.getLength())
5954 // Update with the longer sequence.
5958 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5959 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5960 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5961 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5963 dsq.setSequence(newres);
5965 // TODO: merges will never happen if we 'know' we have the real dataset
5966 // sequence - this should be detected when id==dssid
5968 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5969 // + (pre ? "prepended" : "") + " "
5970 // + (post ? "appended" : ""));
5975 // sequence refs are identical. We may need to update the existing dataset
5976 // alignment with this one, though.
5977 if (ds != null && dseqs == null)
5979 int opos = ds.findIndex(dsq);
5980 SequenceI tseq = null;
5981 if (opos != -1 && vseqpos != opos)
5983 // remove from old position
5984 ds.deleteSequence(dsq);
5986 if (vseqpos < ds.getHeight())
5988 if (vseqpos != opos)
5990 // save sequence at destination position
5991 tseq = ds.getSequenceAt(vseqpos);
5992 ds.replaceSequenceAt(vseqpos, dsq);
5993 ds.addSequence(tseq);
5998 ds.addSequence(dsq);
6005 * TODO use AlignmentI here and in related methods - needs
6006 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6008 Hashtable<String, AlignmentI> datasetIds = null;
6010 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6012 private AlignmentI getDatasetFor(String datasetId)
6014 if (datasetIds == null)
6016 datasetIds = new Hashtable<>();
6019 if (datasetIds.containsKey(datasetId))
6021 return datasetIds.get(datasetId);
6026 private void addDatasetRef(String datasetId, AlignmentI dataset)
6028 if (datasetIds == null)
6030 datasetIds = new Hashtable<>();
6032 datasetIds.put(datasetId, dataset);
6036 * make a new dataset ID for this jalview dataset alignment
6041 private String getDatasetIdRef(AlignmentI dataset)
6043 if (dataset.getDataset() != null)
6045 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6047 String datasetId = makeHashCode(dataset, null);
6048 if (datasetId == null)
6050 // make a new datasetId and record it
6051 if (dataset2Ids == null)
6053 dataset2Ids = new IdentityHashMap<>();
6057 datasetId = dataset2Ids.get(dataset);
6059 if (datasetId == null)
6061 datasetId = "ds" + dataset2Ids.size() + 1;
6062 dataset2Ids.put(dataset, datasetId);
6069 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6070 * constructed as a special subclass GeneLocus.
6072 * @param datasetSequence
6075 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6077 for (int d = 0; d < sequence.getDBRef().size(); d++)
6079 DBRef dr = sequence.getDBRef().get(d);
6083 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6084 dr.getAccessionId());
6088 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6089 dr.getAccessionId());
6091 if (dr.getMapping() != null)
6093 entry.setMap(addMapping(dr.getMapping()));
6095 datasetSequence.addDBRef(entry);
6099 private jalview.datamodel.Mapping addMapping(Mapping m)
6101 SequenceI dsto = null;
6102 // Mapping m = dr.getMapping();
6103 int fr[] = new int[m.getMapListFrom().size() * 2];
6104 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6105 for (int _i = 0; from.hasNext(); _i += 2)
6107 MapListFrom mf = from.next();
6108 fr[_i] = mf.getStart();
6109 fr[_i + 1] = mf.getEnd();
6111 int fto[] = new int[m.getMapListTo().size() * 2];
6112 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6113 for (int _i = 0; to.hasNext(); _i += 2)
6115 MapListTo mf = to.next();
6116 fto[_i] = mf.getStart();
6117 fto[_i + 1] = mf.getEnd();
6119 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6120 fto, m.getMapFromUnit().intValue(),
6121 m.getMapToUnit().intValue());
6124 * (optional) choice of dseqFor or Sequence
6126 if (m.getDseqFor() != null)
6128 String dsfor = m.getDseqFor();
6129 if (seqRefIds.containsKey(dsfor))
6134 jmap.setTo(seqRefIds.get(dsfor));
6138 frefedSequence.add(newMappingRef(dsfor, jmap));
6141 else if (m.getSequence() != null)
6144 * local sequence definition
6146 Sequence ms = m.getSequence();
6147 SequenceI djs = null;
6148 String sqid = ms.getDsseqid();
6149 if (sqid != null && sqid.length() > 0)
6152 * recover dataset sequence
6154 djs = seqRefIds.get(sqid);
6159 "Warning - making up dataset sequence id for DbRef sequence map reference");
6160 sqid = ((Object) ms).toString(); // make up a new hascode for
6161 // undefined dataset sequence hash
6162 // (unlikely to happen)
6168 * make a new dataset sequence and add it to refIds hash
6170 djs = new jalview.datamodel.Sequence(ms.getName(),
6172 djs.setStart(jmap.getMap().getToLowest());
6173 djs.setEnd(jmap.getMap().getToHighest());
6174 djs.setVamsasId(uniqueSetSuffix + sqid);
6176 incompleteSeqs.put(sqid, djs);
6177 seqRefIds.put(sqid, djs);
6179 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
6188 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6189 * view as XML (but not to file), and then reloading it
6194 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6197 JalviewModel jm = saveState(ap, null, null, null);
6200 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6201 ap.getAlignment().getDataset());
6203 uniqueSetSuffix = "";
6204 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6205 jm.getViewport().get(0).setId(null);
6206 // we don't overwrite the view we just copied
6208 if (this.frefedSequence == null)
6210 frefedSequence = new Vector<>();
6213 viewportsAdded.clear();
6215 AlignFrame af = loadFromObject(jm, null, null, false, null);
6216 af.getAlignPanels().clear();
6217 af.closeMenuItem_actionPerformed(true);
6218 af.alignPanel.setHoldRepaint(false);
6219 this.jarFile = null;
6222 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6223 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6224 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6225 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6226 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6229 return af.alignPanel;
6232 private Hashtable jvids2vobj;
6234 private void warn(String msg)
6239 private void warn(String msg, Exception e)
6241 if (Cache.log != null)
6245 Cache.log.warn(msg, e);
6249 Cache.log.warn(msg);
6254 System.err.println("Warning: " + msg);
6257 e.printStackTrace();
6262 private void debug(String string)
6264 debug(string, null);
6267 private void debug(String msg, Exception e)
6269 if (Cache.log != null)
6273 Cache.log.debug(msg, e);
6277 Cache.log.debug(msg);
6282 System.err.println("Warning: " + msg);
6285 e.printStackTrace();
6291 * set the object to ID mapping tables used to write/recover objects and XML
6292 * ID strings for the jalview project. If external tables are provided then
6293 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6294 * object goes out of scope. - also populates the datasetIds hashtable with
6295 * alignment objects containing dataset sequences
6298 * Map from ID strings to jalview datamodel
6300 * Map from jalview datamodel to ID strings
6304 public void setObjectMappingTables(Hashtable vobj2jv,
6305 IdentityHashMap jv2vobj)
6307 this.jv2vobj = jv2vobj;
6308 this.vobj2jv = vobj2jv;
6309 Iterator ds = jv2vobj.keySet().iterator();
6311 while (ds.hasNext())
6313 Object jvobj = ds.next();
6314 id = jv2vobj.get(jvobj).toString();
6315 if (jvobj instanceof jalview.datamodel.Alignment)
6317 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6319 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6322 else if (jvobj instanceof jalview.datamodel.Sequence)
6324 // register sequence object so the XML parser can recover it.
6325 if (seqRefIds == null)
6327 seqRefIds = new HashMap<>();
6329 if (seqsToIds == null)
6331 seqsToIds = new IdentityHashMap<>();
6333 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6334 seqsToIds.put((SequenceI) jvobj, id);
6336 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6339 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6340 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6341 if (jvann.annotationId == null)
6343 jvann.annotationId = anid;
6345 if (!jvann.annotationId.equals(anid))
6347 // TODO verify that this is the correct behaviour
6348 this.warn("Overriding Annotation ID for " + anid
6349 + " from different id : " + jvann.annotationId);
6350 jvann.annotationId = anid;
6353 else if (jvobj instanceof String)
6355 if (jvids2vobj == null)
6357 jvids2vobj = new Hashtable();
6358 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6363 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6369 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6370 * objects created from the project archive. If string is null (default for
6371 * construction) then suffix will be set automatically.
6375 public void setUniqueSetSuffix(String string)
6377 uniqueSetSuffix = string;
6382 * uses skipList2 as the skipList for skipping views on sequence sets
6383 * associated with keys in the skipList
6387 public void setSkipList(Hashtable skipList2)
6389 skipList = skipList2;
6393 * Reads the jar entry of given name and returns its contents, or null if the
6394 * entry is not found.
6397 * @param jarEntryName
6400 protected String readJarEntry(jarInputStreamProvider jprovider,
6401 String jarEntryName)
6403 String result = null;
6404 BufferedReader in = null;
6409 * Reopen the jar input stream and traverse its entries to find a matching
6412 JarInputStream jin = jprovider.getJarInputStream();
6413 JarEntry entry = null;
6416 entry = jin.getNextJarEntry();
6417 } while (entry != null && !entry.getName().equals(jarEntryName));
6421 StringBuilder out = new StringBuilder(256);
6422 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6425 while ((data = in.readLine()) != null)
6429 result = out.toString();
6433 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6435 } catch (Exception ex)
6437 ex.printStackTrace();
6445 } catch (IOException e)
6456 * Returns an incrementing counter (0, 1, 2...)
6460 private synchronized int nextCounter()
6466 * Loads any saved PCA viewers
6471 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6475 List<PcaViewer> pcaviewers = model.getPcaViewer();
6476 for (PcaViewer viewer : pcaviewers)
6478 String modelName = viewer.getScoreModelName();
6479 SimilarityParamsI params = new SimilarityParams(
6480 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6481 viewer.isIncludeGaps(),
6482 viewer.isDenominateByShortestLength());
6485 * create the panel (without computing the PCA)
6487 PCAPanel panel = new PCAPanel(ap, modelName, params);
6489 panel.setTitle(viewer.getTitle());
6490 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6491 viewer.getWidth(), viewer.getHeight()));
6493 boolean showLabels = viewer.isShowLabels();
6494 panel.setShowLabels(showLabels);
6495 panel.getRotatableCanvas().setShowLabels(showLabels);
6496 panel.getRotatableCanvas()
6497 .setBgColour(new Color(viewer.getBgColour()));
6498 panel.getRotatableCanvas()
6499 .setApplyToAllViews(viewer.isLinkToAllViews());
6502 * load PCA output data
6504 ScoreModelI scoreModel = ScoreModels.getInstance()
6505 .getScoreModel(modelName, ap);
6506 PCA pca = new PCA(null, scoreModel, params);
6507 PcaDataType pcaData = viewer.getPcaData();
6509 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6510 pca.setPairwiseScores(pairwise);
6512 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6513 pca.setTridiagonal(triDiag);
6515 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6516 pca.setEigenmatrix(result);
6518 panel.getPcaModel().setPCA(pca);
6521 * we haven't saved the input data! (JAL-2647 to do)
6523 panel.setInputData(null);
6526 * add the sequence points for the PCA display
6528 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6529 for (SequencePoint sp : viewer.getSequencePoint())
6531 String seqId = sp.getSequenceRef();
6532 SequenceI seq = seqRefIds.get(seqId);
6535 throw new IllegalStateException(
6536 "Unmatched seqref for PCA: " + seqId);
6538 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6539 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6541 seqPoints.add(seqPoint);
6543 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6546 * set min-max ranges and scale after setPoints (which recomputes them)
6548 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6549 SeqPointMin spMin = viewer.getSeqPointMin();
6550 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6552 SeqPointMax spMax = viewer.getSeqPointMax();
6553 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6555 panel.getRotatableCanvas().setSeqMinMax(min, max);
6557 // todo: hold points list in PCAModel only
6558 panel.getPcaModel().setSequencePoints(seqPoints);
6560 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6561 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6562 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6564 // is this duplication needed?
6565 panel.setTop(seqPoints.size() - 1);
6566 panel.getPcaModel().setTop(seqPoints.size() - 1);
6569 * add the axes' end points for the display
6571 for (int i = 0; i < 3; i++)
6573 Axis axis = viewer.getAxis().get(i);
6574 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6575 axis.getXPos(), axis.getYPos(), axis.getZPos());
6578 Dimension dim = Platform.getDimIfEmbedded(panel, 475, 450);
6579 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6580 "label.calc_title", "PCA", modelName), dim.width,
6583 } catch (Exception ex)
6585 Cache.log.error("Error loading PCA: " + ex.toString());
6590 * Populates an XML model of the feature colour scheme for one feature type
6592 * @param featureType
6596 public static Colour marshalColour(
6597 String featureType, FeatureColourI fcol)
6599 Colour col = new Colour();
6600 if (fcol.isSimpleColour())
6602 col.setRGB(Format.getHexString(fcol.getColour()));
6606 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6607 col.setMin(fcol.getMin());
6608 col.setMax(fcol.getMax());
6609 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6610 col.setAutoScale(fcol.isAutoScaled());
6611 col.setThreshold(fcol.getThreshold());
6612 col.setColourByLabel(fcol.isColourByLabel());
6613 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6614 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6615 : ThresholdType.NONE));
6616 if (fcol.isColourByAttribute())
6618 final String[] attName = fcol.getAttributeName();
6619 col.getAttributeName().add(attName[0]);
6620 if (attName.length > 1)
6622 col.getAttributeName().add(attName[1]);
6625 Color noColour = fcol.getNoColour();
6626 if (noColour == null)
6628 col.setNoValueColour(NoValueColour.NONE);
6630 else if (noColour == fcol.getMaxColour())
6632 col.setNoValueColour(NoValueColour.MAX);
6636 col.setNoValueColour(NoValueColour.MIN);
6639 col.setName(featureType);
6644 * Populates an XML model of the feature filter(s) for one feature type
6646 * @param firstMatcher
6647 * the first (or only) match condition)
6649 * remaining match conditions (if any)
6651 * if true, conditions are and-ed, else or-ed
6653 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6654 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6657 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6659 if (filters.hasNext())
6664 CompoundMatcher compound = new CompoundMatcher();
6665 compound.setAnd(and);
6666 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6667 firstMatcher, Collections.emptyIterator(), and);
6668 // compound.addMatcherSet(matcher1);
6669 compound.getMatcherSet().add(matcher1);
6670 FeatureMatcherI nextMatcher = filters.next();
6671 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6672 nextMatcher, filters, and);
6673 // compound.addMatcherSet(matcher2);
6674 compound.getMatcherSet().add(matcher2);
6675 result.setCompoundMatcher(compound);
6680 * single condition matcher
6682 // MatchCondition matcherModel = new MatchCondition();
6683 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6684 matcherModel.setCondition(
6685 firstMatcher.getMatcher().getCondition().getStableName());
6686 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6687 if (firstMatcher.isByAttribute())
6689 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6690 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6691 String[] attName = firstMatcher.getAttribute();
6692 matcherModel.getAttributeName().add(attName[0]); // attribute
6693 if (attName.length > 1)
6695 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6698 else if (firstMatcher.isByLabel())
6700 matcherModel.setBy(FilterBy.BY_LABEL);
6702 else if (firstMatcher.isByScore())
6704 matcherModel.setBy(FilterBy.BY_SCORE);
6706 result.setMatchCondition(matcherModel);
6713 * Loads one XML model of a feature filter to a Jalview object
6715 * @param featureType
6716 * @param matcherSetModel
6719 public static FeatureMatcherSetI parseFilter(
6721 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6723 FeatureMatcherSetI result = new FeatureMatcherSet();
6726 parseFilterConditions(result, matcherSetModel, true);
6727 } catch (IllegalStateException e)
6729 // mixing AND and OR conditions perhaps
6731 String.format("Error reading filter conditions for '%s': %s",
6732 featureType, e.getMessage()));
6733 // return as much as was parsed up to the error
6740 * Adds feature match conditions to matcherSet as unmarshalled from XML
6741 * (possibly recursively for compound conditions)
6744 * @param matcherSetModel
6746 * if true, multiple conditions are AND-ed, else they are OR-ed
6747 * @throws IllegalStateException
6748 * if AND and OR conditions are mixed
6750 protected static void parseFilterConditions(
6751 FeatureMatcherSetI matcherSet,
6752 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6755 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6756 .getMatchCondition();
6762 FilterBy filterBy = mc.getBy();
6763 Condition cond = Condition.fromString(mc.getCondition());
6764 String pattern = mc.getValue();
6765 FeatureMatcherI matchCondition = null;
6766 if (filterBy == FilterBy.BY_LABEL)
6768 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6770 else if (filterBy == FilterBy.BY_SCORE)
6772 matchCondition = FeatureMatcher.byScore(cond, pattern);
6775 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6777 final List<String> attributeName = mc.getAttributeName();
6778 String[] attNames = attributeName
6779 .toArray(new String[attributeName.size()]);
6780 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6785 * note this throws IllegalStateException if AND-ing to a
6786 * previously OR-ed compound condition, or vice versa
6790 matcherSet.and(matchCondition);
6794 matcherSet.or(matchCondition);
6800 * compound condition
6802 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6803 .getCompoundMatcher().getMatcherSet();
6804 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6805 if (matchers.size() == 2)
6807 parseFilterConditions(matcherSet, matchers.get(0), anded);
6808 parseFilterConditions(matcherSet, matchers.get(1), anded);
6812 System.err.println("Malformed compound filter condition");
6818 * Loads one XML model of a feature colour to a Jalview object
6820 * @param colourModel
6823 public static FeatureColourI parseColour(Colour colourModel)
6825 FeatureColourI colour = null;
6827 if (colourModel.getMax() != null)
6829 Color mincol = null;
6830 Color maxcol = null;
6831 Color noValueColour = null;
6835 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6836 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6837 } catch (Exception e)
6839 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6842 NoValueColour noCol = colourModel.getNoValueColour();
6843 if (noCol == NoValueColour.MIN)
6845 noValueColour = mincol;
6847 else if (noCol == NoValueColour.MAX)
6849 noValueColour = maxcol;
6852 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6853 safeFloat(colourModel.getMin()),
6854 safeFloat(colourModel.getMax()));
6855 final List<String> attributeName = colourModel.getAttributeName();
6856 String[] attributes = attributeName
6857 .toArray(new String[attributeName.size()]);
6858 if (attributes != null && attributes.length > 0)
6860 colour.setAttributeName(attributes);
6862 if (colourModel.isAutoScale() != null)
6864 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6866 if (colourModel.isColourByLabel() != null)
6868 colour.setColourByLabel(
6869 colourModel.isColourByLabel().booleanValue());
6871 if (colourModel.getThreshold() != null)
6873 colour.setThreshold(colourModel.getThreshold().floatValue());
6875 ThresholdType ttyp = colourModel.getThreshType();
6876 if (ttyp == ThresholdType.ABOVE)
6878 colour.setAboveThreshold(true);
6880 else if (ttyp == ThresholdType.BELOW)
6882 colour.setBelowThreshold(true);
6887 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6888 colour = new FeatureColour(color);