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.GraphLine;
44 import jalview.datamodel.PDBEntry;
45 import jalview.datamodel.Point;
46 import jalview.datamodel.RnaViewerModel;
47 import jalview.datamodel.SequenceFeature;
48 import jalview.datamodel.SequenceGroup;
49 import jalview.datamodel.SequenceI;
50 import jalview.datamodel.StructureViewerModel;
51 import jalview.datamodel.StructureViewerModel.StructureData;
52 import jalview.datamodel.features.FeatureMatcher;
53 import jalview.datamodel.features.FeatureMatcherI;
54 import jalview.datamodel.features.FeatureMatcherSet;
55 import jalview.datamodel.features.FeatureMatcherSetI;
56 import jalview.ext.varna.RnaModel;
57 import jalview.gui.AlignFrame;
58 import jalview.gui.AlignViewport;
59 import jalview.gui.AlignmentPanel;
60 import jalview.gui.AppVarna;
61 import jalview.gui.ChimeraViewFrame;
62 import jalview.gui.Desktop;
63 import jalview.gui.FeatureRenderer;
64 import jalview.gui.JvOptionPane;
65 import jalview.gui.OOMWarning;
66 import jalview.gui.PCAPanel;
67 import jalview.gui.PaintRefresher;
68 import jalview.gui.SplitFrame;
69 import jalview.gui.StructureViewer;
70 import jalview.gui.StructureViewer.ViewerType;
71 import jalview.gui.StructureViewerBase;
72 import jalview.gui.TreePanel;
73 import jalview.io.BackupFiles;
74 import jalview.io.DataSourceType;
75 import jalview.io.FileFormat;
76 import jalview.io.NewickFile;
77 import jalview.math.Matrix;
78 import jalview.math.MatrixI;
79 import jalview.renderer.ResidueShaderI;
80 import jalview.schemes.AnnotationColourGradient;
81 import jalview.schemes.ColourSchemeI;
82 import jalview.schemes.ColourSchemeProperty;
83 import jalview.schemes.FeatureColour;
84 import jalview.schemes.ResidueProperties;
85 import jalview.schemes.UserColourScheme;
86 import jalview.structures.models.AAStructureBindingModel;
87 import jalview.util.Format;
88 import jalview.util.MessageManager;
89 import jalview.util.Platform;
90 import jalview.util.StringUtils;
91 import jalview.util.jarInputStreamProvider;
92 import jalview.util.matcher.Condition;
93 import jalview.viewmodel.AlignmentViewport;
94 import jalview.viewmodel.PCAModel;
95 import jalview.viewmodel.ViewportRanges;
96 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
97 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
98 import jalview.ws.jws2.Jws2Discoverer;
99 import jalview.ws.jws2.dm.AAConSettings;
100 import jalview.ws.jws2.jabaws2.Jws2Instance;
101 import jalview.ws.params.ArgumentI;
102 import jalview.ws.params.AutoCalcSetting;
103 import jalview.ws.params.WsParamSetI;
104 import jalview.xml.binding.jalview.AlcodonFrame;
105 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
106 import jalview.xml.binding.jalview.Annotation;
107 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
108 import jalview.xml.binding.jalview.AnnotationColourScheme;
109 import jalview.xml.binding.jalview.AnnotationElement;
110 import jalview.xml.binding.jalview.DoubleMatrix;
111 import jalview.xml.binding.jalview.DoubleVector;
112 import jalview.xml.binding.jalview.Feature;
113 import jalview.xml.binding.jalview.Feature.OtherData;
114 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
115 import jalview.xml.binding.jalview.FilterBy;
116 import jalview.xml.binding.jalview.JalviewModel;
117 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
118 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
119 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
120 import jalview.xml.binding.jalview.JalviewModel.JGroup;
121 import jalview.xml.binding.jalview.JalviewModel.JSeq;
122 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
123 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
124 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
125 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
126 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
127 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
128 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
129 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
130 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
131 import jalview.xml.binding.jalview.JalviewModel.Tree;
132 import jalview.xml.binding.jalview.JalviewModel.UserColours;
133 import jalview.xml.binding.jalview.JalviewModel.Viewport;
134 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
135 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
136 import jalview.xml.binding.jalview.JalviewUserColours;
137 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
138 import jalview.xml.binding.jalview.MapListType.MapListFrom;
139 import jalview.xml.binding.jalview.MapListType.MapListTo;
140 import jalview.xml.binding.jalview.Mapping;
141 import jalview.xml.binding.jalview.NoValueColour;
142 import jalview.xml.binding.jalview.ObjectFactory;
143 import jalview.xml.binding.jalview.PcaDataType;
144 import jalview.xml.binding.jalview.Pdbentry.Property;
145 import jalview.xml.binding.jalview.Sequence;
146 import jalview.xml.binding.jalview.Sequence.DBRef;
147 import jalview.xml.binding.jalview.SequenceSet;
148 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
149 import jalview.xml.binding.jalview.ThresholdType;
150 import jalview.xml.binding.jalview.VAMSAS;
152 import java.awt.Color;
153 import java.awt.Font;
154 import java.awt.Rectangle;
155 import java.io.BufferedReader;
156 import java.io.ByteArrayInputStream;
157 import java.io.DataInputStream;
158 import java.io.DataOutputStream;
160 import java.io.FileInputStream;
161 import java.io.FileOutputStream;
162 import java.io.IOException;
163 import java.io.InputStreamReader;
164 import java.io.OutputStreamWriter;
165 import java.io.PrintWriter;
166 import java.math.BigInteger;
167 import java.net.MalformedURLException;
169 import java.util.ArrayList;
170 import java.util.Arrays;
171 import java.util.Collections;
172 import java.util.Enumeration;
173 import java.util.GregorianCalendar;
174 import java.util.HashMap;
175 import java.util.HashSet;
176 import java.util.Hashtable;
177 import java.util.IdentityHashMap;
178 import java.util.Iterator;
179 import java.util.LinkedHashMap;
180 import java.util.List;
181 import java.util.Map;
182 import java.util.Map.Entry;
183 import java.util.Set;
184 import java.util.Vector;
185 import java.util.jar.JarEntry;
186 import java.util.jar.JarInputStream;
187 import java.util.jar.JarOutputStream;
189 import javax.swing.JInternalFrame;
190 import javax.swing.SwingUtilities;
191 import javax.xml.bind.JAXBContext;
192 import javax.xml.bind.JAXBElement;
193 import javax.xml.bind.Marshaller;
194 import javax.xml.datatype.DatatypeConfigurationException;
195 import javax.xml.datatype.DatatypeFactory;
196 import javax.xml.datatype.XMLGregorianCalendar;
197 import javax.xml.stream.XMLInputFactory;
198 import javax.xml.stream.XMLStreamReader;
201 * Write out the current jalview desktop state as a Jalview XML stream.
203 * Note: the vamsas objects referred to here are primitive versions of the
204 * VAMSAS project schema elements - they are not the same and most likely never
208 * @version $Revision: 1.134 $
210 public class Jalview2XML
213 // BH 2018 we add the .jvp binary extension to J2S so that
214 // it will declare that binary when we do the file save from the browser
218 Platform.addJ2SBinaryType(".jvp?");
221 private static final String VIEWER_PREFIX = "viewer_";
223 private static final String RNA_PREFIX = "rna_";
225 private static final String UTF_8 = "UTF-8";
228 * prefix for recovering datasets for alignments with multiple views where
229 * non-existent dataset IDs were written for some views
231 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
233 // use this with nextCounter() to make unique names for entities
234 private int counter = 0;
237 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
238 * of sequence objects are created.
240 IdentityHashMap<SequenceI, String> seqsToIds = null;
243 * jalview XML Sequence ID to jalview sequence object reference (both dataset
244 * and alignment sequences. Populated as XML reps of sequence objects are
247 Map<String, SequenceI> seqRefIds = null;
249 Map<String, SequenceI> incompleteSeqs = null;
251 List<SeqFref> frefedSequence = null;
253 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
256 * Map of reconstructed AlignFrame objects that appear to have come from
257 * SplitFrame objects (have a dna/protein complement view).
259 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
262 * Map from displayed rna structure models to their saved session state jar
265 private Map<RnaModel, String> rnaSessions = new HashMap<>();
268 * A helper method for safely using the value of an optional attribute that
269 * may be null if not present in the XML. Answers the boolean value, or false
275 public static boolean safeBoolean(Boolean b)
277 return b == null ? false : b.booleanValue();
281 * A helper method for safely using the value of an optional attribute that
282 * may be null if not present in the XML. Answers the integer value, or zero
288 public static int safeInt(Integer i)
290 return i == null ? 0 : i.intValue();
294 * A helper method for safely using the value of an optional attribute that
295 * may be null if not present in the XML. Answers the float value, or zero if
301 public static float safeFloat(Float f)
303 return f == null ? 0f : f.floatValue();
307 * create/return unique hash string for sq
310 * @return new or existing unique string for sq
312 String seqHash(SequenceI sq)
314 if (seqsToIds == null)
318 if (seqsToIds.containsKey(sq))
320 return seqsToIds.get(sq);
324 // create sequential key
325 String key = "sq" + (seqsToIds.size() + 1);
326 key = makeHashCode(sq, key); // check we don't have an external reference
328 seqsToIds.put(sq, key);
335 if (seqsToIds == null)
337 seqsToIds = new IdentityHashMap<>();
339 if (seqRefIds == null)
341 seqRefIds = new HashMap<>();
343 if (incompleteSeqs == null)
345 incompleteSeqs = new HashMap<>();
347 if (frefedSequence == null)
349 frefedSequence = new ArrayList<>();
357 public Jalview2XML(boolean raiseGUI)
359 this.raiseGUI = raiseGUI;
363 * base class for resolving forward references to sequences by their ID
368 abstract class SeqFref
374 public SeqFref(String _sref, String type)
380 public String getSref()
385 public SequenceI getSrefSeq()
387 return seqRefIds.get(sref);
390 public boolean isResolvable()
392 return seqRefIds.get(sref) != null;
395 public SequenceI getSrefDatasetSeq()
397 SequenceI sq = seqRefIds.get(sref);
400 while (sq.getDatasetSequence() != null)
402 sq = sq.getDatasetSequence();
409 * @return true if the forward reference was fully resolved
411 abstract boolean resolve();
414 public String toString()
416 return type + " reference to " + sref;
421 * create forward reference for a mapping
427 public SeqFref newMappingRef(final String sref,
428 final jalview.datamodel.Mapping _jmap)
430 SeqFref fref = new SeqFref(sref, "Mapping")
432 public jalview.datamodel.Mapping jmap = _jmap;
437 SequenceI seq = getSrefDatasetSeq();
449 public SeqFref newAlcodMapRef(final String sref,
450 final AlignedCodonFrame _cf,
451 final jalview.datamodel.Mapping _jmap)
454 SeqFref fref = new SeqFref(sref, "Codon Frame")
456 AlignedCodonFrame cf = _cf;
458 public jalview.datamodel.Mapping mp = _jmap;
461 public boolean isResolvable()
463 return super.isResolvable() && mp.getTo() != null;
469 SequenceI seq = getSrefDatasetSeq();
474 cf.addMap(seq, mp.getTo(), mp.getMap());
481 public void resolveFrefedSequences()
483 Iterator<SeqFref> nextFref = frefedSequence.iterator();
484 int toresolve = frefedSequence.size();
485 int unresolved = 0, failedtoresolve = 0;
486 while (nextFref.hasNext())
488 SeqFref ref = nextFref.next();
489 if (ref.isResolvable())
501 } catch (Exception x)
504 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
517 System.err.println("Jalview Project Import: There were " + unresolved
518 + " forward references left unresolved on the stack.");
520 if (failedtoresolve > 0)
522 System.err.println("SERIOUS! " + failedtoresolve
523 + " resolvable forward references failed to resolve.");
525 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
528 "Jalview Project Import: There are " + incompleteSeqs.size()
529 + " sequences which may have incomplete metadata.");
530 if (incompleteSeqs.size() < 10)
532 for (SequenceI s : incompleteSeqs.values())
534 System.err.println(s.toString());
540 "Too many to report. Skipping output of incomplete sequences.");
546 * This maintains a map of viewports, the key being the seqSetId. Important to
547 * set historyItem and redoList for multiple views
549 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
551 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
553 String uniqueSetSuffix = "";
556 * List of pdbfiles added to Jar
558 List<String> pdbfiles = null;
560 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
561 public void saveState(File statefile)
563 FileOutputStream fos = null;
568 fos = new FileOutputStream(statefile);
570 JarOutputStream jout = new JarOutputStream(fos);
574 } catch (Exception e)
576 Cache.log.error("Couln't write Jalview state to " + statefile, e);
577 // TODO: inform user of the problem - they need to know if their data was
579 if (errorMessage == null)
581 errorMessage = "Did't write Jalview Archive to output file '"
582 + statefile + "' - See console error log for details";
586 errorMessage += "(Didn't write Jalview Archive to output file '"
597 } catch (IOException e)
607 * Writes a jalview project archive to the given Jar output stream.
611 public void saveState(JarOutputStream jout)
613 AlignFrame[] frames = Desktop.getAlignFrames();
619 saveAllFrames(Arrays.asList(frames), jout);
623 * core method for storing state for a set of AlignFrames.
626 * - frames involving all data to be exported (including those
627 * contained in splitframes, though not the split frames themselves)
629 * - project output stream
631 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
634 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
637 * ensure cached data is clear before starting
639 // todo tidy up seqRefIds, seqsToIds initialisation / reset
641 splitFrameCandidates.clear();
646 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
647 // //////////////////////////////////////////////////
649 List<String> shortNames = new ArrayList<>();
650 List<String> viewIds = new ArrayList<>();
653 for (int i = frames.size() - 1; i > -1; i--)
655 AlignFrame af = frames.get(i);
656 AlignViewport vp = af.getViewport();
658 if (skipList != null && skipList
659 .containsKey(vp.getSequenceSetId()))
664 String shortName = makeFilename(af, shortNames);
666 AlignmentI alignment = vp.getAlignment();
667 List<? extends AlignmentViewPanel> panels = af.getAlignPanels();
668 int apSize = panels.size();
669 for (int ap = 0; ap < apSize; ap++)
671 AlignmentPanel apanel = (AlignmentPanel) panels.get(ap);
672 String fileName = apSize == 1 ? shortName : ap + shortName;
673 if (!fileName.endsWith(".xml"))
675 fileName = fileName + ".xml";
678 saveState(apanel, fileName, jout, viewIds);
682 // BH moved next bit out of inner loop, not that it really matters.
683 // so we are testing to make sure we actually have an alignment,
685 String dssid = getDatasetIdRef(alignment.getDataset());
686 if (!dsses.containsKey(dssid))
688 // We have not already covered this data by reference from another
690 dsses.put(dssid, af);
695 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
701 } catch (Exception foo)
705 } catch (Exception ex)
707 // TODO: inform user of the problem - they need to know if their data was
709 if (errorMessage == null)
711 errorMessage = "Couldn't write Jalview Archive - see error output for details";
713 ex.printStackTrace();
718 * Generates a distinct file name, based on the title of the AlignFrame, by
719 * appending _n for increasing n until an unused name is generated. The new
720 * name (without its extension) is added to the list.
724 * @return the generated name, with .xml extension
726 protected String makeFilename(AlignFrame af, List<String> namesUsed)
728 String shortName = af.getTitle();
730 if (shortName.indexOf(File.separatorChar) > -1)
732 shortName = shortName
733 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
738 while (namesUsed.contains(shortName))
740 if (shortName.endsWith("_" + (count - 1)))
742 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
745 shortName = shortName.concat("_" + count);
749 namesUsed.add(shortName);
751 if (!shortName.endsWith(".xml"))
753 shortName = shortName + ".xml";
758 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
759 public boolean saveAlignment(AlignFrame af, String jarFile,
764 // create backupfiles object and get new temp filename destination
765 boolean doBackup = BackupFiles.getEnabled();
766 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
767 FileOutputStream fos = new FileOutputStream(doBackup ?
768 backupfiles.getTempFilePath() : jarFile);
770 JarOutputStream jout = new JarOutputStream(fos);
771 List<AlignFrame> frames = new ArrayList<>();
773 // resolve splitframes
774 if (af.getViewport().getCodingComplement() != null)
776 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
782 saveAllFrames(frames, jout);
786 } catch (Exception foo)
790 boolean success = true;
794 backupfiles.setWriteSuccess(success);
795 success = backupfiles.rollBackupsAndRenameTempFile();
799 } catch (Exception ex)
801 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
802 ex.printStackTrace();
808 * Each AlignFrame has a single data set associated with it. Note that none of
809 * these frames are split frames, because Desktop.getAlignFrames() collects
810 * top and bottom separately here.
816 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
817 String fileName, JarOutputStream jout)
820 // Note that in saveAllFrames we have associated each specific dataset to
821 // ONE of its associated frames.
823 for (String dssids : dsses.keySet())
825 AlignFrame _af = dsses.get(dssids);
826 String jfileName = fileName + " Dataset for " + _af.getTitle();
827 if (!jfileName.endsWith(".xml"))
829 jfileName = jfileName + ".xml";
831 saveState(_af.alignPanel, jfileName, true, jout, null);
836 * create a JalviewModel from an alignment view and marshall it to a
840 * panel to create jalview model for
842 * name of alignment panel written to output stream
849 public JalviewModel saveState(AlignmentPanel ap, String fileName,
850 JarOutputStream jout, List<String> viewIds)
852 return saveState(ap, fileName, false, jout, viewIds);
856 * create a JalviewModel from an alignment view and marshall it to a
860 * panel to create jalview model for
862 * name of alignment panel written to output stream
864 * when true, only write the dataset for the alignment, not the data
865 * associated with the view.
871 public JalviewModel saveState(AlignmentPanel ap, String fileName,
872 boolean storeDS, JarOutputStream jout, List<String> viewIds)
876 viewIds = new ArrayList<>();
881 List<UserColourScheme> userColours = new ArrayList<>();
883 AlignViewport av = ap.av;
884 ViewportRanges vpRanges = av.getRanges();
886 final ObjectFactory objectFactory = new ObjectFactory();
887 JalviewModel object = objectFactory.createJalviewModel();
888 object.setVamsasModel(new VAMSAS());
890 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
893 GregorianCalendar c = new GregorianCalendar();
894 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
895 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
896 object.setCreationDate(now);
897 } catch (DatatypeConfigurationException e)
899 System.err.println("error writing date: " + e.toString());
902 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
905 * rjal is full height alignment, jal is actual alignment with full metadata
906 * but excludes hidden sequences.
908 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
910 if (av.hasHiddenRows())
912 rjal = jal.getHiddenSequences().getFullAlignment();
915 SequenceSet vamsasSet = new SequenceSet();
917 // JalviewModelSequence jms = new JalviewModelSequence();
919 vamsasSet.setGapChar(jal.getGapCharacter() + "");
921 if (jal.getDataset() != null)
923 // dataset id is the dataset's hashcode
924 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
927 // switch jal and the dataset
928 jal = jal.getDataset();
932 if (jal.getProperties() != null)
934 Enumeration en = jal.getProperties().keys();
935 while (en.hasMoreElements())
937 String key = en.nextElement().toString();
938 SequenceSetProperties ssp = new SequenceSetProperties();
940 ssp.setValue(jal.getProperties().get(key).toString());
941 // vamsasSet.addSequenceSetProperties(ssp);
942 vamsasSet.getSequenceSetProperties().add(ssp);
947 Set<String> calcIdSet = new HashSet<>();
948 // record the set of vamsas sequence XML POJO we create.
949 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
951 for (final SequenceI jds : rjal.getSequences())
953 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
954 : jds.getDatasetSequence();
955 String id = seqHash(jds);
956 if (vamsasSetIds.get(id) == null)
958 if (seqRefIds.get(id) != null && !storeDS)
960 // This happens for two reasons: 1. multiple views are being
962 // 2. the hashCode has collided with another sequence's code. This
964 // HAPPEN! (PF00072.15.stk does this)
965 // JBPNote: Uncomment to debug writing out of files that do not read
966 // back in due to ArrayOutOfBoundExceptions.
967 // System.err.println("vamsasSeq backref: "+id+"");
968 // System.err.println(jds.getName()+"
969 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
970 // System.err.println("Hashcode: "+seqHash(jds));
971 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
972 // System.err.println(rsq.getName()+"
973 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
974 // System.err.println("Hashcode: "+seqHash(rsq));
978 vamsasSeq = createVamsasSequence(id, jds);
979 // vamsasSet.addSequence(vamsasSeq);
980 vamsasSet.getSequence().add(vamsasSeq);
981 vamsasSetIds.put(id, vamsasSeq);
982 seqRefIds.put(id, jds);
986 jseq.setStart(jds.getStart());
987 jseq.setEnd(jds.getEnd());
988 jseq.setColour(av.getSequenceColour(jds).getRGB());
990 jseq.setId(id); // jseq id should be a string not a number
993 // Store any sequences this sequence represents
994 if (av.hasHiddenRows())
996 // use rjal, contains the full height alignment
998 av.getAlignment().getHiddenSequences().isHidden(jds));
1000 if (av.isHiddenRepSequence(jds))
1002 jalview.datamodel.SequenceI[] reps = av
1003 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1005 for (int h = 0; h < reps.length; h++)
1009 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1010 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1015 // mark sequence as reference - if it is the reference for this view
1016 if (jal.hasSeqrep())
1018 jseq.setViewreference(jds == jal.getSeqrep());
1022 // TODO: omit sequence features from each alignment view's XML dump if we
1023 // are storing dataset
1024 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1025 for (SequenceFeature sf : sfs)
1027 // Features features = new Features();
1028 Feature features = new Feature();
1030 features.setBegin(sf.getBegin());
1031 features.setEnd(sf.getEnd());
1032 features.setDescription(sf.getDescription());
1033 features.setType(sf.getType());
1034 features.setFeatureGroup(sf.getFeatureGroup());
1035 features.setScore(sf.getScore());
1036 if (sf.links != null)
1038 for (int l = 0; l < sf.links.size(); l++)
1040 OtherData keyValue = new OtherData();
1041 keyValue.setKey("LINK_" + l);
1042 keyValue.setValue(sf.links.elementAt(l).toString());
1043 // features.addOtherData(keyValue);
1044 features.getOtherData().add(keyValue);
1047 if (sf.otherDetails != null)
1050 * save feature attributes, which may be simple strings or
1051 * map valued (have sub-attributes)
1053 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1055 String key = entry.getKey();
1056 Object value = entry.getValue();
1057 if (value instanceof Map<?, ?>)
1059 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1062 OtherData otherData = new OtherData();
1063 otherData.setKey(key);
1064 otherData.setKey2(subAttribute.getKey());
1065 otherData.setValue(subAttribute.getValue().toString());
1066 // features.addOtherData(otherData);
1067 features.getOtherData().add(otherData);
1072 OtherData otherData = new OtherData();
1073 otherData.setKey(key);
1074 otherData.setValue(value.toString());
1075 // features.addOtherData(otherData);
1076 features.getOtherData().add(otherData);
1081 // jseq.addFeatures(features);
1082 jseq.getFeatures().add(features);
1085 if (jdatasq.getAllPDBEntries() != null)
1087 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1088 while (en.hasMoreElements())
1090 Pdbids pdb = new Pdbids();
1091 jalview.datamodel.PDBEntry entry = en.nextElement();
1093 String pdbId = entry.getId();
1095 pdb.setType(entry.getType());
1098 * Store any structure views associated with this sequence. This
1099 * section copes with duplicate entries in the project, so a dataset
1100 * only view *should* be coped with sensibly.
1102 // This must have been loaded, is it still visible?
1103 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1104 String matchedFile = null;
1105 for (int f = frames.length - 1; f > -1; f--)
1107 if (frames[f] instanceof StructureViewerBase)
1109 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1110 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1111 matchedFile, viewFrame);
1113 * Only store each structure viewer's state once in the project
1114 * jar. First time through only (storeDS==false)
1116 String viewId = viewFrame.getViewId();
1117 if (!storeDS && !viewIds.contains(viewId))
1119 viewIds.add(viewId);
1122 String viewerState = viewFrame.getStateInfo();
1123 writeJarEntry(jout, getViewerJarEntryName(viewId),
1124 viewerState.getBytes());
1125 } catch (IOException e)
1128 "Error saving viewer state: " + e.getMessage());
1134 if (matchedFile != null || entry.getFile() != null)
1136 if (entry.getFile() != null)
1139 matchedFile = entry.getFile();
1141 pdb.setFile(matchedFile); // entry.getFile());
1142 if (pdbfiles == null)
1144 pdbfiles = new ArrayList<>();
1147 if (!pdbfiles.contains(pdbId))
1149 pdbfiles.add(pdbId);
1150 copyFileToJar(jout, matchedFile, pdbId);
1154 Enumeration<String> props = entry.getProperties();
1155 if (props.hasMoreElements())
1157 // PdbentryItem item = new PdbentryItem();
1158 while (props.hasMoreElements())
1160 Property prop = new Property();
1161 String key = props.nextElement();
1163 prop.setValue(entry.getProperty(key).toString());
1164 // item.addProperty(prop);
1165 pdb.getProperty().add(prop);
1167 // pdb.addPdbentryItem(item);
1170 // jseq.addPdbids(pdb);
1171 jseq.getPdbids().add(pdb);
1175 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1177 // jms.addJSeq(jseq);
1178 object.getJSeq().add(jseq);
1181 if (!storeDS && av.hasHiddenRows())
1183 jal = av.getAlignment();
1187 if (storeDS && jal.getCodonFrames() != null)
1189 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1190 for (AlignedCodonFrame acf : jac)
1192 AlcodonFrame alc = new AlcodonFrame();
1193 if (acf.getProtMappings() != null
1194 && acf.getProtMappings().length > 0)
1196 boolean hasMap = false;
1197 SequenceI[] dnas = acf.getdnaSeqs();
1198 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1199 for (int m = 0; m < pmaps.length; m++)
1201 AlcodMap alcmap = new AlcodMap();
1202 alcmap.setDnasq(seqHash(dnas[m]));
1204 createVamsasMapping(pmaps[m], dnas[m], null, false));
1205 // alc.addAlcodMap(alcmap);
1206 alc.getAlcodMap().add(alcmap);
1211 // vamsasSet.addAlcodonFrame(alc);
1212 vamsasSet.getAlcodonFrame().add(alc);
1215 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1217 // AlcodonFrame alc = new AlcodonFrame();
1218 // vamsasSet.addAlcodonFrame(alc);
1219 // for (int p = 0; p < acf.aaWidth; p++)
1221 // Alcodon cmap = new Alcodon();
1222 // if (acf.codons[p] != null)
1224 // // Null codons indicate a gapped column in the translated peptide
1226 // cmap.setPos1(acf.codons[p][0]);
1227 // cmap.setPos2(acf.codons[p][1]);
1228 // cmap.setPos3(acf.codons[p][2]);
1230 // alc.addAlcodon(cmap);
1232 // if (acf.getProtMappings() != null
1233 // && acf.getProtMappings().length > 0)
1235 // SequenceI[] dnas = acf.getdnaSeqs();
1236 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1237 // for (int m = 0; m < pmaps.length; m++)
1239 // AlcodMap alcmap = new AlcodMap();
1240 // alcmap.setDnasq(seqHash(dnas[m]));
1241 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1243 // alc.addAlcodMap(alcmap);
1250 // /////////////////////////////////
1251 if (!storeDS && av.getCurrentTree() != null)
1253 // FIND ANY ASSOCIATED TREES
1254 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1255 if (Desktop.getDesktopPane() != null)
1257 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1259 for (int t = 0; t < frames.length; t++)
1261 if (frames[t] instanceof TreePanel)
1263 TreePanel tp = (TreePanel) frames[t];
1265 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1267 JalviewModel.Tree tree = new JalviewModel.Tree();
1268 tree.setTitle(tp.getTitle());
1269 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1270 tree.setNewick(tp.getTree().print());
1271 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1273 tree.setFitToWindow(tp.fitToWindow.getState());
1274 tree.setFontName(tp.getTreeFont().getName());
1275 tree.setFontSize(tp.getTreeFont().getSize());
1276 tree.setFontStyle(tp.getTreeFont().getStyle());
1277 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1279 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1280 tree.setShowDistances(tp.distanceMenu.getState());
1282 tree.setHeight(tp.getHeight());
1283 tree.setWidth(tp.getWidth());
1284 tree.setXpos(tp.getX());
1285 tree.setYpos(tp.getY());
1286 tree.setId(makeHashCode(tp, null));
1287 tree.setLinkToAllViews(
1288 tp.getTreeCanvas().isApplyToAllViews());
1290 // jms.addTree(tree);
1291 object.getTree().add(tree);
1301 if (!storeDS && Desktop.getDesktopPane() != null)
1303 for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames())
1305 if (frame instanceof PCAPanel)
1307 PCAPanel panel = (PCAPanel) frame;
1308 if (panel.getAlignViewport().getAlignment() == jal)
1310 savePCA(panel, object);
1318 * store forward refs from an annotationRow to any groups
1320 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1323 for (SequenceI sq : jal.getSequences())
1325 // Store annotation on dataset sequences only
1326 AlignmentAnnotation[] aa = sq.getAnnotation();
1327 if (aa != null && aa.length > 0)
1329 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1336 if (jal.getAlignmentAnnotation() != null)
1338 // Store the annotation shown on the alignment.
1339 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1340 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1345 if (jal.getGroups() != null)
1347 JGroup[] groups = new JGroup[jal.getGroups().size()];
1349 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1351 JGroup jGroup = new JGroup();
1352 groups[++i] = jGroup;
1354 jGroup.setStart(sg.getStartRes());
1355 jGroup.setEnd(sg.getEndRes());
1356 jGroup.setName(sg.getName());
1357 if (groupRefs.containsKey(sg))
1359 // group has references so set its ID field
1360 jGroup.setId(groupRefs.get(sg));
1362 ColourSchemeI colourScheme = sg.getColourScheme();
1363 if (colourScheme != null)
1365 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1366 if (groupColourScheme.conservationApplied())
1368 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1370 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1373 setUserColourScheme(colourScheme, userColours,
1378 jGroup.setColour(colourScheme.getSchemeName());
1381 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1383 jGroup.setColour("AnnotationColourGradient");
1384 jGroup.setAnnotationColours(constructAnnotationColours(
1385 (jalview.schemes.AnnotationColourGradient) colourScheme,
1386 userColours, object));
1388 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1391 setUserColourScheme(colourScheme, userColours, object));
1395 jGroup.setColour(colourScheme.getSchemeName());
1398 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1401 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1402 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1403 jGroup.setDisplayText(sg.getDisplayText());
1404 jGroup.setColourText(sg.getColourText());
1405 jGroup.setTextCol1(sg.textColour.getRGB());
1406 jGroup.setTextCol2(sg.textColour2.getRGB());
1407 jGroup.setTextColThreshold(sg.thresholdTextColour);
1408 jGroup.setShowUnconserved(sg.getShowNonconserved());
1409 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1410 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1411 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1412 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1413 for (SequenceI seq : sg.getSequences())
1415 // jGroup.addSeq(seqHash(seq));
1416 jGroup.getSeq().add(seqHash(seq));
1420 //jms.setJGroup(groups);
1422 for (JGroup grp : groups)
1424 object.getJGroup().add(grp);
1429 // /////////SAVE VIEWPORT
1430 Viewport view = new Viewport();
1431 view.setTitle(ap.alignFrame.getTitle());
1432 view.setSequenceSetId(
1433 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1434 view.setId(av.getViewId());
1435 if (av.getCodingComplement() != null)
1437 view.setComplementId(av.getCodingComplement().getViewId());
1439 view.setViewName(av.getViewName());
1440 view.setGatheredViews(av.isGatherViewsHere());
1442 Rectangle size = ap.av.getExplodedGeometry();
1443 Rectangle position = size;
1446 size = ap.alignFrame.getBounds();
1447 if (av.getCodingComplement() != null)
1449 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1457 view.setXpos(position.x);
1458 view.setYpos(position.y);
1460 view.setWidth(size.width);
1461 view.setHeight(size.height);
1463 view.setStartRes(vpRanges.getStartRes());
1464 view.setStartSeq(vpRanges.getStartSeq());
1466 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1468 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1469 userColours, object));
1472 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1474 AnnotationColourScheme ac = constructAnnotationColours(
1475 (jalview.schemes.AnnotationColourGradient) av
1476 .getGlobalColourScheme(),
1477 userColours, object);
1479 view.setAnnotationColours(ac);
1480 view.setBgColour("AnnotationColourGradient");
1484 view.setBgColour(ColourSchemeProperty
1485 .getColourName(av.getGlobalColourScheme()));
1488 ResidueShaderI vcs = av.getResidueShading();
1489 ColourSchemeI cs = av.getGlobalColourScheme();
1493 if (vcs.conservationApplied())
1495 view.setConsThreshold(vcs.getConservationInc());
1496 if (cs instanceof jalview.schemes.UserColourScheme)
1498 view.setBgColour(setUserColourScheme(cs, userColours, object));
1501 view.setPidThreshold(vcs.getThreshold());
1504 view.setConservationSelected(av.getConservationSelected());
1505 view.setPidSelected(av.getAbovePIDThreshold());
1506 final Font font = av.getFont();
1507 view.setFontName(font.getName());
1508 view.setFontSize(font.getSize());
1509 view.setFontStyle(font.getStyle());
1510 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1511 view.setRenderGaps(av.isRenderGaps());
1512 view.setShowAnnotation(av.isShowAnnotation());
1513 view.setShowBoxes(av.getShowBoxes());
1514 view.setShowColourText(av.getColourText());
1515 view.setShowFullId(av.getShowJVSuffix());
1516 view.setRightAlignIds(av.isRightAlignIds());
1517 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1518 view.setShowText(av.getShowText());
1519 view.setShowUnconserved(av.getShowUnconserved());
1520 view.setWrapAlignment(av.getWrapAlignment());
1521 view.setTextCol1(av.getTextColour().getRGB());
1522 view.setTextCol2(av.getTextColour2().getRGB());
1523 view.setTextColThreshold(av.getThresholdTextColour());
1524 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1525 view.setShowSequenceLogo(av.isShowSequenceLogo());
1526 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1527 view.setShowGroupConsensus(av.isShowGroupConsensus());
1528 view.setShowGroupConservation(av.isShowGroupConservation());
1529 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1530 view.setShowDbRefTooltip(av.isShowDBRefs());
1531 view.setFollowHighlight(av.isFollowHighlight());
1532 view.setFollowSelection(av.followSelection);
1533 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1534 if (av.getFeaturesDisplayed() != null)
1536 FeatureSettings fs = new FeatureSettings();
1538 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1539 .getFeatureRenderer();
1540 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1542 Vector<String> settingsAdded = new Vector<>();
1543 if (renderOrder != null)
1545 for (String featureType : renderOrder)
1547 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1548 setting.setType(featureType);
1551 * save any filter for the feature type
1553 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1554 if (filter != null) {
1555 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1556 FeatureMatcherI firstFilter = filters.next();
1557 setting.setMatcherSet(Jalview2XML.marshalFilter(
1558 firstFilter, filters, filter.isAnded()));
1562 * save colour scheme for the feature type
1564 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1565 if (!fcol.isSimpleColour())
1567 setting.setColour(fcol.getMaxColour().getRGB());
1568 setting.setMincolour(fcol.getMinColour().getRGB());
1569 setting.setMin(fcol.getMin());
1570 setting.setMax(fcol.getMax());
1571 setting.setColourByLabel(fcol.isColourByLabel());
1572 if (fcol.isColourByAttribute())
1574 String[] attName = fcol.getAttributeName();
1575 setting.getAttributeName().add(attName[0]);
1576 if (attName.length > 1)
1578 setting.getAttributeName().add(attName[1]);
1581 setting.setAutoScale(fcol.isAutoScaled());
1582 setting.setThreshold(fcol.getThreshold());
1583 Color noColour = fcol.getNoColour();
1584 if (noColour == null)
1586 setting.setNoValueColour(NoValueColour.NONE);
1588 else if (noColour.equals(fcol.getMaxColour()))
1590 setting.setNoValueColour(NoValueColour.MAX);
1594 setting.setNoValueColour(NoValueColour.MIN);
1596 // -1 = No threshold, 0 = Below, 1 = Above
1597 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1598 : (fcol.isBelowThreshold() ? 0 : -1));
1602 setting.setColour(fcol.getColour().getRGB());
1606 av.getFeaturesDisplayed().isVisible(featureType));
1608 .getOrder(featureType);
1611 setting.setOrder(rorder);
1613 /// fs.addSetting(setting);
1614 fs.getSetting().add(setting);
1615 settingsAdded.addElement(featureType);
1619 // is groups actually supposed to be a map here ?
1620 Iterator<String> en = fr.getFeatureGroups().iterator();
1621 Vector<String> groupsAdded = new Vector<>();
1622 while (en.hasNext())
1624 String grp = en.next();
1625 if (groupsAdded.contains(grp))
1629 Group g = new Group();
1631 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1634 fs.getGroup().add(g);
1635 groupsAdded.addElement(grp);
1637 // jms.setFeatureSettings(fs);
1638 object.setFeatureSettings(fs);
1641 if (av.hasHiddenColumns())
1643 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1644 .getHiddenColumns();
1647 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1651 Iterator<int[]> hiddenRegions = hidden.iterator();
1652 while (hiddenRegions.hasNext())
1654 int[] region = hiddenRegions.next();
1655 HiddenColumns hc = new HiddenColumns();
1656 hc.setStart(region[0]);
1657 hc.setEnd(region[1]);
1658 // view.addHiddenColumns(hc);
1659 view.getHiddenColumns().add(hc);
1663 if (calcIdSet.size() > 0)
1665 for (String calcId : calcIdSet)
1667 if (calcId.trim().length() > 0)
1669 CalcIdParam cidp = createCalcIdParam(calcId, av);
1670 // Some calcIds have no parameters.
1673 // view.addCalcIdParam(cidp);
1674 view.getCalcIdParam().add(cidp);
1680 // jms.addViewport(view);
1681 object.getViewport().add(view);
1683 // object.setJalviewModelSequence(jms);
1684 // object.getVamsasModel().addSequenceSet(vamsasSet);
1685 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1687 if (jout != null && fileName != null)
1689 // We may not want to write the object to disk,
1690 // eg we can copy the alignViewport to a new view object
1691 // using save and then load
1694 fileName = fileName.replace('\\', '/');
1695 System.out.println("Writing jar entry " + fileName);
1696 JarEntry entry = new JarEntry(fileName);
1697 jout.putNextEntry(entry);
1698 PrintWriter pout = new PrintWriter(
1699 new OutputStreamWriter(jout, UTF_8));
1700 JAXBContext jaxbContext = JAXBContext
1701 .newInstance(JalviewModel.class);
1702 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1704 // output pretty printed
1705 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1706 jaxbMarshaller.marshal(
1707 new ObjectFactory().createJalviewModel(object), pout);
1709 // jaxbMarshaller.marshal(object, pout);
1710 // marshaller.marshal(object);
1713 } catch (Exception ex)
1715 // TODO: raise error in GUI if marshalling failed.
1716 System.err.println("Error writing Jalview project");
1717 ex.printStackTrace();
1724 * Writes PCA viewer attributes and computed values to an XML model object and
1725 * adds it to the JalviewModel. Any exceptions are reported by logging.
1727 protected void savePCA(PCAPanel panel, JalviewModel object)
1731 PcaViewer viewer = new PcaViewer();
1732 viewer.setHeight(panel.getHeight());
1733 viewer.setWidth(panel.getWidth());
1734 viewer.setXpos(panel.getX());
1735 viewer.setYpos(panel.getY());
1736 viewer.setTitle(panel.getTitle());
1737 PCAModel pcaModel = panel.getPcaModel();
1738 viewer.setScoreModelName(pcaModel.getScoreModelName());
1739 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1740 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1741 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1743 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1744 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1745 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1746 SeqPointMin spmin = new SeqPointMin();
1747 spmin.setXPos(spMin[0]);
1748 spmin.setYPos(spMin[1]);
1749 spmin.setZPos(spMin[2]);
1750 viewer.setSeqPointMin(spmin);
1751 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1752 SeqPointMax spmax = new SeqPointMax();
1753 spmax.setXPos(spMax[0]);
1754 spmax.setYPos(spMax[1]);
1755 spmax.setZPos(spMax[2]);
1756 viewer.setSeqPointMax(spmax);
1757 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1758 viewer.setLinkToAllViews(
1759 panel.getRotatableCanvas().isApplyToAllViews());
1760 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1761 viewer.setIncludeGaps(sp.includeGaps());
1762 viewer.setMatchGaps(sp.matchGaps());
1763 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1764 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1767 * sequence points on display
1769 for (jalview.datamodel.SequencePoint spt : pcaModel
1770 .getSequencePoints())
1772 SequencePoint point = new SequencePoint();
1773 point.setSequenceRef(seqHash(spt.getSequence()));
1774 point.setXPos(spt.coord.x);
1775 point.setYPos(spt.coord.y);
1776 point.setZPos(spt.coord.z);
1777 viewer.getSequencePoint().add(point);
1781 * (end points of) axes on display
1783 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1786 Axis axis = new Axis();
1790 viewer.getAxis().add(axis);
1794 * raw PCA data (note we are not restoring PCA inputs here -
1795 * alignment view, score model, similarity parameters)
1797 PcaDataType data = new PcaDataType();
1798 viewer.setPcaData(data);
1799 PCA pca = pcaModel.getPcaData();
1801 DoubleMatrix pm = new DoubleMatrix();
1802 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1803 data.setPairwiseMatrix(pm);
1805 DoubleMatrix tm = new DoubleMatrix();
1806 saveDoubleMatrix(pca.getTridiagonal(), tm);
1807 data.setTridiagonalMatrix(tm);
1809 DoubleMatrix eigenMatrix = new DoubleMatrix();
1810 data.setEigenMatrix(eigenMatrix);
1811 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1813 object.getPcaViewer().add(viewer);
1814 } catch (Throwable t)
1816 Cache.log.error("Error saving PCA: " + t.getMessage());
1821 * Stores values from a matrix into an XML element, including (if present) the
1826 * @see #loadDoubleMatrix(DoubleMatrix)
1828 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1830 xmlMatrix.setRows(m.height());
1831 xmlMatrix.setColumns(m.width());
1832 for (int i = 0; i < m.height(); i++)
1834 DoubleVector row = new DoubleVector();
1835 for (int j = 0; j < m.width(); j++)
1837 row.getV().add(m.getValue(i, j));
1839 xmlMatrix.getRow().add(row);
1841 if (m.getD() != null)
1843 DoubleVector dVector = new DoubleVector();
1844 for (double d : m.getD())
1846 dVector.getV().add(d);
1848 xmlMatrix.setD(dVector);
1850 if (m.getE() != null)
1852 DoubleVector eVector = new DoubleVector();
1853 for (double e : m.getE())
1855 eVector.getV().add(e);
1857 xmlMatrix.setE(eVector);
1862 * Loads XML matrix data into a new Matrix object, including the D and/or E
1863 * vectors (if present)
1867 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1869 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1871 int rows = mData.getRows();
1872 double[][] vals = new double[rows][];
1874 for (int i = 0; i < rows; i++)
1876 List<Double> dVector = mData.getRow().get(i).getV();
1877 vals[i] = new double[dVector.size()];
1879 for (Double d : dVector)
1885 MatrixI m = new Matrix(vals);
1887 if (mData.getD() != null)
1889 List<Double> dVector = mData.getD().getV();
1890 double[] vec = new double[dVector.size()];
1892 for (Double d : dVector)
1898 if (mData.getE() != null)
1900 List<Double> dVector = mData.getE().getV();
1901 double[] vec = new double[dVector.size()];
1903 for (Double d : dVector)
1914 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1915 * for each viewer, with
1917 * <li>viewer geometry (position, size, split pane divider location)</li>
1918 * <li>index of the selected structure in the viewer (currently shows gapped
1920 * <li>the id of the annotation holding RNA secondary structure</li>
1921 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1923 * Varna viewer state is also written out (in native Varna XML) to separate
1924 * project jar entries. A separate entry is written for each RNA structure
1925 * displayed, with the naming convention
1927 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1935 * @param storeDataset
1937 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1938 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1939 boolean storeDataset)
1941 if (Desktop.getDesktopPane() == null)
1945 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1946 for (int f = frames.length - 1; f > -1; f--)
1948 if (frames[f] instanceof AppVarna)
1950 AppVarna varna = (AppVarna) frames[f];
1952 * link the sequence to every viewer that is showing it and is linked to
1953 * its alignment panel
1955 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1957 String viewId = varna.getViewId();
1958 RnaViewer rna = new RnaViewer();
1959 rna.setViewId(viewId);
1960 rna.setTitle(varna.getTitle());
1961 rna.setXpos(varna.getX());
1962 rna.setYpos(varna.getY());
1963 rna.setWidth(varna.getWidth());
1964 rna.setHeight(varna.getHeight());
1965 rna.setDividerLocation(varna.getDividerLocation());
1966 rna.setSelectedRna(varna.getSelectedIndex());
1967 // jseq.addRnaViewer(rna);
1968 jseq.getRnaViewer().add(rna);
1971 * Store each Varna panel's state once in the project per sequence.
1972 * First time through only (storeDataset==false)
1974 // boolean storeSessions = false;
1975 // String sequenceViewId = viewId + seqsToIds.get(jds);
1976 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1978 // viewIds.add(sequenceViewId);
1979 // storeSessions = true;
1981 for (RnaModel model : varna.getModels())
1983 if (model.seq == jds)
1986 * VARNA saves each view (sequence or alignment secondary
1987 * structure, gapped or trimmed) as a separate XML file
1989 String jarEntryName = rnaSessions.get(model);
1990 if (jarEntryName == null)
1993 String varnaStateFile = varna.getStateInfo(model.rna);
1994 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1995 copyFileToJar(jout, varnaStateFile, jarEntryName);
1996 rnaSessions.put(model, jarEntryName);
1998 SecondaryStructure ss = new SecondaryStructure();
1999 String annotationId = varna.getAnnotation(jds).annotationId;
2000 ss.setAnnotationId(annotationId);
2001 ss.setViewerState(jarEntryName);
2002 ss.setGapped(model.gapped);
2003 ss.setTitle(model.title);
2004 // rna.addSecondaryStructure(ss);
2005 rna.getSecondaryStructure().add(ss);
2014 * Copy the contents of a file to a new entry added to the output jar
2018 * @param jarEntryName
2020 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2021 String jarEntryName)
2023 DataInputStream dis = null;
2026 File file = new File(infilePath);
2027 if (file.exists() && jout != null)
2029 dis = new DataInputStream(new FileInputStream(file));
2030 byte[] data = new byte[(int) file.length()];
2031 dis.readFully(data);
2032 writeJarEntry(jout, jarEntryName, data);
2034 } catch (Exception ex)
2036 ex.printStackTrace();
2044 } catch (IOException e)
2053 * Write the data to a new entry of given name in the output jar file
2056 * @param jarEntryName
2058 * @throws IOException
2060 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2061 byte[] data) throws IOException
2065 jarEntryName = jarEntryName.replace('\\','/');
2066 System.out.println("Writing jar entry " + jarEntryName);
2067 jout.putNextEntry(new JarEntry(jarEntryName));
2068 DataOutputStream dout = new DataOutputStream(jout);
2069 dout.write(data, 0, data.length);
2076 * Save the state of a structure viewer
2081 * the archive XML element under which to save the state
2084 * @param matchedFile
2088 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2089 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2090 String matchedFile, StructureViewerBase viewFrame)
2092 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2095 * Look for any bindings for this viewer to the PDB file of interest
2096 * (including part matches excluding chain id)
2098 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2100 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2101 final String pdbId = pdbentry.getId();
2102 if (!pdbId.equals(entry.getId())
2103 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2104 .startsWith(pdbId.toLowerCase())))
2107 * not interested in a binding to a different PDB entry here
2111 if (matchedFile == null)
2113 matchedFile = pdbentry.getFile();
2115 else if (!matchedFile.equals(pdbentry.getFile()))
2118 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2119 + pdbentry.getFile());
2123 // can get at it if the ID
2124 // match is ambiguous (e.g.
2127 for (int smap = 0; smap < viewFrame.getBinding()
2128 .getSequence()[peid].length; smap++)
2130 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2131 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2133 StructureState state = new StructureState();
2134 state.setVisible(true);
2135 state.setXpos(viewFrame.getX());
2136 state.setYpos(viewFrame.getY());
2137 state.setWidth(viewFrame.getWidth());
2138 state.setHeight(viewFrame.getHeight());
2139 final String viewId = viewFrame.getViewId();
2140 state.setViewId(viewId);
2141 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2142 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2143 state.setColourByJmol(viewFrame.isColouredByViewer());
2144 state.setType(viewFrame.getViewerType().toString());
2145 // pdb.addStructureState(state);
2146 pdb.getStructureState().add(state);
2154 * Populates the AnnotationColourScheme xml for save. This captures the
2155 * settings of the options in the 'Colour by Annotation' dialog.
2158 * @param userColours
2162 private AnnotationColourScheme constructAnnotationColours(
2163 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2166 AnnotationColourScheme ac = new AnnotationColourScheme();
2167 ac.setAboveThreshold(acg.getAboveThreshold());
2168 ac.setThreshold(acg.getAnnotationThreshold());
2169 // 2.10.2 save annotationId (unique) not annotation label
2170 ac.setAnnotation(acg.getAnnotation().annotationId);
2171 if (acg.getBaseColour() instanceof UserColourScheme)
2174 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2179 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2182 ac.setMaxColour(acg.getMaxColour().getRGB());
2183 ac.setMinColour(acg.getMinColour().getRGB());
2184 ac.setPerSequence(acg.isSeqAssociated());
2185 ac.setPredefinedColours(acg.isPredefinedColours());
2189 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2190 IdentityHashMap<SequenceGroup, String> groupRefs,
2191 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2192 SequenceSet vamsasSet)
2195 for (int i = 0; i < aa.length; i++)
2197 Annotation an = new Annotation();
2199 AlignmentAnnotation annotation = aa[i];
2200 if (annotation.annotationId != null)
2202 annotationIds.put(annotation.annotationId, annotation);
2205 an.setId(annotation.annotationId);
2207 an.setVisible(annotation.visible);
2209 an.setDescription(annotation.description);
2211 if (annotation.sequenceRef != null)
2213 // 2.9 JAL-1781 xref on sequence id rather than name
2214 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2216 if (annotation.groupRef != null)
2218 String groupIdr = groupRefs.get(annotation.groupRef);
2219 if (groupIdr == null)
2221 // make a locally unique String
2222 groupRefs.put(annotation.groupRef,
2223 groupIdr = ("" + System.currentTimeMillis()
2224 + annotation.groupRef.getName()
2225 + groupRefs.size()));
2227 an.setGroupRef(groupIdr.toString());
2230 // store all visualization attributes for annotation
2231 an.setGraphHeight(annotation.graphHeight);
2232 an.setCentreColLabels(annotation.centreColLabels);
2233 an.setScaleColLabels(annotation.scaleColLabel);
2234 an.setShowAllColLabels(annotation.showAllColLabels);
2235 an.setBelowAlignment(annotation.belowAlignment);
2237 if (annotation.graph > 0)
2240 an.setGraphType(annotation.graph);
2241 an.setGraphGroup(annotation.graphGroup);
2242 if (annotation.getThreshold() != null)
2244 ThresholdLine line = new ThresholdLine();
2245 line.setLabel(annotation.getThreshold().label);
2246 line.setValue(annotation.getThreshold().value);
2247 line.setColour(annotation.getThreshold().colour.getRGB());
2248 an.setThresholdLine(line);
2256 an.setLabel(annotation.label);
2258 if (annotation == av.getAlignmentQualityAnnot()
2259 || annotation == av.getAlignmentConservationAnnotation()
2260 || annotation == av.getAlignmentConsensusAnnotation()
2261 || annotation.autoCalculated)
2263 // new way of indicating autocalculated annotation -
2264 an.setAutoCalculated(annotation.autoCalculated);
2266 if (annotation.hasScore())
2268 an.setScore(annotation.getScore());
2271 if (annotation.getCalcId() != null)
2273 calcIdSet.add(annotation.getCalcId());
2274 an.setCalcId(annotation.getCalcId());
2276 if (annotation.hasProperties())
2278 for (String pr : annotation.getProperties())
2280 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2282 prop.setValue(annotation.getProperty(pr));
2283 // an.addProperty(prop);
2284 an.getProperty().add(prop);
2288 AnnotationElement ae;
2289 if (annotation.annotations != null)
2291 an.setScoreOnly(false);
2292 for (int a = 0; a < annotation.annotations.length; a++)
2294 if ((annotation == null) || (annotation.annotations[a] == null))
2299 ae = new AnnotationElement();
2300 if (annotation.annotations[a].description != null)
2302 ae.setDescription(annotation.annotations[a].description);
2304 if (annotation.annotations[a].displayCharacter != null)
2306 ae.setDisplayCharacter(
2307 annotation.annotations[a].displayCharacter);
2310 if (!Float.isNaN(annotation.annotations[a].value))
2312 ae.setValue(annotation.annotations[a].value);
2316 if (annotation.annotations[a].secondaryStructure > ' ')
2318 ae.setSecondaryStructure(
2319 annotation.annotations[a].secondaryStructure + "");
2322 if (annotation.annotations[a].colour != null
2323 && annotation.annotations[a].colour != java.awt.Color.black)
2325 ae.setColour(annotation.annotations[a].colour.getRGB());
2328 // an.addAnnotationElement(ae);
2329 an.getAnnotationElement().add(ae);
2330 if (annotation.autoCalculated)
2332 // only write one non-null entry into the annotation row -
2333 // sufficient to get the visualization attributes necessary to
2341 an.setScoreOnly(true);
2343 if (!storeDS || (storeDS && !annotation.autoCalculated))
2345 // skip autocalculated annotation - these are only provided for
2347 // vamsasSet.addAnnotation(an);
2348 vamsasSet.getAnnotation().add(an);
2354 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2356 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2357 if (settings != null)
2359 CalcIdParam vCalcIdParam = new CalcIdParam();
2360 vCalcIdParam.setCalcId(calcId);
2361 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2362 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2363 // generic URI allowing a third party to resolve another instance of the
2364 // service used for this calculation
2365 for (String url : settings.getServiceURLs())
2367 // vCalcIdParam.addServiceURL(urls);
2368 vCalcIdParam.getServiceURL().add(url);
2370 vCalcIdParam.setVersion("1.0");
2371 if (settings.getPreset() != null)
2373 WsParamSetI setting = settings.getPreset();
2374 vCalcIdParam.setName(setting.getName());
2375 vCalcIdParam.setDescription(setting.getDescription());
2379 vCalcIdParam.setName("");
2380 vCalcIdParam.setDescription("Last used parameters");
2382 // need to be able to recover 1) settings 2) user-defined presets or
2383 // recreate settings from preset 3) predefined settings provided by
2384 // service - or settings that can be transferred (or discarded)
2385 vCalcIdParam.setParameters(
2386 settings.getWsParamFile().replace("\n", "|\\n|"));
2387 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2388 // todo - decide if updateImmediately is needed for any projects.
2390 return vCalcIdParam;
2395 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2398 if (calcIdParam.getVersion().equals("1.0"))
2400 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2401 Jws2Instance service = Jws2Discoverer.getInstance()
2402 .getPreferredServiceFor(calcIds);
2403 if (service != null)
2405 WsParamSetI parmSet = null;
2408 parmSet = service.getParamStore().parseServiceParameterFile(
2409 calcIdParam.getName(), calcIdParam.getDescription(),
2411 calcIdParam.getParameters().replace("|\\n|", "\n"));
2412 } catch (IOException x)
2414 warn("Couldn't parse parameter data for "
2415 + calcIdParam.getCalcId(), x);
2418 List<ArgumentI> argList = null;
2419 if (calcIdParam.getName().length() > 0)
2421 parmSet = service.getParamStore()
2422 .getPreset(calcIdParam.getName());
2423 if (parmSet != null)
2425 // TODO : check we have a good match with settings in AACon -
2426 // otherwise we'll need to create a new preset
2431 argList = parmSet.getArguments();
2434 AAConSettings settings = new AAConSettings(
2435 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2436 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2437 calcIdParam.isNeedsUpdate());
2442 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2446 throw new Error(MessageManager.formatMessage(
2447 "error.unsupported_version_calcIdparam", new Object[]
2448 { calcIdParam.toString() }));
2452 * External mapping between jalview objects and objects yielding a valid and
2453 * unique object ID string. This is null for normal Jalview project IO, but
2454 * non-null when a jalview project is being read or written as part of a
2457 IdentityHashMap jv2vobj = null;
2460 * Construct a unique ID for jvobj using either existing bindings or if none
2461 * exist, the result of the hashcode call for the object.
2464 * jalview data object
2465 * @return unique ID for referring to jvobj
2467 private String makeHashCode(Object jvobj, String altCode)
2469 if (jv2vobj != null)
2471 Object id = jv2vobj.get(jvobj);
2474 return id.toString();
2476 // check string ID mappings
2477 if (jvids2vobj != null && jvobj instanceof String)
2479 id = jvids2vobj.get(jvobj);
2483 return id.toString();
2485 // give up and warn that something has gone wrong
2486 warn("Cannot find ID for object in external mapping : " + jvobj);
2492 * return local jalview object mapped to ID, if it exists
2496 * @return null or object bound to idcode
2498 private Object retrieveExistingObj(String idcode)
2500 if (idcode != null && vobj2jv != null)
2502 return vobj2jv.get(idcode);
2508 * binding from ID strings from external mapping table to jalview data model
2511 private Hashtable vobj2jv;
2513 private Sequence createVamsasSequence(String id, SequenceI jds)
2515 return createVamsasSequence(true, id, jds, null);
2518 private Sequence createVamsasSequence(boolean recurse, String id,
2519 SequenceI jds, SequenceI parentseq)
2521 Sequence vamsasSeq = new Sequence();
2522 vamsasSeq.setId(id);
2523 vamsasSeq.setName(jds.getName());
2524 vamsasSeq.setSequence(jds.getSequenceAsString());
2525 vamsasSeq.setDescription(jds.getDescription());
2526 List<DBRefEntry> dbrefs = null;
2527 if (jds.getDatasetSequence() != null)
2529 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2533 // seqId==dsseqid so we can tell which sequences really are
2534 // dataset sequences only
2535 vamsasSeq.setDsseqid(id);
2536 dbrefs = jds.getDBRefs();
2537 if (parentseq == null)
2544 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2546 DBRef dbref = new DBRef();
2547 DBRefEntry ref = dbrefs.get(d);
2548 dbref.setSource(ref.getSource());
2549 dbref.setVersion(ref.getVersion());
2550 dbref.setAccessionId(ref.getAccessionId());
2553 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2555 dbref.setMapping(mp);
2557 // vamsasSeq.addDBRef(dbref);
2558 vamsasSeq.getDBRef().add(dbref);
2564 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2565 SequenceI parentseq, SequenceI jds, boolean recurse)
2568 if (jmp.getMap() != null)
2572 jalview.util.MapList mlst = jmp.getMap();
2573 List<int[]> r = mlst.getFromRanges();
2574 for (int[] range : r)
2576 MapListFrom mfrom = new MapListFrom();
2577 mfrom.setStart(range[0]);
2578 mfrom.setEnd(range[1]);
2579 // mp.addMapListFrom(mfrom);
2580 mp.getMapListFrom().add(mfrom);
2582 r = mlst.getToRanges();
2583 for (int[] range : r)
2585 MapListTo mto = new MapListTo();
2586 mto.setStart(range[0]);
2587 mto.setEnd(range[1]);
2588 // mp.addMapListTo(mto);
2589 mp.getMapListTo().add(mto);
2591 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2592 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2593 if (jmp.getTo() != null)
2595 // MappingChoice mpc = new MappingChoice();
2597 // check/create ID for the sequence referenced by getTo()
2600 SequenceI ps = null;
2601 if (parentseq != jmp.getTo()
2602 && parentseq.getDatasetSequence() != jmp.getTo())
2604 // chaining dbref rather than a handshaking one
2605 jmpid = seqHash(ps = jmp.getTo());
2609 jmpid = seqHash(ps = parentseq);
2611 // mpc.setDseqFor(jmpid);
2612 mp.setDseqFor(jmpid);
2613 if (!seqRefIds.containsKey(jmpid))
2615 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2616 seqRefIds.put(jmpid, ps);
2620 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2623 // mp.setMappingChoice(mpc);
2629 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2630 List<UserColourScheme> userColours, JalviewModel jm)
2633 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2634 boolean newucs = false;
2635 if (!userColours.contains(ucs))
2637 userColours.add(ucs);
2640 id = "ucs" + userColours.indexOf(ucs);
2643 // actually create the scheme's entry in the XML model
2644 java.awt.Color[] colours = ucs.getColours();
2645 UserColours uc = new UserColours();
2646 // UserColourScheme jbucs = new UserColourScheme();
2647 JalviewUserColours jbucs = new JalviewUserColours();
2649 for (int i = 0; i < colours.length; i++)
2651 Colour col = new Colour();
2652 col.setName(ResidueProperties.aa[i]);
2653 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2654 // jbucs.addColour(col);
2655 jbucs.getColour().add(col);
2657 if (ucs.getLowerCaseColours() != null)
2659 colours = ucs.getLowerCaseColours();
2660 for (int i = 0; i < colours.length; i++)
2662 Colour col = new Colour();
2663 col.setName(ResidueProperties.aa[i].toLowerCase());
2664 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2665 // jbucs.addColour(col);
2666 jbucs.getColour().add(col);
2671 uc.setUserColourScheme(jbucs);
2672 // jm.addUserColours(uc);
2673 jm.getUserColours().add(uc);
2679 jalview.schemes.UserColourScheme getUserColourScheme(
2680 JalviewModel jm, String id)
2682 List<UserColours> uc = jm.getUserColours();
2683 UserColours colours = null;
2685 for (int i = 0; i < uc.length; i++)
2687 if (uc[i].getId().equals(id))
2694 for (UserColours c : uc)
2696 if (c.getId().equals(id))
2703 java.awt.Color[] newColours = new java.awt.Color[24];
2705 for (int i = 0; i < 24; i++)
2707 newColours[i] = new java.awt.Color(Integer.parseInt(
2708 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2709 colours.getUserColourScheme().getColour().get(i).getRGB(),
2713 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2716 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2718 newColours = new java.awt.Color[23];
2719 for (int i = 0; i < 23; i++)
2721 newColours[i] = new java.awt.Color(Integer.parseInt(
2722 colours.getUserColourScheme().getColour().get(i + 24)
2726 ucs.setLowerCaseColours(newColours);
2733 * contains last error message (if any) encountered by XML loader.
2735 String errorMessage = null;
2738 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2739 * exceptions are raised during project XML parsing
2741 public boolean attemptversion1parse = false;
2744 * Load a jalview project archive from a jar file
2747 * - HTTP URL or filename
2749 public AlignFrame loadJalviewAlign(final Object file)
2752 jalview.gui.AlignFrame af = null;
2756 // create list to store references for any new Jmol viewers created
2757 newStructureViewers = new Vector<>();
2758 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2759 // Workaround is to make sure caller implements the JarInputStreamProvider
2761 // so we can re-open the jar input stream for each entry.
2763 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2764 af = loadJalviewAlign(jprovider);
2767 af.setMenusForViewport();
2769 } catch (MalformedURLException e)
2771 errorMessage = "Invalid URL format for '" + file + "'";
2777 // BH 2019 -- can't wait
2778 SwingUtilities.invokeLater(new Runnable()
2783 setLoadingFinishedForNewStructureViewers();
2786 } catch (Exception x)
2788 System.err.println("Error loading alignment: " + x.getMessage());
2794 @SuppressWarnings("unused")
2795 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2797 // BH 2018 allow for bytes already attached to File object
2799 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2800 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2803 errorMessage = null;
2804 uniqueSetSuffix = null;
2806 viewportsAdded.clear();
2807 frefedSequence = null;
2809 if (file.startsWith("http://")) {
2810 url = new URL(file);
2812 final URL _url = url;
2813 return new jarInputStreamProvider() {
2816 public JarInputStream getJarInputStream() throws IOException {
2817 if (bytes != null) {
2818 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2819 return new JarInputStream(new ByteArrayInputStream(bytes));
2822 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2823 return new JarInputStream(_url.openStream());
2825 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2826 return new JarInputStream(new FileInputStream(file));
2831 public String getFilename() {
2835 } catch (IOException e) {
2836 e.printStackTrace();
2842 * Recover jalview session from a jalview project archive. Caller may
2843 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2844 * themselves. Any null fields will be initialised with default values,
2845 * non-null fields are left alone.
2850 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2852 errorMessage = null;
2853 if (uniqueSetSuffix == null)
2855 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2857 if (seqRefIds == null)
2861 AlignFrame af = null, _af = null;
2862 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2863 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2864 final String file = jprovider.getFilename();
2867 JarInputStream jin = null;
2868 JarEntry jarentry = null;
2871 // Look for all the entry names ending with ".xml"
2872 // This includes all panels and at least one frame.
2873 // Platform.timeCheck(null, Platform.TIME_MARK);
2876 jin = jprovider.getJarInputStream();
2877 for (int i = 0; i < entryCount; i++)
2879 jarentry = jin.getNextJarEntry();
2881 String name = (jarentry == null ? null : jarentry.getName());
2882 if (name != null && name.endsWith(".xml"))
2885 // The question here is what to do with the two
2886 // .xml files in the jvp file.
2887 // Some number of them, "...Dataset for...", will be the
2888 // Only AlignPanels and will have Viewport.
2889 // One or more will be the source data, with the DBRefs.
2891 // JVP file writing (above) ensures tha the AlignPanels are written
2892 // first, then all relevant datasets (which are
2893 // Jalview.datamodel.Alignment).
2896 // Platform.timeCheck("Jalview2XML JAXB " + name, Platform.TIME_MARK);
2897 JAXBContext jc = JAXBContext
2898 .newInstance("jalview.xml.binding.jalview");
2899 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2900 .createXMLStreamReader(jin);
2901 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2902 JAXBElement<JalviewModel> jbe = um
2903 .unmarshal(streamReader, JalviewModel.class);
2904 JalviewModel model = jbe.getValue();
2906 if (true) // !skipViewport(object))
2908 // Q: Do we have to load from the model, even if it
2909 // does not have a viewport, could we discover that early on?
2910 // Q: Do we need to load this object?
2911 _af = loadFromObject(model, file, true, jprovider);
2912 // Platform.timeCheck("Jalview2XML.loadFromObject",
2913 // Platform.TIME_MARK);
2914 if (_af != null && model.getViewport().size() > 0)
2916 // That is, this is one of the AlignmentPanel models
2919 // store a reference to the first view
2922 if (_af.getViewport().isGatherViewsHere())
2924 // if this is a gathered view, keep its reference since
2925 // after gathering views, only this frame will remain
2927 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2930 // Save dataset to register mappings once all resolved
2931 importedDatasets.put(
2932 af.getViewport().getAlignment().getDataset(),
2933 af.getViewport().getAlignment().getDataset());
2936 // Platform.timeCheck("JAXB " + name, Platform.TIME_MARK);
2939 else if (jarentry != null)
2941 // Some other file here.
2944 } while (jarentry != null);
2945 // Platform.timeCheck("JAXB loop exit", Platform.TIME_MARK);
2946 resolveFrefedSequences();
2947 // Platform.timeCheck("JAXB resolveFrefed", Platform.TIME_MARK);
2949 } catch (IOException ex)
2951 ex.printStackTrace();
2952 errorMessage = "Couldn't locate Jalview XML file : " + file;
2954 "Exception whilst loading jalview XML file : " + ex + "\n");
2955 } catch (Exception ex)
2957 System.err.println("Parsing as Jalview Version 2 file failed.");
2958 ex.printStackTrace(System.err);
2959 if (attemptversion1parse)
2961 // used to attempt to parse as V1 castor-generated xml
2963 if (Desktop.getInstance() != null)
2965 Desktop.getInstance().stopLoading();
2969 System.out.println("Successfully loaded archive file");
2972 ex.printStackTrace();
2975 "Exception whilst loading jalview XML file : " + ex + "\n");
2976 } catch (OutOfMemoryError e)
2978 // Don't use the OOM Window here
2979 errorMessage = "Out of memory loading jalview XML file";
2980 System.err.println("Out of memory whilst loading jalview XML file");
2981 e.printStackTrace();
2985 * Regather multiple views (with the same sequence set id) to the frame (if
2986 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2987 * views instead of separate frames. Note this doesn't restore a state where
2988 * some expanded views in turn have tabbed views - the last "first tab" read
2989 * in will play the role of gatherer for all.
2991 for (AlignFrame fr : gatherToThisFrame.values())
2993 Desktop.getInstance().gatherViews(fr);
2996 restoreSplitFrames();
2997 for (AlignmentI ds : importedDatasets.keySet())
2999 if (ds.getCodonFrames() != null)
3001 Desktop.getInstance().getStructureSelectionManager()
3002 .registerMappings(ds.getCodonFrames());
3005 if (errorMessage != null)
3010 if (Desktop.getInstance() != null)
3012 Desktop.getInstance().stopLoading();
3019 * Try to reconstruct and display SplitFrame windows, where each contains
3020 * complementary dna and protein alignments. Done by pairing up AlignFrame
3021 * objects (created earlier) which have complementary viewport ids associated.
3023 protected void restoreSplitFrames()
3025 List<SplitFrame> gatherTo = new ArrayList<>();
3026 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3027 Map<String, AlignFrame> dna = new HashMap<>();
3030 * Identify the DNA alignments
3032 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3035 AlignFrame af = candidate.getValue();
3036 if (af.getViewport().getAlignment().isNucleotide())
3038 dna.put(candidate.getKey().getId(), af);
3043 * Try to match up the protein complements
3045 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3048 AlignFrame af = candidate.getValue();
3049 if (!af.getViewport().getAlignment().isNucleotide())
3051 String complementId = candidate.getKey().getComplementId();
3052 // only non-null complements should be in the Map
3053 if (complementId != null && dna.containsKey(complementId))
3055 final AlignFrame dnaFrame = dna.get(complementId);
3056 SplitFrame sf = createSplitFrame(dnaFrame, af);
3057 addedToSplitFrames.add(dnaFrame);
3058 addedToSplitFrames.add(af);
3059 dnaFrame.setMenusForViewport();
3060 af.setMenusForViewport();
3061 if (af.getViewport().isGatherViewsHere())
3070 * Open any that we failed to pair up (which shouldn't happen!) as
3071 * standalone AlignFrame's.
3073 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3076 AlignFrame af = candidate.getValue();
3077 if (!addedToSplitFrames.contains(af))
3079 Viewport view = candidate.getKey();
3080 Desktop.addInternalFrame(af, view.getTitle(),
3081 safeInt(view.getWidth()), safeInt(view.getHeight()));
3082 af.setMenusForViewport();
3083 System.err.println("Failed to restore view " + view.getTitle()
3084 + " to split frame");
3089 * Gather back into tabbed views as flagged.
3091 for (SplitFrame sf : gatherTo)
3093 Desktop.getInstance().gatherViews(sf);
3096 splitFrameCandidates.clear();
3100 * Construct and display one SplitFrame holding DNA and protein alignments.
3103 * @param proteinFrame
3106 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3107 AlignFrame proteinFrame)
3109 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3110 String title = MessageManager.getString("label.linked_view_title");
3111 int width = (int) dnaFrame.getBounds().getWidth();
3112 int height = (int) (dnaFrame.getBounds().getHeight()
3113 + proteinFrame.getBounds().getHeight() + 50);
3116 * SplitFrame location is saved to both enclosed frames
3118 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3119 Desktop.addInternalFrame(splitFrame, title, width, height);
3122 * And compute cDNA consensus (couldn't do earlier with consensus as
3123 * mappings were not yet present)
3125 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3131 * check errorMessage for a valid error message and raise an error box in the
3132 * GUI or write the current errorMessage to stderr and then clear the error
3135 protected void reportErrors()
3137 reportErrors(false);
3140 protected void reportErrors(final boolean saving)
3142 if (errorMessage != null)
3144 final String finalErrorMessage = errorMessage;
3147 javax.swing.SwingUtilities.invokeLater(new Runnable()
3152 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3154 "Error " + (saving ? "saving" : "loading")
3156 JvOptionPane.WARNING_MESSAGE);
3162 System.err.println("Problem loading Jalview file: " + errorMessage);
3165 errorMessage = null;
3168 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3171 * when set, local views will be updated from view stored in JalviewXML
3172 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3173 * sync if this is set to true.
3175 private final boolean updateLocalViews = false;
3178 * Returns the path to a temporary file holding the PDB file for the given PDB
3179 * id. The first time of asking, searches for a file of that name in the
3180 * Jalview project jar, and copies it to a new temporary file. Any repeat
3181 * requests just return the path to the file previously created.
3187 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3190 if (alreadyLoadedPDB.containsKey(pdbId))
3192 return alreadyLoadedPDB.get(pdbId).toString();
3195 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3197 if (tempFile != null)
3199 alreadyLoadedPDB.put(pdbId, tempFile);
3205 * Copies the jar entry of given name to a new temporary file and returns the
3206 * path to the file, or null if the entry is not found.
3209 * @param jarEntryName
3211 * a prefix for the temporary file name, must be at least three
3214 * null or original file - so new file can be given the same suffix
3218 protected String copyJarEntry(jarInputStreamProvider jprovider,
3219 String jarEntryName, String prefix, String origFile)
3221 BufferedReader in = null;
3222 PrintWriter out = null;
3223 String suffix = ".tmp";
3224 if (origFile == null)
3226 origFile = jarEntryName;
3228 int sfpos = origFile.lastIndexOf(".");
3229 if (sfpos > -1 && sfpos < (origFile.length() - 3))
3231 suffix = "." + origFile.substring(sfpos + 1);
3235 JarInputStream jin = jprovider.getJarInputStream();
3237 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3238 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3239 * FileInputStream(jprovider)); }
3242 JarEntry entry = null;
3245 entry = jin.getNextJarEntry();
3246 } while (entry != null && !entry.getName().equals(jarEntryName));
3249 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3250 File outFile = File.createTempFile(prefix, suffix);
3251 outFile.deleteOnExit();
3252 out = new PrintWriter(new FileOutputStream(outFile));
3255 while ((data = in.readLine()) != null)
3260 String t = outFile.getAbsolutePath();
3265 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3267 } catch (Exception ex)
3269 ex.printStackTrace();
3277 } catch (IOException e)
3291 private class JvAnnotRow
3293 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3300 * persisted version of annotation row from which to take vis properties
3302 public jalview.datamodel.AlignmentAnnotation template;
3305 * original position of the annotation row in the alignment
3311 * Load alignment frame from jalview XML DOM object. For a DOM object that
3312 * includes one or more Viewport elements (one with a title that does NOT
3313 * contain "Dataset for"), create the frame.
3315 * @param jalviewModel
3318 * filename source string
3319 * @param loadTreesAndStructures
3320 * when false only create Viewport
3322 * data source provider
3323 * @return alignment frame created from view stored in DOM
3325 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3326 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3329 // Platform.timeCheck("Jalview2XML.loadFromObject0", Platform.TIME_MARK);
3331 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3332 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3335 // JalviewModelSequence jms = object.getJalviewModelSequence();
3337 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3339 Viewport view = (jalviewModel.getViewport().size() > 0)
3340 ? jalviewModel.getViewport().get(0)
3343 // ////////////////////////////////
3344 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3347 // If we just load in the same jar file again, the sequenceSetId
3348 // will be the same, and we end up with multiple references
3349 // to the same sequenceSet. We must modify this id on load
3350 // so that each load of the file gives a unique id
3353 * used to resolve correct alignment dataset for alignments with multiple
3356 String uniqueSeqSetId = null;
3357 String viewId = null;
3360 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3361 viewId = (view.getId() == null ? null
3362 : view.getId() + uniqueSetSuffix);
3365 // Platform.timeCheck("Jalview2XML.loadFromObject1", Platform.TIME_MARK);
3366 // ////////////////////////////////
3369 List<SequenceI> hiddenSeqs = null;
3371 List<SequenceI> tmpseqs = new ArrayList<>();
3373 boolean multipleView = false;
3374 SequenceI referenceseqForView = null;
3375 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3376 List<JSeq> jseqs = jalviewModel.getJSeq();
3377 int vi = 0; // counter in vamsasSeq array
3378 for (int i = 0; i < jseqs.size(); i++)
3380 JSeq jseq = jseqs.get(i);
3381 String seqId = jseq.getId();
3383 SequenceI tmpSeq = seqRefIds.get(seqId);
3387 if (!incompleteSeqs.containsKey(seqId))
3389 // may not need this check, but keep it for at least 2.9,1 release
3390 if (tmpSeq.getStart() != jseq.getStart()
3391 || tmpSeq.getEnd() != jseq.getEnd())
3394 "Warning JAL-2154 regression: updating start/end for sequence "
3395 + tmpSeq.toString() + " to " + jseq);
3400 incompleteSeqs.remove(seqId);
3402 if (vamsasSeqs.size() > vi
3403 && vamsasSeqs.get(vi).getId().equals(seqId))
3405 // most likely we are reading a dataset XML document so
3406 // update from vamsasSeq section of XML for this sequence
3407 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3408 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3409 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3414 // reading multiple views, so vamsasSeq set is a subset of JSeq
3415 multipleView = true;
3417 tmpSeq.setStart(jseq.getStart());
3418 tmpSeq.setEnd(jseq.getEnd());
3419 tmpseqs.add(tmpSeq);
3423 Sequence vamsasSeq = vamsasSeqs.get(vi);
3424 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3425 vamsasSeq.getSequence());
3426 tmpSeq.setDescription(vamsasSeq.getDescription());
3427 tmpSeq.setStart(jseq.getStart());
3428 tmpSeq.setEnd(jseq.getEnd());
3429 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3430 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3431 tmpseqs.add(tmpSeq);
3435 if (safeBoolean(jseq.isViewreference()))
3437 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3440 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3442 if (hiddenSeqs == null)
3444 hiddenSeqs = new ArrayList<>();
3447 hiddenSeqs.add(tmpSeq);
3451 // Platform.timeCheck("Jalview2XML.loadFromObject-seq",
3452 // Platform.TIME_MARK);
3454 // Create the alignment object from the sequence set
3455 // ///////////////////////////////
3456 SequenceI[] orderedSeqs = tmpseqs
3457 .toArray(new SequenceI[tmpseqs.size()]);
3459 AlignmentI al = null;
3460 // so we must create or recover the dataset alignment before going further
3461 // ///////////////////////////////
3462 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3464 // older jalview projects do not have a dataset - so creat alignment and
3466 al = new Alignment(orderedSeqs);
3467 al.setDataset(null);
3471 boolean isdsal = jalviewModel.getViewport().isEmpty();
3474 // we are importing a dataset record, so
3475 // recover reference to an alignment already materialsed as dataset
3476 al = getDatasetFor(vamsasSet.getDatasetId());
3480 // materialse the alignment
3481 al = new Alignment(orderedSeqs);
3485 addDatasetRef(vamsasSet.getDatasetId(), al);
3488 // finally, verify all data in vamsasSet is actually present in al
3489 // passing on flag indicating if it is actually a stored dataset
3490 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3493 // Platform.timeCheck("Jalview2XML.loadFromObject-align",
3494 // Platform.TIME_MARK);
3495 if (referenceseqForView != null)
3497 al.setSeqrep(referenceseqForView);
3499 // / Add the alignment properties
3500 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3502 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3504 al.setProperty(ssp.getKey(), ssp.getValue());
3507 // Platform.timeCheck("Jalview2XML.loadFromObject-setseqprop",
3508 // Platform.TIME_MARK);
3509 // ///////////////////////////////
3511 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3514 // load sequence features, database references and any associated PDB
3515 // structures for the alignment
3517 // prior to 2.10, this part would only be executed the first time a
3518 // sequence was encountered, but not afterwards.
3519 // now, for 2.10 projects, this is also done if the xml doc includes
3520 // dataset sequences not actually present in any particular view.
3522 for (int i = 0; i < vamsasSeqs.size(); i++)
3524 JSeq jseq = jseqs.get(i);
3525 if (jseq.getFeatures().size() > 0)
3527 List<Feature> features = jseq.getFeatures();
3528 for (int f = 0; f < features.size(); f++)
3530 Feature feat = features.get(f);
3531 SequenceFeature sf = new SequenceFeature(feat.getType(),
3532 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3533 safeFloat(feat.getScore()), feat.getFeatureGroup());
3534 sf.setStatus(feat.getStatus());
3537 * load any feature attributes - include map-valued attributes
3539 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3540 for (int od = 0; od < feat.getOtherData().size(); od++)
3542 OtherData keyValue = feat.getOtherData().get(od);
3543 String attributeName = keyValue.getKey();
3544 String attributeValue = keyValue.getValue();
3545 if (attributeName.startsWith("LINK"))
3547 sf.addLink(attributeValue);
3551 String subAttribute = keyValue.getKey2();
3552 if (subAttribute == null)
3554 // simple string-valued attribute
3555 sf.setValue(attributeName, attributeValue);
3559 // attribute 'key' has sub-attribute 'key2'
3560 if (!mapAttributes.containsKey(attributeName))
3562 mapAttributes.put(attributeName, new HashMap<>());
3564 mapAttributes.get(attributeName).put(subAttribute,
3569 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3572 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3575 // adds feature to datasequence's feature set (since Jalview 2.10)
3576 al.getSequenceAt(i).addSequenceFeature(sf);
3579 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3581 // adds dbrefs to datasequence's set (since Jalview 2.10)
3583 al.getSequenceAt(i).getDatasetSequence() == null
3584 ? al.getSequenceAt(i)
3585 : al.getSequenceAt(i).getDatasetSequence(),
3588 if (jseq.getPdbids().size() > 0)
3590 List<Pdbids> ids = jseq.getPdbids();
3591 for (int p = 0; p < ids.size(); p++)
3593 Pdbids pdbid = ids.get(p);
3594 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3595 entry.setId(pdbid.getId());
3596 if (pdbid.getType() != null)
3598 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3600 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3604 entry.setType(PDBEntry.Type.FILE);
3607 // jprovider is null when executing 'New View'
3608 if (pdbid.getFile() != null && jprovider != null)
3610 if (!pdbloaded.containsKey(pdbid.getFile()))
3612 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3617 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3621 if (pdbid.getPdbentryItem() != null)
3623 for (PdbentryItem item : pdbid.getPdbentryItem())
3625 for (Property pr : item.getProperty())
3627 entry.setProperty(pr.getName(), pr.getValue());
3632 for (Property prop : pdbid.getProperty())
3634 entry.setProperty(prop.getName(), prop.getValue());
3636 Desktop.getInstance().getStructureSelectionManager()
3637 .registerPDBEntry(entry);
3638 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3639 if (al.getSequenceAt(i).getDatasetSequence() != null)
3641 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3645 al.getSequenceAt(i).addPDBId(entry);
3650 // Platform.timeCheck("Jalview2XML.loadFromObject-endmultiview",
3651 // Platform.TIME_MARK);
3652 } // end !multipleview
3654 // ///////////////////////////////
3655 // LOAD SEQUENCE MAPPINGS
3657 if (vamsasSet.getAlcodonFrame().size() > 0)
3659 // TODO Potentially this should only be done once for all views of an
3661 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3662 for (int i = 0; i < alc.size(); i++)
3664 AlignedCodonFrame cf = new AlignedCodonFrame();
3665 if (alc.get(i).getAlcodMap().size() > 0)
3667 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3668 for (int m = 0; m < maps.size(); m++)
3670 AlcodMap map = maps.get(m);
3671 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3673 jalview.datamodel.Mapping mapping = null;
3674 // attach to dna sequence reference.
3675 if (map.getMapping() != null)
3677 mapping = addMapping(map.getMapping());
3678 if (dnaseq != null && mapping.getTo() != null)
3680 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3686 newAlcodMapRef(map.getDnasq(), cf, mapping));
3690 al.addCodonFrame(cf);
3693 // Platform.timeCheck("Jalview2XML.loadFromObject-seqmap",
3694 // Platform.TIME_MARK);
3697 // ////////////////////////////////
3699 List<JvAnnotRow> autoAlan = new ArrayList<>();
3702 * store any annotations which forward reference a group's ID
3704 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3706 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3708 List<Annotation> an = vamsasSet.getAnnotation();
3710 for (int i = 0; i < an.size(); i++)
3712 Annotation annotation = an.get(i);
3715 * test if annotation is automatically calculated for this view only
3717 boolean autoForView = false;
3718 if (annotation.getLabel().equals("Quality")
3719 || annotation.getLabel().equals("Conservation")
3720 || annotation.getLabel().equals("Consensus"))
3722 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3724 // JAXB has no has() test; schema defaults value to false
3725 // if (!annotation.hasAutoCalculated())
3727 // annotation.setAutoCalculated(true);
3730 if (autoForView || annotation.isAutoCalculated())
3732 // remove ID - we don't recover annotation from other views for
3733 // view-specific annotation
3734 annotation.setId(null);
3737 // set visibility for other annotation in this view
3738 String annotationId = annotation.getId();
3739 if (annotationId != null && annotationIds.containsKey(annotationId))
3741 AlignmentAnnotation jda = annotationIds.get(annotationId);
3742 // in principle Visible should always be true for annotation displayed
3743 // in multiple views
3744 if (annotation.isVisible() != null)
3746 jda.visible = annotation.isVisible();
3749 al.addAnnotation(jda);
3753 // Construct new annotation from model.
3754 List<AnnotationElement> ae = annotation.getAnnotationElement();
3755 // System.err.println(
3756 // "Jalview2XML processing " + ae.size() + " annotations");
3758 jalview.datamodel.Annotation[] anot = null;
3759 java.awt.Color firstColour = null;
3761 if (!annotation.isScoreOnly())
3763 anot = new jalview.datamodel.Annotation[al.getWidth()];
3764 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3766 AnnotationElement annElement = ae.get(aa);
3767 anpos = annElement.getPosition();
3769 if (anpos >= anot.length)
3774 float value = safeFloat(annElement.getValue());
3775 anot[anpos] = new jalview.datamodel.Annotation(
3776 annElement.getDisplayCharacter(),
3777 annElement.getDescription(),
3778 (annElement.getSecondaryStructure() == null
3779 || annElement.getSecondaryStructure()
3783 .getSecondaryStructure()
3786 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3787 if (firstColour == null)
3789 firstColour = anot[anpos].colour;
3793 // create the new AlignmentAnnotation
3794 jalview.datamodel.AlignmentAnnotation jaa = null;
3796 if (annotation.isGraph())
3798 float llim = 0, hlim = 0;
3799 // if (autoForView || an[i].isAutoCalculated()) {
3802 jaa = new jalview.datamodel.AlignmentAnnotation(
3803 annotation.getLabel(), annotation.getDescription(), anot,
3804 llim, hlim, safeInt(annotation.getGraphType()));
3806 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3807 jaa._linecolour = firstColour;
3808 if (annotation.getThresholdLine() != null)
3810 jaa.setThreshold(new jalview.datamodel.GraphLine(
3811 safeFloat(annotation.getThresholdLine().getValue()),
3812 annotation.getThresholdLine().getLabel(),
3813 new java.awt.Color(safeInt(
3814 annotation.getThresholdLine().getColour()))));
3816 if (autoForView || annotation.isAutoCalculated())
3818 // Hardwire the symbol display line to ensure that labels for
3819 // histograms are displayed
3825 jaa = new jalview.datamodel.AlignmentAnnotation(
3826 annotation.getLabel(), annotation.getDescription(), anot);
3827 jaa._linecolour = firstColour;
3829 // register new annotation
3830 // Annotation graphs such as Conservation will not have id.
3831 if (annotation.getId() != null)
3833 annotationIds.put(annotation.getId(), jaa);
3834 jaa.annotationId = annotation.getId();
3836 // recover sequence association
3837 String sequenceRef = annotation.getSequenceRef();
3838 if (sequenceRef != null)
3840 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3841 SequenceI sequence = seqRefIds.get(sequenceRef);
3842 if (sequence == null)
3844 // in pre-2.9 projects sequence ref is to sequence name
3845 sequence = al.findName(sequenceRef);
3847 if (sequence != null)
3849 jaa.createSequenceMapping(sequence, 1, true);
3850 sequence.addAlignmentAnnotation(jaa);
3853 // and make a note of any group association
3854 if (annotation.getGroupRef() != null
3855 && annotation.getGroupRef().length() > 0)
3857 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3858 .get(annotation.getGroupRef());
3861 aal = new ArrayList<>();
3862 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3867 if (annotation.getScore() != null)
3869 jaa.setScore(annotation.getScore().doubleValue());
3871 if (annotation.isVisible() != null)
3873 jaa.visible = annotation.isVisible().booleanValue();
3876 if (annotation.isCentreColLabels() != null)
3878 jaa.centreColLabels = annotation.isCentreColLabels()
3882 if (annotation.isScaleColLabels() != null)
3884 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3886 if (annotation.isAutoCalculated())
3888 // newer files have an 'autoCalculated' flag and store calculation
3889 // state in viewport properties
3890 jaa.autoCalculated = true; // means annotation will be marked for
3891 // update at end of load.
3893 if (annotation.getGraphHeight() != null)
3895 jaa.graphHeight = annotation.getGraphHeight().intValue();
3897 jaa.belowAlignment = annotation.isBelowAlignment();
3898 jaa.setCalcId(annotation.getCalcId());
3899 if (annotation.getProperty().size() > 0)
3901 for (Annotation.Property prop : annotation
3904 jaa.setProperty(prop.getName(), prop.getValue());
3907 if (jaa.autoCalculated)
3909 autoAlan.add(new JvAnnotRow(i, jaa));
3912 // if (!autoForView)
3914 // add autocalculated group annotation and any user created annotation
3916 al.addAnnotation(jaa);
3919 // Platform.timeCheck("Jalview2XML.loadFromObject-annot",
3920 // Platform.TIME_MARK);
3922 // ///////////////////////
3924 // Create alignment markup and styles for this view
3925 if (jalviewModel.getJGroup().size() > 0)
3927 List<JGroup> groups = jalviewModel.getJGroup();
3928 boolean addAnnotSchemeGroup = false;
3929 for (int i = 0; i < groups.size(); i++)
3931 JGroup jGroup = groups.get(i);
3932 ColourSchemeI cs = null;
3933 if (jGroup.getColour() != null)
3935 if (jGroup.getColour().startsWith("ucs"))
3937 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3939 else if (jGroup.getColour().equals("AnnotationColourGradient")
3940 && jGroup.getAnnotationColours() != null)
3942 addAnnotSchemeGroup = true;
3946 cs = ColourSchemeProperty.getColourScheme(null, al,
3947 jGroup.getColour());
3950 int pidThreshold = safeInt(jGroup.getPidThreshold());
3952 Vector<SequenceI> seqs = new Vector<>();
3954 for (int s = 0; s < jGroup.getSeq().size(); s++)
3956 String seqId = jGroup.getSeq().get(s);
3957 SequenceI ts = seqRefIds.get(seqId);
3961 seqs.addElement(ts);
3965 if (seqs.size() < 1)
3970 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3971 safeBoolean(jGroup.isDisplayBoxes()),
3972 safeBoolean(jGroup.isDisplayText()),
3973 safeBoolean(jGroup.isColourText()),
3974 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3975 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3976 sg.getGroupColourScheme()
3977 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3978 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3980 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3981 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3982 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3983 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3984 // attributes with a default in the schema are never null
3985 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3986 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3987 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3988 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3989 if (jGroup.getConsThreshold() != null
3990 && jGroup.getConsThreshold().intValue() != 0)
3992 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3995 c.verdict(false, 25);
3996 sg.cs.setConservation(c);
3999 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4001 // re-instate unique group/annotation row reference
4002 List<AlignmentAnnotation> jaal = groupAnnotRefs
4003 .get(jGroup.getId());
4006 for (AlignmentAnnotation jaa : jaal)
4009 if (jaa.autoCalculated)
4011 // match up and try to set group autocalc alignment row for this
4013 if (jaa.label.startsWith("Consensus for "))
4015 sg.setConsensus(jaa);
4017 // match up and try to set group autocalc alignment row for this
4019 if (jaa.label.startsWith("Conservation for "))
4021 sg.setConservationRow(jaa);
4028 if (addAnnotSchemeGroup)
4030 // reconstruct the annotation colourscheme
4031 sg.setColourScheme(constructAnnotationColour(
4032 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
4035 // Platform.timeCheck("Jalview2XML.loadFromObject-groups",
4036 // Platform.TIME_MARK);
4040 // only dataset in this model, so just return.
4043 // ///////////////////////////////
4046 // now check to see if we really need to create a new viewport.
4047 if (multipleView && viewportsAdded.size() == 0)
4049 // We recovered an alignment for which a viewport already exists.
4050 // TODO: fix up any settings necessary for overlaying stored state onto
4051 // state recovered from another document. (may not be necessary).
4052 // we may need a binding from a viewport in memory to one recovered from
4054 // and then recover its containing af to allow the settings to be applied.
4055 // TODO: fix for vamsas demo
4057 "About to recover a viewport for existing alignment: Sequence set ID is "
4059 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4060 if (seqsetobj != null)
4062 if (seqsetobj instanceof String)
4064 uniqueSeqSetId = (String) seqsetobj;
4066 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4072 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4076 // Platform.timeCheck("Jalview2XML.loadFromObject-viewport",
4077 // Platform.TIME_MARK);
4080 * indicate that annotation colours are applied across all groups (pre
4081 * Jalview 2.8.1 behaviour)
4083 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4084 jalviewModel.getVersion());
4086 AlignFrame af = null;
4087 AlignmentPanel ap = null;
4088 AlignViewport av = null;
4091 // Check to see if this alignment already has a view id == viewId
4092 jalview.gui.AlignmentPanel views[] = Desktop
4093 .getAlignmentPanels(uniqueSeqSetId);
4094 if (views != null && views.length > 0)
4096 for (int v = 0; v < views.length; v++)
4100 if (av.getViewId().equalsIgnoreCase(viewId))
4102 // recover the existing alignpanel, alignframe, viewport
4105 // TODO: could even skip resetting view settings if we don't want to
4106 // change the local settings from other jalview processes
4114 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4115 uniqueSeqSetId, viewId, autoAlan);
4116 av = af.getViewport();
4117 // note that this only retrieves the most recently accessed
4118 // tab of an AlignFrame.
4123 * Load any trees, PDB structures and viewers
4125 * Not done if flag is false (when this method is used for New View)
4127 final AlignFrame af0 = af;
4128 final AlignViewport av0 = av;
4129 final AlignmentPanel ap0 = ap;
4130 // Platform.timeCheck("Jalview2XML.loadFromObject-beforetree",
4131 // Platform.TIME_MARK);
4132 if (loadTreesAndStructures)
4134 if (!jalviewModel.getTree().isEmpty())
4136 SwingUtilities.invokeLater(new Runnable()
4141 // Platform.timeCheck(null, Platform.TIME_MARK);
4142 loadTrees(jalviewModel, view, af0, av0, ap0);
4143 // Platform.timeCheck("Jalview2XML.loadTrees", Platform.TIME_MARK);
4147 if (!jalviewModel.getPcaViewer().isEmpty())
4149 SwingUtilities.invokeLater(new Runnable()
4154 // Platform.timeCheck(null, Platform.TIME_MARK);
4155 loadPCAViewers(jalviewModel, ap0);
4156 // Platform.timeCheck("Jalview2XML.loadPCA", Platform.TIME_MARK);
4160 SwingUtilities.invokeLater(new Runnable()
4165 // Platform.timeCheck(null, Platform.TIME_MARK);
4166 loadPDBStructures(jprovider, jseqs, af0, ap0);
4167 // Platform.timeCheck("Jalview2XML.loadPDB", Platform.TIME_MARK);
4170 SwingUtilities.invokeLater(new Runnable()
4175 loadRnaViewers(jprovider, jseqs, ap0);
4179 // and finally return.
4184 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4185 * panel is restored from separate jar entries, two (gapped and trimmed) per
4186 * sequence and secondary structure.
4188 * Currently each viewer shows just one sequence and structure (gapped and
4189 * trimmed), however this method is designed to support multiple sequences or
4190 * structures in viewers if wanted in future.
4196 protected void loadRnaViewers(jarInputStreamProvider jprovider,
4197 List<JSeq> jseqs, AlignmentPanel ap)
4200 * scan the sequences for references to viewers; create each one the first
4201 * time it is referenced, add Rna models to existing viewers
4203 for (JSeq jseq : jseqs)
4205 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4207 RnaViewer viewer = jseq.getRnaViewer().get(i);
4208 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4211 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4213 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4214 SequenceI seq = seqRefIds.get(jseq.getId());
4215 AlignmentAnnotation ann = this.annotationIds
4216 .get(ss.getAnnotationId());
4219 * add the structure to the Varna display (with session state copied
4220 * from the jar to a temporary file)
4222 boolean gapped = safeBoolean(ss.isGapped());
4223 String rnaTitle = ss.getTitle();
4224 String sessionState = ss.getViewerState();
4225 String tempStateFile = copyJarEntry(jprovider, sessionState,
4227 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4228 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4230 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4236 * Locate and return an already instantiated matching AppVarna, or create one
4240 * @param viewIdSuffix
4244 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4245 String viewIdSuffix, AlignmentPanel ap)
4248 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4249 * if load is repeated
4251 String postLoadId = viewer.getViewId() + viewIdSuffix;
4252 for (JInternalFrame frame : getAllFrames())
4254 if (frame instanceof AppVarna)
4256 AppVarna varna = (AppVarna) frame;
4257 if (postLoadId.equals(varna.getViewId()))
4259 // this viewer is already instantiated
4260 // could in future here add ap as another 'parent' of the
4261 // AppVarna window; currently just 1-to-many
4268 * viewer not found - make it
4270 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4271 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4272 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4273 safeInt(viewer.getDividerLocation()));
4274 AppVarna varna = new AppVarna(model, ap);
4280 * Load any saved trees
4288 protected void loadTrees(JalviewModel jm, Viewport view,
4289 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4291 // TODO result of automated refactoring - are all these parameters needed?
4294 for (int t = 0; t < jm.getTree().size(); t++)
4297 Tree tree = jm.getTree().get(t);
4299 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4302 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4303 tree.getTitle(), safeInt(tree.getWidth()),
4304 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4305 safeInt(tree.getYpos()));
4306 if (tree.getId() != null)
4308 // perhaps bind the tree id to something ?
4313 // update local tree attributes ?
4314 // TODO: should check if tp has been manipulated by user - if so its
4315 // settings shouldn't be modified
4316 tp.setTitle(tree.getTitle());
4317 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4318 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4319 safeInt(tree.getHeight())));
4320 tp.setViewport(av); // af.viewport;
4321 // TODO: verify 'associate with all views' works still
4322 tp.getTreeCanvas().setViewport(av); // af.viewport;
4323 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4325 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4328 warn("There was a problem recovering stored Newick tree: \n"
4329 + tree.getNewick());
4333 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4334 tp.fitToWindow_actionPerformed(null);
4336 if (tree.getFontName() != null)
4339 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4340 safeInt(tree.getFontSize())));
4345 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4346 safeInt(view.getFontSize())));
4349 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4350 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4351 tp.showDistances(safeBoolean(tree.isShowDistances()));
4353 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4355 if (safeBoolean(tree.isCurrentTree()))
4357 af.getViewport().setCurrentTree(tp.getTree());
4361 } catch (Exception ex)
4363 ex.printStackTrace();
4368 * Load and link any saved structure viewers.
4375 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4376 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4379 * Run through all PDB ids on the alignment, and collect mappings between
4380 * distinct view ids and all sequences referring to that view.
4382 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4384 for (int i = 0; i < jseqs.size(); i++)
4386 JSeq jseq = jseqs.get(i);
4387 if (jseq.getPdbids().size() > 0)
4389 List<Pdbids> ids = jseq.getPdbids();
4390 for (int p = 0; p < ids.size(); p++)
4392 Pdbids pdbid = ids.get(p);
4393 final int structureStateCount = pdbid.getStructureState().size();
4394 for (int s = 0; s < structureStateCount; s++)
4396 // check to see if we haven't already created this structure view
4397 final StructureState structureState = pdbid
4398 .getStructureState().get(s);
4399 String sviewid = (structureState.getViewId() == null) ? null
4400 : structureState.getViewId() + uniqueSetSuffix;
4401 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4402 // Originally : pdbid.getFile()
4403 // : TODO: verify external PDB file recovery still works in normal
4404 // jalview project load
4406 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4407 jpdb.setId(pdbid.getId());
4409 int x = safeInt(structureState.getXpos());
4410 int y = safeInt(structureState.getYpos());
4411 int width = safeInt(structureState.getWidth());
4412 int height = safeInt(structureState.getHeight());
4414 // Probably don't need to do this anymore...
4415 // Desktop.getDesktop().getComponentAt(x, y);
4416 // TODO: NOW: check that this recovers the PDB file correctly.
4417 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4419 jalview.datamodel.SequenceI seq = seqRefIds
4420 .get(jseq.getId() + "");
4421 if (sviewid == null)
4423 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4426 if (!structureViewers.containsKey(sviewid))
4428 structureViewers.put(sviewid,
4429 new StructureViewerModel(x, y, width, height, false,
4430 false, true, structureState.getViewId(),
4431 structureState.getType()));
4432 // Legacy pre-2.7 conversion JAL-823 :
4433 // do not assume any view has to be linked for colour by
4437 // assemble String[] { pdb files }, String[] { id for each
4438 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4439 // seqs_file 2}, boolean[] {
4440 // linkAlignPanel,superposeWithAlignpanel}} from hash
4441 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4442 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4443 || structureState.isAlignwithAlignPanel());
4446 * Default colour by linked panel to false if not specified (e.g.
4447 * for pre-2.7 projects)
4449 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4450 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4451 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4454 * Default colour by viewer to true if not specified (e.g. for
4457 boolean colourByViewer = jmoldat.isColourByViewer();
4458 colourByViewer &= structureState.isColourByJmol();
4459 jmoldat.setColourByViewer(colourByViewer);
4461 if (jmoldat.getStateData().length() < structureState
4462 .getValue()/*Content()*/.length())
4464 jmoldat.setStateData(structureState.getValue());// Content());
4466 if (pdbid.getFile() != null)
4468 File mapkey = new File(pdbid.getFile());
4469 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4470 if (seqstrmaps == null)
4472 jmoldat.getFileData().put(mapkey,
4473 seqstrmaps = jmoldat.new StructureData(pdbFile,
4476 if (!seqstrmaps.getSeqList().contains(seq))
4478 seqstrmaps.getSeqList().add(seq);
4484 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");
4491 // Instantiate the associated structure views
4492 for (Entry<String, StructureViewerModel> entry : structureViewers
4497 createOrLinkStructureViewer(entry, af, ap, jprovider);
4498 } catch (Exception e)
4501 "Error loading structure viewer: " + e.getMessage());
4502 // failed - try the next one
4514 protected void createOrLinkStructureViewer(
4515 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4516 AlignmentPanel ap, jarInputStreamProvider jprovider)
4518 final StructureViewerModel stateData = viewerData.getValue();
4521 * Search for any viewer windows already open from other alignment views
4522 * that exactly match the stored structure state
4524 StructureViewerBase comp = findMatchingViewer(viewerData);
4528 linkStructureViewer(ap, comp, stateData);
4533 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4534 * "viewer_"+stateData.viewId
4536 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4538 createChimeraViewer(viewerData, af, jprovider);
4543 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4545 createJmolViewer(viewerData, af, jprovider);
4550 * Create a new Chimera viewer.
4556 protected void createChimeraViewer(
4557 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4558 jarInputStreamProvider jprovider)
4560 StructureViewerModel data = viewerData.getValue();
4561 String chimeraSessionFile = data.getStateData();
4564 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4566 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4567 * 'uniquified' sviewid used to reconstruct the viewer here
4569 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4570 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4573 Set<Entry<File, StructureData>> fileData = data.getFileData()
4575 List<PDBEntry> pdbs = new ArrayList<>();
4576 List<SequenceI[]> allseqs = new ArrayList<>();
4577 for (Entry<File, StructureData> pdb : fileData)
4579 String filePath = pdb.getValue().getFilePath();
4580 String pdbId = pdb.getValue().getPdbId();
4581 // pdbs.add(new PDBEntry(filePath, pdbId));
4582 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4583 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4584 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4588 boolean colourByChimera = data.isColourByViewer();
4589 boolean colourBySequence = data.isColourWithAlignPanel();
4591 // TODO use StructureViewer as a factory here, see JAL-1761
4592 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4593 final SequenceI[][] seqsArray = allseqs
4594 .toArray(new SequenceI[allseqs.size()][]);
4595 String newViewId = viewerData.getKey();
4597 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4598 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4599 colourBySequence, newViewId);
4600 cvf.setSize(data.getWidth(), data.getHeight());
4601 cvf.setLocation(data.getX(), data.getY());
4605 * Create a new Jmol window. First parse the Jmol state to translate filenames
4606 * loaded into the view, and record the order in which files are shown in the
4607 * Jmol view, so we can add the sequence mappings in same order.
4613 protected void createJmolViewer(
4614 final Entry<String, StructureViewerModel> viewerData,
4615 AlignFrame af, jarInputStreamProvider jprovider)
4617 final StructureViewerModel svattrib = viewerData.getValue();
4618 String state = svattrib.getStateData();
4621 * Pre-2.9: state element value is the Jmol state string
4623 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4626 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4628 state = readJarEntry(jprovider,
4629 getViewerJarEntryName(svattrib.getViewId()));
4632 List<String> pdbfilenames = new ArrayList<>();
4633 List<SequenceI[]> seqmaps = new ArrayList<>();
4634 List<String> pdbids = new ArrayList<>();
4635 StringBuilder newFileLoc = new StringBuilder(64);
4636 int cp = 0, ncp, ecp;
4637 Map<File, StructureData> oldFiles = svattrib.getFileData();
4638 while ((ncp = state.indexOf("load ", cp)) > -1)
4642 // look for next filename in load statement
4643 newFileLoc.append(state.substring(cp,
4644 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4645 String oldfilenam = state.substring(ncp,
4646 ecp = state.indexOf("\"", ncp));
4647 // recover the new mapping data for this old filename
4648 // have to normalize filename - since Jmol and jalview do
4650 // translation differently.
4651 StructureData filedat = oldFiles.get(new File(oldfilenam));
4652 if (filedat == null)
4654 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4655 filedat = oldFiles.get(new File(reformatedOldFilename));
4657 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4658 pdbfilenames.add(filedat.getFilePath());
4659 pdbids.add(filedat.getPdbId());
4660 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4661 newFileLoc.append("\"");
4662 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4663 // look for next file statement.
4664 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4668 // just append rest of state
4669 newFileLoc.append(state.substring(cp));
4673 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4674 newFileLoc = new StringBuilder(state);
4675 newFileLoc.append("; load append ");
4676 for (File id : oldFiles.keySet())
4678 // add this and any other pdb files that should be present in
4680 StructureData filedat = oldFiles.get(id);
4681 newFileLoc.append(filedat.getFilePath());
4682 pdbfilenames.add(filedat.getFilePath());
4683 pdbids.add(filedat.getPdbId());
4684 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4685 newFileLoc.append(" \"");
4686 newFileLoc.append(filedat.getFilePath());
4687 newFileLoc.append("\"");
4690 newFileLoc.append(";");
4693 if (newFileLoc.length() == 0)
4697 int histbug = newFileLoc.indexOf("history = ");
4701 * change "history = [true|false];" to "history = [1|0];"
4704 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4705 String val = (diff == -1) ? null
4706 : newFileLoc.substring(histbug, diff);
4707 if (val != null && val.length() >= 4)
4709 if (val.contains("e")) // eh? what can it be?
4711 if (val.trim().equals("true"))
4719 newFileLoc.replace(histbug, diff, val);
4724 final String[] pdbf = pdbfilenames
4725 .toArray(new String[pdbfilenames.size()]);
4726 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4727 final SequenceI[][] sq = seqmaps
4728 .toArray(new SequenceI[seqmaps.size()][]);
4729 final String fileloc = newFileLoc.toString();
4730 final String sviewid = viewerData.getKey();
4731 final AlignFrame alf = af;
4732 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4733 svattrib.getWidth(), svattrib.getHeight());
4736 javax.swing.SwingUtilities.invokeLater(new Runnable()
4741 JalviewStructureDisplayI sview = null;
4744 sview = new StructureViewer(
4745 alf.alignPanel.getStructureSelectionManager())
4746 .createView(StructureViewer.ViewerType.JMOL,
4747 pdbf, id, sq, alf.alignPanel, svattrib,
4748 fileloc, rect, sviewid);
4749 addNewStructureViewer(sview);
4750 } catch (OutOfMemoryError ex)
4752 new OOMWarning("restoring structure view for PDB id " + id,
4753 (OutOfMemoryError) ex.getCause());
4754 if (sview != null && sview.isVisible())
4756 sview.closeViewer(false);
4757 sview.setVisible(false);
4763 // } catch (InvocationTargetException ex)
4765 // warn("Unexpected error when opening Jmol view.", ex);
4767 // } catch (InterruptedException e)
4769 // // e.printStackTrace();
4775 * Generates a name for the entry in the project jar file to hold state
4776 * information for a structure viewer
4781 protected String getViewerJarEntryName(String viewId)
4783 return VIEWER_PREFIX + viewId;
4787 * Returns any open frame that matches given structure viewer data. The match
4788 * is based on the unique viewId, or (for older project versions) the frame's
4794 protected StructureViewerBase findMatchingViewer(
4795 Entry<String, StructureViewerModel> viewerData)
4797 final String sviewid = viewerData.getKey();
4798 final StructureViewerModel svattrib = viewerData.getValue();
4799 StructureViewerBase comp = null;
4800 JInternalFrame[] frames = getAllFrames();
4801 for (JInternalFrame frame : frames)
4803 if (frame instanceof StructureViewerBase)
4806 * Post jalview 2.4 schema includes structure view id
4808 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4811 comp = (StructureViewerBase) frame;
4812 break; // break added in 2.9
4815 * Otherwise test for matching position and size of viewer frame
4817 else if (frame.getX() == svattrib.getX()
4818 && frame.getY() == svattrib.getY()
4819 && frame.getHeight() == svattrib.getHeight()
4820 && frame.getWidth() == svattrib.getWidth())
4822 comp = (StructureViewerBase) frame;
4823 // no break in faint hope of an exact match on viewId
4831 * Link an AlignmentPanel to an existing structure viewer.
4836 * @param useinViewerSuperpos
4837 * @param usetoColourbyseq
4838 * @param viewerColouring
4840 protected void linkStructureViewer(AlignmentPanel ap,
4841 StructureViewerBase viewer, StructureViewerModel stateData)
4843 // NOTE: if the jalview project is part of a shared session then
4844 // view synchronization should/could be done here.
4846 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4847 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4848 final boolean viewerColouring = stateData.isColourByViewer();
4849 Map<File, StructureData> oldFiles = stateData.getFileData();
4852 * Add mapping for sequences in this view to an already open viewer
4854 final AAStructureBindingModel binding = viewer.getBinding();
4855 for (File id : oldFiles.keySet())
4857 // add this and any other pdb files that should be present in the
4859 StructureData filedat = oldFiles.get(id);
4860 String pdbFile = filedat.getFilePath();
4861 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4862 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4864 binding.addSequenceForStructFile(pdbFile, seq);
4866 // and add the AlignmentPanel's reference to the view panel
4867 viewer.addAlignmentPanel(ap);
4868 if (useinViewerSuperpos)
4870 viewer.useAlignmentPanelForSuperposition(ap);
4874 viewer.excludeAlignmentPanelForSuperposition(ap);
4876 if (usetoColourbyseq)
4878 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4882 viewer.excludeAlignmentPanelForColourbyseq(ap);
4887 * Get all frames within the Desktop.
4891 protected JInternalFrame[] getAllFrames()
4893 JInternalFrame[] frames = null;
4894 // TODO is this necessary - is it safe - risk of hanging?
4899 frames = Desktop.getDesktopPane().getAllFrames();
4900 } catch (ArrayIndexOutOfBoundsException e)
4902 // occasional No such child exceptions are thrown here...
4906 } catch (InterruptedException f)
4910 } while (frames == null);
4915 * Answers true if 'version' is equal to or later than 'supported', where each
4916 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4917 * changes. Development and test values for 'version' are leniently treated
4921 * - minimum version we are comparing against
4923 * - version of data being processsed
4926 public static boolean isVersionStringLaterThan(String supported,
4929 if (supported == null || version == null
4930 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4931 || version.equalsIgnoreCase("Test")
4932 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4934 System.err.println("Assuming project file with "
4935 + (version == null ? "null" : version)
4936 + " is compatible with Jalview version " + supported);
4941 return StringUtils.compareVersions(version, supported, "b") >= 0;
4945 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4947 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4949 if (newStructureViewers != null)
4951 sview.getBinding().setFinishedLoadingFromArchive(false);
4952 newStructureViewers.add(sview);
4956 protected void setLoadingFinishedForNewStructureViewers()
4958 if (newStructureViewers != null)
4960 for (JalviewStructureDisplayI sview : newStructureViewers)
4962 sview.getBinding().setFinishedLoadingFromArchive(true);
4964 newStructureViewers.clear();
4965 newStructureViewers = null;
4969 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4970 List<SequenceI> hiddenSeqs, AlignmentI al,
4971 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4972 String viewId, List<JvAnnotRow> autoAlan)
4974 AlignFrame af = null;
4975 af = new AlignFrame(al, safeInt(view.getWidth()),
4976 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4980 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4981 // System.out.println("Jalview2XML AF " + e);
4982 // super.processKeyEvent(e);
4989 af.setFileName(file, FileFormat.Jalview);
4991 final AlignViewport viewport = af.getViewport();
4992 for (int i = 0; i < JSEQ.size(); i++)
4994 int colour = safeInt(JSEQ.get(i).getColour());
4995 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5001 viewport.setColourByReferenceSeq(true);
5002 viewport.setDisplayReferenceSeq(true);
5005 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5007 if (view.getSequenceSetId() != null)
5009 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5011 viewport.setSequenceSetId(uniqueSeqSetId);
5014 // propagate shared settings to this new view
5015 viewport.setHistoryList(av.getHistoryList());
5016 viewport.setRedoList(av.getRedoList());
5020 viewportsAdded.put(uniqueSeqSetId, viewport);
5022 // TODO: check if this method can be called repeatedly without
5023 // side-effects if alignpanel already registered.
5024 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5026 // apply Hidden regions to view.
5027 if (hiddenSeqs != null)
5029 for (int s = 0; s < JSEQ.size(); s++)
5031 SequenceGroup hidden = new SequenceGroup();
5032 boolean isRepresentative = false;
5033 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5035 isRepresentative = true;
5036 SequenceI sequenceToHide = al
5037 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5038 hidden.addSequence(sequenceToHide, false);
5039 // remove from hiddenSeqs list so we don't try to hide it twice
5040 hiddenSeqs.remove(sequenceToHide);
5042 if (isRepresentative)
5044 SequenceI representativeSequence = al.getSequenceAt(s);
5045 hidden.addSequence(representativeSequence, false);
5046 viewport.hideRepSequences(representativeSequence, hidden);
5050 SequenceI[] hseqs = hiddenSeqs
5051 .toArray(new SequenceI[hiddenSeqs.size()]);
5052 viewport.hideSequence(hseqs);
5055 // recover view properties and display parameters
5057 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5058 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5059 final int pidThreshold = safeInt(view.getPidThreshold());
5060 viewport.setThreshold(pidThreshold);
5062 viewport.setColourText(safeBoolean(view.isShowColourText()));
5065 .setConservationSelected(
5066 safeBoolean(view.isConservationSelected()));
5067 viewport.setIncrement(safeInt(view.getConsThreshold()));
5068 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5069 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5070 viewport.setFont(new Font(view.getFontName(),
5071 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
5073 ViewStyleI vs = viewport.getViewStyle();
5074 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5075 viewport.setViewStyle(vs);
5076 // TODO: allow custom charWidth/Heights to be restored by updating them
5077 // after setting font - which means set above to false
5078 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5079 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5080 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5082 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5084 viewport.setShowText(safeBoolean(view.isShowText()));
5086 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5087 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5088 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5089 viewport.setShowUnconserved(view.isShowUnconserved());
5090 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5092 if (view.getViewName() != null)
5094 viewport.setViewName(view.getViewName());
5095 af.setInitialTabVisible();
5097 int x = safeInt(view.getXpos());
5098 int y = safeInt(view.getYpos());
5099 int w = safeInt(view.getWidth());
5100 int h = safeInt(view.getHeight());
5101 // // BH we cannot let the title bar go off the top
5102 // if (Platform.isJS())
5104 // x = Math.max(50 - w, x);
5105 // y = Math.max(0, y);
5108 af.setBounds(x, y, w, h);
5109 // startSeq set in af.alignPanel.updateLayout below
5110 af.alignPanel.updateLayout();
5111 ColourSchemeI cs = null;
5112 // apply colourschemes
5113 if (view.getBgColour() != null)
5115 if (view.getBgColour().startsWith("ucs"))
5117 cs = getUserColourScheme(jm, view.getBgColour());
5119 else if (view.getBgColour().startsWith("Annotation"))
5121 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5122 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5129 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5130 view.getBgColour());
5135 * turn off 'alignment colour applies to all groups'
5136 * while restoring global colour scheme
5138 viewport.setColourAppliesToAllGroups(false);
5139 viewport.setGlobalColourScheme(cs);
5140 viewport.getResidueShading().setThreshold(pidThreshold,
5141 view.isIgnoreGapsinConsensus());
5142 viewport.getResidueShading()
5143 .setConsensus(viewport.getSequenceConsensusHash());
5144 if (safeBoolean(view.isConservationSelected()) && cs != null)
5146 viewport.getResidueShading()
5147 .setConservationInc(safeInt(view.getConsThreshold()));
5149 af.changeColour(cs);
5150 viewport.setColourAppliesToAllGroups(true);
5153 .setShowSequenceFeatures(
5154 safeBoolean(view.isShowSequenceFeatures()));
5156 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5157 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5158 viewport.setFollowHighlight(view.isFollowHighlight());
5159 viewport.followSelection = view.isFollowSelection();
5160 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5161 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5162 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5163 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5164 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5165 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5166 viewport.setShowGroupConservation(view.isShowGroupConservation());
5168 // recover feature settings
5169 if (jm.getFeatureSettings() != null)
5171 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
5172 .getFeatureRenderer();
5173 FeaturesDisplayed fdi;
5174 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5175 String[] renderOrder = new String[jm.getFeatureSettings()
5176 .getSetting().size()];
5177 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5178 Map<String, Float> featureOrder = new Hashtable<>();
5180 for (int fs = 0; fs < jm.getFeatureSettings()
5181 .getSetting().size(); fs++)
5183 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5184 String featureType = setting.getType();
5187 * restore feature filters (if any)
5189 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5191 if (filters != null)
5193 FeatureMatcherSetI filter = Jalview2XML
5194 .parseFilter(featureType, filters);
5195 if (!filter.isEmpty())
5197 fr.setFeatureFilter(featureType, filter);
5202 * restore feature colour scheme
5204 Color maxColour = new Color(setting.getColour());
5205 if (setting.getMincolour() != null)
5208 * minColour is always set unless a simple colour
5209 * (including for colour by label though it doesn't use it)
5211 Color minColour = new Color(setting.getMincolour().intValue());
5212 Color noValueColour = minColour;
5213 NoValueColour noColour = setting.getNoValueColour();
5214 if (noColour == NoValueColour.NONE)
5216 noValueColour = null;
5218 else if (noColour == NoValueColour.MAX)
5220 noValueColour = maxColour;
5222 float min = safeFloat(safeFloat(setting.getMin()));
5223 float max = setting.getMax() == null ? 1f
5224 : setting.getMax().floatValue();
5225 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5227 noValueColour, min, max);
5228 if (setting.getAttributeName().size() > 0)
5230 gc.setAttributeName(setting.getAttributeName().toArray(
5231 new String[setting.getAttributeName().size()]));
5233 if (setting.getThreshold() != null)
5235 gc.setThreshold(setting.getThreshold().floatValue());
5236 int threshstate = safeInt(setting.getThreshstate());
5237 // -1 = None, 0 = Below, 1 = Above threshold
5238 if (threshstate == 0)
5240 gc.setBelowThreshold(true);
5242 else if (threshstate == 1)
5244 gc.setAboveThreshold(true);
5247 gc.setAutoScaled(true); // default
5248 if (setting.isAutoScale() != null)
5250 gc.setAutoScaled(setting.isAutoScale());
5252 if (setting.isColourByLabel() != null)
5254 gc.setColourByLabel(setting.isColourByLabel());
5256 // and put in the feature colour table.
5257 featureColours.put(featureType, gc);
5261 featureColours.put(featureType,
5262 new FeatureColour(maxColour));
5264 renderOrder[fs] = featureType;
5265 if (setting.getOrder() != null)
5267 featureOrder.put(featureType, setting.getOrder().floatValue());
5271 featureOrder.put(featureType, new Float(
5272 fs / jm.getFeatureSettings().getSetting().size()));
5274 if (safeBoolean(setting.isDisplay()))
5276 fdi.setVisible(featureType);
5279 Map<String, Boolean> fgtable = new Hashtable<>();
5280 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5282 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5283 fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
5285 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5286 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5287 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5288 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5289 fgtable, featureColours, 1.0f, featureOrder);
5290 fr.transferSettings(frs);
5293 if (view.getHiddenColumns().size() > 0)
5295 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5297 final HiddenColumns hc = view.getHiddenColumns().get(c);
5298 viewport.hideColumns(safeInt(hc.getStart()),
5299 safeInt(hc.getEnd()) /* +1 */);
5302 if (view.getCalcIdParam() != null)
5304 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5306 if (calcIdParam != null)
5308 if (recoverCalcIdParam(calcIdParam, viewport))
5313 warn("Couldn't recover parameters for "
5314 + calcIdParam.getCalcId());
5319 af.setMenusFromViewport(viewport);
5320 af.setTitle(view.getTitle());
5321 // TODO: we don't need to do this if the viewport is aready visible.
5323 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5324 * has a 'cdna/protein complement' view, in which case save it in order to
5325 * populate a SplitFrame once all views have been read in.
5327 String complementaryViewId = view.getComplementId();
5328 if (complementaryViewId == null)
5330 Desktop.addInternalFrame(af, view.getTitle(),
5331 safeInt(view.getWidth()), safeInt(view.getHeight()));
5332 // recompute any autoannotation
5333 af.alignPanel.updateAnnotation(false, true);
5334 reorderAutoannotation(af, al, autoAlan);
5335 af.alignPanel.alignmentChanged();
5339 splitFrameCandidates.put(view, af);
5345 * Reads saved data to restore Colour by Annotation settings
5347 * @param viewAnnColour
5351 * @param checkGroupAnnColour
5354 private ColourSchemeI constructAnnotationColour(
5355 AnnotationColourScheme viewAnnColour, AlignFrame af,
5356 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5358 boolean propagateAnnColour = false;
5359 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5361 if (checkGroupAnnColour && al.getGroups() != null
5362 && al.getGroups().size() > 0)
5364 // pre 2.8.1 behaviour
5365 // check to see if we should transfer annotation colours
5366 propagateAnnColour = true;
5367 for (SequenceGroup sg : al.getGroups())
5369 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5371 propagateAnnColour = false;
5377 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5379 String annotationId = viewAnnColour.getAnnotation();
5380 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5383 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5385 if (matchedAnnotation == null
5386 && annAlignment.getAlignmentAnnotation() != null)
5388 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5391 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5393 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5398 if (matchedAnnotation == null)
5400 System.err.println("Failed to match annotation colour scheme for "
5404 if (matchedAnnotation.getThreshold() == null)
5406 matchedAnnotation.setThreshold(
5407 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5408 "Threshold", Color.black));
5411 AnnotationColourGradient cs = null;
5412 if (viewAnnColour.getColourScheme().equals("None"))
5414 cs = new AnnotationColourGradient(matchedAnnotation,
5415 new Color(safeInt(viewAnnColour.getMinColour())),
5416 new Color(safeInt(viewAnnColour.getMaxColour())),
5417 safeInt(viewAnnColour.getAboveThreshold()));
5419 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5421 cs = new AnnotationColourGradient(matchedAnnotation,
5422 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5423 safeInt(viewAnnColour.getAboveThreshold()));
5427 cs = new AnnotationColourGradient(matchedAnnotation,
5428 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5429 viewAnnColour.getColourScheme()),
5430 safeInt(viewAnnColour.getAboveThreshold()));
5433 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5434 boolean useOriginalColours = safeBoolean(
5435 viewAnnColour.isPredefinedColours());
5436 cs.setSeqAssociated(perSequenceOnly);
5437 cs.setPredefinedColours(useOriginalColours);
5439 if (propagateAnnColour && al.getGroups() != null)
5441 // Also use these settings for all the groups
5442 for (int g = 0; g < al.getGroups().size(); g++)
5444 SequenceGroup sg = al.getGroups().get(g);
5445 if (sg.getGroupColourScheme() == null)
5450 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5451 matchedAnnotation, sg.getColourScheme(),
5452 safeInt(viewAnnColour.getAboveThreshold()));
5453 sg.setColourScheme(groupScheme);
5454 groupScheme.setSeqAssociated(perSequenceOnly);
5455 groupScheme.setPredefinedColours(useOriginalColours);
5461 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5462 List<JvAnnotRow> autoAlan)
5464 // copy over visualization settings for autocalculated annotation in the
5466 if (al.getAlignmentAnnotation() != null)
5469 * Kludge for magic autoannotation names (see JAL-811)
5471 String[] magicNames = new String[] { "Consensus", "Quality",
5473 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5474 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5475 for (String nm : magicNames)
5477 visan.put(nm, nullAnnot);
5479 for (JvAnnotRow auan : autoAlan)
5481 visan.put(auan.template.label
5482 + (auan.template.getCalcId() == null ? ""
5483 : "\t" + auan.template.getCalcId()),
5486 int hSize = al.getAlignmentAnnotation().length;
5487 List<JvAnnotRow> reorder = new ArrayList<>();
5488 // work through any autoCalculated annotation already on the view
5489 // removing it if it should be placed in a different location on the
5490 // annotation panel.
5491 List<String> remains = new ArrayList<>(visan.keySet());
5492 for (int h = 0; h < hSize; h++)
5494 jalview.datamodel.AlignmentAnnotation jalan = al
5495 .getAlignmentAnnotation()[h];
5496 if (jalan.autoCalculated)
5499 JvAnnotRow valan = visan.get(k = jalan.label);
5500 if (jalan.getCalcId() != null)
5502 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5507 // delete the auto calculated row from the alignment
5508 al.deleteAnnotation(jalan, false);
5512 if (valan != nullAnnot)
5514 if (jalan != valan.template)
5516 // newly created autoannotation row instance
5517 // so keep a reference to the visible annotation row
5518 // and copy over all relevant attributes
5519 if (valan.template.graphHeight >= 0)
5522 jalan.graphHeight = valan.template.graphHeight;
5524 jalan.visible = valan.template.visible;
5526 reorder.add(new JvAnnotRow(valan.order, jalan));
5531 // Add any (possibly stale) autocalculated rows that were not appended to
5532 // the view during construction
5533 for (String other : remains)
5535 JvAnnotRow othera = visan.get(other);
5536 if (othera != nullAnnot && othera.template.getCalcId() != null
5537 && othera.template.getCalcId().length() > 0)
5539 reorder.add(othera);
5542 // now put the automatic annotation in its correct place
5543 int s = 0, srt[] = new int[reorder.size()];
5544 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5545 for (JvAnnotRow jvar : reorder)
5548 srt[s++] = jvar.order;
5551 jalview.util.QuickSort.sort(srt, rws);
5552 // and re-insert the annotation at its correct position
5553 for (JvAnnotRow jvar : rws)
5555 al.addAnnotation(jvar.template, jvar.order);
5557 af.alignPanel.adjustAnnotationHeight();
5561 Hashtable skipList = null;
5564 * TODO remove this method
5567 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5568 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5569 * throw new Error("Implementation Error. No skipList defined for this
5570 * Jalview2XML instance."); } return (AlignFrame)
5571 * skipList.get(view.getSequenceSetId()); }
5575 * Check if the Jalview view contained in object should be skipped or not.
5578 * @return true if view's sequenceSetId is a key in skipList
5580 private boolean skipViewport(JalviewModel object)
5582 if (skipList == null)
5586 String id = object.getViewport().get(0).getSequenceSetId();
5587 if (skipList.containsKey(id))
5589 if (Cache.log != null && Cache.log.isDebugEnabled())
5591 Cache.log.debug("Skipping seuqence set id " + id);
5598 public void addToSkipList(AlignFrame af)
5600 if (skipList == null)
5602 skipList = new Hashtable();
5604 skipList.put(af.getViewport().getSequenceSetId(), af);
5607 public void clearSkipList()
5609 if (skipList != null)
5616 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5617 boolean ignoreUnrefed, String uniqueSeqSetId)
5619 jalview.datamodel.AlignmentI ds = getDatasetFor(
5620 vamsasSet.getDatasetId());
5621 AlignmentI xtant_ds = ds;
5622 if (xtant_ds == null)
5624 // good chance we are about to create a new dataset, but check if we've
5625 // seen some of the dataset sequence IDs before.
5626 // TODO: skip this check if we are working with project generated by
5627 // version 2.11 or later
5628 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5629 if (xtant_ds != null)
5632 addDatasetRef(vamsasSet.getDatasetId(), ds);
5635 Vector dseqs = null;
5638 // recovering an alignment View
5639 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5640 if (seqSetDS != null)
5642 if (ds != null && ds != seqSetDS)
5644 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5645 + " - CDS/Protein crossreference data may be lost");
5646 if (xtant_ds != null)
5648 // This can only happen if the unique sequence set ID was bound to a
5649 // dataset that did not contain any of the sequences in the view
5650 // currently being restored.
5651 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.");
5655 addDatasetRef(vamsasSet.getDatasetId(), ds);
5660 // try even harder to restore dataset
5661 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5662 // create a list of new dataset sequences
5663 dseqs = new Vector();
5665 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5667 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5668 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5670 // create a new dataset
5673 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5674 dseqs.copyInto(dsseqs);
5675 ds = new jalview.datamodel.Alignment(dsseqs);
5676 debug("Created new dataset " + vamsasSet.getDatasetId()
5677 + " for alignment " + System.identityHashCode(al));
5678 addDatasetRef(vamsasSet.getDatasetId(), ds);
5680 // set the dataset for the newly imported alignment.
5681 if (al.getDataset() == null && !ignoreUnrefed)
5684 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5685 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5687 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5691 * XML dataset sequence ID to materialised dataset reference
5693 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5696 * @return the first materialised dataset reference containing a dataset
5697 * sequence referenced in the given view
5699 * - sequences from the view
5701 AlignmentI checkIfHasDataset(List<Sequence> list)
5703 for (Sequence restoredSeq : list)
5705 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5706 if (datasetFor != null)
5715 * Register ds as the containing dataset for the dataset sequences referenced
5716 * by sequences in list
5719 * - sequences in a view
5722 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5724 for (Sequence restoredSeq : list)
5726 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5727 if (prevDS != null && prevDS != ds)
5729 warn("Dataset sequence appears in many datasets: "
5730 + restoredSeq.getDsseqid());
5731 // TODO: try to merge!
5738 * sequence definition to create/merge dataset sequence for
5742 * vector to add new dataset sequence to
5743 * @param ignoreUnrefed
5744 * - when true, don't create new sequences from vamsasSeq if it's id
5745 * doesn't already have an asssociated Jalview sequence.
5747 * - used to reorder the sequence in the alignment according to the
5748 * vamsasSeq array ordering, to preserve ordering of dataset
5750 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5751 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5753 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5755 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5756 boolean reorder = false;
5757 SequenceI dsq = null;
5758 if (sq != null && sq.getDatasetSequence() != null)
5760 dsq = sq.getDatasetSequence();
5766 if (sq == null && ignoreUnrefed)
5770 String sqid = vamsasSeq.getDsseqid();
5773 // need to create or add a new dataset sequence reference to this sequence
5776 dsq = seqRefIds.get(sqid);
5781 // make a new dataset sequence
5782 dsq = sq.createDatasetSequence();
5785 // make up a new dataset reference for this sequence
5786 sqid = seqHash(dsq);
5788 dsq.setVamsasId(uniqueSetSuffix + sqid);
5789 seqRefIds.put(sqid, dsq);
5794 dseqs.addElement(dsq);
5799 ds.addSequence(dsq);
5805 { // make this dataset sequence sq's dataset sequence
5806 sq.setDatasetSequence(dsq);
5807 // and update the current dataset alignment
5812 if (!dseqs.contains(dsq))
5819 if (ds.findIndex(dsq) < 0)
5821 ds.addSequence(dsq);
5828 // TODO: refactor this as a merge dataset sequence function
5829 // now check that sq (the dataset sequence) sequence really is the union of
5830 // all references to it
5831 // boolean pre = sq.getStart() < dsq.getStart();
5832 // boolean post = sq.getEnd() > dsq.getEnd();
5836 // StringBuffer sb = new StringBuffer();
5837 String newres = jalview.analysis.AlignSeq.extractGaps(
5838 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5839 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5840 && newres.length() > dsq.getLength())
5842 // Update with the longer sequence.
5846 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5847 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5848 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5849 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5851 dsq.setSequence(newres);
5853 // TODO: merges will never happen if we 'know' we have the real dataset
5854 // sequence - this should be detected when id==dssid
5856 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5857 // + (pre ? "prepended" : "") + " "
5858 // + (post ? "appended" : ""));
5863 // sequence refs are identical. We may need to update the existing dataset
5864 // alignment with this one, though.
5865 if (ds != null && dseqs == null)
5867 int opos = ds.findIndex(dsq);
5868 SequenceI tseq = null;
5869 if (opos != -1 && vseqpos != opos)
5871 // remove from old position
5872 ds.deleteSequence(dsq);
5874 if (vseqpos < ds.getHeight())
5876 if (vseqpos != opos)
5878 // save sequence at destination position
5879 tseq = ds.getSequenceAt(vseqpos);
5880 ds.replaceSequenceAt(vseqpos, dsq);
5881 ds.addSequence(tseq);
5886 ds.addSequence(dsq);
5893 * TODO use AlignmentI here and in related methods - needs
5894 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5896 Hashtable<String, AlignmentI> datasetIds = null;
5898 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5900 private AlignmentI getDatasetFor(String datasetId)
5902 if (datasetIds == null)
5904 datasetIds = new Hashtable<>();
5907 if (datasetIds.containsKey(datasetId))
5909 return datasetIds.get(datasetId);
5914 private void addDatasetRef(String datasetId, AlignmentI dataset)
5916 if (datasetIds == null)
5918 datasetIds = new Hashtable<>();
5920 datasetIds.put(datasetId, dataset);
5924 * make a new dataset ID for this jalview dataset alignment
5929 private String getDatasetIdRef(AlignmentI dataset)
5931 if (dataset.getDataset() != null)
5933 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5935 String datasetId = makeHashCode(dataset, null);
5936 if (datasetId == null)
5938 // make a new datasetId and record it
5939 if (dataset2Ids == null)
5941 dataset2Ids = new IdentityHashMap<>();
5945 datasetId = dataset2Ids.get(dataset);
5947 if (datasetId == null)
5949 datasetId = "ds" + dataset2Ids.size() + 1;
5950 dataset2Ids.put(dataset, datasetId);
5956 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5958 for (int d = 0; d < sequence.getDBRef().size(); d++)
5960 DBRef dr = sequence.getDBRef().get(d);
5961 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5962 dr.getSource(), dr.getVersion(), dr.getAccessionId());
5963 if (dr.getMapping() != null)
5965 entry.setMap(addMapping(dr.getMapping()));
5967 datasetSequence.addDBRef(entry);
5971 private jalview.datamodel.Mapping addMapping(Mapping m)
5973 SequenceI dsto = null;
5974 // Mapping m = dr.getMapping();
5975 int fr[] = new int[m.getMapListFrom().size() * 2];
5976 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5977 for (int _i = 0; from.hasNext(); _i += 2)
5979 MapListFrom mf = from.next();
5980 fr[_i] = mf.getStart();
5981 fr[_i + 1] = mf.getEnd();
5983 int fto[] = new int[m.getMapListTo().size() * 2];
5984 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5985 for (int _i = 0; to.hasNext(); _i += 2)
5987 MapListTo mf = to.next();
5988 fto[_i] = mf.getStart();
5989 fto[_i + 1] = mf.getEnd();
5991 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5992 fto, m.getMapFromUnit().intValue(),
5993 m.getMapToUnit().intValue());
5996 * (optional) choice of dseqFor or Sequence
5998 if (m.getDseqFor() != null)
6000 String dsfor = m.getDseqFor();
6001 if (seqRefIds.containsKey(dsfor))
6006 jmap.setTo(seqRefIds.get(dsfor));
6010 frefedSequence.add(newMappingRef(dsfor, jmap));
6013 else if (m.getSequence() != null)
6016 * local sequence definition
6018 Sequence ms = m.getSequence();
6019 SequenceI djs = null;
6020 String sqid = ms.getDsseqid();
6021 if (sqid != null && sqid.length() > 0)
6024 * recover dataset sequence
6026 djs = seqRefIds.get(sqid);
6031 "Warning - making up dataset sequence id for DbRef sequence map reference");
6032 sqid = ((Object) ms).toString(); // make up a new hascode for
6033 // undefined dataset sequence hash
6034 // (unlikely to happen)
6040 * make a new dataset sequence and add it to refIds hash
6042 djs = new jalview.datamodel.Sequence(ms.getName(),
6044 djs.setStart(jmap.getMap().getToLowest());
6045 djs.setEnd(jmap.getMap().getToHighest());
6046 djs.setVamsasId(uniqueSetSuffix + sqid);
6048 incompleteSeqs.put(sqid, djs);
6049 seqRefIds.put(sqid, djs);
6052 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
6061 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6062 * view as XML (but not to file), and then reloading it
6067 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6070 JalviewModel jm = saveState(ap, null, null, null);
6073 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6074 ap.getAlignment().getDataset());
6076 uniqueSetSuffix = "";
6077 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6078 jm.getViewport().get(0).setId(null);
6079 // we don't overwrite the view we just copied
6081 if (this.frefedSequence == null)
6083 frefedSequence = new Vector<>();
6086 viewportsAdded.clear();
6088 AlignFrame af = loadFromObject(jm, null, false, null);
6089 af.getAlignPanels().clear();
6090 af.closeMenuItem_actionPerformed(true);
6093 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6094 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6095 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6096 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6097 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6100 return af.alignPanel;
6103 private Hashtable jvids2vobj;
6105 private void warn(String msg)
6110 private void warn(String msg, Exception e)
6112 if (Cache.log != null)
6116 Cache.log.warn(msg, e);
6120 Cache.log.warn(msg);
6125 System.err.println("Warning: " + msg);
6128 e.printStackTrace();
6133 private void debug(String string)
6135 debug(string, null);
6138 private void debug(String msg, Exception e)
6140 if (Cache.log != null)
6144 Cache.log.debug(msg, e);
6148 Cache.log.debug(msg);
6153 System.err.println("Warning: " + msg);
6156 e.printStackTrace();
6162 * set the object to ID mapping tables used to write/recover objects and XML
6163 * ID strings for the jalview project. If external tables are provided then
6164 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6165 * object goes out of scope. - also populates the datasetIds hashtable with
6166 * alignment objects containing dataset sequences
6169 * Map from ID strings to jalview datamodel
6171 * Map from jalview datamodel to ID strings
6175 public void setObjectMappingTables(Hashtable vobj2jv,
6176 IdentityHashMap jv2vobj)
6178 this.jv2vobj = jv2vobj;
6179 this.vobj2jv = vobj2jv;
6180 Iterator ds = jv2vobj.keySet().iterator();
6182 while (ds.hasNext())
6184 Object jvobj = ds.next();
6185 id = jv2vobj.get(jvobj).toString();
6186 if (jvobj instanceof jalview.datamodel.Alignment)
6188 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6190 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6193 else if (jvobj instanceof jalview.datamodel.Sequence)
6195 // register sequence object so the XML parser can recover it.
6196 if (seqRefIds == null)
6198 seqRefIds = new HashMap<>();
6200 if (seqsToIds == null)
6202 seqsToIds = new IdentityHashMap<>();
6204 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6205 seqsToIds.put((SequenceI) jvobj, id);
6207 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6210 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6211 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6212 if (jvann.annotationId == null)
6214 jvann.annotationId = anid;
6216 if (!jvann.annotationId.equals(anid))
6218 // TODO verify that this is the correct behaviour
6219 this.warn("Overriding Annotation ID for " + anid
6220 + " from different id : " + jvann.annotationId);
6221 jvann.annotationId = anid;
6224 else if (jvobj instanceof String)
6226 if (jvids2vobj == null)
6228 jvids2vobj = new Hashtable();
6229 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6234 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6240 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6241 * objects created from the project archive. If string is null (default for
6242 * construction) then suffix will be set automatically.
6246 public void setUniqueSetSuffix(String string)
6248 uniqueSetSuffix = string;
6253 * uses skipList2 as the skipList for skipping views on sequence sets
6254 * associated with keys in the skipList
6258 public void setSkipList(Hashtable skipList2)
6260 skipList = skipList2;
6264 * Reads the jar entry of given name and returns its contents, or null if the
6265 * entry is not found.
6268 * @param jarEntryName
6271 protected String readJarEntry(jarInputStreamProvider jprovider,
6272 String jarEntryName)
6274 String result = null;
6275 BufferedReader in = null;
6280 * Reopen the jar input stream and traverse its entries to find a matching
6283 JarInputStream jin = jprovider.getJarInputStream();
6284 JarEntry entry = null;
6287 entry = jin.getNextJarEntry();
6288 } while (entry != null && !entry.getName().equals(jarEntryName));
6292 StringBuilder out = new StringBuilder(256);
6293 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6296 while ((data = in.readLine()) != null)
6300 result = out.toString();
6304 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6306 } catch (Exception ex)
6308 ex.printStackTrace();
6316 } catch (IOException e)
6327 * Returns an incrementing counter (0, 1, 2...)
6331 private synchronized int nextCounter()
6337 * Loads any saved PCA viewers
6342 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6346 List<PcaViewer> pcaviewers = model.getPcaViewer();
6347 for (PcaViewer viewer : pcaviewers)
6349 String modelName = viewer.getScoreModelName();
6350 SimilarityParamsI params = new SimilarityParams(
6351 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6352 viewer.isIncludeGaps(),
6353 viewer.isDenominateByShortestLength());
6356 * create the panel (without computing the PCA)
6358 PCAPanel panel = new PCAPanel(ap, modelName, params);
6360 panel.setTitle(viewer.getTitle());
6361 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6362 viewer.getWidth(), viewer.getHeight()));
6364 boolean showLabels = viewer.isShowLabels();
6365 panel.setShowLabels(showLabels);
6366 panel.getRotatableCanvas().setShowLabels(showLabels);
6367 panel.getRotatableCanvas()
6368 .setBgColour(new Color(viewer.getBgColour()));
6369 panel.getRotatableCanvas()
6370 .setApplyToAllViews(viewer.isLinkToAllViews());
6373 * load PCA output data
6375 ScoreModelI scoreModel = ScoreModels.getInstance()
6376 .getScoreModel(modelName, ap);
6377 PCA pca = new PCA(null, scoreModel, params);
6378 PcaDataType pcaData = viewer.getPcaData();
6380 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6381 pca.setPairwiseScores(pairwise);
6383 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6384 pca.setTridiagonal(triDiag);
6386 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6387 pca.setEigenmatrix(result);
6389 panel.getPcaModel().setPCA(pca);
6392 * we haven't saved the input data! (JAL-2647 to do)
6394 panel.setInputData(null);
6397 * add the sequence points for the PCA display
6399 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6400 for (SequencePoint sp : viewer.getSequencePoint())
6402 String seqId = sp.getSequenceRef();
6403 SequenceI seq = seqRefIds.get(seqId);
6406 throw new IllegalStateException(
6407 "Unmatched seqref for PCA: " + seqId);
6409 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6410 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6412 seqPoints.add(seqPoint);
6414 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6417 * set min-max ranges and scale after setPoints (which recomputes them)
6419 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6420 SeqPointMin spMin = viewer.getSeqPointMin();
6421 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6423 SeqPointMax spMax = viewer.getSeqPointMax();
6424 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6426 panel.getRotatableCanvas().setSeqMinMax(min, max);
6428 // todo: hold points list in PCAModel only
6429 panel.getPcaModel().setSequencePoints(seqPoints);
6431 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6432 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6433 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6435 // is this duplication needed?
6436 panel.setTop(seqPoints.size() - 1);
6437 panel.getPcaModel().setTop(seqPoints.size() - 1);
6440 * add the axes' end points for the display
6442 for (int i = 0; i < 3; i++)
6444 Axis axis = viewer.getAxis().get(i);
6445 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6446 axis.getXPos(), axis.getYPos(), axis.getZPos());
6449 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6450 "label.calc_title", "PCA", modelName), 475, 450);
6452 } catch (Exception ex)
6454 Cache.log.error("Error loading PCA: " + ex.toString());
6459 * Populates an XML model of the feature colour scheme for one feature type
6461 * @param featureType
6465 public static Colour marshalColour(
6466 String featureType, FeatureColourI fcol)
6468 Colour col = new Colour();
6469 if (fcol.isSimpleColour())
6471 col.setRGB(Format.getHexString(fcol.getColour()));
6475 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6476 col.setMin(fcol.getMin());
6477 col.setMax(fcol.getMax());
6478 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6479 col.setAutoScale(fcol.isAutoScaled());
6480 col.setThreshold(fcol.getThreshold());
6481 col.setColourByLabel(fcol.isColourByLabel());
6482 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6483 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6484 : ThresholdType.NONE));
6485 if (fcol.isColourByAttribute())
6487 final String[] attName = fcol.getAttributeName();
6488 col.getAttributeName().add(attName[0]);
6489 if (attName.length > 1)
6491 col.getAttributeName().add(attName[1]);
6494 Color noColour = fcol.getNoColour();
6495 if (noColour == null)
6497 col.setNoValueColour(NoValueColour.NONE);
6499 else if (noColour == fcol.getMaxColour())
6501 col.setNoValueColour(NoValueColour.MAX);
6505 col.setNoValueColour(NoValueColour.MIN);
6508 col.setName(featureType);
6513 * Populates an XML model of the feature filter(s) for one feature type
6515 * @param firstMatcher
6516 * the first (or only) match condition)
6518 * remaining match conditions (if any)
6520 * if true, conditions are and-ed, else or-ed
6522 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6523 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6526 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6528 if (filters.hasNext())
6533 CompoundMatcher compound = new CompoundMatcher();
6534 compound.setAnd(and);
6535 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6536 firstMatcher, Collections.emptyIterator(), and);
6537 // compound.addMatcherSet(matcher1);
6538 compound.getMatcherSet().add(matcher1);
6539 FeatureMatcherI nextMatcher = filters.next();
6540 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6541 nextMatcher, filters, and);
6542 // compound.addMatcherSet(matcher2);
6543 compound.getMatcherSet().add(matcher2);
6544 result.setCompoundMatcher(compound);
6549 * single condition matcher
6551 // MatchCondition matcherModel = new MatchCondition();
6552 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6553 matcherModel.setCondition(
6554 firstMatcher.getMatcher().getCondition().getStableName());
6555 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6556 if (firstMatcher.isByAttribute())
6558 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6559 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6560 String[] attName = firstMatcher.getAttribute();
6561 matcherModel.getAttributeName().add(attName[0]); // attribute
6562 if (attName.length > 1)
6564 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6567 else if (firstMatcher.isByLabel())
6569 matcherModel.setBy(FilterBy.BY_LABEL);
6571 else if (firstMatcher.isByScore())
6573 matcherModel.setBy(FilterBy.BY_SCORE);
6575 result.setMatchCondition(matcherModel);
6582 * Loads one XML model of a feature filter to a Jalview object
6584 * @param featureType
6585 * @param matcherSetModel
6588 public static FeatureMatcherSetI parseFilter(
6590 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6592 FeatureMatcherSetI result = new FeatureMatcherSet();
6595 parseFilterConditions(result, matcherSetModel, true);
6596 } catch (IllegalStateException e)
6598 // mixing AND and OR conditions perhaps
6600 String.format("Error reading filter conditions for '%s': %s",
6601 featureType, e.getMessage()));
6602 // return as much as was parsed up to the error
6609 * Adds feature match conditions to matcherSet as unmarshalled from XML
6610 * (possibly recursively for compound conditions)
6613 * @param matcherSetModel
6615 * if true, multiple conditions are AND-ed, else they are OR-ed
6616 * @throws IllegalStateException
6617 * if AND and OR conditions are mixed
6619 protected static void parseFilterConditions(
6620 FeatureMatcherSetI matcherSet,
6621 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6624 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6625 .getMatchCondition();
6631 FilterBy filterBy = mc.getBy();
6632 Condition cond = Condition.fromString(mc.getCondition());
6633 String pattern = mc.getValue();
6634 FeatureMatcherI matchCondition = null;
6635 if (filterBy == FilterBy.BY_LABEL)
6637 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6639 else if (filterBy == FilterBy.BY_SCORE)
6641 matchCondition = FeatureMatcher.byScore(cond, pattern);
6644 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6646 final List<String> attributeName = mc.getAttributeName();
6647 String[] attNames = attributeName
6648 .toArray(new String[attributeName.size()]);
6649 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6654 * note this throws IllegalStateException if AND-ing to a
6655 * previously OR-ed compound condition, or vice versa
6659 matcherSet.and(matchCondition);
6663 matcherSet.or(matchCondition);
6669 * compound condition
6671 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6672 .getCompoundMatcher().getMatcherSet();
6673 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6674 if (matchers.size() == 2)
6676 parseFilterConditions(matcherSet, matchers.get(0), anded);
6677 parseFilterConditions(matcherSet, matchers.get(1), anded);
6681 System.err.println("Malformed compound filter condition");
6687 * Loads one XML model of a feature colour to a Jalview object
6689 * @param colourModel
6692 public static FeatureColourI parseColour(Colour colourModel)
6694 FeatureColourI colour = null;
6696 if (colourModel.getMax() != null)
6698 Color mincol = null;
6699 Color maxcol = null;
6700 Color noValueColour = null;
6704 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6705 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6706 } catch (Exception e)
6708 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6711 NoValueColour noCol = colourModel.getNoValueColour();
6712 if (noCol == NoValueColour.MIN)
6714 noValueColour = mincol;
6716 else if (noCol == NoValueColour.MAX)
6718 noValueColour = maxcol;
6721 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6722 safeFloat(colourModel.getMin()),
6723 safeFloat(colourModel.getMax()));
6724 final List<String> attributeName = colourModel.getAttributeName();
6725 String[] attributes = attributeName
6726 .toArray(new String[attributeName.size()]);
6727 if (attributes != null && attributes.length > 0)
6729 colour.setAttributeName(attributes);
6731 if (colourModel.isAutoScale() != null)
6733 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6735 if (colourModel.isColourByLabel() != null)
6737 colour.setColourByLabel(
6738 colourModel.isColourByLabel().booleanValue());
6740 if (colourModel.getThreshold() != null)
6742 colour.setThreshold(colourModel.getThreshold().floatValue());
6744 ThresholdType ttyp = colourModel.getThreshType();
6745 if (ttyp == ThresholdType.ABOVE)
6747 colour.setAboveThreshold(true);
6749 else if (ttyp == ThresholdType.BELOW)
6751 colour.setBelowThreshold(true);
6756 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6757 colour = new FeatureColour(color);