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 java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.BitSet;
48 import java.util.Collections;
49 import java.util.Enumeration;
50 import java.util.GregorianCalendar;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Hashtable;
54 import java.util.IdentityHashMap;
55 import java.util.Iterator;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Locale;
60 import java.util.Map.Entry;
62 import java.util.Vector;
63 import java.util.jar.JarEntry;
64 import java.util.jar.JarInputStream;
65 import java.util.jar.JarOutputStream;
67 import javax.swing.JInternalFrame;
68 import javax.swing.SwingUtilities;
69 import javax.xml.bind.JAXBContext;
70 import javax.xml.bind.JAXBElement;
71 import javax.xml.bind.Marshaller;
72 import javax.xml.datatype.DatatypeConfigurationException;
73 import javax.xml.datatype.DatatypeFactory;
74 import javax.xml.datatype.XMLGregorianCalendar;
75 import javax.xml.stream.XMLInputFactory;
76 import javax.xml.stream.XMLStreamReader;
78 import jalview.analysis.Conservation;
79 import jalview.analysis.PCA;
80 import jalview.analysis.PaSiMap;
81 import jalview.analysis.scoremodels.ScoreModels;
82 import jalview.analysis.scoremodels.SimilarityParams;
83 import jalview.api.FeatureColourI;
84 import jalview.api.ViewStyleI;
85 import jalview.api.analysis.ScoreModelI;
86 import jalview.api.analysis.SimilarityParamsI;
87 import jalview.api.structures.JalviewStructureDisplayI;
88 import jalview.bin.Cache;
89 import jalview.bin.Console;
90 import jalview.bin.Jalview;
91 import jalview.datamodel.AlignedCodonFrame;
92 import jalview.datamodel.Alignment;
93 import jalview.datamodel.AlignmentAnnotation;
94 import jalview.datamodel.AlignmentI;
95 import jalview.datamodel.ContactListI;
96 import jalview.datamodel.ContactMatrix;
97 import jalview.datamodel.ContactMatrixI;
98 import jalview.datamodel.DBRefEntry;
99 import jalview.datamodel.FloatContactMatrix;
100 import jalview.datamodel.GeneLocus;
101 import jalview.datamodel.GraphLine;
102 import jalview.datamodel.GroupSet;
103 import jalview.datamodel.GroupSetI;
104 import jalview.datamodel.PDBEntry;
105 import jalview.datamodel.Point;
106 import jalview.datamodel.RnaViewerModel;
107 import jalview.datamodel.SequenceFeature;
108 import jalview.datamodel.SequenceGroup;
109 import jalview.datamodel.SequenceI;
110 import jalview.datamodel.StructureViewerModel;
111 import jalview.datamodel.StructureViewerModel.StructureData;
112 import jalview.datamodel.features.FeatureMatcher;
113 import jalview.datamodel.features.FeatureMatcherI;
114 import jalview.datamodel.features.FeatureMatcherSet;
115 import jalview.datamodel.features.FeatureMatcherSetI;
116 import jalview.ext.varna.RnaModel;
117 import jalview.gui.AlignFrame;
118 import jalview.gui.AlignViewport;
119 import jalview.gui.AlignmentPanel;
120 import jalview.gui.AppVarna;
121 import jalview.gui.Desktop;
122 import jalview.gui.JvOptionPane;
123 import jalview.gui.OOMWarning;
124 import jalview.gui.OverviewPanel;
125 import jalview.gui.PCAPanel;
126 import jalview.gui.PaSiMapPanel;
127 import jalview.gui.PaintRefresher;
128 import jalview.gui.SplitFrame;
129 import jalview.gui.StructureViewer;
130 import jalview.gui.StructureViewer.ViewerType;
131 import jalview.gui.StructureViewerBase;
132 import jalview.gui.TreePanel;
133 import jalview.io.BackupFiles;
134 import jalview.io.DataSourceType;
135 import jalview.io.FileFormat;
136 import jalview.io.NewickFile;
137 import jalview.math.Matrix;
138 import jalview.math.MatrixI;
139 import jalview.renderer.ResidueShaderI;
140 import jalview.schemes.AnnotationColourGradient;
141 import jalview.schemes.ColourSchemeI;
142 import jalview.schemes.ColourSchemeProperty;
143 import jalview.schemes.FeatureColour;
144 import jalview.schemes.ResidueProperties;
145 import jalview.schemes.UserColourScheme;
146 import jalview.structure.StructureSelectionManager;
147 import jalview.structures.models.AAStructureBindingModel;
148 import jalview.util.Format;
149 import jalview.util.HttpUtils;
150 import jalview.util.MessageManager;
151 import jalview.util.Platform;
152 import jalview.util.StringUtils;
153 import jalview.util.jarInputStreamProvider;
154 import jalview.util.matcher.Condition;
155 import jalview.viewmodel.AlignmentViewport;
156 import jalview.viewmodel.PCAModel;
157 import jalview.viewmodel.PaSiMapModel;
158 import jalview.viewmodel.ViewportRanges;
159 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
160 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
161 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
162 import jalview.ws.datamodel.MappableContactMatrixI;
163 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
164 import jalview.ws.jws2.Jws2Discoverer;
165 import jalview.ws.jws2.dm.AAConSettings;
166 import jalview.ws.jws2.jabaws2.Jws2Instance;
167 import jalview.ws.params.ArgumentI;
168 import jalview.ws.params.AutoCalcSetting;
169 import jalview.ws.params.WsParamSetI;
170 import jalview.xml.binding.jalview.AlcodonFrame;
171 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
172 import jalview.xml.binding.jalview.Annotation;
173 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
174 import jalview.xml.binding.jalview.AnnotationColourScheme;
175 import jalview.xml.binding.jalview.AnnotationElement;
176 import jalview.xml.binding.jalview.DoubleMatrix;
177 import jalview.xml.binding.jalview.DoubleVector;
178 import jalview.xml.binding.jalview.Feature;
179 import jalview.xml.binding.jalview.Feature.OtherData;
180 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
181 import jalview.xml.binding.jalview.FilterBy;
182 import jalview.xml.binding.jalview.JalviewModel;
183 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
184 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
185 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
186 import jalview.xml.binding.jalview.JalviewModel.JGroup;
187 import jalview.xml.binding.jalview.JalviewModel.JSeq;
188 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
189 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
190 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
191 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
192 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
193 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
194 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
195 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
196 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
197 import jalview.xml.binding.jalview.JalviewModel.Tree;
198 import jalview.xml.binding.jalview.JalviewModel.UserColours;
199 import jalview.xml.binding.jalview.JalviewModel.Viewport;
200 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
201 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
202 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
203 import jalview.xml.binding.jalview.JalviewUserColours;
204 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
205 import jalview.xml.binding.jalview.MapListType;
206 import jalview.xml.binding.jalview.MapListType.MapListFrom;
207 import jalview.xml.binding.jalview.MapListType.MapListTo;
208 import jalview.xml.binding.jalview.MapOnAMatrixType;
209 import jalview.xml.binding.jalview.Mapping;
210 import jalview.xml.binding.jalview.MatrixType;
211 import jalview.xml.binding.jalview.NoValueColour;
212 import jalview.xml.binding.jalview.ObjectFactory;
213 import jalview.xml.binding.jalview.PcaDataType;
214 import jalview.xml.binding.jalview.Pdbentry.Property;
215 import jalview.xml.binding.jalview.Sequence;
216 import jalview.xml.binding.jalview.Sequence.DBRef;
217 import jalview.xml.binding.jalview.SequenceSet;
218 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
219 import jalview.xml.binding.jalview.ThresholdType;
220 import jalview.xml.binding.jalview.VAMSAS;
223 * Write out the current jalview desktop state as a Jalview XML stream.
225 * Note: the vamsas objects referred to here are primitive versions of the
226 * VAMSAS project schema elements - they are not the same and most likely never
230 * @version $Revision: 1.134 $
232 public class Jalview2XML
235 // BH 2018 we add the .jvp binary extension to J2S so that
236 // it will declare that binary when we do the file save from the browser
240 Platform.addJ2SBinaryType(".jvp?");
243 private static final String VIEWER_PREFIX = "viewer_";
245 private static final String RNA_PREFIX = "rna_";
247 private static final String UTF_8 = "UTF-8";
250 * used in decision if quit confirmation should be issued
252 private static boolean stateSavedUpToDate = false;
255 * prefix for recovering datasets for alignments with multiple views where
256 * non-existent dataset IDs were written for some views
258 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
260 // use this with nextCounter() to make unique names for entities
261 private int counter = 0;
264 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
265 * of sequence objects are created.
267 IdentityHashMap<SequenceI, String> seqsToIds = null;
270 * jalview XML Sequence ID to jalview sequence object reference (both dataset
271 * and alignment sequences. Populated as XML reps of sequence objects are
274 Map<String, SequenceI> seqRefIds = null;
276 Map<String, SequenceI> incompleteSeqs = null;
278 List<forwardRef> frefedSequence = null;
280 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
283 * Map of reconstructed AlignFrame objects that appear to have come from
284 * SplitFrame objects (have a dna/protein complement view).
286 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
289 * Map from displayed rna structure models to their saved session state jar
292 private Map<RnaModel, String> rnaSessions = new HashMap<>();
295 * map from contact matrices to their XML ids
297 private Map<ContactMatrixI, String> contactMatrices = new HashMap<>();
299 private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
301 private List<jalview.xml.binding.jalview.MatrixType> xmlMatrices = new ArrayList<>();
304 * A helper method for safely using the value of an optional attribute that
305 * may be null if not present in the XML. Answers the boolean value, or false
311 public static boolean safeBoolean(Boolean b)
313 return b == null ? false : b.booleanValue();
317 * A helper method for safely using the value of an optional attribute that
318 * may be null if not present in the XML. Answers the integer value, or zero
324 public static int safeInt(Integer i)
326 return i == null ? 0 : i.intValue();
330 * A helper method for safely using the value of an optional attribute that
331 * may be null if not present in the XML. Answers the float value, or zero if
337 public static float safeFloat(Float f)
339 return f == null ? 0f : f.floatValue();
343 * create/return unique hash string for sq
346 * @return new or existing unique string for sq
348 String seqHash(SequenceI sq)
350 if (seqsToIds == null)
354 if (seqsToIds.containsKey(sq))
356 return seqsToIds.get(sq);
360 // create sequential key
361 String key = "sq" + (seqsToIds.size() + 1);
362 key = makeHashCode(sq, key); // check we don't have an external reference
364 seqsToIds.put(sq, key);
371 if (seqsToIds == null)
373 seqsToIds = new IdentityHashMap<>();
375 if (seqRefIds == null)
377 seqRefIds = new HashMap<>();
379 if (incompleteSeqs == null)
381 incompleteSeqs = new HashMap<>();
383 if (frefedSequence == null)
385 frefedSequence = new ArrayList<>();
393 public Jalview2XML(boolean raiseGUI)
395 this.raiseGUI = raiseGUI;
399 * base class for resolving forward references to an as-yet unmarshalled
400 * object referenced by already unmarshalled objects
405 abstract class forwardRef
411 public forwardRef(String _sref, String type)
417 public String getSref()
422 public abstract boolean isResolvable();
425 * @return true if the forward reference was fully resolved
427 abstract boolean resolve();
430 public String toString()
432 return type + " reference to " + sref;
437 * resolve forward references to sequences by their ID
441 abstract class SeqFref extends forwardRef
443 public SeqFref(String _sref, String type)
448 public SequenceI getSrefSeq()
450 return seqRefIds.get(sref);
453 public boolean isResolvable()
455 return seqRefIds.get(sref) != null;
458 public SequenceI getSrefDatasetSeq()
460 SequenceI sq = seqRefIds.get(sref);
463 while (sq.getDatasetSequence() != null)
465 sq = sq.getDatasetSequence();
473 * create forward reference for a mapping
479 public SeqFref newMappingRef(final String sref,
480 final jalview.datamodel.Mapping _jmap)
482 SeqFref fref = new SeqFref(sref, "Mapping")
484 public jalview.datamodel.Mapping jmap = _jmap;
489 SequenceI seq = getSrefDatasetSeq();
501 public SeqFref newAlcodMapRef(final String sref,
502 final AlignedCodonFrame _cf,
503 final jalview.datamodel.Mapping _jmap)
506 SeqFref fref = new SeqFref(sref, "Codon Frame")
508 AlignedCodonFrame cf = _cf;
510 public jalview.datamodel.Mapping mp = _jmap;
513 public boolean isResolvable()
515 return super.isResolvable() && mp.getTo() != null;
521 SequenceI seq = getSrefDatasetSeq();
526 cf.addMap(seq, mp.getTo(), mp.getMap());
533 public forwardRef newMatrixFref(final String matRef,
534 final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
536 forwardRef fref = new forwardRef(matRef,
537 "Matrix Reference for sequence and annotation")
543 ContactMatrixI cm = contactMatrixRefs.get(matRef);
544 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
547 jaa.sequenceRef.addContactListFor(jaa, newpae);
552 public boolean isResolvable()
554 return (contactMatrixRefs.get(matRef) != null);
560 public void resolveFrefedSequences()
562 Iterator<forwardRef> nextFref = frefedSequence.iterator();
563 int toresolve = frefedSequence.size();
564 int unresolved = 0, failedtoresolve = 0;
565 while (nextFref.hasNext())
567 forwardRef ref = nextFref.next();
568 if (ref.isResolvable())
580 } catch (Exception x)
582 jalview.bin.Console.errPrintln(
583 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
596 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
598 + " forward references left unresolved on the stack.");
600 if (failedtoresolve > 0)
602 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
603 + " resolvable forward references failed to resolve.");
605 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
607 jalview.bin.Console.errPrintln(
608 "Jalview Project Import: There are " + incompleteSeqs.size()
609 + " sequences which may have incomplete metadata.");
610 if (incompleteSeqs.size() < 10)
612 for (SequenceI s : incompleteSeqs.values())
614 jalview.bin.Console.errPrintln(s.toString());
619 jalview.bin.Console.errPrintln(
620 "Too many to report. Skipping output of incomplete sequences.");
626 * This maintains a map of viewports, the key being the seqSetId. Important to
627 * set historyItem and redoList for multiple views
629 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
631 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
633 String uniqueSetSuffix = "";
636 * List of pdbfiles added to Jar
638 List<String> pdbfiles = null;
640 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
641 public void saveState(File statefile)
643 FileOutputStream fos = null;
648 fos = new FileOutputStream(statefile);
650 JarOutputStream jout = new JarOutputStream(fos);
654 } catch (Exception e)
656 Console.error("Couln't write Jalview state to " + statefile, e);
657 // TODO: inform user of the problem - they need to know if their data was
659 if (errorMessage == null)
661 errorMessage = "Did't write Jalview Archive to output file '"
662 + statefile + "' - See console error log for details";
666 errorMessage += "(Didn't write Jalview Archive to output file '"
677 } catch (IOException e)
687 * Writes a jalview project archive to the given Jar output stream.
691 public void saveState(JarOutputStream jout)
693 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
695 setStateSavedUpToDate(true);
697 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
699 int n = debugDelaySave;
703 Console.debug("***** debugging save sleep " + i + "/" + n);
707 } catch (InterruptedException e)
709 // TODO Auto-generated catch block
720 saveAllFrames(Arrays.asList(frames), jout);
724 * core method for storing state for a set of AlignFrames.
727 * - frames involving all data to be exported (including containing
730 * - project output stream
732 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
734 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
737 * ensure cached data is clear before starting
739 // todo tidy up seqRefIds, seqsToIds initialisation / reset
741 splitFrameCandidates.clear();
746 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
747 // //////////////////////////////////////////////////
749 List<String> shortNames = new ArrayList<>();
750 List<String> viewIds = new ArrayList<>();
753 for (int i = frames.size() - 1; i > -1; i--)
755 AlignFrame af = frames.get(i);
757 if (skipList != null && skipList
758 .containsKey(af.getViewport().getSequenceSetId()))
763 String shortName = makeFilename(af, shortNames);
765 int apSize = af.getAlignPanels().size();
767 for (int ap = 0; ap < apSize; ap++)
769 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
771 String fileName = apSize == 1 ? shortName : ap + shortName;
772 if (!fileName.endsWith(".xml"))
774 fileName = fileName + ".xml";
777 saveState(apanel, fileName, jout, viewIds);
779 String dssid = getDatasetIdRef(
780 af.getViewport().getAlignment().getDataset());
781 if (!dsses.containsKey(dssid))
783 dsses.put(dssid, af);
788 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
794 } catch (Exception foo)
798 } catch (Exception ex)
800 // TODO: inform user of the problem - they need to know if their data was
802 if (errorMessage == null)
804 errorMessage = "Couldn't write Jalview Archive - see error output for details";
806 ex.printStackTrace();
811 * Generates a distinct file name, based on the title of the AlignFrame, by
812 * appending _n for increasing n until an unused name is generated. The new
813 * name (without its extension) is added to the list.
817 * @return the generated name, with .xml extension
819 protected String makeFilename(AlignFrame af, List<String> namesUsed)
821 String shortName = af.getTitle();
823 if (shortName.indexOf(File.separatorChar) > -1)
825 shortName = shortName
826 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
831 while (namesUsed.contains(shortName))
833 if (shortName.endsWith("_" + (count - 1)))
835 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
838 shortName = shortName.concat("_" + count);
842 namesUsed.add(shortName);
844 if (!shortName.endsWith(".xml"))
846 shortName = shortName + ".xml";
851 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
852 public boolean saveAlignment(AlignFrame af, String jarFile,
857 // create backupfiles object and get new temp filename destination
858 boolean doBackup = BackupFiles.getEnabled();
859 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
860 FileOutputStream fos = new FileOutputStream(
861 doBackup ? backupfiles.getTempFilePath() : jarFile);
863 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
865 int n = debugDelaySave;
869 Console.debug("***** debugging save sleep " + i + "/" + n);
873 } catch (InterruptedException e)
875 // TODO Auto-generated catch block
882 JarOutputStream jout = new JarOutputStream(fos);
883 List<AlignFrame> frames = new ArrayList<>();
885 // resolve splitframes
886 if (af.getViewport().getCodingComplement() != null)
888 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
894 saveAllFrames(frames, jout);
898 } catch (Exception foo)
902 boolean success = true;
906 backupfiles.setWriteSuccess(success);
907 success = backupfiles.rollBackupsAndRenameTempFile();
911 } catch (Exception ex)
913 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
914 ex.printStackTrace();
919 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
920 String fileName, JarOutputStream jout)
923 for (String dssids : dsses.keySet())
925 AlignFrame _af = dsses.get(dssids);
926 String jfileName = fileName + " Dataset for " + _af.getTitle();
927 if (!jfileName.endsWith(".xml"))
929 jfileName = jfileName + ".xml";
931 saveState(_af.alignPanel, jfileName, true, jout, null);
936 * create a JalviewModel from an alignment view and marshall it to a
940 * panel to create jalview model for
942 * name of alignment panel written to output stream
949 public JalviewModel saveState(AlignmentPanel ap, String fileName,
950 JarOutputStream jout, List<String> viewIds)
952 return saveState(ap, fileName, false, jout, viewIds);
956 * create a JalviewModel from an alignment view and marshall it to a
960 * panel to create jalview model for
962 * name of alignment panel written to output stream
964 * when true, only write the dataset for the alignment, not the data
965 * associated with the view.
971 public JalviewModel saveState(AlignmentPanel ap, String fileName,
972 boolean storeDS, JarOutputStream jout, List<String> viewIds)
976 viewIds = new ArrayList<>();
981 List<UserColourScheme> userColours = new ArrayList<>();
983 AlignViewport av = ap.av;
984 ViewportRanges vpRanges = av.getRanges();
986 final ObjectFactory objectFactory = new ObjectFactory();
987 JalviewModel object = objectFactory.createJalviewModel();
988 object.setVamsasModel(new VAMSAS());
990 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
993 GregorianCalendar c = new GregorianCalendar();
994 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
995 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
996 object.setCreationDate(now);
997 } catch (DatatypeConfigurationException e)
999 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
1001 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
1004 * rjal is full height alignment, jal is actual alignment with full metadata
1005 * but excludes hidden sequences.
1007 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
1009 if (av.hasHiddenRows())
1011 rjal = jal.getHiddenSequences().getFullAlignment();
1014 SequenceSet vamsasSet = new SequenceSet();
1016 // JalviewModelSequence jms = new JalviewModelSequence();
1018 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1020 if (jal.getDataset() != null)
1022 // dataset id is the dataset's hashcode
1023 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1026 // switch jal and the dataset
1027 jal = jal.getDataset();
1031 if (jal.getProperties() != null)
1033 Enumeration en = jal.getProperties().keys();
1034 while (en.hasMoreElements())
1036 String key = en.nextElement().toString();
1037 SequenceSetProperties ssp = new SequenceSetProperties();
1039 ssp.setValue(jal.getProperties().get(key).toString());
1040 // vamsasSet.addSequenceSetProperties(ssp);
1041 vamsasSet.getSequenceSetProperties().add(ssp);
1046 Set<String> calcIdSet = new HashSet<>();
1047 // record the set of vamsas sequence XML POJO we create.
1048 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1050 for (final SequenceI jds : rjal.getSequences())
1052 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1053 : jds.getDatasetSequence();
1054 String id = seqHash(jds);
1055 if (vamsasSetIds.get(id) == null)
1057 if (seqRefIds.get(id) != null && !storeDS)
1059 // This happens for two reasons: 1. multiple views are being
1061 // 2. the hashCode has collided with another sequence's code. This
1063 // HAPPEN! (PF00072.15.stk does this)
1064 // JBPNote: Uncomment to debug writing out of files that do not read
1065 // back in due to ArrayOutOfBoundExceptions.
1066 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1067 // jalview.bin.Console.errPrintln(jds.getName()+"
1068 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1069 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1070 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1071 // jalview.bin.Console.errPrintln(rsq.getName()+"
1072 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1073 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1077 vamsasSeq = createVamsasSequence(id, jds);
1078 // vamsasSet.addSequence(vamsasSeq);
1079 vamsasSet.getSequence().add(vamsasSeq);
1080 vamsasSetIds.put(id, vamsasSeq);
1081 seqRefIds.put(id, jds);
1085 jseq.setStart(jds.getStart());
1086 jseq.setEnd(jds.getEnd());
1087 jseq.setColour(av.getSequenceColour(jds).getRGB());
1089 jseq.setId(id); // jseq id should be a string not a number
1092 // Store any sequences this sequence represents
1093 if (av.hasHiddenRows())
1095 // use rjal, contains the full height alignment
1097 av.getAlignment().getHiddenSequences().isHidden(jds));
1099 if (av.isHiddenRepSequence(jds))
1101 jalview.datamodel.SequenceI[] reps = av
1102 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1104 for (int h = 0; h < reps.length; h++)
1108 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1109 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1114 // mark sequence as reference - if it is the reference for this view
1115 if (jal.hasSeqrep())
1117 jseq.setViewreference(jds == jal.getSeqrep());
1121 // TODO: omit sequence features from each alignment view's XML dump if we
1122 // are storing dataset
1123 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1124 for (SequenceFeature sf : sfs)
1126 // Features features = new Features();
1127 Feature features = new Feature();
1129 features.setBegin(sf.getBegin());
1130 features.setEnd(sf.getEnd());
1131 features.setDescription(sf.getDescription());
1132 features.setType(sf.getType());
1133 features.setFeatureGroup(sf.getFeatureGroup());
1134 features.setScore(sf.getScore());
1135 if (sf.links != null)
1137 for (int l = 0; l < sf.links.size(); l++)
1139 OtherData keyValue = new OtherData();
1140 keyValue.setKey("LINK_" + l);
1141 keyValue.setValue(sf.links.elementAt(l).toString());
1142 // features.addOtherData(keyValue);
1143 features.getOtherData().add(keyValue);
1146 if (sf.otherDetails != null)
1149 * save feature attributes, which may be simple strings or
1150 * map valued (have sub-attributes)
1152 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1154 String key = entry.getKey();
1155 Object value = entry.getValue();
1156 if (value instanceof Map<?, ?>)
1158 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1161 OtherData otherData = new OtherData();
1162 otherData.setKey(key);
1163 otherData.setKey2(subAttribute.getKey());
1164 otherData.setValue(subAttribute.getValue().toString());
1165 // features.addOtherData(otherData);
1166 features.getOtherData().add(otherData);
1171 OtherData otherData = new OtherData();
1172 otherData.setKey(key);
1173 otherData.setValue(value.toString());
1174 // features.addOtherData(otherData);
1175 features.getOtherData().add(otherData);
1180 // jseq.addFeatures(features);
1181 jseq.getFeatures().add(features);
1184 if (jdatasq.getAllPDBEntries() != null)
1186 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1187 while (en.hasMoreElements())
1189 Pdbids pdb = new Pdbids();
1190 jalview.datamodel.PDBEntry entry = en.nextElement();
1192 String pdbId = entry.getId();
1194 pdb.setType(entry.getType());
1197 * Store any structure views associated with this sequence. This
1198 * section copes with duplicate entries in the project, so a dataset
1199 * only view *should* be coped with sensibly.
1201 // This must have been loaded, is it still visible?
1202 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1203 if (Desktop.desktop != null)
1205 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1208 for (JInternalFrame jif : jifs)
1210 if (jif instanceof JalviewStructureDisplayI)
1212 viewFrames.add((JalviewStructureDisplayI) jif);
1217 else if (Jalview.isHeadlessMode()
1218 && Jalview.getInstance().getCommands() != null)
1221 StructureViewerBase.getAllStructureViewerBases());
1224 String matchedFile = null;
1225 for (JalviewStructureDisplayI viewFrame : viewFrames)
1227 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1228 matchedFile, viewFrame);
1230 * Only store each structure viewer's state once in the project
1231 * jar. First time through only (storeDS==false)
1233 String viewId = viewFrame.getViewId();
1234 String viewerType = viewFrame.getViewerType().toString();
1235 if (!storeDS && !viewIds.contains(viewId))
1237 viewIds.add(viewId);
1238 File viewerState = viewFrame.saveSession();
1239 if (viewerState != null)
1241 copyFileToJar(jout, viewerState.getPath(),
1242 getViewerJarEntryName(viewId), viewerType);
1247 "Failed to save viewer state for " + viewerType);
1252 if (matchedFile != null || entry.getFile() != null)
1254 if (entry.getFile() != null)
1257 matchedFile = entry.getFile();
1259 pdb.setFile(matchedFile); // entry.getFile());
1260 if (pdbfiles == null)
1262 pdbfiles = new ArrayList<>();
1265 if (!pdbfiles.contains(pdbId))
1267 pdbfiles.add(pdbId);
1268 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1272 Enumeration<String> props = entry.getProperties();
1273 if (props.hasMoreElements())
1275 // PdbentryItem item = new PdbentryItem();
1276 while (props.hasMoreElements())
1278 Property prop = new Property();
1279 String key = props.nextElement();
1281 prop.setValue(entry.getProperty(key).toString());
1282 // item.addProperty(prop);
1283 pdb.getProperty().add(prop);
1285 // pdb.addPdbentryItem(item);
1288 // jseq.addPdbids(pdb);
1289 jseq.getPdbids().add(pdb);
1293 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1295 // jms.addJSeq(jseq);
1296 object.getJSeq().add(jseq);
1299 if (!storeDS && av.hasHiddenRows())
1301 jal = av.getAlignment();
1305 if (storeDS && jal.getCodonFrames() != null)
1307 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1308 for (AlignedCodonFrame acf : jac)
1310 AlcodonFrame alc = new AlcodonFrame();
1311 if (acf.getProtMappings() != null
1312 && acf.getProtMappings().length > 0)
1314 boolean hasMap = false;
1315 SequenceI[] dnas = acf.getdnaSeqs();
1316 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1317 for (int m = 0; m < pmaps.length; m++)
1319 AlcodMap alcmap = new AlcodMap();
1320 alcmap.setDnasq(seqHash(dnas[m]));
1322 createVamsasMapping(pmaps[m], dnas[m], null, false));
1323 // alc.addAlcodMap(alcmap);
1324 alc.getAlcodMap().add(alcmap);
1329 // vamsasSet.addAlcodonFrame(alc);
1330 vamsasSet.getAlcodonFrame().add(alc);
1333 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1335 // AlcodonFrame alc = new AlcodonFrame();
1336 // vamsasSet.addAlcodonFrame(alc);
1337 // for (int p = 0; p < acf.aaWidth; p++)
1339 // Alcodon cmap = new Alcodon();
1340 // if (acf.codons[p] != null)
1342 // // Null codons indicate a gapped column in the translated peptide
1344 // cmap.setPos1(acf.codons[p][0]);
1345 // cmap.setPos2(acf.codons[p][1]);
1346 // cmap.setPos3(acf.codons[p][2]);
1348 // alc.addAlcodon(cmap);
1350 // if (acf.getProtMappings() != null
1351 // && acf.getProtMappings().length > 0)
1353 // SequenceI[] dnas = acf.getdnaSeqs();
1354 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1355 // for (int m = 0; m < pmaps.length; m++)
1357 // AlcodMap alcmap = new AlcodMap();
1358 // alcmap.setDnasq(seqHash(dnas[m]));
1359 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1361 // alc.addAlcodMap(alcmap);
1368 // /////////////////////////////////
1369 if (!storeDS && av.getCurrentTree() != null)
1371 // FIND ANY ASSOCIATED TREES
1372 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1373 if (Desktop.desktop != null)
1375 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1377 for (int t = 0; t < frames.length; t++)
1379 if (frames[t] instanceof TreePanel)
1381 TreePanel tp = (TreePanel) frames[t];
1383 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1385 JalviewModel.Tree tree = new JalviewModel.Tree();
1386 tree.setTitle(tp.getTitle());
1387 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1388 tree.setNewick(tp.getTree().print());
1389 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1391 tree.setFitToWindow(tp.fitToWindow.getState());
1392 tree.setFontName(tp.getTreeFont().getName());
1393 tree.setFontSize(tp.getTreeFont().getSize());
1394 tree.setFontStyle(tp.getTreeFont().getStyle());
1395 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1397 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1398 tree.setShowDistances(tp.distanceMenu.getState());
1400 tree.setHeight(tp.getHeight());
1401 tree.setWidth(tp.getWidth());
1402 tree.setXpos(tp.getX());
1403 tree.setYpos(tp.getY());
1404 tree.setId(makeHashCode(tp, null));
1405 tree.setLinkToAllViews(
1406 tp.getTreeCanvas().isApplyToAllViews());
1409 if (tp.isColumnWise())
1411 tree.setColumnWise(true);
1412 String annId = tp.getAssocAnnotation().annotationId;
1413 tree.setColumnReference(annId);
1415 // jms.addTree(tree);
1416 object.getTree().add(tree);
1426 if (!storeDS && Desktop.desktop != null)
1428 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1430 if (frame instanceof PCAPanel)
1432 PCAPanel panel = (PCAPanel) frame;
1433 if (panel.getAlignViewport().getAlignment() == jal)
1435 savePCA(panel, object);
1438 if (frame instanceof PaSiMapPanel)
1440 PaSiMapPanel panel = (PaSiMapPanel) frame;
1441 if (panel.getAlignViewport().getAlignment() == jal)
1443 savePaSiMap(panel, object);
1451 * store forward refs from an annotationRow to any groups
1453 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1456 for (SequenceI sq : jal.getSequences())
1458 // Store annotation on dataset sequences only
1459 AlignmentAnnotation[] aa = sq.getAnnotation();
1460 if (aa != null && aa.length > 0)
1462 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1469 if (jal.getAlignmentAnnotation() != null)
1471 // Store the annotation shown on the alignment.
1472 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1473 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1478 if (jal.getGroups() != null)
1480 JGroup[] groups = new JGroup[jal.getGroups().size()];
1482 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1484 JGroup jGroup = new JGroup();
1485 groups[++i] = jGroup;
1487 jGroup.setStart(sg.getStartRes());
1488 jGroup.setEnd(sg.getEndRes());
1489 jGroup.setName(sg.getName());
1490 if (groupRefs.containsKey(sg))
1492 // group has references so set its ID field
1493 jGroup.setId(groupRefs.get(sg));
1495 ColourSchemeI colourScheme = sg.getColourScheme();
1496 if (colourScheme != null)
1498 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1499 if (groupColourScheme.conservationApplied())
1501 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1503 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1505 jGroup.setColour(setUserColourScheme(colourScheme,
1506 userColours, object));
1510 jGroup.setColour(colourScheme.getSchemeName());
1513 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1515 jGroup.setColour("AnnotationColourGradient");
1516 jGroup.setAnnotationColours(constructAnnotationColours(
1517 (jalview.schemes.AnnotationColourGradient) colourScheme,
1518 userColours, object));
1520 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1523 setUserColourScheme(colourScheme, userColours, object));
1527 jGroup.setColour(colourScheme.getSchemeName());
1530 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1533 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1534 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1535 jGroup.setDisplayText(sg.getDisplayText());
1536 jGroup.setColourText(sg.getColourText());
1537 jGroup.setTextCol1(sg.textColour.getRGB());
1538 jGroup.setTextCol2(sg.textColour2.getRGB());
1539 jGroup.setTextColThreshold(sg.thresholdTextColour);
1540 jGroup.setShowUnconserved(sg.getShowNonconserved());
1541 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1542 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1543 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1544 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1545 for (SequenceI seq : sg.getSequences())
1547 // jGroup.addSeq(seqHash(seq));
1548 jGroup.getSeq().add(seqHash(seq));
1552 // jms.setJGroup(groups);
1554 for (JGroup grp : groups)
1556 object.getJGroup().add(grp);
1561 // /////////SAVE VIEWPORT
1562 Viewport view = new Viewport();
1563 view.setTitle(ap.alignFrame.getTitle());
1564 view.setSequenceSetId(
1565 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1566 view.setId(av.getViewId());
1567 if (av.getCodingComplement() != null)
1569 view.setComplementId(av.getCodingComplement().getViewId());
1571 view.setViewName(av.getViewName());
1572 view.setGatheredViews(av.isGatherViewsHere());
1574 Rectangle size = ap.av.getExplodedGeometry();
1575 Rectangle position = size;
1578 size = ap.alignFrame.getBounds();
1579 if (av.getCodingComplement() != null)
1581 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1589 view.setXpos(position.x);
1590 view.setYpos(position.y);
1592 view.setWidth(size.width);
1593 view.setHeight(size.height);
1595 view.setStartRes(vpRanges.getStartRes());
1596 view.setStartSeq(vpRanges.getStartSeq());
1598 OverviewPanel ov = ap.getOverviewPanel();
1601 Overview overview = new Overview();
1602 overview.setTitle(ov.getTitle());
1603 Rectangle bounds = ov.getFrameBounds();
1604 overview.setXpos(bounds.x);
1605 overview.setYpos(bounds.y);
1606 overview.setWidth(bounds.width);
1607 overview.setHeight(bounds.height);
1608 overview.setShowHidden(ov.isShowHiddenRegions());
1609 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1610 overview.setResidueColour(
1611 ov.getCanvas().getResidueColour().getRGB());
1612 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1613 view.setOverview(overview);
1615 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1617 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1618 userColours, object));
1621 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1623 AnnotationColourScheme ac = constructAnnotationColours(
1624 (jalview.schemes.AnnotationColourGradient) av
1625 .getGlobalColourScheme(),
1626 userColours, object);
1628 view.setAnnotationColours(ac);
1629 view.setBgColour("AnnotationColourGradient");
1633 view.setBgColour(ColourSchemeProperty
1634 .getColourName(av.getGlobalColourScheme()));
1637 ResidueShaderI vcs = av.getResidueShading();
1638 ColourSchemeI cs = av.getGlobalColourScheme();
1642 if (vcs.conservationApplied())
1644 view.setConsThreshold(vcs.getConservationInc());
1645 if (cs instanceof jalview.schemes.UserColourScheme)
1647 view.setBgColour(setUserColourScheme(cs, userColours, object));
1650 view.setPidThreshold(vcs.getThreshold());
1653 view.setConservationSelected(av.getConservationSelected());
1654 view.setPidSelected(av.getAbovePIDThreshold());
1655 view.setCharHeight(av.getCharHeight());
1656 view.setCharWidth(av.getCharWidth());
1657 final Font font = av.getFont();
1658 view.setFontName(font.getName());
1659 view.setFontSize(font.getSize());
1660 view.setFontStyle(font.getStyle());
1661 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1662 view.setRenderGaps(av.isRenderGaps());
1663 view.setShowAnnotation(av.isShowAnnotation());
1664 view.setShowBoxes(av.getShowBoxes());
1665 view.setShowColourText(av.getColourText());
1666 view.setShowFullId(av.getShowJVSuffix());
1667 view.setRightAlignIds(av.isRightAlignIds());
1668 view.setIdWidth(av.getIdWidth());
1669 view.setIdWidthManuallyAdjusted(
1670 ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1672 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1673 view.setShowText(av.getShowText());
1674 view.setShowUnconserved(av.getShowUnconserved());
1675 view.setWrapAlignment(av.getWrapAlignment());
1676 view.setTextCol1(av.getTextColour().getRGB());
1677 view.setTextCol2(av.getTextColour2().getRGB());
1678 view.setTextColThreshold(av.getThresholdTextColour());
1679 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1680 view.setShowSequenceLogo(av.isShowSequenceLogo());
1681 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1682 view.setShowGroupConsensus(av.isShowGroupConsensus());
1683 view.setShowGroupConservation(av.isShowGroupConservation());
1684 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1685 view.setShowDbRefTooltip(av.isShowDBRefs());
1686 view.setFollowHighlight(av.isFollowHighlight());
1687 view.setFollowSelection(av.followSelection);
1688 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1689 view.setShowComplementFeatures(av.isShowComplementFeatures());
1690 view.setShowComplementFeaturesOnTop(
1691 av.isShowComplementFeaturesOnTop());
1692 if (av.getFeaturesDisplayed() != null)
1694 FeatureSettings fs = new FeatureSettings();
1696 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1697 .getFeatureRenderer();
1698 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1700 Vector<String> settingsAdded = new Vector<>();
1701 if (renderOrder != null)
1703 for (String featureType : renderOrder)
1705 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1706 setting.setType(featureType);
1709 * save any filter for the feature type
1711 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1714 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1716 FeatureMatcherI firstFilter = filters.next();
1717 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1718 filters, filter.isAnded()));
1722 * save colour scheme for the feature type
1724 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1725 if (!fcol.isSimpleColour())
1727 setting.setColour(fcol.getMaxColour().getRGB());
1728 setting.setMincolour(fcol.getMinColour().getRGB());
1729 setting.setMin(fcol.getMin());
1730 setting.setMax(fcol.getMax());
1731 setting.setColourByLabel(fcol.isColourByLabel());
1732 if (fcol.isColourByAttribute())
1734 String[] attName = fcol.getAttributeName();
1735 setting.getAttributeName().add(attName[0]);
1736 if (attName.length > 1)
1738 setting.getAttributeName().add(attName[1]);
1741 setting.setAutoScale(fcol.isAutoScaled());
1742 setting.setThreshold(fcol.getThreshold());
1743 Color noColour = fcol.getNoColour();
1744 if (noColour == null)
1746 setting.setNoValueColour(NoValueColour.NONE);
1748 else if (noColour.equals(fcol.getMaxColour()))
1750 setting.setNoValueColour(NoValueColour.MAX);
1754 setting.setNoValueColour(NoValueColour.MIN);
1756 // -1 = No threshold, 0 = Below, 1 = Above
1757 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1758 : (fcol.isBelowThreshold() ? 0 : -1));
1762 setting.setColour(fcol.getColour().getRGB());
1766 av.getFeaturesDisplayed().isVisible(featureType));
1767 float rorder = fr.getOrder(featureType);
1770 setting.setOrder(rorder);
1772 /// fs.addSetting(setting);
1773 fs.getSetting().add(setting);
1774 settingsAdded.addElement(featureType);
1778 // is groups actually supposed to be a map here ?
1779 Iterator<String> en = fr.getFeatureGroups().iterator();
1780 Vector<String> groupsAdded = new Vector<>();
1781 while (en.hasNext())
1783 String grp = en.next();
1784 if (groupsAdded.contains(grp))
1788 Group g = new Group();
1790 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1793 fs.getGroup().add(g);
1794 groupsAdded.addElement(grp);
1796 // jms.setFeatureSettings(fs);
1797 object.setFeatureSettings(fs);
1800 if (av.hasHiddenColumns())
1802 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1803 .getHiddenColumns();
1807 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1811 Iterator<int[]> hiddenRegions = hidden.iterator();
1812 while (hiddenRegions.hasNext())
1814 int[] region = hiddenRegions.next();
1815 HiddenColumns hc = new HiddenColumns();
1816 hc.setStart(region[0]);
1817 hc.setEnd(region[1]);
1818 // view.addHiddenColumns(hc);
1819 view.getHiddenColumns().add(hc);
1823 if (calcIdSet.size() > 0)
1825 for (String calcId : calcIdSet)
1827 if (calcId.trim().length() > 0)
1829 CalcIdParam cidp = createCalcIdParam(calcId, av);
1830 // Some calcIds have no parameters.
1833 // view.addCalcIdParam(cidp);
1834 view.getCalcIdParam().add(cidp);
1840 // jms.addViewport(view);
1841 object.getViewport().add(view);
1846 // store matrices referenced by any views or annotation in this dataset
1847 if (xmlMatrices != null && xmlMatrices.size() > 0)
1850 "Adding " + xmlMatrices.size() + " matrices to dataset.");
1851 vamsasSet.getMatrix().addAll(xmlMatrices);
1852 xmlMatrices.clear();
1856 // object.setJalviewModelSequence(jms);
1857 // object.getVamsasModel().addSequenceSet(vamsasSet);
1858 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1860 if (jout != null && fileName != null)
1862 // We may not want to write the object to disk,
1863 // eg we can copy the alignViewport to a new view object
1864 // using save and then load
1867 fileName = fileName.replace('\\', '/');
1868 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1869 JarEntry entry = new JarEntry(fileName);
1870 jout.putNextEntry(entry);
1871 PrintWriter pout = new PrintWriter(
1872 new OutputStreamWriter(jout, UTF_8));
1873 JAXBContext jaxbContext = JAXBContext
1874 .newInstance(JalviewModel.class);
1875 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1877 // output pretty printed
1878 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1879 jaxbMarshaller.marshal(
1880 new ObjectFactory().createJalviewModel(object), pout);
1882 // jaxbMarshaller.marshal(object, pout);
1883 // marshaller.marshal(object);
1886 } catch (Exception ex)
1888 // TODO: raise error in GUI if marshalling failed.
1889 jalview.bin.Console.errPrintln("Error writing Jalview project");
1890 ex.printStackTrace();
1897 * Writes PCA viewer attributes and computed values to an XML model object and
1898 * adds it to the JalviewModel. Any exceptions are reported by logging.
1900 protected void savePCA(PCAPanel panel, JalviewModel object)
1904 PcaViewer viewer = new PcaViewer();
1905 viewer.setHeight(panel.getHeight());
1906 viewer.setWidth(panel.getWidth());
1907 viewer.setXpos(panel.getX());
1908 viewer.setYpos(panel.getY());
1909 viewer.setTitle(panel.getTitle());
1910 PCAModel pcaModel = panel.getPcaModel();
1911 viewer.setScoreModelName(pcaModel.getScoreModelName());
1912 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1913 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1914 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1916 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1917 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1918 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1919 SeqPointMin spmin = new SeqPointMin();
1920 spmin.setXPos(spMin[0]);
1921 spmin.setYPos(spMin[1]);
1922 spmin.setZPos(spMin[2]);
1923 viewer.setSeqPointMin(spmin);
1924 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1925 SeqPointMax spmax = new SeqPointMax();
1926 spmax.setXPos(spMax[0]);
1927 spmax.setYPos(spMax[1]);
1928 spmax.setZPos(spMax[2]);
1929 viewer.setSeqPointMax(spmax);
1930 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1931 viewer.setLinkToAllViews(
1932 panel.getRotatableCanvas().isApplyToAllViews());
1933 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1934 viewer.setIncludeGaps(sp.includeGaps());
1935 viewer.setMatchGaps(sp.matchGaps());
1936 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1937 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1940 * sequence points on display
1942 for (jalview.datamodel.SequencePoint spt : pcaModel
1943 .getSequencePoints())
1945 SequencePoint point = new SequencePoint();
1946 point.setSequenceRef(seqHash(spt.getSequence()));
1947 point.setXPos(spt.coord.x);
1948 point.setYPos(spt.coord.y);
1949 point.setZPos(spt.coord.z);
1950 viewer.getSequencePoint().add(point);
1954 * (end points of) axes on display
1956 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1959 Axis axis = new Axis();
1963 viewer.getAxis().add(axis);
1967 * raw PCA data (note we are not restoring PCA inputs here -
1968 * alignment view, score model, similarity parameters)
1970 PcaDataType data = new PcaDataType();
1971 viewer.setPcaData(data);
1972 PCA pca = pcaModel.getPcaData();
1974 DoubleMatrix pm = new DoubleMatrix();
1975 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1976 data.setPairwiseMatrix(pm);
1978 DoubleMatrix tm = new DoubleMatrix();
1979 saveDoubleMatrix(pca.getTridiagonal(), tm);
1980 data.setTridiagonalMatrix(tm);
1982 DoubleMatrix eigenMatrix = new DoubleMatrix();
1983 data.setEigenMatrix(eigenMatrix);
1984 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1986 object.getPcaViewer().add(viewer);
1987 } catch (Throwable t)
1989 Console.error("Error saving PCA: " + t.getMessage());
1994 * Writes PaSiMap viewer attributes and computed values to an XML model object and
1995 * adds it to the JalviewModel. Any exceptions are reported by logging.
1996 * uses the functions from PCA
1998 protected void savePaSiMap(PaSiMapPanel panel, JalviewModel object)
2000 // TODO: this should be merged with above savePCAPanel - otherwise it is essentially redundant code
2003 PcaViewer viewer = new PcaViewer();
2004 viewer.setHeight(panel.getHeight());
2005 viewer.setWidth(panel.getWidth());
2006 viewer.setXpos(panel.getX());
2007 viewer.setYpos(panel.getY());
2008 viewer.setTitle(panel.getTitle());
2009 PaSiMapModel pasimapModel = panel.getPasimapModel();
2010 viewer.setScoreModelName(pasimapModel.getScoreModelName());
2011 viewer.setXDim(panel.getSelectedDimensionIndex(X));
2012 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
2013 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
2015 panel.getRotatableCanvas().getBackgroundColour().getRGB());
2016 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
2017 float[] spMin = panel.getRotatableCanvas().getSeqMin();
2018 SeqPointMin spmin = new SeqPointMin();
2019 spmin.setXPos(spMin[0]);
2020 spmin.setYPos(spMin[1]);
2021 spmin.setZPos(spMin[2]);
2022 viewer.setSeqPointMin(spmin);
2023 float[] spMax = panel.getRotatableCanvas().getSeqMax();
2024 SeqPointMax spmax = new SeqPointMax();
2025 spmax.setXPos(spMax[0]);
2026 spmax.setYPos(spMax[1]);
2027 spmax.setZPos(spMax[2]);
2028 viewer.setSeqPointMax(spmax);
2029 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
2030 viewer.setLinkToAllViews(
2031 panel.getRotatableCanvas().isApplyToAllViews());
2032 /* NOT FOR PASIMAP CALCULATIONS
2034 SimilarityParamsI sp = pasimapModel.getSimilarityParameters();
2035 viewer.setIncludeGaps(sp.includeGaps());
2036 viewer.setMatchGaps(sp.matchGaps());
2037 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
2038 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
2042 * sequence points on display
2044 for (jalview.datamodel.SequencePoint spt : pasimapModel
2045 .getSequencePoints())
2047 SequencePoint point = new SequencePoint();
2048 point.setSequenceRef(seqHash(spt.getSequence()));
2049 point.setXPos(spt.coord.x);
2050 point.setYPos(spt.coord.y);
2051 point.setZPos(spt.coord.z);
2052 viewer.getSequencePoint().add(point);
2056 * (end points of) axes on display
2058 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
2061 Axis axis = new Axis();
2065 viewer.getAxis().add(axis);
2069 * raw PaSiMap data (note we are not restoring PaSiMap inputs here -
2070 * alignment view, score model, similarity parameters)
2072 PcaDataType data = new PcaDataType();
2073 viewer.setPcaData(data);
2074 PaSiMap pasimap = pasimapModel.getPasimapData();
2076 DoubleMatrix pm = new DoubleMatrix();
2077 saveDoubleMatrix(pasimap.getPairwiseScores(), pm);
2078 data.setPairwiseMatrix(pm);
2080 DoubleMatrix eigenMatrix = new DoubleMatrix();
2081 data.setEigenMatrix(eigenMatrix);
2082 saveDoubleMatrix(pasimap.getEigenmatrix(), eigenMatrix);
2084 object.getPcaViewer().add(viewer);
2085 } catch (Throwable t)
2087 Console.error("Error saving PaSiMap: " + t.getMessage());
2091 * Stores values from a matrix into an XML element, including (if present) the
2096 * @see #loadDoubleMatrix(DoubleMatrix)
2098 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
2100 xmlMatrix.setRows(m.height());
2101 xmlMatrix.setColumns(m.width());
2102 for (int i = 0; i < m.height(); i++)
2104 DoubleVector row = new DoubleVector();
2105 for (int j = 0; j < m.width(); j++)
2107 row.getV().add(m.getValue(i, j));
2109 xmlMatrix.getRow().add(row);
2111 if (m.getD() != null)
2113 DoubleVector dVector = new DoubleVector();
2114 for (double d : m.getD())
2116 dVector.getV().add(d);
2118 xmlMatrix.setD(dVector);
2120 if (m.getE() != null)
2122 DoubleVector eVector = new DoubleVector();
2123 for (double e : m.getE())
2125 eVector.getV().add(e);
2127 xmlMatrix.setE(eVector);
2132 * Loads XML matrix data into a new Matrix object, including the D and/or E
2133 * vectors (if present)
2137 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2139 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2141 int rows = mData.getRows();
2142 double[][] vals = new double[rows][];
2144 for (int i = 0; i < rows; i++)
2146 List<Double> dVector = mData.getRow().get(i).getV();
2147 vals[i] = new double[dVector.size()];
2149 for (Double d : dVector)
2155 MatrixI m = new Matrix(vals);
2157 if (mData.getD() != null)
2159 List<Double> dVector = mData.getD().getV();
2160 double[] vec = new double[dVector.size()];
2162 for (Double d : dVector)
2168 if (mData.getE() != null)
2170 List<Double> dVector = mData.getE().getV();
2171 double[] vec = new double[dVector.size()];
2173 for (Double d : dVector)
2184 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2185 * for each viewer, with
2187 * <li>viewer geometry (position, size, split pane divider location)</li>
2188 * <li>index of the selected structure in the viewer (currently shows gapped
2190 * <li>the id of the annotation holding RNA secondary structure</li>
2191 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2193 * Varna viewer state is also written out (in native Varna XML) to separate
2194 * project jar entries. A separate entry is written for each RNA structure
2195 * displayed, with the naming convention
2197 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2205 * @param storeDataset
2207 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2208 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2209 boolean storeDataset)
2211 if (Desktop.desktop == null)
2215 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2216 for (int f = frames.length - 1; f > -1; f--)
2218 if (frames[f] instanceof AppVarna)
2220 AppVarna varna = (AppVarna) frames[f];
2222 * link the sequence to every viewer that is showing it and is linked to
2223 * its alignment panel
2225 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2227 String viewId = varna.getViewId();
2228 RnaViewer rna = new RnaViewer();
2229 rna.setViewId(viewId);
2230 rna.setTitle(varna.getTitle());
2231 rna.setXpos(varna.getX());
2232 rna.setYpos(varna.getY());
2233 rna.setWidth(varna.getWidth());
2234 rna.setHeight(varna.getHeight());
2235 rna.setDividerLocation(varna.getDividerLocation());
2236 rna.setSelectedRna(varna.getSelectedIndex());
2237 // jseq.addRnaViewer(rna);
2238 jseq.getRnaViewer().add(rna);
2241 * Store each Varna panel's state once in the project per sequence.
2242 * First time through only (storeDataset==false)
2244 // boolean storeSessions = false;
2245 // String sequenceViewId = viewId + seqsToIds.get(jds);
2246 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2248 // viewIds.add(sequenceViewId);
2249 // storeSessions = true;
2251 for (RnaModel model : varna.getModels())
2253 if (model.seq == jds)
2256 * VARNA saves each view (sequence or alignment secondary
2257 * structure, gapped or trimmed) as a separate XML file
2259 String jarEntryName = rnaSessions.get(model);
2260 if (jarEntryName == null)
2263 String varnaStateFile = varna.getStateInfo(model.rna);
2264 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2265 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2266 rnaSessions.put(model, jarEntryName);
2268 SecondaryStructure ss = new SecondaryStructure();
2269 String annotationId = varna.getAnnotation(jds).annotationId;
2270 ss.setAnnotationId(annotationId);
2271 ss.setViewerState(jarEntryName);
2272 ss.setGapped(model.gapped);
2273 ss.setTitle(model.title);
2274 // rna.addSecondaryStructure(ss);
2275 rna.getSecondaryStructure().add(ss);
2284 * Copy the contents of a file to a new entry added to the output jar
2288 * @param jarEntryName
2290 * additional identifying info to log to the console
2292 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2293 String jarEntryName, String msg)
2295 try (InputStream is = new FileInputStream(infilePath))
2297 File file = new File(infilePath);
2298 if (file.exists() && jout != null)
2300 jalview.bin.Console.outPrintln(
2301 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2302 jout.putNextEntry(new JarEntry(jarEntryName));
2305 // dis = new DataInputStream(new FileInputStream(file));
2306 // byte[] data = new byte[(int) file.length()];
2307 // dis.readFully(data);
2308 // writeJarEntry(jout, jarEntryName, data);
2310 } catch (Exception ex)
2312 ex.printStackTrace();
2317 * Copies input to output, in 4K buffers; handles any data (text or binary)
2321 * @throws IOException
2323 protected void copyAll(InputStream in, OutputStream out)
2326 byte[] buffer = new byte[4096];
2328 while ((bytesRead = in.read(buffer)) != -1)
2330 out.write(buffer, 0, bytesRead);
2335 * Save the state of a structure viewer
2340 * the archive XML element under which to save the state
2343 * @param matchedFile
2347 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2348 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2349 String matchedFile, JalviewStructureDisplayI viewFrame)
2351 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2354 * Look for any bindings for this viewer to the PDB file of interest
2355 * (including part matches excluding chain id)
2357 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2359 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2360 final String pdbId = pdbentry.getId();
2361 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2362 && entry.getId().toLowerCase(Locale.ROOT)
2363 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2366 * not interested in a binding to a different PDB entry here
2370 if (matchedFile == null)
2372 matchedFile = pdbentry.getFile();
2374 else if (!matchedFile.equals(pdbentry.getFile()))
2377 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2378 + pdbentry.getFile());
2382 // can get at it if the ID
2383 // match is ambiguous (e.g.
2386 for (int smap = 0; smap < viewFrame.getBinding()
2387 .getSequence()[peid].length; smap++)
2389 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2390 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2392 StructureState state = new StructureState();
2393 state.setVisible(true);
2394 state.setXpos(viewFrame.getY());
2395 state.setYpos(viewFrame.getY());
2396 state.setWidth(viewFrame.getWidth());
2397 state.setHeight(viewFrame.getHeight());
2398 final String viewId = viewFrame.getViewId();
2399 state.setViewId(viewId);
2400 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2401 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2402 state.setColourByJmol(viewFrame.isColouredByViewer());
2403 state.setType(viewFrame.getViewerType().toString());
2404 // pdb.addStructureState(state);
2405 pdb.getStructureState().add(state);
2413 * Populates the AnnotationColourScheme xml for save. This captures the
2414 * settings of the options in the 'Colour by Annotation' dialog.
2417 * @param userColours
2421 private AnnotationColourScheme constructAnnotationColours(
2422 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2425 AnnotationColourScheme ac = new AnnotationColourScheme();
2426 ac.setAboveThreshold(acg.getAboveThreshold());
2427 ac.setThreshold(acg.getAnnotationThreshold());
2428 // 2.10.2 save annotationId (unique) not annotation label
2429 ac.setAnnotation(acg.getAnnotation().annotationId);
2430 if (acg.getBaseColour() instanceof UserColourScheme)
2433 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2438 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2441 ac.setMaxColour(acg.getMaxColour().getRGB());
2442 ac.setMinColour(acg.getMinColour().getRGB());
2443 ac.setPerSequence(acg.isSeqAssociated());
2444 ac.setPredefinedColours(acg.isPredefinedColours());
2448 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2449 IdentityHashMap<SequenceGroup, String> groupRefs,
2450 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2451 SequenceSet vamsasSet)
2454 for (int i = 0; i < aa.length; i++)
2456 Annotation an = new Annotation();
2458 AlignmentAnnotation annotation = aa[i];
2459 if (annotation.annotationId != null)
2461 annotationIds.put(annotation.annotationId, annotation);
2464 an.setId(annotation.annotationId);
2466 an.setVisible(annotation.visible);
2468 an.setDescription(annotation.description);
2470 if (annotation.sequenceRef != null)
2472 // 2.9 JAL-1781 xref on sequence id rather than name
2473 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2475 if (annotation.groupRef != null)
2477 String groupIdr = groupRefs.get(annotation.groupRef);
2478 if (groupIdr == null)
2480 // make a locally unique String
2481 groupRefs.put(annotation.groupRef,
2482 groupIdr = ("" + System.currentTimeMillis()
2483 + annotation.groupRef.getName()
2484 + groupRefs.size()));
2486 an.setGroupRef(groupIdr.toString());
2489 // store all visualization attributes for annotation
2490 an.setGraphHeight(annotation.graphHeight);
2491 an.setCentreColLabels(annotation.centreColLabels);
2492 an.setScaleColLabels(annotation.scaleColLabel);
2493 an.setShowAllColLabels(annotation.showAllColLabels);
2494 an.setBelowAlignment(annotation.belowAlignment);
2496 if (annotation.graph > 0)
2499 an.setGraphType(annotation.graph);
2500 an.setGraphGroup(annotation.graphGroup);
2501 if (annotation.getThreshold() != null)
2503 ThresholdLine line = new ThresholdLine();
2504 line.setLabel(annotation.getThreshold().label);
2505 line.setValue(annotation.getThreshold().value);
2506 line.setColour(annotation.getThreshold().colour.getRGB());
2507 an.setThresholdLine(line);
2509 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2511 if (annotation.sequenceRef.getContactMaps() != null)
2513 ContactMatrixI cm = annotation.sequenceRef
2514 .getContactMatrixFor(annotation);
2517 storeMatrixFor(vamsasSet, an, annotation, cm);
2527 an.setLabel(annotation.label);
2529 if (annotation == av.getAlignmentQualityAnnot()
2530 || annotation == av.getAlignmentConservationAnnotation()
2531 || annotation == av.getAlignmentConsensusAnnotation()
2532 || annotation.autoCalculated)
2534 // new way of indicating autocalculated annotation -
2535 an.setAutoCalculated(annotation.autoCalculated);
2537 if (annotation.hasScore())
2539 an.setScore(annotation.getScore());
2542 if (annotation.getCalcId() != null)
2544 calcIdSet.add(annotation.getCalcId());
2545 an.setCalcId(annotation.getCalcId());
2547 if (annotation.hasProperties())
2549 for (String pr : annotation.getProperties())
2551 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2553 prop.setValue(annotation.getProperty(pr));
2554 an.getProperty().add(prop);
2558 AnnotationElement ae;
2559 if (annotation.annotations != null)
2561 an.setScoreOnly(false);
2562 for (int a = 0; a < annotation.annotations.length; a++)
2564 if ((annotation == null) || (annotation.annotations[a] == null))
2569 ae = new AnnotationElement();
2570 if (annotation.annotations[a].description != null)
2572 ae.setDescription(annotation.annotations[a].description);
2574 if (annotation.annotations[a].displayCharacter != null)
2576 ae.setDisplayCharacter(
2577 annotation.annotations[a].displayCharacter);
2580 if (!Float.isNaN(annotation.annotations[a].value))
2582 ae.setValue(annotation.annotations[a].value);
2586 if (annotation.annotations[a].secondaryStructure > ' ')
2588 ae.setSecondaryStructure(
2589 annotation.annotations[a].secondaryStructure + "");
2592 if (annotation.annotations[a].colour != null
2593 && annotation.annotations[a].colour != java.awt.Color.black)
2595 ae.setColour(annotation.annotations[a].colour.getRGB());
2598 // an.addAnnotationElement(ae);
2599 an.getAnnotationElement().add(ae);
2600 if (annotation.autoCalculated)
2602 // only write one non-null entry into the annotation row -
2603 // sufficient to get the visualization attributes necessary to
2611 an.setScoreOnly(true);
2613 if (!storeDS || (storeDS && !annotation.autoCalculated))
2615 // skip autocalculated annotation - these are only provided for
2617 // vamsasSet.addAnnotation(an);
2618 vamsasSet.getAnnotation().add(an);
2624 private void storeMatrixFor(SequenceSet root, Annotation an,
2625 AlignmentAnnotation annotation, ContactMatrixI cm)
2627 String cmId = contactMatrices.get(cm);
2628 MatrixType xmlmat = null;
2630 // first create an xml ref for the matrix data, if none exist
2633 xmlmat = new MatrixType();
2634 xmlmat.setType(cm.getType());
2635 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2636 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2637 // consider using an opaque to/from -> allow instance to control
2638 // its representation ?
2639 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2642 for (BitSet gp : cm.getGroups())
2644 xmlmat.getGroups().add(stringifyBitset(gp));
2649 // provenance object for tree ?
2650 xmlmat.getNewick().add(cm.getNewick());
2651 xmlmat.setTreeMethod(cm.getTreeMethod());
2653 if (cm.hasCutHeight())
2655 xmlmat.setCutHeight(cm.getCutHeight());
2657 xmlmat.setId(cmId = "m" + contactMatrices.size()
2658 + System.currentTimeMillis());
2659 Console.trace("Matrix data stored :" + cmId);
2660 contactMatrices.put(cm, cmId);
2661 contactMatrixRefs.put(cmId, cm);
2662 xmlMatrices.add(xmlmat);
2666 Console.trace("Existing Matrix stored :" + cmId);
2669 // now store mapping
2671 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2672 xmlmatmapping.setMatrix(cmId);
2674 // Pretty much all matrices currently managed in this way are
2675 // mappableContactMatrixI implementations - but check anyway
2676 if (cm instanceof MappableContactMatrixI)
2678 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2679 .getMapFor(annotation.sequenceRef);
2682 MapListType mp = new MapListType();
2683 List<int[]> r = mlst.getFromRanges();
2684 for (int[] range : r)
2686 MapListFrom mfrom = new MapListFrom();
2687 mfrom.setStart(range[0]);
2688 mfrom.setEnd(range[1]);
2689 // mp.addMapListFrom(mfrom);
2690 mp.getMapListFrom().add(mfrom);
2692 r = mlst.getToRanges();
2693 for (int[] range : r)
2695 MapListTo mto = new MapListTo();
2696 mto.setStart(range[0]);
2697 mto.setEnd(range[1]);
2698 // mp.addMapListTo(mto);
2699 mp.getMapListTo().add(mto);
2701 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2702 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2703 xmlmatmapping.setMapping(mp);
2707 an.getContactmatrix().add(xmlmatmapping);
2710 private String stringifyBitset(BitSet gp)
2712 StringBuilder sb = new StringBuilder();
2713 for (long val : gp.toLongArray())
2715 if (sb.length() > 0)
2721 return sb.toString();
2724 private BitSet deStringifyBitset(String stringified)
2726 if ("".equals(stringified) || stringified == null)
2728 return new BitSet();
2730 String[] longvals = stringified.split(",");
2731 long[] newlongvals = new long[longvals.length];
2732 for (int lv = 0; lv < longvals.length; lv++)
2736 newlongvals[lv] = Long.valueOf(longvals[lv]);
2737 } catch (Exception x)
2739 errorMessage += "Couldn't destringify bitset from: '" + stringified
2741 newlongvals[lv] = 0;
2744 return BitSet.valueOf(newlongvals);
2748 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2750 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2751 if (settings != null)
2753 CalcIdParam vCalcIdParam = new CalcIdParam();
2754 vCalcIdParam.setCalcId(calcId);
2755 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2756 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2757 // generic URI allowing a third party to resolve another instance of the
2758 // service used for this calculation
2759 for (String url : settings.getServiceURLs())
2761 // vCalcIdParam.addServiceURL(urls);
2762 vCalcIdParam.getServiceURL().add(url);
2764 vCalcIdParam.setVersion("1.0");
2765 if (settings.getPreset() != null)
2767 WsParamSetI setting = settings.getPreset();
2768 vCalcIdParam.setName(setting.getName());
2769 vCalcIdParam.setDescription(setting.getDescription());
2773 vCalcIdParam.setName("");
2774 vCalcIdParam.setDescription("Last used parameters");
2776 // need to be able to recover 1) settings 2) user-defined presets or
2777 // recreate settings from preset 3) predefined settings provided by
2778 // service - or settings that can be transferred (or discarded)
2779 vCalcIdParam.setParameters(
2780 settings.getWsParamFile().replace("\n", "|\\n|"));
2781 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2782 // todo - decide if updateImmediately is needed for any projects.
2784 return vCalcIdParam;
2789 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2792 if (calcIdParam.getVersion().equals("1.0"))
2794 final String[] calcIds = calcIdParam.getServiceURL()
2795 .toArray(new String[0]);
2796 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2797 .getPreferredServiceFor(calcIds);
2798 if (service != null)
2800 WsParamSetI parmSet = null;
2803 parmSet = service.getParamStore().parseServiceParameterFile(
2804 calcIdParam.getName(), calcIdParam.getDescription(),
2806 calcIdParam.getParameters().replace("|\\n|", "\n"));
2807 } catch (IOException x)
2809 Console.warn("Couldn't parse parameter data for "
2810 + calcIdParam.getCalcId(), x);
2813 List<ArgumentI> argList = null;
2814 if (calcIdParam.getName().length() > 0)
2816 parmSet = service.getParamStore()
2817 .getPreset(calcIdParam.getName());
2818 if (parmSet != null)
2820 // TODO : check we have a good match with settings in AACon -
2821 // otherwise we'll need to create a new preset
2826 argList = parmSet.getArguments();
2829 AAConSettings settings = new AAConSettings(
2830 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2831 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2832 calcIdParam.isNeedsUpdate());
2838 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2842 throw new Error(MessageManager.formatMessage(
2843 "error.unsupported_version_calcIdparam", new Object[]
2844 { calcIdParam.toString() }));
2848 * External mapping between jalview objects and objects yielding a valid and
2849 * unique object ID string. This is null for normal Jalview project IO, but
2850 * non-null when a jalview project is being read or written as part of a
2853 IdentityHashMap jv2vobj = null;
2856 * Construct a unique ID for jvobj using either existing bindings or if none
2857 * exist, the result of the hashcode call for the object.
2860 * jalview data object
2861 * @return unique ID for referring to jvobj
2863 private String makeHashCode(Object jvobj, String altCode)
2865 if (jv2vobj != null)
2867 Object id = jv2vobj.get(jvobj);
2870 return id.toString();
2872 // check string ID mappings
2873 if (jvids2vobj != null && jvobj instanceof String)
2875 id = jvids2vobj.get(jvobj);
2879 return id.toString();
2881 // give up and warn that something has gone wrong
2883 "Cannot find ID for object in external mapping : " + jvobj);
2889 * return local jalview object mapped to ID, if it exists
2893 * @return null or object bound to idcode
2895 private Object retrieveExistingObj(String idcode)
2897 if (idcode != null && vobj2jv != null)
2899 return vobj2jv.get(idcode);
2905 * binding from ID strings from external mapping table to jalview data model
2908 private Hashtable vobj2jv;
2910 private Sequence createVamsasSequence(String id, SequenceI jds)
2912 return createVamsasSequence(true, id, jds, null);
2915 private Sequence createVamsasSequence(boolean recurse, String id,
2916 SequenceI jds, SequenceI parentseq)
2918 Sequence vamsasSeq = new Sequence();
2919 vamsasSeq.setId(id);
2920 vamsasSeq.setName(jds.getName());
2921 vamsasSeq.setSequence(jds.getSequenceAsString());
2922 vamsasSeq.setDescription(jds.getDescription());
2923 List<DBRefEntry> dbrefs = null;
2924 if (jds.getDatasetSequence() != null)
2926 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2930 // seqId==dsseqid so we can tell which sequences really are
2931 // dataset sequences only
2932 vamsasSeq.setDsseqid(id);
2933 dbrefs = jds.getDBRefs();
2934 if (parentseq == null)
2941 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2945 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2947 DBRef dbref = new DBRef();
2948 DBRefEntry ref = dbrefs.get(d);
2949 dbref.setSource(ref.getSource());
2950 dbref.setVersion(ref.getVersion());
2951 dbref.setAccessionId(ref.getAccessionId());
2952 dbref.setCanonical(ref.isCanonical());
2953 if (ref instanceof GeneLocus)
2955 dbref.setLocus(true);
2959 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2961 dbref.setMapping(mp);
2963 vamsasSeq.getDBRef().add(dbref);
2969 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2970 SequenceI parentseq, SequenceI jds, boolean recurse)
2973 if (jmp.getMap() != null)
2977 jalview.util.MapList mlst = jmp.getMap();
2978 List<int[]> r = mlst.getFromRanges();
2979 for (int[] range : r)
2981 MapListFrom mfrom = new MapListFrom();
2982 mfrom.setStart(range[0]);
2983 mfrom.setEnd(range[1]);
2984 // mp.addMapListFrom(mfrom);
2985 mp.getMapListFrom().add(mfrom);
2987 r = mlst.getToRanges();
2988 for (int[] range : r)
2990 MapListTo mto = new MapListTo();
2991 mto.setStart(range[0]);
2992 mto.setEnd(range[1]);
2993 // mp.addMapListTo(mto);
2994 mp.getMapListTo().add(mto);
2996 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2997 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2998 if (jmp.getTo() != null)
3000 // MappingChoice mpc = new MappingChoice();
3002 // check/create ID for the sequence referenced by getTo()
3005 SequenceI ps = null;
3006 if (parentseq != jmp.getTo()
3007 && parentseq.getDatasetSequence() != jmp.getTo())
3009 // chaining dbref rather than a handshaking one
3010 jmpid = seqHash(ps = jmp.getTo());
3014 jmpid = seqHash(ps = parentseq);
3016 // mpc.setDseqFor(jmpid);
3017 mp.setDseqFor(jmpid);
3018 if (!seqRefIds.containsKey(jmpid))
3020 Console.debug("creatign new DseqFor ID");
3021 seqRefIds.put(jmpid, ps);
3025 Console.debug("reusing DseqFor ID");
3028 // mp.setMappingChoice(mpc);
3034 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
3035 List<UserColourScheme> userColours, JalviewModel jm)
3038 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
3039 boolean newucs = false;
3040 if (!userColours.contains(ucs))
3042 userColours.add(ucs);
3045 id = "ucs" + userColours.indexOf(ucs);
3048 // actually create the scheme's entry in the XML model
3049 java.awt.Color[] colours = ucs.getColours();
3050 UserColours uc = new UserColours();
3051 // UserColourScheme jbucs = new UserColourScheme();
3052 JalviewUserColours jbucs = new JalviewUserColours();
3054 for (int i = 0; i < colours.length; i++)
3056 Colour col = new Colour();
3057 col.setName(ResidueProperties.aa[i]);
3058 col.setRGB(jalview.util.Format.getHexString(colours[i]));
3059 // jbucs.addColour(col);
3060 jbucs.getColour().add(col);
3062 if (ucs.getLowerCaseColours() != null)
3064 colours = ucs.getLowerCaseColours();
3065 for (int i = 0; i < colours.length; i++)
3067 Colour col = new Colour();
3068 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
3069 col.setRGB(jalview.util.Format.getHexString(colours[i]));
3070 // jbucs.addColour(col);
3071 jbucs.getColour().add(col);
3076 uc.setUserColourScheme(jbucs);
3077 // jm.addUserColours(uc);
3078 jm.getUserColours().add(uc);
3084 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
3087 List<UserColours> uc = jm.getUserColours();
3088 UserColours colours = null;
3090 for (int i = 0; i < uc.length; i++)
3092 if (uc[i].getId().equals(id))
3099 for (UserColours c : uc)
3101 if (c.getId().equals(id))
3108 java.awt.Color[] newColours = new java.awt.Color[24];
3110 for (int i = 0; i < 24; i++)
3112 newColours[i] = new java.awt.Color(Integer.parseInt(
3113 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
3114 colours.getUserColourScheme().getColour().get(i).getRGB(),
3118 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
3121 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3123 newColours = new java.awt.Color[23];
3124 for (int i = 0; i < 23; i++)
3126 newColours[i] = new java.awt.Color(
3127 Integer.parseInt(colours.getUserColourScheme().getColour()
3128 .get(i + 24).getRGB(), 16));
3130 ucs.setLowerCaseColours(newColours);
3137 * contains last error message (if any) encountered by XML loader.
3139 String errorMessage = null;
3142 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3143 * exceptions are raised during project XML parsing
3145 public boolean attemptversion1parse = false;
3148 * Load a jalview project archive from a jar file
3151 * - HTTP URL or filename
3153 public AlignFrame loadJalviewAlign(final Object file)
3156 jalview.gui.AlignFrame af = null;
3160 // create list to store references for any new Jmol viewers created
3161 newStructureViewers = new Vector<>();
3162 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3163 // Workaround is to make sure caller implements the JarInputStreamProvider
3165 // so we can re-open the jar input stream for each entry.
3167 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3168 af = loadJalviewAlign(jprovider);
3171 af.setMenusForViewport();
3173 } catch (MalformedURLException e)
3175 errorMessage = "Invalid URL format for '" + file + "'";
3181 SwingUtilities.invokeAndWait(new Runnable()
3186 setLoadingFinishedForNewStructureViewers();
3189 } catch (Exception x)
3192 .errPrintln("Error loading alignment: " + x.getMessage());
3198 @SuppressWarnings("unused")
3199 private jarInputStreamProvider createjarInputStreamProvider(
3200 final Object ofile) throws MalformedURLException
3203 // BH 2018 allow for bytes already attached to File object
3206 String file = (ofile instanceof File
3207 ? ((File) ofile).getCanonicalPath()
3208 : ofile.toString());
3209 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3212 errorMessage = null;
3213 uniqueSetSuffix = null;
3215 viewportsAdded.clear();
3216 frefedSequence = null;
3218 if (HttpUtils.startsWithHttpOrHttps(file))
3220 url = new URL(file);
3222 final URL _url = url;
3223 return new jarInputStreamProvider()
3227 public JarInputStream getJarInputStream() throws IOException
3231 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3232 // jarInputStream for
3233 // bytes.length=" + bytes.length);
3234 return new JarInputStream(new ByteArrayInputStream(bytes));
3238 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3239 // jarInputStream for "
3241 return new JarInputStream(_url.openStream());
3245 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3246 // jarInputStream for
3248 return new JarInputStream(new FileInputStream(file));
3253 public String getFilename()
3258 } catch (IOException e)
3260 e.printStackTrace();
3266 * Recover jalview session from a jalview project archive. Caller may
3267 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3268 * themselves. Any null fields will be initialised with default values,
3269 * non-null fields are left alone.
3274 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3276 errorMessage = null;
3277 if (uniqueSetSuffix == null)
3279 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3281 if (seqRefIds == null)
3285 AlignFrame af = null, _af = null;
3286 List<AlignFrame> toRepaint = new ArrayList<AlignFrame>();
3287 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3288 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3289 final String file = jprovider.getFilename();
3292 JarInputStream jin = null;
3293 JarEntry jarentry = null;
3298 jin = jprovider.getJarInputStream();
3299 for (int i = 0; i < entryCount; i++)
3301 jarentry = jin.getNextJarEntry();
3304 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3306 JAXBContext jc = JAXBContext
3307 .newInstance("jalview.xml.binding.jalview");
3308 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3309 .createXMLStreamReader(jin);
3310 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3311 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3312 JalviewModel.class);
3313 JalviewModel object = jbe.getValue();
3315 if (true) // !skipViewport(object))
3317 _af = loadFromObject(object, file, true, jprovider);
3318 if (_af != null && object.getViewport().size() > 0)
3319 // getJalviewModelSequence().getViewportCount() > 0)
3324 // store a reference to the first view
3327 if (_af.getViewport().isGatherViewsHere())
3329 // if this is a gathered view, keep its reference since
3330 // after gathering views, only this frame will remain
3332 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3335 // Save dataset to register mappings once all resolved
3336 importedDatasets.put(
3337 af.getViewport().getAlignment().getDataset(),
3338 af.getViewport().getAlignment().getDataset());
3343 else if (jarentry != null)
3345 // Some other file here.
3348 } while (jarentry != null);
3350 resolveFrefedSequences();
3351 for (AlignFrame alignFrame : toRepaint)
3353 alignFrame.repaint();
3355 } catch (IOException ex)
3357 ex.printStackTrace();
3358 errorMessage = "Couldn't locate Jalview XML file : " + file;
3359 jalview.bin.Console.errPrintln(
3360 "Exception whilst loading jalview XML file : " + ex + "\n");
3361 } catch (Exception ex)
3364 .errPrintln("Parsing as Jalview Version 2 file failed.");
3365 ex.printStackTrace(System.err);
3366 if (attemptversion1parse)
3368 // used to attempt to parse as V1 castor-generated xml
3370 if (Desktop.instance != null)
3372 Desktop.instance.stopLoading();
3376 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3379 ex.printStackTrace();
3381 jalview.bin.Console.errPrintln(
3382 "Exception whilst loading jalview XML file : " + ex + "\n");
3383 } catch (OutOfMemoryError e)
3385 // Don't use the OOM Window here
3386 errorMessage = "Out of memory loading jalview XML file";
3388 .errPrintln("Out of memory whilst loading jalview XML file");
3389 e.printStackTrace();
3393 * Regather multiple views (with the same sequence set id) to the frame (if
3394 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3395 * views instead of separate frames. Note this doesn't restore a state where
3396 * some expanded views in turn have tabbed views - the last "first tab" read
3397 * in will play the role of gatherer for all.
3399 for (AlignFrame fr : gatherToThisFrame.values())
3401 Desktop.instance.gatherViews(fr);
3404 restoreSplitFrames();
3405 for (AlignmentI ds : importedDatasets.keySet())
3407 if (ds.getCodonFrames() != null)
3409 StructureSelectionManager
3410 .getStructureSelectionManager(Desktop.instance)
3411 .registerMappings(ds.getCodonFrames());
3414 if (errorMessage != null)
3419 if (Desktop.instance != null)
3421 Desktop.instance.stopLoading();
3428 * Try to reconstruct and display SplitFrame windows, where each contains
3429 * complementary dna and protein alignments. Done by pairing up AlignFrame
3430 * objects (created earlier) which have complementary viewport ids associated.
3432 protected void restoreSplitFrames()
3434 List<SplitFrame> gatherTo = new ArrayList<>();
3435 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3436 Map<String, AlignFrame> dna = new HashMap<>();
3439 * Identify the DNA alignments
3441 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3444 AlignFrame af = candidate.getValue();
3445 if (af.getViewport().getAlignment().isNucleotide())
3447 dna.put(candidate.getKey().getId(), af);
3452 * Try to match up the protein complements
3454 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3457 AlignFrame af = candidate.getValue();
3458 if (!af.getViewport().getAlignment().isNucleotide())
3460 String complementId = candidate.getKey().getComplementId();
3461 // only non-null complements should be in the Map
3462 if (complementId != null && dna.containsKey(complementId))
3464 final AlignFrame dnaFrame = dna.get(complementId);
3465 SplitFrame sf = createSplitFrame(dnaFrame, af);
3466 addedToSplitFrames.add(dnaFrame);
3467 addedToSplitFrames.add(af);
3468 dnaFrame.setMenusForViewport();
3469 af.setMenusForViewport();
3470 if (af.getViewport().isGatherViewsHere())
3479 * Open any that we failed to pair up (which shouldn't happen!) as
3480 * standalone AlignFrame's.
3482 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3485 AlignFrame af = candidate.getValue();
3486 if (!addedToSplitFrames.contains(af))
3488 Viewport view = candidate.getKey();
3489 Desktop.addInternalFrame(af, view.getTitle(),
3490 safeInt(view.getWidth()), safeInt(view.getHeight()));
3491 af.setMenusForViewport();
3492 jalview.bin.Console.errPrintln("Failed to restore view "
3493 + view.getTitle() + " to split frame");
3498 * Gather back into tabbed views as flagged.
3500 for (SplitFrame sf : gatherTo)
3502 Desktop.instance.gatherViews(sf);
3505 splitFrameCandidates.clear();
3509 * Construct and display one SplitFrame holding DNA and protein alignments.
3512 * @param proteinFrame
3515 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3516 AlignFrame proteinFrame)
3518 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3519 String title = MessageManager.getString("label.linked_view_title");
3520 int width = (int) dnaFrame.getBounds().getWidth();
3521 int height = (int) (dnaFrame.getBounds().getHeight()
3522 + proteinFrame.getBounds().getHeight() + 50);
3525 * SplitFrame location is saved to both enclosed frames
3527 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3528 Desktop.addInternalFrame(splitFrame, title, width, height);
3531 * And compute cDNA consensus (couldn't do earlier with consensus as
3532 * mappings were not yet present)
3534 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3540 * check errorMessage for a valid error message and raise an error box in the
3541 * GUI or write the current errorMessage to stderr and then clear the error
3544 protected void reportErrors()
3546 reportErrors(false);
3549 protected void reportErrors(final boolean saving)
3551 if (errorMessage != null)
3553 final String finalErrorMessage = errorMessage;
3556 javax.swing.SwingUtilities.invokeLater(new Runnable()
3561 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3563 "Error " + (saving ? "saving" : "loading")
3565 JvOptionPane.WARNING_MESSAGE);
3571 jalview.bin.Console.errPrintln(
3572 "Problem loading Jalview file: " + errorMessage);
3575 errorMessage = null;
3578 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3581 * when set, local views will be updated from view stored in JalviewXML
3582 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3583 * sync if this is set to true.
3585 private final boolean updateLocalViews = false;
3588 * Returns the path to a temporary file holding the PDB file for the given PDB
3589 * id. The first time of asking, searches for a file of that name in the
3590 * Jalview project jar, and copies it to a new temporary file. Any repeat
3591 * requests just return the path to the file previously created.
3597 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3600 if (alreadyLoadedPDB.containsKey(pdbId))
3602 return alreadyLoadedPDB.get(pdbId).toString();
3605 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3607 if (tempFile != null)
3609 alreadyLoadedPDB.put(pdbId, tempFile);
3615 * Copies the jar entry of given name to a new temporary file and returns the
3616 * path to the file, or null if the entry is not found.
3619 * @param jarEntryName
3621 * a prefix for the temporary file name, must be at least three
3623 * @param suffixModel
3624 * null or original file - so new file can be given the same suffix
3628 protected String copyJarEntry(jarInputStreamProvider jprovider,
3629 String jarEntryName, String prefix, String suffixModel)
3631 String suffix = ".tmp";
3632 if (suffixModel == null)
3634 suffixModel = jarEntryName;
3636 int sfpos = suffixModel.lastIndexOf(".");
3637 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3639 suffix = "." + suffixModel.substring(sfpos + 1);
3642 try (JarInputStream jin = jprovider.getJarInputStream())
3644 JarEntry entry = null;
3647 entry = jin.getNextJarEntry();
3648 } while (entry != null && !entry.getName().equals(jarEntryName));
3652 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3653 File outFile = File.createTempFile(prefix, suffix);
3654 outFile.deleteOnExit();
3655 try (OutputStream os = new FileOutputStream(outFile))
3659 String t = outFile.getAbsolutePath();
3665 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3667 } catch (Exception ex)
3669 ex.printStackTrace();
3675 private class JvAnnotRow
3677 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3684 * persisted version of annotation row from which to take vis properties
3686 public jalview.datamodel.AlignmentAnnotation template;
3689 * original position of the annotation row in the alignment
3695 * Load alignment frame from jalview XML DOM object
3697 * @param jalviewModel
3700 * filename source string
3701 * @param loadTreesAndStructures
3702 * when false only create Viewport
3704 * data source provider
3705 * @return alignment frame created from view stored in DOM
3707 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3708 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3710 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3712 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3714 // JalviewModelSequence jms = object.getJalviewModelSequence();
3716 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3718 Viewport view = (jalviewModel.getViewport().size() > 0)
3719 ? jalviewModel.getViewport().get(0)
3722 // ////////////////////////////////
3723 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3726 // If we just load in the same jar file again, the sequenceSetId
3727 // will be the same, and we end up with multiple references
3728 // to the same sequenceSet. We must modify this id on load
3729 // so that each load of the file gives a unique id
3732 * used to resolve correct alignment dataset for alignments with multiple
3735 String uniqueSeqSetId = null;
3736 String viewId = null;
3739 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3740 viewId = (view.getId() == null ? null
3741 : view.getId() + uniqueSetSuffix);
3744 // ////////////////////////////////
3745 // LOAD MATRICES (IF ANY)
3747 if (vamsasSet.getMatrix() != null && vamsasSet.getMatrix().size() > 0)
3749 importMatrixData(vamsasSet.getMatrix());
3752 // ////////////////////////////////
3755 List<SequenceI> hiddenSeqs = null;
3757 List<SequenceI> tmpseqs = new ArrayList<>();
3759 boolean multipleView = false;
3760 SequenceI referenceseqForView = null;
3761 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3762 List<JSeq> jseqs = jalviewModel.getJSeq();
3763 int vi = 0; // counter in vamsasSeq array
3764 for (int i = 0; i < jseqs.size(); i++)
3766 JSeq jseq = jseqs.get(i);
3767 String seqId = jseq.getId();
3769 SequenceI tmpSeq = seqRefIds.get(seqId);
3772 if (!incompleteSeqs.containsKey(seqId))
3774 // may not need this check, but keep it for at least 2.9,1 release
3775 if (tmpSeq.getStart() != jseq.getStart()
3776 || tmpSeq.getEnd() != jseq.getEnd())
3778 jalview.bin.Console.errPrintln(String.format(
3779 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3780 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3781 jseq.getStart(), jseq.getEnd()));
3786 incompleteSeqs.remove(seqId);
3788 if (vamsasSeqs.size() > vi
3789 && vamsasSeqs.get(vi).getId().equals(seqId))
3791 // most likely we are reading a dataset XML document so
3792 // update from vamsasSeq section of XML for this sequence
3793 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3794 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3795 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3800 // reading multiple views, so vamsasSeq set is a subset of JSeq
3801 multipleView = true;
3803 tmpSeq.setStart(jseq.getStart());
3804 tmpSeq.setEnd(jseq.getEnd());
3805 tmpseqs.add(tmpSeq);
3809 Sequence vamsasSeq = vamsasSeqs.get(vi);
3810 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3811 vamsasSeq.getSequence());
3812 tmpSeq.setDescription(vamsasSeq.getDescription());
3813 tmpSeq.setStart(jseq.getStart());
3814 tmpSeq.setEnd(jseq.getEnd());
3815 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3816 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3817 tmpseqs.add(tmpSeq);
3821 if (safeBoolean(jseq.isViewreference()))
3823 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3826 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3828 if (hiddenSeqs == null)
3830 hiddenSeqs = new ArrayList<>();
3833 hiddenSeqs.add(tmpSeq);
3838 // Create the alignment object from the sequence set
3839 // ///////////////////////////////
3840 SequenceI[] orderedSeqs = tmpseqs
3841 .toArray(new SequenceI[tmpseqs.size()]);
3843 AlignmentI al = null;
3844 // so we must create or recover the dataset alignment before going further
3845 // ///////////////////////////////
3846 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3848 // older jalview projects do not have a dataset - so creat alignment and
3850 al = new Alignment(orderedSeqs);
3851 al.setDataset(null);
3855 boolean isdsal = jalviewModel.getViewport().isEmpty();
3858 // we are importing a dataset record, so
3859 // recover reference to an alignment already materialsed as dataset
3860 al = getDatasetFor(vamsasSet.getDatasetId());
3864 // materialse the alignment
3865 al = new Alignment(orderedSeqs);
3869 addDatasetRef(vamsasSet.getDatasetId(), al);
3872 // finally, verify all data in vamsasSet is actually present in al
3873 // passing on flag indicating if it is actually a stored dataset
3874 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3877 if (referenceseqForView != null)
3879 al.setSeqrep(referenceseqForView);
3881 // / Add the alignment properties
3882 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3884 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3886 al.setProperty(ssp.getKey(), ssp.getValue());
3889 // ///////////////////////////////
3891 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3894 // load sequence features, database references and any associated PDB
3895 // structures for the alignment
3897 // prior to 2.10, this part would only be executed the first time a
3898 // sequence was encountered, but not afterwards.
3899 // now, for 2.10 projects, this is also done if the xml doc includes
3900 // dataset sequences not actually present in any particular view.
3902 for (int i = 0; i < vamsasSeqs.size(); i++)
3904 JSeq jseq = jseqs.get(i);
3905 if (jseq.getFeatures().size() > 0)
3907 List<Feature> features = jseq.getFeatures();
3908 for (int f = 0; f < features.size(); f++)
3910 Feature feat = features.get(f);
3911 SequenceFeature sf = new SequenceFeature(feat.getType(),
3912 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3913 safeFloat(feat.getScore()), feat.getFeatureGroup());
3914 sf.setStatus(feat.getStatus());
3917 * load any feature attributes - include map-valued attributes
3919 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3920 for (int od = 0; od < feat.getOtherData().size(); od++)
3922 OtherData keyValue = feat.getOtherData().get(od);
3923 String attributeName = keyValue.getKey();
3924 String attributeValue = keyValue.getValue();
3925 if (attributeName.startsWith("LINK"))
3927 sf.addLink(attributeValue);
3931 String subAttribute = keyValue.getKey2();
3932 if (subAttribute == null)
3934 // simple string-valued attribute
3935 sf.setValue(attributeName, attributeValue);
3939 // attribute 'key' has sub-attribute 'key2'
3940 if (!mapAttributes.containsKey(attributeName))
3942 mapAttributes.put(attributeName, new HashMap<>());
3944 mapAttributes.get(attributeName).put(subAttribute,
3949 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3952 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3955 // adds feature to datasequence's feature set (since Jalview 2.10)
3956 al.getSequenceAt(i).addSequenceFeature(sf);
3959 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3961 // adds dbrefs to datasequence's set (since Jalview 2.10)
3963 al.getSequenceAt(i).getDatasetSequence() == null
3964 ? al.getSequenceAt(i)
3965 : al.getSequenceAt(i).getDatasetSequence(),
3968 if (jseq.getPdbids().size() > 0)
3970 List<Pdbids> ids = jseq.getPdbids();
3971 for (int p = 0; p < ids.size(); p++)
3973 Pdbids pdbid = ids.get(p);
3974 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3975 entry.setId(pdbid.getId());
3976 if (pdbid.getType() != null)
3978 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3980 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3984 entry.setType(PDBEntry.Type.FILE);
3987 // jprovider is null when executing 'New View'
3988 if (pdbid.getFile() != null && jprovider != null)
3990 if (!pdbloaded.containsKey(pdbid.getFile()))
3992 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3997 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
4001 if (pdbid.getPdbentryItem() != null)
4003 for (PdbentryItem item : pdbid.getPdbentryItem())
4005 for (Property pr : item.getProperty())
4007 entry.setProperty(pr.getName(), pr.getValue());
4012 for (Property prop : pdbid.getProperty())
4014 entry.setProperty(prop.getName(), prop.getValue());
4016 StructureSelectionManager
4017 .getStructureSelectionManager(Desktop.instance)
4018 .registerPDBEntry(entry);
4019 // adds PDBEntry to datasequence's set (since Jalview 2.10)
4020 if (al.getSequenceAt(i).getDatasetSequence() != null)
4022 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
4026 al.getSequenceAt(i).addPDBId(entry);
4031 } // end !multipleview
4033 // ///////////////////////////////
4034 // LOAD SEQUENCE MAPPINGS
4036 if (vamsasSet.getAlcodonFrame().size() > 0)
4038 // TODO Potentially this should only be done once for all views of an
4040 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
4041 for (int i = 0; i < alc.size(); i++)
4043 AlignedCodonFrame cf = new AlignedCodonFrame();
4044 if (alc.get(i).getAlcodMap().size() > 0)
4046 List<AlcodMap> maps = alc.get(i).getAlcodMap();
4047 for (int m = 0; m < maps.size(); m++)
4049 AlcodMap map = maps.get(m);
4050 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
4052 jalview.datamodel.Mapping mapping = null;
4053 // attach to dna sequence reference.
4054 if (map.getMapping() != null)
4056 mapping = addMapping(map.getMapping());
4057 if (dnaseq != null && mapping.getTo() != null)
4059 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
4065 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
4069 al.addCodonFrame(cf);
4074 // ////////////////////////////////
4076 List<JvAnnotRow> autoAlan = new ArrayList<>();
4079 * store any annotations which forward reference a group's ID
4081 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
4083 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
4085 List<Annotation> an = vamsasSet.getAnnotation();
4087 for (int i = 0; i < an.size(); i++)
4089 Annotation annotation = an.get(i);
4092 * test if annotation is automatically calculated for this view only
4094 boolean autoForView = false;
4095 if (annotation.getLabel().equals("Quality")
4096 || annotation.getLabel().equals("Conservation")
4097 || annotation.getLabel().equals("Consensus"))
4099 // Kludge for pre 2.5 projects which lacked the autocalculated flag
4101 // JAXB has no has() test; schema defaults value to false
4102 // if (!annotation.hasAutoCalculated())
4104 // annotation.setAutoCalculated(true);
4107 if (autoForView || annotation.isAutoCalculated())
4109 // remove ID - we don't recover annotation from other views for
4110 // view-specific annotation
4111 annotation.setId(null);
4114 // set visibility for other annotation in this view
4115 String annotationId = annotation.getId();
4116 if (annotationId != null && annotationIds.containsKey(annotationId))
4118 AlignmentAnnotation jda = annotationIds.get(annotationId);
4119 // in principle Visible should always be true for annotation displayed
4120 // in multiple views
4121 if (annotation.isVisible() != null)
4123 jda.visible = annotation.isVisible();
4126 al.addAnnotation(jda);
4130 // Construct new annotation from model.
4131 List<AnnotationElement> ae = annotation.getAnnotationElement();
4132 jalview.datamodel.Annotation[] anot = null;
4133 java.awt.Color firstColour = null;
4135 if (!annotation.isScoreOnly())
4137 anot = new jalview.datamodel.Annotation[al.getWidth()];
4138 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4140 AnnotationElement annElement = ae.get(aa);
4141 anpos = annElement.getPosition();
4143 if (anpos >= anot.length)
4148 float value = safeFloat(annElement.getValue());
4149 anot[anpos] = new jalview.datamodel.Annotation(
4150 annElement.getDisplayCharacter(),
4151 annElement.getDescription(),
4152 (annElement.getSecondaryStructure() == null
4153 || annElement.getSecondaryStructure()
4157 .getSecondaryStructure()
4160 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4161 if (firstColour == null)
4163 firstColour = anot[anpos].colour;
4167 jalview.datamodel.AlignmentAnnotation jaa = null;
4169 if (annotation.isGraph())
4171 float llim = 0, hlim = 0;
4172 // if (autoForView || an[i].isAutoCalculated()) {
4175 jaa = new jalview.datamodel.AlignmentAnnotation(
4176 annotation.getLabel(), annotation.getDescription(), anot,
4177 llim, hlim, safeInt(annotation.getGraphType()));
4179 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4180 jaa._linecolour = firstColour;
4181 if (annotation.getThresholdLine() != null)
4183 jaa.setThreshold(new jalview.datamodel.GraphLine(
4184 safeFloat(annotation.getThresholdLine().getValue()),
4185 annotation.getThresholdLine().getLabel(),
4186 new java.awt.Color(safeInt(
4187 annotation.getThresholdLine().getColour()))));
4189 if (autoForView || annotation.isAutoCalculated())
4191 // Hardwire the symbol display line to ensure that labels for
4192 // histograms are displayed
4198 jaa = new jalview.datamodel.AlignmentAnnotation(
4199 annotation.getLabel(), annotation.getDescription(), anot);
4200 jaa._linecolour = firstColour;
4202 // register new annotation
4203 if (annotation.getId() != null)
4205 annotationIds.put(annotation.getId(), jaa);
4206 jaa.annotationId = annotation.getId();
4208 // recover sequence association
4209 String sequenceRef = annotation.getSequenceRef();
4210 if (sequenceRef != null)
4212 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4213 SequenceI sequence = seqRefIds.get(sequenceRef);
4214 if (sequence == null)
4216 // in pre-2.9 projects sequence ref is to sequence name
4217 sequence = al.findName(sequenceRef);
4219 if (sequence != null)
4221 jaa.createSequenceMapping(sequence, 1, true);
4222 sequence.addAlignmentAnnotation(jaa);
4225 // and make a note of any group association
4226 if (annotation.getGroupRef() != null
4227 && annotation.getGroupRef().length() > 0)
4229 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4230 .get(annotation.getGroupRef());
4233 aal = new ArrayList<>();
4234 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4239 if (annotation.getScore() != null)
4241 jaa.setScore(annotation.getScore().doubleValue());
4243 if (annotation.isVisible() != null)
4245 jaa.visible = annotation.isVisible().booleanValue();
4248 if (annotation.isCentreColLabels() != null)
4250 jaa.centreColLabels = annotation.isCentreColLabels()
4254 if (annotation.isScaleColLabels() != null)
4256 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4258 if (annotation.isAutoCalculated())
4260 // newer files have an 'autoCalculated' flag and store calculation
4261 // state in viewport properties
4262 jaa.autoCalculated = true; // means annotation will be marked for
4263 // update at end of load.
4265 if (annotation.getGraphHeight() != null)
4267 jaa.graphHeight = annotation.getGraphHeight().intValue();
4269 jaa.belowAlignment = annotation.isBelowAlignment();
4270 jaa.setCalcId(annotation.getCalcId());
4271 if (annotation.getProperty().size() > 0)
4273 for (jalview.xml.binding.jalview.Property prop : annotation
4276 jaa.setProperty(prop.getName(), prop.getValue());
4279 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4281 if (annotation.getContactmatrix() != null
4282 && annotation.getContactmatrix().size() > 0)
4284 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4286 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4291 if (jaa.autoCalculated)
4293 autoAlan.add(new JvAnnotRow(i, jaa));
4296 // if (!autoForView)
4298 // add autocalculated group annotation and any user created annotation
4300 al.addAnnotation(jaa);
4304 // ///////////////////////
4306 // Create alignment markup and styles for this view
4307 if (jalviewModel.getJGroup().size() > 0)
4309 List<JGroup> groups = jalviewModel.getJGroup();
4310 boolean addAnnotSchemeGroup = false;
4311 for (int i = 0; i < groups.size(); i++)
4313 JGroup jGroup = groups.get(i);
4314 ColourSchemeI cs = null;
4315 if (jGroup.getColour() != null)
4317 if (jGroup.getColour().startsWith("ucs"))
4319 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4321 else if (jGroup.getColour().equals("AnnotationColourGradient")
4322 && jGroup.getAnnotationColours() != null)
4324 addAnnotSchemeGroup = true;
4328 cs = ColourSchemeProperty.getColourScheme(null, al,
4329 jGroup.getColour());
4332 int pidThreshold = safeInt(jGroup.getPidThreshold());
4334 Vector<SequenceI> seqs = new Vector<>();
4336 for (int s = 0; s < jGroup.getSeq().size(); s++)
4338 String seqId = jGroup.getSeq().get(s);
4339 SequenceI ts = seqRefIds.get(seqId);
4343 seqs.addElement(ts);
4347 if (seqs.size() < 1)
4352 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4353 safeBoolean(jGroup.isDisplayBoxes()),
4354 safeBoolean(jGroup.isDisplayText()),
4355 safeBoolean(jGroup.isColourText()),
4356 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4357 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4358 sg.getGroupColourScheme()
4359 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4360 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4362 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4363 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4364 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4365 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4366 // attributes with a default in the schema are never null
4367 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4368 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4369 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4370 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4371 if (jGroup.getConsThreshold() != null
4372 && jGroup.getConsThreshold().intValue() != 0)
4374 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4377 c.verdict(false, 25);
4378 sg.cs.setConservation(c);
4381 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4383 // re-instate unique group/annotation row reference
4384 List<AlignmentAnnotation> jaal = groupAnnotRefs
4385 .get(jGroup.getId());
4388 for (AlignmentAnnotation jaa : jaal)
4391 if (jaa.autoCalculated)
4393 // match up and try to set group autocalc alignment row for this
4395 if (jaa.label.startsWith("Consensus for "))
4397 sg.setConsensus(jaa);
4399 // match up and try to set group autocalc alignment row for this
4401 if (jaa.label.startsWith("Conservation for "))
4403 sg.setConservationRow(jaa);
4410 if (addAnnotSchemeGroup)
4412 // reconstruct the annotation colourscheme
4414 constructAnnotationColour(jGroup.getAnnotationColours(),
4415 null, al, jalviewModel, false));
4421 // only dataset in this model, so just return.
4424 // ///////////////////////////////
4427 AlignFrame af = null;
4428 AlignViewport av = null;
4429 // now check to see if we really need to create a new viewport.
4430 if (multipleView && viewportsAdded.size() == 0)
4432 // We recovered an alignment for which a viewport already exists.
4433 // TODO: fix up any settings necessary for overlaying stored state onto
4434 // state recovered from another document. (may not be necessary).
4435 // we may need a binding from a viewport in memory to one recovered from
4437 // and then recover its containing af to allow the settings to be applied.
4438 // TODO: fix for vamsas demo
4439 jalview.bin.Console.errPrintln(
4440 "About to recover a viewport for existing alignment: Sequence set ID is "
4442 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4443 if (seqsetobj != null)
4445 if (seqsetobj instanceof String)
4447 uniqueSeqSetId = (String) seqsetobj;
4448 jalview.bin.Console.errPrintln(
4449 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4454 jalview.bin.Console.errPrintln(
4455 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4461 * indicate that annotation colours are applied across all groups (pre
4462 * Jalview 2.8.1 behaviour)
4464 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4465 jalviewModel.getVersion());
4467 AlignmentPanel ap = null;
4468 boolean isnewview = true;
4471 // Check to see if this alignment already has a view id == viewId
4472 jalview.gui.AlignmentPanel views[] = Desktop
4473 .getAlignmentPanels(uniqueSeqSetId);
4474 if (views != null && views.length > 0)
4476 for (int v = 0; v < views.length; v++)
4478 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4480 // recover the existing alignpanel, alignframe, viewport
4481 af = views[v].alignFrame;
4484 // TODO: could even skip resetting view settings if we don't want to
4485 // change the local settings from other jalview processes
4494 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4495 uniqueSeqSetId, viewId, autoAlan);
4496 av = af.getViewport();
4501 * Load any trees, PDB structures and viewers, Overview
4503 * Not done if flag is false (when this method is used for New View)
4505 if (loadTreesAndStructures)
4507 loadTrees(jalviewModel, view, af, av, ap);
4508 loadPCAViewers(jalviewModel, ap);
4509 loadPaSiMapViewers(jalviewModel, ap);
4510 loadPDBStructures(jprovider, jseqs, af, ap);
4511 loadRnaViewers(jprovider, jseqs, ap);
4512 loadOverview(view, jalviewModel.getVersion(), af);
4514 // and finally return.
4518 private void importMatrixData(List<MatrixType> xmlmatrices)
4520 for (MatrixType xmlmat : xmlmatrices)
4522 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4524 Console.error("Ignoring matrix '" + xmlmat.getId() + "' of type '"
4525 + xmlmat.getType());
4529 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4531 Console.error("Can't handle non square matrices");
4535 float[][] elements = ContactMatrix.fromFloatStringToContacts(
4536 xmlmat.getElements(), xmlmat.getCols().intValue(),
4537 xmlmat.getRows().intValue());
4539 List<BitSet> newgroups = new ArrayList<BitSet>();
4540 if (xmlmat.getGroups().size() > 0)
4542 for (String sgroup : xmlmat.getGroups())
4544 newgroups.add(deStringifyBitset(sgroup));
4547 String nwk = xmlmat.getNewick().size() > 0 ? xmlmat.getNewick().get(0)
4549 if (xmlmat.getNewick().size() > 1)
4552 .info("Ignoring additional clusterings for contact matrix");
4554 String treeMethod = xmlmat.getTreeMethod();
4555 double thresh = xmlmat.getCutHeight() != null ? xmlmat.getCutHeight()
4557 GroupSet grpset = new GroupSet();
4558 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4560 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4561 contactMatrixRefs.put(xmlmat.getId(), newcm);
4562 Console.trace("Restored base contact matrix " + xmlmat.getId());
4566 private void restoreMatrixFor(SequenceI sequenceRef,
4567 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4569 // restore mapping data to matrix data
4570 jalview.util.MapList mapping = null;
4571 if (xmlmatmapping.getMapping() != null)
4573 MapListType m = xmlmatmapping.getMapping();
4574 // Mapping m = dr.getMapping();
4575 int fr[] = new int[m.getMapListFrom().size() * 2];
4576 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4577 for (int _i = 0; from.hasNext(); _i += 2)
4579 MapListFrom mf = from.next();
4580 fr[_i] = mf.getStart();
4581 fr[_i + 1] = mf.getEnd();
4583 int fto[] = new int[m.getMapListTo().size() * 2];
4584 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4585 for (int _i = 0; to.hasNext(); _i += 2)
4587 MapListTo mf = to.next();
4588 fto[_i] = mf.getStart();
4589 fto[_i + 1] = mf.getEnd();
4592 mapping = new jalview.util.MapList(fr, fto,
4593 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4596 // locate matrix data in project XML and import
4597 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4601 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4605 // create the PAEMatrix now
4606 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4609 jaa.sequenceRef.addContactListFor(jaa, newpae);
4616 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4617 * and geometry as saved
4622 protected void loadOverview(Viewport view, String version, AlignFrame af)
4624 if (!isVersionStringLaterThan("2.11.3", version)
4625 && view.getOverview() == null)
4630 * first close any Overview that was opened automatically
4631 * (if so configured in Preferences) so that the view is
4632 * restored in the same state as saved
4634 af.alignPanel.closeOverviewPanel();
4636 Overview overview = view.getOverview();
4637 if (overview != null)
4639 OverviewPanel overviewPanel = af
4640 .openOverviewPanel(overview.isShowHidden());
4641 overviewPanel.setTitle(overview.getTitle());
4642 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4643 overview.getWidth(), overview.getHeight());
4644 Color gap = new Color(overview.getGapColour());
4645 Color residue = new Color(overview.getResidueColour());
4646 Color hidden = new Color(overview.getHiddenColour());
4647 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4652 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4653 * panel is restored from separate jar entries, two (gapped and trimmed) per
4654 * sequence and secondary structure.
4656 * Currently each viewer shows just one sequence and structure (gapped and
4657 * trimmed), however this method is designed to support multiple sequences or
4658 * structures in viewers if wanted in future.
4664 private void loadRnaViewers(jarInputStreamProvider jprovider,
4665 List<JSeq> jseqs, AlignmentPanel ap)
4668 * scan the sequences for references to viewers; create each one the first
4669 * time it is referenced, add Rna models to existing viewers
4671 for (JSeq jseq : jseqs)
4673 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4675 RnaViewer viewer = jseq.getRnaViewer().get(i);
4676 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4679 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4681 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4682 SequenceI seq = seqRefIds.get(jseq.getId());
4683 AlignmentAnnotation ann = this.annotationIds
4684 .get(ss.getAnnotationId());
4687 * add the structure to the Varna display (with session state copied
4688 * from the jar to a temporary file)
4690 boolean gapped = safeBoolean(ss.isGapped());
4691 String rnaTitle = ss.getTitle();
4692 String sessionState = ss.getViewerState();
4693 String tempStateFile = copyJarEntry(jprovider, sessionState,
4695 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4696 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4698 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4704 * Locate and return an already instantiated matching AppVarna, or create one
4708 * @param viewIdSuffix
4712 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4713 String viewIdSuffix, AlignmentPanel ap)
4716 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4717 * if load is repeated
4719 String postLoadId = viewer.getViewId() + viewIdSuffix;
4720 for (JInternalFrame frame : getAllFrames())
4722 if (frame instanceof AppVarna)
4724 AppVarna varna = (AppVarna) frame;
4725 if (postLoadId.equals(varna.getViewId()))
4727 // this viewer is already instantiated
4728 // could in future here add ap as another 'parent' of the
4729 // AppVarna window; currently just 1-to-many
4736 * viewer not found - make it
4738 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4739 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4740 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4741 safeInt(viewer.getDividerLocation()));
4742 AppVarna varna = new AppVarna(model, ap);
4748 * Load any saved trees
4756 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4757 AlignViewport av, AlignmentPanel ap)
4759 // TODO result of automated refactoring - are all these parameters needed?
4762 for (int t = 0; t < jm.getTree().size(); t++)
4765 Tree tree = jm.getTree().get(t);
4767 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4770 if (tree.isColumnWise())
4772 AlignmentAnnotation aa = annotationIds
4773 .get(tree.getColumnReference());
4777 "Null alignment annotation when restoring columnwise tree");
4779 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4780 tree.getTitle(), safeInt(tree.getWidth()),
4781 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4782 safeInt(tree.getYpos()));
4787 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4788 tree.getTitle(), safeInt(tree.getWidth()),
4789 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4790 safeInt(tree.getYpos()));
4792 if (tree.getId() != null)
4794 // perhaps bind the tree id to something ?
4799 // update local tree attributes ?
4800 // TODO: should check if tp has been manipulated by user - if so its
4801 // settings shouldn't be modified
4802 tp.setTitle(tree.getTitle());
4803 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4804 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4805 safeInt(tree.getHeight())));
4806 tp.setViewport(av); // af.viewport;
4807 // TODO: verify 'associate with all views' works still
4808 tp.getTreeCanvas().setViewport(av); // af.viewport;
4809 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4811 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4815 "There was a problem recovering stored Newick tree: \n"
4816 + tree.getNewick());
4820 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4821 tp.fitToWindow_actionPerformed(null);
4823 if (tree.getFontName() != null)
4826 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4827 safeInt(tree.getFontSize())));
4832 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4833 safeInt(view.getFontSize())));
4836 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4837 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4838 tp.showDistances(safeBoolean(tree.isShowDistances()));
4840 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4842 if (safeBoolean(tree.isCurrentTree()))
4844 af.getViewport().setCurrentTree(tp.getTree());
4848 } catch (Exception ex)
4850 ex.printStackTrace();
4855 * Load and link any saved structure viewers.
4862 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4863 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4866 * Run through all PDB ids on the alignment, and collect mappings between
4867 * distinct view ids and all sequences referring to that view.
4869 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4871 for (int i = 0; i < jseqs.size(); i++)
4873 JSeq jseq = jseqs.get(i);
4874 if (jseq.getPdbids().size() > 0)
4876 List<Pdbids> ids = jseq.getPdbids();
4877 for (int p = 0; p < ids.size(); p++)
4879 Pdbids pdbid = ids.get(p);
4880 final int structureStateCount = pdbid.getStructureState().size();
4881 for (int s = 0; s < structureStateCount; s++)
4883 // check to see if we haven't already created this structure view
4884 final StructureState structureState = pdbid.getStructureState()
4886 String sviewid = (structureState.getViewId() == null) ? null
4887 : structureState.getViewId() + uniqueSetSuffix;
4888 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4889 // Originally : pdbid.getFile()
4890 // : TODO: verify external PDB file recovery still works in normal
4891 // jalview project load
4893 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4894 jpdb.setId(pdbid.getId());
4896 int x = safeInt(structureState.getXpos());
4897 int y = safeInt(structureState.getYpos());
4898 int width = safeInt(structureState.getWidth());
4899 int height = safeInt(structureState.getHeight());
4901 // Probably don't need to do this anymore...
4902 // Desktop.desktop.getComponentAt(x, y);
4903 // TODO: NOW: check that this recovers the PDB file correctly.
4904 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4906 jalview.datamodel.SequenceI seq = seqRefIds
4907 .get(jseq.getId() + "");
4908 if (sviewid == null)
4910 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4913 if (!structureViewers.containsKey(sviewid))
4915 String viewerType = structureState.getType();
4916 if (viewerType == null) // pre Jalview 2.9
4918 viewerType = ViewerType.JMOL.toString();
4920 structureViewers.put(sviewid,
4921 new StructureViewerModel(x, y, width, height, false,
4922 false, true, structureState.getViewId(),
4924 // Legacy pre-2.7 conversion JAL-823 :
4925 // do not assume any view has to be linked for colour by
4929 // assemble String[] { pdb files }, String[] { id for each
4930 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4931 // seqs_file 2}, boolean[] {
4932 // linkAlignPanel,superposeWithAlignpanel}} from hash
4933 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4934 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4935 || structureState.isAlignwithAlignPanel());
4938 * Default colour by linked panel to false if not specified (e.g.
4939 * for pre-2.7 projects)
4941 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4942 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4943 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4946 * Default colour by viewer to true if not specified (e.g. for
4949 boolean colourByViewer = jmoldat.isColourByViewer();
4950 colourByViewer &= structureState.isColourByJmol();
4951 jmoldat.setColourByViewer(colourByViewer);
4953 if (jmoldat.getStateData().length() < structureState.getValue()
4954 /*Content()*/.length())
4956 jmoldat.setStateData(structureState.getValue());// Content());
4958 if (pdbid.getFile() != null)
4960 File mapkey = new File(pdbid.getFile());
4961 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4962 if (seqstrmaps == null)
4964 jmoldat.getFileData().put(mapkey,
4965 seqstrmaps = jmoldat.new StructureData(pdbFile,
4968 if (!seqstrmaps.getSeqList().contains(seq))
4970 seqstrmaps.getSeqList().add(seq);
4976 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");
4977 Console.warn(errorMessage);
4983 // Instantiate the associated structure views
4984 for (Entry<String, StructureViewerModel> entry : structureViewers
4989 createOrLinkStructureViewer(entry, af, ap, jprovider);
4990 } catch (Exception e)
4992 jalview.bin.Console.errPrintln(
4993 "Error loading structure viewer: " + e.getMessage());
4994 // failed - try the next one
5006 protected void createOrLinkStructureViewer(
5007 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
5008 AlignmentPanel ap, jarInputStreamProvider jprovider)
5010 final StructureViewerModel stateData = viewerData.getValue();
5013 * Search for any viewer windows already open from other alignment views
5014 * that exactly match the stored structure state
5016 StructureViewerBase comp = findMatchingViewer(viewerData);
5020 linkStructureViewer(ap, comp, stateData);
5024 String type = stateData.getType();
5027 ViewerType viewerType = ViewerType.valueOf(type);
5028 createStructureViewer(viewerType, viewerData, af, jprovider);
5029 } catch (IllegalArgumentException | NullPointerException e)
5031 // TODO JAL-3619 show error dialog / offer an alternative viewer
5032 Console.error("Invalid structure viewer type: " + type);
5037 * Generates a name for the entry in the project jar file to hold state
5038 * information for a structure viewer
5043 protected String getViewerJarEntryName(String viewId)
5045 return VIEWER_PREFIX + viewId;
5049 * Returns any open frame that matches given structure viewer data. The match
5050 * is based on the unique viewId, or (for older project versions) the frame's
5056 protected StructureViewerBase findMatchingViewer(
5057 Entry<String, StructureViewerModel> viewerData)
5059 final String sviewid = viewerData.getKey();
5060 final StructureViewerModel svattrib = viewerData.getValue();
5061 StructureViewerBase comp = null;
5062 JInternalFrame[] frames = getAllFrames();
5063 for (JInternalFrame frame : frames)
5065 if (frame instanceof StructureViewerBase)
5068 * Post jalview 2.4 schema includes structure view id
5070 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
5073 comp = (StructureViewerBase) frame;
5074 break; // break added in 2.9
5077 * Otherwise test for matching position and size of viewer frame
5079 else if (frame.getX() == svattrib.getX()
5080 && frame.getY() == svattrib.getY()
5081 && frame.getHeight() == svattrib.getHeight()
5082 && frame.getWidth() == svattrib.getWidth())
5084 comp = (StructureViewerBase) frame;
5085 // no break in faint hope of an exact match on viewId
5093 * Link an AlignmentPanel to an existing structure viewer.
5098 * @param useinViewerSuperpos
5099 * @param usetoColourbyseq
5100 * @param viewerColouring
5102 protected void linkStructureViewer(AlignmentPanel ap,
5103 StructureViewerBase viewer, StructureViewerModel stateData)
5105 // NOTE: if the jalview project is part of a shared session then
5106 // view synchronization should/could be done here.
5108 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
5109 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
5110 final boolean viewerColouring = stateData.isColourByViewer();
5111 Map<File, StructureData> oldFiles = stateData.getFileData();
5114 * Add mapping for sequences in this view to an already open viewer
5116 final AAStructureBindingModel binding = viewer.getBinding();
5117 for (File id : oldFiles.keySet())
5119 // add this and any other pdb files that should be present in the
5121 StructureData filedat = oldFiles.get(id);
5122 String pdbFile = filedat.getFilePath();
5123 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5124 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5126 binding.addSequenceForStructFile(pdbFile, seq);
5128 // and add the AlignmentPanel's reference to the view panel
5129 viewer.addAlignmentPanel(ap);
5130 if (useinViewerSuperpos)
5132 viewer.useAlignmentPanelForSuperposition(ap);
5136 viewer.excludeAlignmentPanelForSuperposition(ap);
5138 if (usetoColourbyseq)
5140 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5144 viewer.excludeAlignmentPanelForColourbyseq(ap);
5149 * Get all frames within the Desktop.
5153 protected JInternalFrame[] getAllFrames()
5155 JInternalFrame[] frames = null;
5156 // TODO is this necessary - is it safe - risk of hanging?
5161 frames = Desktop.desktop.getAllFrames();
5162 } catch (ArrayIndexOutOfBoundsException e)
5164 // occasional No such child exceptions are thrown here...
5168 } catch (InterruptedException f)
5172 } while (frames == null);
5177 * Answers true if 'version' is equal to or later than 'supported', where each
5178 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5179 * changes. Development and test values for 'version' are leniently treated
5183 * - minimum version we are comparing against
5185 * - version of data being processsed
5186 * @return true if version is equal to or later than supported
5188 public static boolean isVersionStringLaterThan(String supported,
5191 if (supported == null || version == null
5192 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5193 || version.equalsIgnoreCase("Test")
5194 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5196 jalview.bin.Console.errPrintln("Assuming project file with "
5197 + (version == null ? "null" : version)
5198 + " is compatible with Jalview version " + supported);
5203 return StringUtils.compareVersions(version, supported, "b") >= 0;
5207 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5209 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5211 if (newStructureViewers != null)
5213 sview.getBinding().setFinishedLoadingFromArchive(false);
5214 newStructureViewers.add(sview);
5218 protected void setLoadingFinishedForNewStructureViewers()
5220 if (newStructureViewers != null)
5222 for (JalviewStructureDisplayI sview : newStructureViewers)
5224 sview.getBinding().setFinishedLoadingFromArchive(true);
5226 newStructureViewers.clear();
5227 newStructureViewers = null;
5231 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5232 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5233 Viewport view, String uniqueSeqSetId, String viewId,
5234 List<JvAnnotRow> autoAlan)
5236 AlignFrame af = null;
5237 af = new AlignFrame(al, safeInt(view.getWidth()),
5238 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5242 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5243 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5244 // super.processKeyEvent(e);
5251 af.setFileName(file, FileFormat.Jalview);
5253 final AlignViewport viewport = af.getViewport();
5254 for (int i = 0; i < JSEQ.size(); i++)
5256 int colour = safeInt(JSEQ.get(i).getColour());
5257 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5263 viewport.setColourByReferenceSeq(true);
5264 viewport.setDisplayReferenceSeq(true);
5267 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5269 if (view.getSequenceSetId() != null)
5271 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5273 viewport.setSequenceSetId(uniqueSeqSetId);
5276 // propagate shared settings to this new view
5277 viewport.setHistoryList(av.getHistoryList());
5278 viewport.setRedoList(av.getRedoList());
5282 viewportsAdded.put(uniqueSeqSetId, viewport);
5284 // TODO: check if this method can be called repeatedly without
5285 // side-effects if alignpanel already registered.
5286 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5288 // apply Hidden regions to view.
5289 if (hiddenSeqs != null)
5291 for (int s = 0; s < JSEQ.size(); s++)
5293 SequenceGroup hidden = new SequenceGroup();
5294 boolean isRepresentative = false;
5295 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5297 isRepresentative = true;
5298 SequenceI sequenceToHide = al
5299 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5300 hidden.addSequence(sequenceToHide, false);
5301 // remove from hiddenSeqs list so we don't try to hide it twice
5302 hiddenSeqs.remove(sequenceToHide);
5304 if (isRepresentative)
5306 SequenceI representativeSequence = al.getSequenceAt(s);
5307 hidden.addSequence(representativeSequence, false);
5308 viewport.hideRepSequences(representativeSequence, hidden);
5312 SequenceI[] hseqs = hiddenSeqs
5313 .toArray(new SequenceI[hiddenSeqs.size()]);
5314 viewport.hideSequence(hseqs);
5317 // recover view properties and display parameters
5319 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5320 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5321 final int pidThreshold = safeInt(view.getPidThreshold());
5322 viewport.setThreshold(pidThreshold);
5324 viewport.setColourText(safeBoolean(view.isShowColourText()));
5326 viewport.setConservationSelected(
5327 safeBoolean(view.isConservationSelected()));
5328 viewport.setIncrement(safeInt(view.getConsThreshold()));
5329 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5330 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5332 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5333 safeInt(view.getFontSize())),
5334 (view.getCharWidth() != null) ? false : true);
5335 if (view.getCharWidth() != null)
5337 viewport.setCharWidth(view.getCharWidth());
5338 viewport.setCharHeight(view.getCharHeight());
5340 ViewStyleI vs = viewport.getViewStyle();
5341 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5342 viewport.setViewStyle(vs);
5343 // TODO: allow custom charWidth/Heights to be restored by updating them
5344 // after setting font - which means set above to false
5345 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5346 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5347 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5349 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5351 viewport.setShowText(safeBoolean(view.isShowText()));
5353 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5354 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5355 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5356 viewport.setShowUnconserved(view.isShowUnconserved());
5357 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5359 if (view.getViewName() != null)
5361 viewport.setViewName(view.getViewName());
5362 af.setInitialTabVisible();
5364 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5365 safeInt(view.getWidth()), safeInt(view.getHeight()));
5367 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID
5369 if (view.getIdWidth() == null)
5371 if (!isVersionStringLaterThan("2.11.3", jm.getVersion()))
5373 // Pre 2.11.3 jalview projects do not store the id width
5374 // idWidth was also calculated in a different way.
5375 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5376 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5381 viewport.setIdWidth(view.getIdWidth());
5382 af.alignPanel.getIdPanel().getIdCanvas()
5383 .setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5386 // startSeq set in af.alignPanel.updateLayout below
5387 af.alignPanel.updateLayout();
5388 ColourSchemeI cs = null;
5389 // apply colourschemes
5390 if (view.getBgColour() != null)
5392 if (view.getBgColour().startsWith("ucs"))
5394 cs = getUserColourScheme(jm, view.getBgColour());
5396 else if (view.getBgColour().startsWith("Annotation"))
5398 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5399 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5406 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5407 view.getBgColour());
5412 * turn off 'alignment colour applies to all groups'
5413 * while restoring global colour scheme
5415 viewport.setColourAppliesToAllGroups(false);
5416 viewport.setGlobalColourScheme(cs);
5417 viewport.getResidueShading().setThreshold(pidThreshold,
5418 view.isIgnoreGapsinConsensus());
5419 viewport.getResidueShading()
5420 .setConsensus(viewport.getSequenceConsensusHash());
5421 viewport.getResidueShading()
5422 .setSsConsensus(viewport.getSequenceSSConsensusHash());
5423 if (safeBoolean(view.isConservationSelected()) && cs != null)
5425 viewport.getResidueShading()
5426 .setConservationInc(safeInt(view.getConsThreshold()));
5428 af.changeColour(cs);
5429 viewport.setColourAppliesToAllGroups(true);
5431 viewport.setShowSequenceFeatures(
5432 safeBoolean(view.isShowSequenceFeatures()));
5434 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5435 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5436 viewport.setFollowHighlight(view.isFollowHighlight());
5437 viewport.followSelection = view.isFollowSelection();
5438 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5439 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5440 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5441 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5442 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5443 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5444 viewport.setShowGroupConservation(view.isShowGroupConservation());
5445 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5446 viewport.setShowComplementFeaturesOnTop(
5447 view.isShowComplementFeaturesOnTop());
5449 // recover feature settings
5450 if (jm.getFeatureSettings() != null)
5452 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5453 .getFeatureRenderer();
5454 FeaturesDisplayed fdi;
5455 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5456 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5458 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5459 Map<String, Float> featureOrder = new Hashtable<>();
5461 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5464 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5465 String featureType = setting.getType();
5468 * restore feature filters (if any)
5470 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5472 if (filters != null)
5474 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5476 if (!filter.isEmpty())
5478 fr.setFeatureFilter(featureType, filter);
5483 * restore feature colour scheme
5485 Color maxColour = new Color(setting.getColour());
5486 if (setting.getMincolour() != null)
5489 * minColour is always set unless a simple colour
5490 * (including for colour by label though it doesn't use it)
5492 Color minColour = new Color(setting.getMincolour().intValue());
5493 Color noValueColour = minColour;
5494 NoValueColour noColour = setting.getNoValueColour();
5495 if (noColour == NoValueColour.NONE)
5497 noValueColour = null;
5499 else if (noColour == NoValueColour.MAX)
5501 noValueColour = maxColour;
5503 float min = safeFloat(safeFloat(setting.getMin()));
5504 float max = setting.getMax() == null ? 1f
5505 : setting.getMax().floatValue();
5506 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5507 maxColour, noValueColour, min, max);
5508 if (setting.getAttributeName().size() > 0)
5510 gc.setAttributeName(setting.getAttributeName().toArray(
5511 new String[setting.getAttributeName().size()]));
5513 if (setting.getThreshold() != null)
5515 gc.setThreshold(setting.getThreshold().floatValue());
5516 int threshstate = safeInt(setting.getThreshstate());
5517 // -1 = None, 0 = Below, 1 = Above threshold
5518 if (threshstate == 0)
5520 gc.setBelowThreshold(true);
5522 else if (threshstate == 1)
5524 gc.setAboveThreshold(true);
5527 gc.setAutoScaled(true); // default
5528 if (setting.isAutoScale() != null)
5530 gc.setAutoScaled(setting.isAutoScale());
5532 if (setting.isColourByLabel() != null)
5534 gc.setColourByLabel(setting.isColourByLabel());
5536 // and put in the feature colour table.
5537 featureColours.put(featureType, gc);
5541 featureColours.put(featureType, new FeatureColour(maxColour));
5543 renderOrder[fs] = featureType;
5544 if (setting.getOrder() != null)
5546 featureOrder.put(featureType, setting.getOrder().floatValue());
5550 featureOrder.put(featureType, Float.valueOf(
5551 fs / jm.getFeatureSettings().getSetting().size()));
5553 if (safeBoolean(setting.isDisplay()))
5555 fdi.setVisible(featureType);
5558 Map<String, Boolean> fgtable = new Hashtable<>();
5559 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5561 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5562 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5564 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5565 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5566 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5567 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5568 fgtable, featureColours, 1.0f, featureOrder);
5569 fr.transferSettings(frs);
5572 if (view.getHiddenColumns().size() > 0)
5574 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5576 final HiddenColumns hc = view.getHiddenColumns().get(c);
5577 viewport.hideColumns(safeInt(hc.getStart()),
5578 safeInt(hc.getEnd()) /* +1 */);
5581 if (view.getCalcIdParam() != null)
5583 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5585 if (calcIdParam != null)
5587 if (recoverCalcIdParam(calcIdParam, viewport))
5592 Console.warn("Couldn't recover parameters for "
5593 + calcIdParam.getCalcId());
5598 af.setMenusFromViewport(viewport);
5599 af.setTitle(view.getTitle());
5600 // TODO: we don't need to do this if the viewport is aready visible.
5602 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5603 * has a 'cdna/protein complement' view, in which case save it in order to
5604 * populate a SplitFrame once all views have been read in.
5606 String complementaryViewId = view.getComplementId();
5607 if (complementaryViewId == null)
5609 Desktop.addInternalFrame(af, view.getTitle(),
5610 safeInt(view.getWidth()), safeInt(view.getHeight()));
5611 // recompute any autoannotation
5612 af.alignPanel.updateAnnotation(false, true);
5613 reorderAutoannotation(af, al, autoAlan);
5614 af.alignPanel.alignmentChanged();
5618 splitFrameCandidates.put(view, af);
5625 * Reads saved data to restore Colour by Annotation settings
5627 * @param viewAnnColour
5631 * @param checkGroupAnnColour
5634 private ColourSchemeI constructAnnotationColour(
5635 AnnotationColourScheme viewAnnColour, AlignFrame af,
5636 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5638 boolean propagateAnnColour = false;
5639 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5641 if (checkGroupAnnColour && al.getGroups() != null
5642 && al.getGroups().size() > 0)
5644 // pre 2.8.1 behaviour
5645 // check to see if we should transfer annotation colours
5646 propagateAnnColour = true;
5647 for (SequenceGroup sg : al.getGroups())
5649 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5651 propagateAnnColour = false;
5657 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5659 String annotationId = viewAnnColour.getAnnotation();
5660 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5663 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5665 if (matchedAnnotation == null
5666 && annAlignment.getAlignmentAnnotation() != null)
5668 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5671 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5673 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5678 if (matchedAnnotation == null)
5681 .errPrintln("Failed to match annotation colour scheme for "
5685 // belt-and-braces create a threshold line if the
5686 // colourscheme needs one but the matchedAnnotation doesn't have one
5687 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5688 && matchedAnnotation.getThreshold() == null)
5690 matchedAnnotation.setThreshold(
5691 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5692 "Threshold", Color.black));
5695 AnnotationColourGradient cs = null;
5696 if (viewAnnColour.getColourScheme().equals("None"))
5698 cs = new AnnotationColourGradient(matchedAnnotation,
5699 new Color(safeInt(viewAnnColour.getMinColour())),
5700 new Color(safeInt(viewAnnColour.getMaxColour())),
5701 safeInt(viewAnnColour.getAboveThreshold()));
5703 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5705 cs = new AnnotationColourGradient(matchedAnnotation,
5706 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5707 safeInt(viewAnnColour.getAboveThreshold()));
5711 cs = new AnnotationColourGradient(matchedAnnotation,
5712 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5713 viewAnnColour.getColourScheme()),
5714 safeInt(viewAnnColour.getAboveThreshold()));
5717 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5718 boolean useOriginalColours = safeBoolean(
5719 viewAnnColour.isPredefinedColours());
5720 cs.setSeqAssociated(perSequenceOnly);
5721 cs.setPredefinedColours(useOriginalColours);
5723 if (propagateAnnColour && al.getGroups() != null)
5725 // Also use these settings for all the groups
5726 for (int g = 0; g < al.getGroups().size(); g++)
5728 SequenceGroup sg = al.getGroups().get(g);
5729 if (sg.getGroupColourScheme() == null)
5734 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5735 matchedAnnotation, sg.getColourScheme(),
5736 safeInt(viewAnnColour.getAboveThreshold()));
5737 sg.setColourScheme(groupScheme);
5738 groupScheme.setSeqAssociated(perSequenceOnly);
5739 groupScheme.setPredefinedColours(useOriginalColours);
5745 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5746 List<JvAnnotRow> autoAlan)
5748 // copy over visualization settings for autocalculated annotation in the
5750 if (al.getAlignmentAnnotation() != null)
5753 * Kludge for magic autoannotation names (see JAL-811)
5755 String[] magicNames = new String[] { "Consensus", "Quality",
5757 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5758 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5759 for (String nm : magicNames)
5761 visan.put(nm, nullAnnot);
5763 for (JvAnnotRow auan : autoAlan)
5765 visan.put(auan.template.label
5766 + (auan.template.getCalcId() == null ? ""
5767 : "\t" + auan.template.getCalcId()),
5770 int hSize = al.getAlignmentAnnotation().length;
5771 List<JvAnnotRow> reorder = new ArrayList<>();
5772 // work through any autoCalculated annotation already on the view
5773 // removing it if it should be placed in a different location on the
5774 // annotation panel.
5775 List<String> remains = new ArrayList<>(visan.keySet());
5776 for (int h = 0; h < hSize; h++)
5778 jalview.datamodel.AlignmentAnnotation jalan = al
5779 .getAlignmentAnnotation()[h];
5780 if (jalan.autoCalculated)
5783 JvAnnotRow valan = visan.get(k = jalan.label);
5784 if (jalan.getCalcId() != null)
5786 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5791 // delete the auto calculated row from the alignment
5792 al.deleteAnnotation(jalan, false);
5796 if (valan != nullAnnot)
5798 if (jalan != valan.template)
5800 // newly created autoannotation row instance
5801 // so keep a reference to the visible annotation row
5802 // and copy over all relevant attributes
5803 if (valan.template.graphHeight >= 0)
5806 jalan.graphHeight = valan.template.graphHeight;
5808 jalan.visible = valan.template.visible;
5810 reorder.add(new JvAnnotRow(valan.order, jalan));
5815 // Add any (possibly stale) autocalculated rows that were not appended to
5816 // the view during construction
5817 for (String other : remains)
5819 JvAnnotRow othera = visan.get(other);
5820 if (othera != nullAnnot && othera.template.getCalcId() != null
5821 && othera.template.getCalcId().length() > 0)
5823 reorder.add(othera);
5826 // now put the automatic annotation in its correct place
5827 int s = 0, srt[] = new int[reorder.size()];
5828 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5829 for (JvAnnotRow jvar : reorder)
5832 srt[s++] = jvar.order;
5835 jalview.util.QuickSort.sort(srt, rws);
5836 // and re-insert the annotation at its correct position
5837 for (JvAnnotRow jvar : rws)
5839 al.addAnnotation(jvar.template, jvar.order);
5841 af.alignPanel.adjustAnnotationHeight();
5845 Hashtable skipList = null;
5848 * TODO remove this method
5851 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5852 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5853 * throw new Error("Implementation Error. No skipList defined for this
5854 * Jalview2XML instance."); } return (AlignFrame)
5855 * skipList.get(view.getSequenceSetId()); }
5859 * Check if the Jalview view contained in object should be skipped or not.
5862 * @return true if view's sequenceSetId is a key in skipList
5864 private boolean skipViewport(JalviewModel object)
5866 if (skipList == null)
5870 String id = object.getViewport().get(0).getSequenceSetId();
5871 if (skipList.containsKey(id))
5873 Console.debug("Skipping seuqence set id " + id);
5879 public void addToSkipList(AlignFrame af)
5881 if (skipList == null)
5883 skipList = new Hashtable();
5885 skipList.put(af.getViewport().getSequenceSetId(), af);
5888 public void clearSkipList()
5890 if (skipList != null)
5897 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5898 boolean ignoreUnrefed, String uniqueSeqSetId)
5900 jalview.datamodel.AlignmentI ds = getDatasetFor(
5901 vamsasSet.getDatasetId());
5902 AlignmentI xtant_ds = ds;
5903 if (xtant_ds == null)
5905 // good chance we are about to create a new dataset, but check if we've
5906 // seen some of the dataset sequence IDs before.
5907 // TODO: skip this check if we are working with project generated by
5908 // version 2.11 or later
5909 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5910 if (xtant_ds != null)
5913 addDatasetRef(vamsasSet.getDatasetId(), ds);
5916 Vector<SequenceI> dseqs = null;
5919 // recovering an alignment View
5920 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5921 if (seqSetDS != null)
5923 if (ds != null && ds != seqSetDS)
5926 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5927 + " - CDS/Protein crossreference data may be lost");
5928 if (xtant_ds != null)
5930 // This can only happen if the unique sequence set ID was bound to a
5931 // dataset that did not contain any of the sequences in the view
5932 // currently being restored.
5934 "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.");
5938 addDatasetRef(vamsasSet.getDatasetId(), ds);
5943 // try even harder to restore dataset
5944 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5945 // create a list of new dataset sequences
5946 dseqs = new Vector<>();
5948 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5950 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5951 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5953 // create a new dataset
5956 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5957 dseqs.copyInto(dsseqs);
5958 ds = new jalview.datamodel.Alignment(dsseqs);
5959 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5960 + " for alignment " + System.identityHashCode(al));
5961 addDatasetRef(vamsasSet.getDatasetId(), ds);
5963 // set the dataset for the newly imported alignment.
5964 if (al.getDataset() == null && !ignoreUnrefed)
5967 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5968 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5970 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5974 * XML dataset sequence ID to materialised dataset reference
5976 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5979 * @return the first materialised dataset reference containing a dataset
5980 * sequence referenced in the given view
5982 * - sequences from the view
5984 AlignmentI checkIfHasDataset(List<Sequence> list)
5986 for (Sequence restoredSeq : list)
5988 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5989 if (datasetFor != null)
5998 * Register ds as the containing dataset for the dataset sequences referenced
5999 * by sequences in list
6002 * - sequences in a view
6005 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
6007 for (Sequence restoredSeq : list)
6009 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
6010 if (prevDS != null && prevDS != ds)
6012 Console.warn("Dataset sequence appears in many datasets: "
6013 + restoredSeq.getDsseqid());
6014 // TODO: try to merge!
6022 * sequence definition to create/merge dataset sequence for
6026 * vector to add new dataset sequence to
6027 * @param ignoreUnrefed
6028 * - when true, don't create new sequences from vamsasSeq if it's id
6029 * doesn't already have an asssociated Jalview sequence.
6031 * - used to reorder the sequence in the alignment according to the
6032 * vamsasSeq array ordering, to preserve ordering of dataset
6034 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
6035 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
6038 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
6040 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
6041 boolean reorder = false;
6042 SequenceI dsq = null;
6043 if (sq != null && sq.getDatasetSequence() != null)
6045 dsq = sq.getDatasetSequence();
6051 if (sq == null && ignoreUnrefed)
6055 String sqid = vamsasSeq.getDsseqid();
6058 // need to create or add a new dataset sequence reference to this sequence
6061 dsq = seqRefIds.get(sqid);
6066 // make a new dataset sequence
6067 dsq = sq.createDatasetSequence();
6070 // make up a new dataset reference for this sequence
6071 sqid = seqHash(dsq);
6073 dsq.setVamsasId(uniqueSetSuffix + sqid);
6074 seqRefIds.put(sqid, dsq);
6079 dseqs.addElement(dsq);
6084 ds.addSequence(dsq);
6090 { // make this dataset sequence sq's dataset sequence
6091 sq.setDatasetSequence(dsq);
6092 // and update the current dataset alignment
6097 if (!dseqs.contains(dsq))
6104 if (ds.findIndex(dsq) < 0)
6106 ds.addSequence(dsq);
6113 // TODO: refactor this as a merge dataset sequence function
6114 // now check that sq (the dataset sequence) sequence really is the union of
6115 // all references to it
6116 // boolean pre = sq.getStart() < dsq.getStart();
6117 // boolean post = sq.getEnd() > dsq.getEnd();
6121 // StringBuffer sb = new StringBuffer();
6122 String newres = jalview.analysis.AlignSeq.extractGaps(
6123 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
6124 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
6125 && newres.length() > dsq.getLength())
6127 // Update with the longer sequence.
6131 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
6132 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
6133 * sb.append(newres.substring(newres.length() - sq.getEnd() -
6134 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
6136 dsq.setSequence(newres);
6138 // TODO: merges will never happen if we 'know' we have the real dataset
6139 // sequence - this should be detected when id==dssid
6140 jalview.bin.Console.errPrintln(
6141 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
6142 // + (pre ? "prepended" : "") + " "
6143 // + (post ? "appended" : ""));
6148 // sequence refs are identical. We may need to update the existing dataset
6149 // alignment with this one, though.
6150 if (ds != null && dseqs == null)
6152 int opos = ds.findIndex(dsq);
6153 SequenceI tseq = null;
6154 if (opos != -1 && vseqpos != opos)
6156 // remove from old position
6157 ds.deleteSequence(dsq);
6159 if (vseqpos < ds.getHeight())
6161 if (vseqpos != opos)
6163 // save sequence at destination position
6164 tseq = ds.getSequenceAt(vseqpos);
6165 ds.replaceSequenceAt(vseqpos, dsq);
6166 ds.addSequence(tseq);
6171 ds.addSequence(dsq);
6178 * TODO use AlignmentI here and in related methods - needs
6179 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6181 Hashtable<String, AlignmentI> datasetIds = null;
6183 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6185 private AlignmentI getDatasetFor(String datasetId)
6187 if (datasetIds == null)
6189 datasetIds = new Hashtable<>();
6192 if (datasetIds.containsKey(datasetId))
6194 return datasetIds.get(datasetId);
6199 private void addDatasetRef(String datasetId, AlignmentI dataset)
6201 if (datasetIds == null)
6203 datasetIds = new Hashtable<>();
6205 datasetIds.put(datasetId, dataset);
6209 * make a new dataset ID for this jalview dataset alignment
6214 private String getDatasetIdRef(AlignmentI dataset)
6216 if (dataset.getDataset() != null)
6219 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6221 String datasetId = makeHashCode(dataset, null);
6222 if (datasetId == null)
6224 // make a new datasetId and record it
6225 if (dataset2Ids == null)
6227 dataset2Ids = new IdentityHashMap<>();
6231 datasetId = dataset2Ids.get(dataset);
6233 if (datasetId == null)
6235 datasetId = "ds" + dataset2Ids.size() + 1;
6236 dataset2Ids.put(dataset, datasetId);
6243 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6244 * constructed as a special subclass GeneLocus.
6246 * @param datasetSequence
6249 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6251 for (int d = 0; d < sequence.getDBRef().size(); d++)
6253 DBRef dr = sequence.getDBRef().get(d);
6257 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6258 dr.getAccessionId());
6262 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6263 dr.getAccessionId());
6265 if (dr.getMapping() != null)
6267 entry.setMap(addMapping(dr.getMapping()));
6269 entry.setCanonical(dr.isCanonical());
6270 datasetSequence.addDBRef(entry);
6274 private jalview.datamodel.Mapping addMapping(Mapping m)
6276 SequenceI dsto = null;
6277 // Mapping m = dr.getMapping();
6278 int fr[] = new int[m.getMapListFrom().size() * 2];
6279 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6280 for (int _i = 0; from.hasNext(); _i += 2)
6282 MapListFrom mf = from.next();
6283 fr[_i] = mf.getStart();
6284 fr[_i + 1] = mf.getEnd();
6286 int fto[] = new int[m.getMapListTo().size() * 2];
6287 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6288 for (int _i = 0; to.hasNext(); _i += 2)
6290 MapListTo mf = to.next();
6291 fto[_i] = mf.getStart();
6292 fto[_i + 1] = mf.getEnd();
6294 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6295 fto, m.getMapFromUnit().intValue(),
6296 m.getMapToUnit().intValue());
6299 * (optional) choice of dseqFor or Sequence
6301 if (m.getDseqFor() != null)
6303 String dsfor = m.getDseqFor();
6304 if (seqRefIds.containsKey(dsfor))
6309 jmap.setTo(seqRefIds.get(dsfor));
6313 frefedSequence.add(newMappingRef(dsfor, jmap));
6316 else if (m.getSequence() != null)
6319 * local sequence definition
6321 Sequence ms = m.getSequence();
6322 SequenceI djs = null;
6323 String sqid = ms.getDsseqid();
6324 if (sqid != null && sqid.length() > 0)
6327 * recover dataset sequence
6329 djs = seqRefIds.get(sqid);
6333 jalview.bin.Console.errPrintln(
6334 "Warning - making up dataset sequence id for DbRef sequence map reference");
6335 sqid = ((Object) ms).toString(); // make up a new hascode for
6336 // undefined dataset sequence hash
6337 // (unlikely to happen)
6343 * make a new dataset sequence and add it to refIds hash
6345 djs = new jalview.datamodel.Sequence(ms.getName(),
6347 djs.setStart(jmap.getMap().getToLowest());
6348 djs.setEnd(jmap.getMap().getToHighest());
6349 djs.setVamsasId(uniqueSetSuffix + sqid);
6351 incompleteSeqs.put(sqid, djs);
6352 seqRefIds.put(sqid, djs);
6355 Console.debug("about to recurse on addDBRefs.");
6364 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6365 * view as XML (but not to file), and then reloading it
6370 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6373 JalviewModel jm = saveState(ap, null, null, null);
6376 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6377 ap.getAlignment().getDataset());
6379 uniqueSetSuffix = "";
6380 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6381 jm.getViewport().get(0).setId(null);
6382 // we don't overwrite the view we just copied
6384 if (this.frefedSequence == null)
6386 frefedSequence = new Vector<>();
6389 viewportsAdded.clear();
6391 AlignFrame af = loadFromObject(jm, null, false, null);
6392 af.getAlignPanels().clear();
6393 af.closeMenuItem_actionPerformed(true);
6396 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6397 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6398 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6399 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6400 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6403 return af.alignPanel;
6406 private Hashtable jvids2vobj;
6409 * set the object to ID mapping tables used to write/recover objects and XML
6410 * ID strings for the jalview project. If external tables are provided then
6411 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6412 * object goes out of scope. - also populates the datasetIds hashtable with
6413 * alignment objects containing dataset sequences
6416 * Map from ID strings to jalview datamodel
6418 * Map from jalview datamodel to ID strings
6422 public void setObjectMappingTables(Hashtable vobj2jv,
6423 IdentityHashMap jv2vobj)
6425 this.jv2vobj = jv2vobj;
6426 this.vobj2jv = vobj2jv;
6427 Iterator ds = jv2vobj.keySet().iterator();
6429 while (ds.hasNext())
6431 Object jvobj = ds.next();
6432 id = jv2vobj.get(jvobj).toString();
6433 if (jvobj instanceof jalview.datamodel.Alignment)
6435 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6437 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6440 else if (jvobj instanceof jalview.datamodel.Sequence)
6442 // register sequence object so the XML parser can recover it.
6443 if (seqRefIds == null)
6445 seqRefIds = new HashMap<>();
6447 if (seqsToIds == null)
6449 seqsToIds = new IdentityHashMap<>();
6451 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6452 seqsToIds.put((SequenceI) jvobj, id);
6454 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6457 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6458 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6459 if (jvann.annotationId == null)
6461 jvann.annotationId = anid;
6463 if (!jvann.annotationId.equals(anid))
6465 // TODO verify that this is the correct behaviour
6466 Console.warn("Overriding Annotation ID for " + anid
6467 + " from different id : " + jvann.annotationId);
6468 jvann.annotationId = anid;
6471 else if (jvobj instanceof String)
6473 if (jvids2vobj == null)
6475 jvids2vobj = new Hashtable();
6476 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6481 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6487 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6488 * objects created from the project archive. If string is null (default for
6489 * construction) then suffix will be set automatically.
6493 public void setUniqueSetSuffix(String string)
6495 uniqueSetSuffix = string;
6500 * uses skipList2 as the skipList for skipping views on sequence sets
6501 * associated with keys in the skipList
6505 public void setSkipList(Hashtable skipList2)
6507 skipList = skipList2;
6511 * Reads the jar entry of given name and returns its contents, or null if the
6512 * entry is not found.
6515 * @param jarEntryName
6518 protected String readJarEntry(jarInputStreamProvider jprovider,
6519 String jarEntryName)
6521 String result = null;
6522 BufferedReader in = null;
6527 * Reopen the jar input stream and traverse its entries to find a matching
6530 JarInputStream jin = jprovider.getJarInputStream();
6531 JarEntry entry = null;
6534 entry = jin.getNextJarEntry();
6535 } while (entry != null && !entry.getName().equals(jarEntryName));
6539 StringBuilder out = new StringBuilder(256);
6540 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6543 while ((data = in.readLine()) != null)
6547 result = out.toString();
6552 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6554 } catch (Exception ex)
6556 ex.printStackTrace();
6564 } catch (IOException e)
6575 * Returns an incrementing counter (0, 1, 2...)
6579 private synchronized int nextCounter()
6585 * Loads any saved PCA viewers
6590 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6594 List<PcaViewer> pcaviewers = model.getPcaViewer();
6595 for (PcaViewer viewer : pcaviewers)
6597 if (isPasimap(viewer))
6601 String modelName = viewer.getScoreModelName();
6602 SimilarityParamsI params = new SimilarityParams(
6603 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6604 viewer.isIncludeGaps(),
6605 viewer.isDenominateByShortestLength());
6608 * create the panel (without computing the PCA)
6610 PCAPanel panel = new PCAPanel(ap, modelName, params);
6612 panel.setTitle(viewer.getTitle());
6613 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6614 viewer.getWidth(), viewer.getHeight()));
6616 boolean showLabels = viewer.isShowLabels();
6617 panel.setShowLabels(showLabels);
6618 panel.getRotatableCanvas().setShowLabels(showLabels);
6619 panel.getRotatableCanvas()
6620 .setBgColour(new Color(viewer.getBgColour()));
6621 panel.getRotatableCanvas()
6622 .setApplyToAllViews(viewer.isLinkToAllViews());
6625 * load PCA output data
6627 ScoreModelI scoreModel = ScoreModels.getInstance()
6628 .getScoreModel(modelName, ap);
6629 PCA pca = new PCA(null, scoreModel, params);
6630 PcaDataType pcaData = viewer.getPcaData();
6632 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6633 pca.setPairwiseScores(pairwise);
6635 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6636 pca.setTridiagonal(triDiag);
6638 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6639 pca.setEigenmatrix(result);
6641 panel.getPcaModel().setPCA(pca);
6644 * we haven't saved the input data! (JAL-2647 to do)
6646 panel.setInputData(null);
6649 * add the sequence points for the PCA display
6651 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6652 for (SequencePoint sp : viewer.getSequencePoint())
6654 String seqId = sp.getSequenceRef();
6655 SequenceI seq = seqRefIds.get(seqId);
6658 throw new IllegalStateException(
6659 "Unmatched seqref for PCA: " + seqId);
6661 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6662 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6664 seqPoints.add(seqPoint);
6666 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6669 * set min-max ranges and scale after setPoints (which recomputes them)
6671 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6672 SeqPointMin spMin = viewer.getSeqPointMin();
6673 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6675 SeqPointMax spMax = viewer.getSeqPointMax();
6676 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6678 panel.getRotatableCanvas().setSeqMinMax(min, max);
6680 // todo: hold points list in PCAModel only
6681 panel.getPcaModel().setSequencePoints(seqPoints);
6683 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6684 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6685 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6687 // is this duplication needed?
6688 panel.setTop(seqPoints.size() - 1);
6689 panel.getPcaModel().setTop(seqPoints.size() - 1);
6692 * add the axes' end points for the display
6694 for (int i = 0; i < 3; i++)
6696 Axis axis = viewer.getAxis().get(i);
6697 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6698 axis.getXPos(), axis.getYPos(), axis.getZPos());
6701 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6702 "label.calc_title", "PCA", modelName), 475, 450);
6704 } catch (Exception ex)
6706 Console.error("Error loading PCA: " + ex.toString());
6710 private boolean isPasimap(PcaViewer viewer)
6712 return viewer.getTitle().toLowerCase(Locale.ROOT)
6713 .startsWith("pasimap");
6716 * Loads any saved PaSiMAp viewers using the function from PCA
6721 protected void loadPaSiMapViewers(JalviewModel model, AlignmentPanel ap)
6725 List<PcaViewer> pcaviewers = model.getPcaViewer();
6726 for (PcaViewer viewer : pcaviewers)
6728 if (!isPasimap(viewer))
6732 String modelName = viewer.getScoreModelName();
6734 SimilarityParamsI params = new SimilarityParams(
6735 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6736 viewer.isIncludeGaps(),
6737 viewer.isDenominateByShortestLength());
6741 * create the panel (without computing the PaSiMAp)
6743 PaSiMapPanel panel = new PaSiMapPanel(ap, modelName);
6745 panel.setTitle(viewer.getTitle());
6746 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6747 viewer.getWidth(), viewer.getHeight()));
6749 boolean showLabels = viewer.isShowLabels();
6750 panel.setShowLabels(showLabels);
6751 panel.getRotatableCanvas().setShowLabels(showLabels);
6752 panel.getRotatableCanvas()
6753 .setBgColour(new Color(viewer.getBgColour()));
6754 panel.getRotatableCanvas()
6755 .setApplyToAllViews(viewer.isLinkToAllViews());
6758 * load PaSiMap output data
6760 ScoreModelI scoreModel = ScoreModels.getInstance()
6761 .getScoreModel(modelName, ap);
6762 PaSiMap pasimap = new PaSiMap(null, scoreModel, null);
6763 PcaDataType pasimapData = viewer.getPcaData();
6765 MatrixI pairwise = loadDoubleMatrix(pasimapData.getPairwiseMatrix());
6766 pasimap.setPairwiseScores(pairwise);
6768 MatrixI result = loadDoubleMatrix(pasimapData.getEigenMatrix());
6769 pasimap.setEigenmatrix(result);
6771 panel.getPasimapModel().setPaSiMap(pasimap);
6774 * we haven't saved the input data! (JAL-2647 to do)
6776 panel.setInputData(null);
6779 * add the sequence points for the PCA display
6781 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6782 for (SequencePoint sp : viewer.getSequencePoint())
6784 String seqId = sp.getSequenceRef();
6785 SequenceI seq = seqRefIds.get(seqId);
6788 throw new IllegalStateException(
6789 "Unmatched seqref for PaSiMap: " + seqId);
6791 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6792 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6794 seqPoints.add(seqPoint);
6796 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6799 * set min-max ranges and scale after setPoints (which recomputes them)
6801 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6802 SeqPointMin spMin = viewer.getSeqPointMin();
6803 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6805 SeqPointMax spMax = viewer.getSeqPointMax();
6806 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6808 panel.getRotatableCanvas().setSeqMinMax(min, max);
6810 // todo: hold points list in PCAModel only
6811 panel.getPasimapModel().setSequencePoints(seqPoints);
6813 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6814 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6815 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6817 // is this duplication needed?
6818 panel.setTop(seqPoints.size() - 1);
6819 panel.getPasimapModel().setTop(seqPoints.size() - 1);
6822 * add the axes' end points for the display
6824 for (int i = 0; i < 3; i++)
6826 Axis axis = viewer.getAxis().get(i);
6827 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6828 axis.getXPos(), axis.getYPos(), axis.getZPos());
6831 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6832 "label.calc_title", "PaSiMap", modelName), 475, 450);
6834 } catch (Exception ex)
6836 Console.error("Error loading PaSiMap: " + ex.toString());
6841 * Creates a new structure viewer window
6848 protected void createStructureViewer(ViewerType viewerType,
6849 final Entry<String, StructureViewerModel> viewerData,
6850 AlignFrame af, jarInputStreamProvider jprovider)
6852 final StructureViewerModel viewerModel = viewerData.getValue();
6853 String sessionFilePath = null;
6855 if (viewerType == ViewerType.JMOL)
6857 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6861 String viewerJarEntryName = getViewerJarEntryName(
6862 viewerModel.getViewId());
6863 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6864 "viewerSession", ".tmp");
6866 final String sessionPath = sessionFilePath;
6867 final String sviewid = viewerData.getKey();
6870 SwingUtilities.invokeAndWait(new Runnable()
6875 JalviewStructureDisplayI sview = null;
6878 sview = StructureViewer.createView(viewerType, af.alignPanel,
6879 viewerModel, sessionPath, sviewid);
6880 addNewStructureViewer(sview);
6881 } catch (OutOfMemoryError ex)
6883 new OOMWarning("Restoring structure view for " + viewerType,
6884 (OutOfMemoryError) ex.getCause());
6885 if (sview != null && sview.isVisible())
6887 sview.closeViewer(false);
6888 sview.setVisible(false);
6894 } catch (InvocationTargetException | InterruptedException ex)
6896 Console.warn("Unexpected error when opening " + viewerType
6897 + " structure viewer", ex);
6902 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6903 * the path of the file. "load file" commands are rewritten to change the
6904 * original PDB file names to those created as the Jalview project is loaded.
6910 private String rewriteJmolSession(StructureViewerModel svattrib,
6911 jarInputStreamProvider jprovider)
6913 String state = svattrib.getStateData(); // Jalview < 2.9
6914 if (state == null || state.isEmpty()) // Jalview >= 2.9
6916 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6917 state = readJarEntry(jprovider, jarEntryName);
6919 // TODO or simpler? for each key in oldFiles,
6920 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6921 // (allowing for different path escapings)
6922 StringBuilder rewritten = new StringBuilder(state.length());
6923 int cp = 0, ncp, ecp;
6924 Map<File, StructureData> oldFiles = svattrib.getFileData();
6925 while ((ncp = state.indexOf("load ", cp)) > -1)
6929 // look for next filename in load statement
6930 rewritten.append(state.substring(cp,
6931 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6932 String oldfilenam = state.substring(ncp,
6933 ecp = state.indexOf("\"", ncp));
6934 // recover the new mapping data for this old filename
6935 // have to normalize filename - since Jmol and jalview do
6936 // filename translation differently.
6937 StructureData filedat = oldFiles.get(new File(oldfilenam));
6938 if (filedat == null)
6940 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6941 filedat = oldFiles.get(new File(reformatedOldFilename));
6943 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6944 rewritten.append("\"");
6945 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6946 // look for next file statement.
6947 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6951 // just append rest of state
6952 rewritten.append(state.substring(cp));
6956 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6957 rewritten = new StringBuilder(state);
6958 rewritten.append("; load append ");
6959 for (File id : oldFiles.keySet())
6961 // add pdb files that should be present in the viewer
6962 StructureData filedat = oldFiles.get(id);
6963 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6965 rewritten.append(";");
6968 if (rewritten.length() == 0)
6972 final String history = "history = ";
6973 int historyIndex = rewritten.indexOf(history);
6974 if (historyIndex > -1)
6977 * change "history = [true|false];" to "history = [1|0];"
6979 historyIndex += history.length();
6980 String val = rewritten.substring(historyIndex, historyIndex + 5);
6981 if (val.startsWith("true"))
6983 rewritten.replace(historyIndex, historyIndex + 4, "1");
6985 else if (val.startsWith("false"))
6987 rewritten.replace(historyIndex, historyIndex + 5, "0");
6993 File tmp = File.createTempFile("viewerSession", ".tmp");
6994 try (OutputStream os = new FileOutputStream(tmp))
6996 InputStream is = new ByteArrayInputStream(
6997 rewritten.toString().getBytes());
6999 return tmp.getAbsolutePath();
7001 } catch (IOException e)
7003 Console.error("Error restoring Jmol session: " + e.toString());
7009 * Populates an XML model of the feature colour scheme for one feature type
7011 * @param featureType
7015 public static Colour marshalColour(String featureType,
7016 FeatureColourI fcol)
7018 Colour col = new Colour();
7019 if (fcol.isSimpleColour())
7021 col.setRGB(Format.getHexString(fcol.getColour()));
7025 col.setRGB(Format.getHexString(fcol.getMaxColour()));
7026 col.setMin(fcol.getMin());
7027 col.setMax(fcol.getMax());
7028 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
7029 col.setAutoScale(fcol.isAutoScaled());
7030 col.setThreshold(fcol.getThreshold());
7031 col.setColourByLabel(fcol.isColourByLabel());
7032 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
7033 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
7034 : ThresholdType.NONE));
7035 if (fcol.isColourByAttribute())
7037 final String[] attName = fcol.getAttributeName();
7038 col.getAttributeName().add(attName[0]);
7039 if (attName.length > 1)
7041 col.getAttributeName().add(attName[1]);
7044 Color noColour = fcol.getNoColour();
7045 if (noColour == null)
7047 col.setNoValueColour(NoValueColour.NONE);
7049 else if (noColour == fcol.getMaxColour())
7051 col.setNoValueColour(NoValueColour.MAX);
7055 col.setNoValueColour(NoValueColour.MIN);
7058 col.setName(featureType);
7063 * Populates an XML model of the feature filter(s) for one feature type
7065 * @param firstMatcher
7066 * the first (or only) match condition)
7068 * remaining match conditions (if any)
7070 * if true, conditions are and-ed, else or-ed
7072 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
7073 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
7076 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
7078 if (filters.hasNext())
7083 CompoundMatcher compound = new CompoundMatcher();
7084 compound.setAnd(and);
7085 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
7086 firstMatcher, Collections.emptyIterator(), and);
7087 // compound.addMatcherSet(matcher1);
7088 compound.getMatcherSet().add(matcher1);
7089 FeatureMatcherI nextMatcher = filters.next();
7090 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
7091 nextMatcher, filters, and);
7092 // compound.addMatcherSet(matcher2);
7093 compound.getMatcherSet().add(matcher2);
7094 result.setCompoundMatcher(compound);
7099 * single condition matcher
7101 // MatchCondition matcherModel = new MatchCondition();
7102 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
7103 matcherModel.setCondition(
7104 firstMatcher.getMatcher().getCondition().getStableName());
7105 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
7106 if (firstMatcher.isByAttribute())
7108 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
7109 // matcherModel.setAttributeName(firstMatcher.getAttribute());
7110 String[] attName = firstMatcher.getAttribute();
7111 matcherModel.getAttributeName().add(attName[0]); // attribute
7112 if (attName.length > 1)
7114 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
7117 else if (firstMatcher.isByLabel())
7119 matcherModel.setBy(FilterBy.BY_LABEL);
7121 else if (firstMatcher.isByScore())
7123 matcherModel.setBy(FilterBy.BY_SCORE);
7125 result.setMatchCondition(matcherModel);
7132 * Loads one XML model of a feature filter to a Jalview object
7134 * @param featureType
7135 * @param matcherSetModel
7138 public static FeatureMatcherSetI parseFilter(String featureType,
7139 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
7141 FeatureMatcherSetI result = new FeatureMatcherSet();
7144 parseFilterConditions(result, matcherSetModel, true);
7145 } catch (IllegalStateException e)
7147 // mixing AND and OR conditions perhaps
7148 jalview.bin.Console.errPrintln(
7149 String.format("Error reading filter conditions for '%s': %s",
7150 featureType, e.getMessage()));
7151 // return as much as was parsed up to the error
7158 * Adds feature match conditions to matcherSet as unmarshalled from XML
7159 * (possibly recursively for compound conditions)
7162 * @param matcherSetModel
7164 * if true, multiple conditions are AND-ed, else they are OR-ed
7165 * @throws IllegalStateException
7166 * if AND and OR conditions are mixed
7168 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
7169 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
7172 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
7173 .getMatchCondition();
7179 FilterBy filterBy = mc.getBy();
7180 Condition cond = Condition.fromString(mc.getCondition());
7181 String pattern = mc.getValue();
7182 FeatureMatcherI matchCondition = null;
7183 if (filterBy == FilterBy.BY_LABEL)
7185 matchCondition = FeatureMatcher.byLabel(cond, pattern);
7187 else if (filterBy == FilterBy.BY_SCORE)
7189 matchCondition = FeatureMatcher.byScore(cond, pattern);
7192 else if (filterBy == FilterBy.BY_ATTRIBUTE)
7194 final List<String> attributeName = mc.getAttributeName();
7195 String[] attNames = attributeName
7196 .toArray(new String[attributeName.size()]);
7197 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
7202 * note this throws IllegalStateException if AND-ing to a
7203 * previously OR-ed compound condition, or vice versa
7207 matcherSet.and(matchCondition);
7211 matcherSet.or(matchCondition);
7217 * compound condition
7219 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
7220 .getCompoundMatcher().getMatcherSet();
7221 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
7222 if (matchers.size() == 2)
7224 parseFilterConditions(matcherSet, matchers.get(0), anded);
7225 parseFilterConditions(matcherSet, matchers.get(1), anded);
7230 .errPrintln("Malformed compound filter condition");
7236 * Loads one XML model of a feature colour to a Jalview object
7238 * @param colourModel
7241 public static FeatureColourI parseColour(Colour colourModel)
7243 FeatureColourI colour = null;
7245 if (colourModel.getMax() != null)
7247 Color mincol = null;
7248 Color maxcol = null;
7249 Color noValueColour = null;
7253 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
7254 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7255 } catch (Exception e)
7257 Console.warn("Couldn't parse out graduated feature color.", e);
7260 NoValueColour noCol = colourModel.getNoValueColour();
7261 if (noCol == NoValueColour.MIN)
7263 noValueColour = mincol;
7265 else if (noCol == NoValueColour.MAX)
7267 noValueColour = maxcol;
7270 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
7271 safeFloat(colourModel.getMin()),
7272 safeFloat(colourModel.getMax()));
7273 final List<String> attributeName = colourModel.getAttributeName();
7274 String[] attributes = attributeName
7275 .toArray(new String[attributeName.size()]);
7276 if (attributes != null && attributes.length > 0)
7278 colour.setAttributeName(attributes);
7280 if (colourModel.isAutoScale() != null)
7282 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7284 if (colourModel.isColourByLabel() != null)
7286 colour.setColourByLabel(
7287 colourModel.isColourByLabel().booleanValue());
7289 if (colourModel.getThreshold() != null)
7291 colour.setThreshold(colourModel.getThreshold().floatValue());
7293 ThresholdType ttyp = colourModel.getThreshType();
7294 if (ttyp == ThresholdType.ABOVE)
7296 colour.setAboveThreshold(true);
7298 else if (ttyp == ThresholdType.BELOW)
7300 colour.setBelowThreshold(true);
7305 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7306 colour = new FeatureColour(color);
7312 public static void setStateSavedUpToDate(boolean s)
7314 Console.debug("Setting overall stateSavedUpToDate to " + s);
7315 stateSavedUpToDate = s;
7318 public static boolean stateSavedUpToDate()
7320 Console.debug("Returning overall stateSavedUpToDate value: "
7321 + stateSavedUpToDate);
7322 return stateSavedUpToDate;
7325 public static boolean allSavedUpToDate()
7327 if (stateSavedUpToDate()) // nothing happened since last project save
7330 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7333 for (int i = 0; i < frames.length; i++)
7335 if (frames[i] == null)
7337 if (!frames[i].getViewport().savedUpToDate())
7338 return false; // at least one alignment is not individually saved
7344 // used for debugging and tests
7345 private static int debugDelaySave = 20;
7347 public static void setDebugDelaySave(int n)