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.ContactMatrix;
96 import jalview.datamodel.ContactMatrixI;
97 import jalview.datamodel.DBRefEntry;
98 import jalview.datamodel.FloatContactMatrix;
99 import jalview.datamodel.GeneLocus;
100 import jalview.datamodel.GraphLine;
101 import jalview.datamodel.GroupSet;
102 import jalview.datamodel.PDBEntry;
103 import jalview.datamodel.Point;
104 import jalview.datamodel.RnaViewerModel;
105 import jalview.datamodel.SequenceFeature;
106 import jalview.datamodel.SequenceGroup;
107 import jalview.datamodel.SequenceI;
108 import jalview.datamodel.StructureViewerModel;
109 import jalview.datamodel.StructureViewerModel.StructureData;
110 import jalview.datamodel.features.FeatureMatcher;
111 import jalview.datamodel.features.FeatureMatcherI;
112 import jalview.datamodel.features.FeatureMatcherSet;
113 import jalview.datamodel.features.FeatureMatcherSetI;
114 import jalview.ext.varna.RnaModel;
115 import jalview.gui.AlignFrame;
116 import jalview.gui.AlignViewport;
117 import jalview.gui.AlignmentPanel;
118 import jalview.gui.AppVarna;
119 import jalview.gui.Desktop;
120 import jalview.gui.JvOptionPane;
121 import jalview.gui.OOMWarning;
122 import jalview.gui.OverviewPanel;
123 import jalview.gui.PCAPanel;
124 import jalview.gui.PaSiMapPanel;
125 import jalview.gui.PaintRefresher;
126 import jalview.gui.SplitFrame;
127 import jalview.gui.StructureViewer;
128 import jalview.gui.StructureViewer.ViewerType;
129 import jalview.gui.StructureViewerBase;
130 import jalview.gui.TreePanel;
131 import jalview.io.BackupFiles;
132 import jalview.io.DataSourceType;
133 import jalview.io.FileFormat;
134 import jalview.io.NewickFile;
135 import jalview.math.Matrix;
136 import jalview.math.MatrixI;
137 import jalview.renderer.ResidueShaderI;
138 import jalview.schemes.AnnotationColourGradient;
139 import jalview.schemes.ColourSchemeI;
140 import jalview.schemes.ColourSchemeProperty;
141 import jalview.schemes.FeatureColour;
142 import jalview.schemes.ResidueProperties;
143 import jalview.schemes.UserColourScheme;
144 import jalview.structure.StructureSelectionManager;
145 import jalview.structures.models.AAStructureBindingModel;
146 import jalview.util.Format;
147 import jalview.util.HttpUtils;
148 import jalview.util.MessageManager;
149 import jalview.util.Platform;
150 import jalview.util.StringUtils;
151 import jalview.util.jarInputStreamProvider;
152 import jalview.util.matcher.Condition;
153 import jalview.viewmodel.AlignmentViewport;
154 import jalview.viewmodel.PCAModel;
155 import jalview.viewmodel.PaSiMapModel;
156 import jalview.viewmodel.ViewportRanges;
157 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
158 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
159 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
160 import jalview.ws.datamodel.MappableContactMatrixI;
161 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
162 import jalview.ws.jws2.Jws2Discoverer;
163 import jalview.ws.jws2.dm.AAConSettings;
164 import jalview.ws.jws2.jabaws2.Jws2Instance;
165 import jalview.ws.params.ArgumentI;
166 import jalview.ws.params.AutoCalcSetting;
167 import jalview.ws.params.WsParamSetI;
168 import jalview.xml.binding.jalview.AlcodonFrame;
169 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
170 import jalview.xml.binding.jalview.Annotation;
171 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
172 import jalview.xml.binding.jalview.AnnotationColourScheme;
173 import jalview.xml.binding.jalview.AnnotationElement;
174 import jalview.xml.binding.jalview.DoubleMatrix;
175 import jalview.xml.binding.jalview.DoubleVector;
176 import jalview.xml.binding.jalview.Feature;
177 import jalview.xml.binding.jalview.Feature.OtherData;
178 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
179 import jalview.xml.binding.jalview.FilterBy;
180 import jalview.xml.binding.jalview.JalviewModel;
181 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
182 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
183 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
184 import jalview.xml.binding.jalview.JalviewModel.JGroup;
185 import jalview.xml.binding.jalview.JalviewModel.JSeq;
186 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
187 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
188 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
189 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
190 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
191 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
192 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
193 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
194 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
195 import jalview.xml.binding.jalview.JalviewModel.Tree;
196 import jalview.xml.binding.jalview.JalviewModel.UserColours;
197 import jalview.xml.binding.jalview.JalviewModel.Viewport;
198 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
199 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
200 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
201 import jalview.xml.binding.jalview.JalviewUserColours;
202 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
203 import jalview.xml.binding.jalview.MapListType;
204 import jalview.xml.binding.jalview.MapListType.MapListFrom;
205 import jalview.xml.binding.jalview.MapListType.MapListTo;
206 import jalview.xml.binding.jalview.MapOnAMatrixType;
207 import jalview.xml.binding.jalview.Mapping;
208 import jalview.xml.binding.jalview.MatrixType;
209 import jalview.xml.binding.jalview.NoValueColour;
210 import jalview.xml.binding.jalview.ObjectFactory;
211 import jalview.xml.binding.jalview.PcaDataType;
212 import jalview.xml.binding.jalview.Pdbentry.Property;
213 import jalview.xml.binding.jalview.Sequence;
214 import jalview.xml.binding.jalview.Sequence.DBRef;
215 import jalview.xml.binding.jalview.SequenceSet;
216 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
217 import jalview.xml.binding.jalview.ThresholdType;
218 import jalview.xml.binding.jalview.VAMSAS;
221 * Write out the current jalview desktop state as a Jalview XML stream.
223 * Note: the vamsas objects referred to here are primitive versions of the
224 * VAMSAS project schema elements - they are not the same and most likely never
228 * @version $Revision: 1.134 $
230 public class Jalview2XML
233 // BH 2018 we add the .jvp binary extension to J2S so that
234 // it will declare that binary when we do the file save from the browser
238 Platform.addJ2SBinaryType(".jvp?");
241 private static final String VIEWER_PREFIX = "viewer_";
243 private static final String RNA_PREFIX = "rna_";
245 private static final String UTF_8 = "UTF-8";
248 * used in decision if quit confirmation should be issued
250 private static boolean stateSavedUpToDate = false;
253 * prefix for recovering datasets for alignments with multiple views where
254 * non-existent dataset IDs were written for some views
256 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
258 // use this with nextCounter() to make unique names for entities
259 private int counter = 0;
262 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
263 * of sequence objects are created.
265 IdentityHashMap<SequenceI, String> seqsToIds = null;
268 * jalview XML Sequence ID to jalview sequence object reference (both dataset
269 * and alignment sequences. Populated as XML reps of sequence objects are
272 Map<String, SequenceI> seqRefIds = null;
274 Map<String, SequenceI> incompleteSeqs = null;
276 List<forwardRef> frefedSequence = null;
278 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
281 * Map of reconstructed AlignFrame objects that appear to have come from
282 * SplitFrame objects (have a dna/protein complement view).
284 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
287 * Map from displayed rna structure models to their saved session state jar
290 private Map<RnaModel, String> rnaSessions = new HashMap<>();
293 * map from contact matrices to their XML ids
295 private Map<ContactMatrixI, String> contactMatrices = new HashMap<>();
297 private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
299 private List<jalview.xml.binding.jalview.MatrixType> xmlMatrices = new ArrayList<>();
302 * A helper method for safely using the value of an optional attribute that
303 * may be null if not present in the XML. Answers the boolean value, or false
309 public static boolean safeBoolean(Boolean b)
311 return b == null ? false : b.booleanValue();
315 * A helper method for safely using the value of an optional attribute that
316 * may be null if not present in the XML. Answers the integer value, or zero
322 public static int safeInt(Integer i)
324 return i == null ? 0 : i.intValue();
328 * A helper method for safely using the value of an optional attribute that
329 * may be null if not present in the XML. Answers the float value, or zero if
335 public static float safeFloat(Float f)
337 return f == null ? 0f : f.floatValue();
341 * create/return unique hash string for sq
344 * @return new or existing unique string for sq
346 String seqHash(SequenceI sq)
348 if (seqsToIds == null)
352 if (seqsToIds.containsKey(sq))
354 return seqsToIds.get(sq);
358 // create sequential key
359 String key = "sq" + (seqsToIds.size() + 1);
360 key = makeHashCode(sq, key); // check we don't have an external reference
362 seqsToIds.put(sq, key);
369 if (seqsToIds == null)
371 seqsToIds = new IdentityHashMap<>();
373 if (seqRefIds == null)
375 seqRefIds = new HashMap<>();
377 if (incompleteSeqs == null)
379 incompleteSeqs = new HashMap<>();
381 if (frefedSequence == null)
383 frefedSequence = new ArrayList<>();
391 public Jalview2XML(boolean raiseGUI)
393 this.raiseGUI = raiseGUI;
397 * base class for resolving forward references to an as-yet unmarshalled
398 * object referenced by already unmarshalled objects
403 abstract class forwardRef
409 public forwardRef(String _sref, String type)
415 public String getSref()
420 public abstract boolean isResolvable();
423 * @return true if the forward reference was fully resolved
425 abstract boolean resolve();
428 public String toString()
430 return type + " reference to " + sref;
435 * resolve forward references to sequences by their ID
439 abstract class SeqFref extends forwardRef
441 public SeqFref(String _sref, String type)
446 public SequenceI getSrefSeq()
448 return seqRefIds.get(sref);
451 public boolean isResolvable()
453 return seqRefIds.get(sref) != null;
456 public SequenceI getSrefDatasetSeq()
458 SequenceI sq = seqRefIds.get(sref);
461 while (sq.getDatasetSequence() != null)
463 sq = sq.getDatasetSequence();
471 * create forward reference for a mapping
477 public SeqFref newMappingRef(final String sref,
478 final jalview.datamodel.Mapping _jmap)
480 SeqFref fref = new SeqFref(sref, "Mapping")
482 public jalview.datamodel.Mapping jmap = _jmap;
487 SequenceI seq = getSrefDatasetSeq();
499 public SeqFref newAlcodMapRef(final String sref,
500 final AlignedCodonFrame _cf,
501 final jalview.datamodel.Mapping _jmap)
504 SeqFref fref = new SeqFref(sref, "Codon Frame")
506 AlignedCodonFrame cf = _cf;
508 public jalview.datamodel.Mapping mp = _jmap;
511 public boolean isResolvable()
513 return super.isResolvable() && mp.getTo() != null;
519 SequenceI seq = getSrefDatasetSeq();
524 cf.addMap(seq, mp.getTo(), mp.getMap());
531 public forwardRef newMatrixFref(final String matRef,
532 final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
534 forwardRef fref = new forwardRef(matRef,
535 "Matrix Reference for sequence and annotation")
541 ContactMatrixI cm = contactMatrixRefs.get(matRef);
542 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
545 jaa.sequenceRef.addContactListFor(jaa, newpae);
550 public boolean isResolvable()
552 return (contactMatrixRefs.get(matRef) != null);
558 public void resolveFrefedSequences()
560 Iterator<forwardRef> nextFref = frefedSequence.iterator();
561 int toresolve = frefedSequence.size();
562 int unresolved = 0, failedtoresolve = 0;
563 while (nextFref.hasNext())
565 forwardRef ref = nextFref.next();
566 if (ref.isResolvable())
578 } catch (Exception x)
580 jalview.bin.Console.errPrintln(
581 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
594 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
596 + " forward references left unresolved on the stack.");
598 if (failedtoresolve > 0)
600 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
601 + " resolvable forward references failed to resolve.");
603 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
605 jalview.bin.Console.errPrintln(
606 "Jalview Project Import: There are " + incompleteSeqs.size()
607 + " sequences which may have incomplete metadata.");
608 if (incompleteSeqs.size() < 10)
610 for (SequenceI s : incompleteSeqs.values())
612 jalview.bin.Console.errPrintln(s.toString());
617 jalview.bin.Console.errPrintln(
618 "Too many to report. Skipping output of incomplete sequences.");
624 * This maintains a map of viewports, the key being the seqSetId. Important to
625 * set historyItem and redoList for multiple views
627 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
629 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
631 String uniqueSetSuffix = "";
634 * List of pdbfiles added to Jar
636 List<String> pdbfiles = null;
638 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
639 public void saveState(File statefile)
641 FileOutputStream fos = null;
646 fos = new FileOutputStream(statefile);
648 JarOutputStream jout = new JarOutputStream(fos);
652 } catch (Exception e)
654 Console.error("Couln't write Jalview state to " + statefile, e);
655 // TODO: inform user of the problem - they need to know if their data was
657 if (errorMessage == null)
659 errorMessage = "Did't write Jalview Archive to output file '"
660 + statefile + "' - See console error log for details";
664 errorMessage += "(Didn't write Jalview Archive to output file '"
675 } catch (IOException e)
685 * Writes a jalview project archive to the given Jar output stream.
689 public void saveState(JarOutputStream jout)
691 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
693 setStateSavedUpToDate(true);
695 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
697 int n = debugDelaySave;
701 Console.debug("***** debugging save sleep " + i + "/" + n);
705 } catch (InterruptedException e)
707 // TODO Auto-generated catch block
718 saveAllFrames(Arrays.asList(frames), jout);
722 * core method for storing state for a set of AlignFrames.
725 * - frames involving all data to be exported (including containing
728 * - project output stream
730 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
732 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
735 * ensure cached data is clear before starting
737 // todo tidy up seqRefIds, seqsToIds initialisation / reset
739 splitFrameCandidates.clear();
744 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
745 // //////////////////////////////////////////////////
747 List<String> shortNames = new ArrayList<>();
748 List<String> viewIds = new ArrayList<>();
751 for (int i = frames.size() - 1; i > -1; i--)
753 AlignFrame af = frames.get(i);
755 if (skipList != null && skipList
756 .containsKey(af.getViewport().getSequenceSetId()))
761 String shortName = makeFilename(af, shortNames);
763 int apSize = af.getAlignPanels().size();
765 for (int ap = 0; ap < apSize; ap++)
767 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
769 String fileName = apSize == 1 ? shortName : ap + shortName;
770 if (!fileName.endsWith(".xml"))
772 fileName = fileName + ".xml";
775 saveState(apanel, fileName, jout, viewIds);
777 String dssid = getDatasetIdRef(
778 af.getViewport().getAlignment().getDataset());
779 if (!dsses.containsKey(dssid))
781 dsses.put(dssid, af);
786 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
792 } catch (Exception foo)
796 } catch (Exception ex)
798 // TODO: inform user of the problem - they need to know if their data was
800 if (errorMessage == null)
802 errorMessage = "Couldn't write Jalview Archive - see error output for details";
804 ex.printStackTrace();
809 * Generates a distinct file name, based on the title of the AlignFrame, by
810 * appending _n for increasing n until an unused name is generated. The new
811 * name (without its extension) is added to the list.
815 * @return the generated name, with .xml extension
817 protected String makeFilename(AlignFrame af, List<String> namesUsed)
819 String shortName = af.getTitle();
821 if (shortName.indexOf(File.separatorChar) > -1)
823 shortName = shortName
824 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
829 while (namesUsed.contains(shortName))
831 if (shortName.endsWith("_" + (count - 1)))
833 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
836 shortName = shortName.concat("_" + count);
840 namesUsed.add(shortName);
842 if (!shortName.endsWith(".xml"))
844 shortName = shortName + ".xml";
849 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
850 public boolean saveAlignment(AlignFrame af, String jarFile,
855 // create backupfiles object and get new temp filename destination
856 boolean doBackup = BackupFiles.getEnabled();
857 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
858 FileOutputStream fos = new FileOutputStream(
859 doBackup ? backupfiles.getTempFilePath() : jarFile);
861 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
863 int n = debugDelaySave;
867 Console.debug("***** debugging save sleep " + i + "/" + n);
871 } catch (InterruptedException e)
873 // TODO Auto-generated catch block
880 JarOutputStream jout = new JarOutputStream(fos);
881 List<AlignFrame> frames = new ArrayList<>();
883 // resolve splitframes
884 if (af.getViewport().getCodingComplement() != null)
886 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
892 saveAllFrames(frames, jout);
896 } catch (Exception foo)
900 boolean success = true;
904 backupfiles.setWriteSuccess(success);
905 success = backupfiles.rollBackupsAndRenameTempFile();
909 } catch (Exception ex)
911 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
912 ex.printStackTrace();
917 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
918 String fileName, JarOutputStream jout)
921 for (String dssids : dsses.keySet())
923 AlignFrame _af = dsses.get(dssids);
924 String jfileName = fileName + " Dataset for " + _af.getTitle();
925 if (!jfileName.endsWith(".xml"))
927 jfileName = jfileName + ".xml";
929 saveState(_af.alignPanel, jfileName, true, jout, null);
934 * create a JalviewModel from an alignment view and marshall it to a
938 * panel to create jalview model for
940 * name of alignment panel written to output stream
947 public JalviewModel saveState(AlignmentPanel ap, String fileName,
948 JarOutputStream jout, List<String> viewIds)
950 return saveState(ap, fileName, false, jout, viewIds);
954 * create a JalviewModel from an alignment view and marshall it to a
958 * panel to create jalview model for
960 * name of alignment panel written to output stream
962 * when true, only write the dataset for the alignment, not the data
963 * associated with the view.
969 public JalviewModel saveState(AlignmentPanel ap, String fileName,
970 boolean storeDS, JarOutputStream jout, List<String> viewIds)
974 viewIds = new ArrayList<>();
979 List<UserColourScheme> userColours = new ArrayList<>();
981 AlignViewport av = ap.av;
982 ViewportRanges vpRanges = av.getRanges();
984 final ObjectFactory objectFactory = new ObjectFactory();
985 JalviewModel object = objectFactory.createJalviewModel();
986 object.setVamsasModel(new VAMSAS());
988 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
991 GregorianCalendar c = new GregorianCalendar();
992 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
993 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
994 object.setCreationDate(now);
995 } catch (DatatypeConfigurationException e)
997 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
999 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
1002 * rjal is full height alignment, jal is actual alignment with full metadata
1003 * but excludes hidden sequences.
1005 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
1007 if (av.hasHiddenRows())
1009 rjal = jal.getHiddenSequences().getFullAlignment();
1012 SequenceSet vamsasSet = new SequenceSet();
1014 // JalviewModelSequence jms = new JalviewModelSequence();
1016 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1018 if (jal.getDataset() != null)
1020 // dataset id is the dataset's hashcode
1021 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1024 // switch jal and the dataset
1025 jal = jal.getDataset();
1029 if (jal.getProperties() != null)
1031 Enumeration en = jal.getProperties().keys();
1032 while (en.hasMoreElements())
1034 String key = en.nextElement().toString();
1035 SequenceSetProperties ssp = new SequenceSetProperties();
1037 ssp.setValue(jal.getProperties().get(key).toString());
1038 // vamsasSet.addSequenceSetProperties(ssp);
1039 vamsasSet.getSequenceSetProperties().add(ssp);
1044 Set<String> calcIdSet = new HashSet<>();
1045 // record the set of vamsas sequence XML POJO we create.
1046 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1048 for (final SequenceI jds : rjal.getSequences())
1050 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1051 : jds.getDatasetSequence();
1052 String id = seqHash(jds);
1053 if (vamsasSetIds.get(id) == null)
1055 if (seqRefIds.get(id) != null && !storeDS)
1057 // This happens for two reasons: 1. multiple views are being
1059 // 2. the hashCode has collided with another sequence's code. This
1061 // HAPPEN! (PF00072.15.stk does this)
1062 // JBPNote: Uncomment to debug writing out of files that do not read
1063 // back in due to ArrayOutOfBoundExceptions.
1064 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1065 // jalview.bin.Console.errPrintln(jds.getName()+"
1066 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1067 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1068 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1069 // jalview.bin.Console.errPrintln(rsq.getName()+"
1070 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1071 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1075 vamsasSeq = createVamsasSequence(id, jds);
1076 // vamsasSet.addSequence(vamsasSeq);
1077 vamsasSet.getSequence().add(vamsasSeq);
1078 vamsasSetIds.put(id, vamsasSeq);
1079 seqRefIds.put(id, jds);
1083 jseq.setStart(jds.getStart());
1084 jseq.setEnd(jds.getEnd());
1085 jseq.setColour(av.getSequenceColour(jds).getRGB());
1087 jseq.setId(id); // jseq id should be a string not a number
1090 // Store any sequences this sequence represents
1091 if (av.hasHiddenRows())
1093 // use rjal, contains the full height alignment
1095 av.getAlignment().getHiddenSequences().isHidden(jds));
1097 if (av.isHiddenRepSequence(jds))
1099 jalview.datamodel.SequenceI[] reps = av
1100 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1102 for (int h = 0; h < reps.length; h++)
1106 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1107 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1112 // mark sequence as reference - if it is the reference for this view
1113 if (jal.hasSeqrep())
1115 jseq.setViewreference(jds == jal.getSeqrep());
1119 // TODO: omit sequence features from each alignment view's XML dump if we
1120 // are storing dataset
1121 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1122 for (SequenceFeature sf : sfs)
1124 // Features features = new Features();
1125 Feature features = new Feature();
1127 features.setBegin(sf.getBegin());
1128 features.setEnd(sf.getEnd());
1129 features.setDescription(sf.getDescription());
1130 features.setType(sf.getType());
1131 features.setFeatureGroup(sf.getFeatureGroup());
1132 features.setScore(sf.getScore());
1133 if (sf.links != null)
1135 for (int l = 0; l < sf.links.size(); l++)
1137 OtherData keyValue = new OtherData();
1138 keyValue.setKey("LINK_" + l);
1139 keyValue.setValue(sf.links.elementAt(l).toString());
1140 // features.addOtherData(keyValue);
1141 features.getOtherData().add(keyValue);
1144 if (sf.otherDetails != null)
1147 * save feature attributes, which may be simple strings or
1148 * map valued (have sub-attributes)
1150 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1152 String key = entry.getKey();
1153 Object value = entry.getValue();
1154 if (value instanceof Map<?, ?>)
1156 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1159 OtherData otherData = new OtherData();
1160 otherData.setKey(key);
1161 otherData.setKey2(subAttribute.getKey());
1162 otherData.setValue(subAttribute.getValue().toString());
1163 // features.addOtherData(otherData);
1164 features.getOtherData().add(otherData);
1169 OtherData otherData = new OtherData();
1170 otherData.setKey(key);
1171 otherData.setValue(value.toString());
1172 // features.addOtherData(otherData);
1173 features.getOtherData().add(otherData);
1178 // jseq.addFeatures(features);
1179 jseq.getFeatures().add(features);
1182 if (jdatasq.getAllPDBEntries() != null)
1184 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1185 while (en.hasMoreElements())
1187 Pdbids pdb = new Pdbids();
1188 jalview.datamodel.PDBEntry entry = en.nextElement();
1190 String pdbId = entry.getId();
1192 pdb.setType(entry.getType());
1195 * Store any structure views associated with this sequence. This
1196 * section copes with duplicate entries in the project, so a dataset
1197 * only view *should* be coped with sensibly.
1199 // This must have been loaded, is it still visible?
1200 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1201 if (Desktop.desktop != null)
1203 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1206 for (JInternalFrame jif : jifs)
1208 if (jif instanceof JalviewStructureDisplayI)
1210 viewFrames.add((JalviewStructureDisplayI) jif);
1215 else if (Jalview.isHeadlessMode()
1216 && Jalview.getInstance().getCommands() != null)
1219 StructureViewerBase.getAllStructureViewerBases());
1222 String matchedFile = null;
1223 for (JalviewStructureDisplayI viewFrame : viewFrames)
1225 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1226 matchedFile, viewFrame);
1228 * Only store each structure viewer's state once in the project
1229 * jar. First time through only (storeDS==false)
1231 String viewId = viewFrame.getViewId();
1232 String viewerType = viewFrame.getViewerType().toString();
1233 if (!storeDS && !viewIds.contains(viewId))
1235 viewIds.add(viewId);
1236 File viewerState = viewFrame.saveSession();
1237 if (viewerState != null)
1239 copyFileToJar(jout, viewerState.getPath(),
1240 getViewerJarEntryName(viewId), viewerType);
1245 "Failed to save viewer state for " + viewerType);
1250 if (matchedFile != null || entry.getFile() != null)
1252 if (entry.getFile() != null)
1255 matchedFile = entry.getFile();
1257 pdb.setFile(matchedFile); // entry.getFile());
1258 if (pdbfiles == null)
1260 pdbfiles = new ArrayList<>();
1263 if (!pdbfiles.contains(pdbId))
1265 pdbfiles.add(pdbId);
1266 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1270 Enumeration<String> props = entry.getProperties();
1271 if (props.hasMoreElements())
1273 // PdbentryItem item = new PdbentryItem();
1274 while (props.hasMoreElements())
1276 Property prop = new Property();
1277 String key = props.nextElement();
1279 prop.setValue(entry.getProperty(key).toString());
1280 // item.addProperty(prop);
1281 pdb.getProperty().add(prop);
1283 // pdb.addPdbentryItem(item);
1286 // jseq.addPdbids(pdb);
1287 jseq.getPdbids().add(pdb);
1291 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1293 // jms.addJSeq(jseq);
1294 object.getJSeq().add(jseq);
1297 if (!storeDS && av.hasHiddenRows())
1299 jal = av.getAlignment();
1303 if (storeDS && jal.getCodonFrames() != null)
1305 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1306 for (AlignedCodonFrame acf : jac)
1308 AlcodonFrame alc = new AlcodonFrame();
1309 if (acf.getProtMappings() != null
1310 && acf.getProtMappings().length > 0)
1312 boolean hasMap = false;
1313 SequenceI[] dnas = acf.getdnaSeqs();
1314 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1315 for (int m = 0; m < pmaps.length; m++)
1317 AlcodMap alcmap = new AlcodMap();
1318 alcmap.setDnasq(seqHash(dnas[m]));
1320 createVamsasMapping(pmaps[m], dnas[m], null, false));
1321 // alc.addAlcodMap(alcmap);
1322 alc.getAlcodMap().add(alcmap);
1327 // vamsasSet.addAlcodonFrame(alc);
1328 vamsasSet.getAlcodonFrame().add(alc);
1331 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1333 // AlcodonFrame alc = new AlcodonFrame();
1334 // vamsasSet.addAlcodonFrame(alc);
1335 // for (int p = 0; p < acf.aaWidth; p++)
1337 // Alcodon cmap = new Alcodon();
1338 // if (acf.codons[p] != null)
1340 // // Null codons indicate a gapped column in the translated peptide
1342 // cmap.setPos1(acf.codons[p][0]);
1343 // cmap.setPos2(acf.codons[p][1]);
1344 // cmap.setPos3(acf.codons[p][2]);
1346 // alc.addAlcodon(cmap);
1348 // if (acf.getProtMappings() != null
1349 // && acf.getProtMappings().length > 0)
1351 // SequenceI[] dnas = acf.getdnaSeqs();
1352 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1353 // for (int m = 0; m < pmaps.length; m++)
1355 // AlcodMap alcmap = new AlcodMap();
1356 // alcmap.setDnasq(seqHash(dnas[m]));
1357 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1359 // alc.addAlcodMap(alcmap);
1366 // /////////////////////////////////
1367 if (!storeDS && av.getCurrentTree() != null)
1369 // FIND ANY ASSOCIATED TREES
1370 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1371 if (Desktop.desktop != null)
1373 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1375 for (int t = 0; t < frames.length; t++)
1377 if (frames[t] instanceof TreePanel)
1379 TreePanel tp = (TreePanel) frames[t];
1381 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1383 JalviewModel.Tree tree = new JalviewModel.Tree();
1384 tree.setTitle(tp.getTitle());
1385 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1386 tree.setNewick(tp.getTree().print());
1387 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1389 tree.setFitToWindow(tp.fitToWindow.getState());
1390 tree.setFontName(tp.getTreeFont().getName());
1391 tree.setFontSize(tp.getTreeFont().getSize());
1392 tree.setFontStyle(tp.getTreeFont().getStyle());
1393 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1395 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1396 tree.setShowDistances(tp.distanceMenu.getState());
1398 tree.setHeight(tp.getHeight());
1399 tree.setWidth(tp.getWidth());
1400 tree.setXpos(tp.getX());
1401 tree.setYpos(tp.getY());
1402 tree.setId(makeHashCode(tp, null));
1403 tree.setLinkToAllViews(
1404 tp.getTreeCanvas().isApplyToAllViews());
1407 if (tp.isColumnWise())
1409 tree.setColumnWise(true);
1410 String annId = tp.getAssocAnnotation().annotationId;
1411 tree.setColumnReference(annId);
1413 // jms.addTree(tree);
1414 object.getTree().add(tree);
1424 if (!storeDS && Desktop.desktop != null)
1426 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1428 if (frame instanceof PCAPanel)
1430 PCAPanel panel = (PCAPanel) frame;
1431 if (panel.getAlignViewport().getAlignment() == jal)
1433 savePCA(panel, object);
1436 if (frame instanceof PaSiMapPanel)
1438 PaSiMapPanel panel = (PaSiMapPanel) frame;
1439 if (panel.getAlignViewport().getAlignment() == jal)
1441 savePaSiMap(panel, object);
1449 * store forward refs from an annotationRow to any groups
1451 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1454 for (SequenceI sq : jal.getSequences())
1456 // Store annotation on dataset sequences only
1457 AlignmentAnnotation[] aa = sq.getAnnotation();
1458 if (aa != null && aa.length > 0)
1460 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1467 if (jal.getAlignmentAnnotation() != null)
1469 // Store the annotation shown on the alignment.
1470 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1471 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1476 if (jal.getGroups() != null)
1478 JGroup[] groups = new JGroup[jal.getGroups().size()];
1480 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1482 JGroup jGroup = new JGroup();
1483 groups[++i] = jGroup;
1485 jGroup.setStart(sg.getStartRes());
1486 jGroup.setEnd(sg.getEndRes());
1487 jGroup.setName(sg.getName());
1488 if (groupRefs.containsKey(sg))
1490 // group has references so set its ID field
1491 jGroup.setId(groupRefs.get(sg));
1493 ColourSchemeI colourScheme = sg.getColourScheme();
1494 if (colourScheme != null)
1496 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1497 if (groupColourScheme.conservationApplied())
1499 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1501 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1503 jGroup.setColour(setUserColourScheme(colourScheme,
1504 userColours, object));
1508 jGroup.setColour(colourScheme.getSchemeName());
1511 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1513 jGroup.setColour("AnnotationColourGradient");
1514 jGroup.setAnnotationColours(constructAnnotationColours(
1515 (jalview.schemes.AnnotationColourGradient) colourScheme,
1516 userColours, object));
1518 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1521 setUserColourScheme(colourScheme, userColours, object));
1525 jGroup.setColour(colourScheme.getSchemeName());
1528 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1531 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1532 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1533 jGroup.setDisplayText(sg.getDisplayText());
1534 jGroup.setColourText(sg.getColourText());
1535 jGroup.setTextCol1(sg.textColour.getRGB());
1536 jGroup.setTextCol2(sg.textColour2.getRGB());
1537 jGroup.setTextColThreshold(sg.thresholdTextColour);
1538 jGroup.setShowUnconserved(sg.getShowNonconserved());
1539 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1540 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1541 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1542 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1543 for (SequenceI seq : sg.getSequences())
1545 // jGroup.addSeq(seqHash(seq));
1546 jGroup.getSeq().add(seqHash(seq));
1550 // jms.setJGroup(groups);
1552 for (JGroup grp : groups)
1554 object.getJGroup().add(grp);
1559 // /////////SAVE VIEWPORT
1560 Viewport view = new Viewport();
1561 view.setTitle(ap.alignFrame.getTitle());
1562 view.setSequenceSetId(
1563 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1564 view.setId(av.getViewId());
1565 if (av.getCodingComplement() != null)
1567 view.setComplementId(av.getCodingComplement().getViewId());
1569 view.setViewName(av.getViewName());
1570 view.setGatheredViews(av.isGatherViewsHere());
1572 Rectangle size = ap.av.getExplodedGeometry();
1573 Rectangle position = size;
1576 size = ap.alignFrame.getBounds();
1577 if (av.getCodingComplement() != null)
1579 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1587 view.setXpos(position.x);
1588 view.setYpos(position.y);
1590 view.setWidth(size.width);
1591 view.setHeight(size.height);
1593 view.setStartRes(vpRanges.getStartRes());
1594 view.setStartSeq(vpRanges.getStartSeq());
1596 OverviewPanel ov = ap.getOverviewPanel();
1599 Overview overview = new Overview();
1600 overview.setTitle(ov.getTitle());
1601 Rectangle bounds = ov.getFrameBounds();
1602 overview.setXpos(bounds.x);
1603 overview.setYpos(bounds.y);
1604 overview.setWidth(bounds.width);
1605 overview.setHeight(bounds.height);
1606 overview.setShowHidden(ov.isShowHiddenRegions());
1607 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1608 overview.setResidueColour(
1609 ov.getCanvas().getResidueColour().getRGB());
1610 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1611 view.setOverview(overview);
1613 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1615 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1616 userColours, object));
1619 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1621 AnnotationColourScheme ac = constructAnnotationColours(
1622 (jalview.schemes.AnnotationColourGradient) av
1623 .getGlobalColourScheme(),
1624 userColours, object);
1626 view.setAnnotationColours(ac);
1627 view.setBgColour("AnnotationColourGradient");
1631 view.setBgColour(ColourSchemeProperty
1632 .getColourName(av.getGlobalColourScheme()));
1635 ResidueShaderI vcs = av.getResidueShading();
1636 ColourSchemeI cs = av.getGlobalColourScheme();
1640 if (vcs.conservationApplied())
1642 view.setConsThreshold(vcs.getConservationInc());
1643 if (cs instanceof jalview.schemes.UserColourScheme)
1645 view.setBgColour(setUserColourScheme(cs, userColours, object));
1648 view.setPidThreshold(vcs.getThreshold());
1651 view.setConservationSelected(av.getConservationSelected());
1652 view.setPidSelected(av.getAbovePIDThreshold());
1653 view.setCharHeight(av.getCharHeight());
1654 view.setCharWidth(av.getCharWidth());
1655 final Font font = av.getFont();
1656 view.setFontName(font.getName());
1657 view.setFontSize(font.getSize());
1658 view.setFontStyle(font.getStyle());
1659 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1660 view.setRenderGaps(av.isRenderGaps());
1661 view.setShowAnnotation(av.isShowAnnotation());
1662 view.setShowBoxes(av.getShowBoxes());
1663 view.setShowColourText(av.getColourText());
1664 view.setShowFullId(av.getShowJVSuffix());
1665 view.setRightAlignIds(av.isRightAlignIds());
1666 view.setIdWidth(av.getIdWidth());
1667 view.setIdWidthManuallyAdjusted(
1668 ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1670 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1671 view.setShowText(av.getShowText());
1672 view.setShowUnconserved(av.getShowUnconserved());
1673 view.setWrapAlignment(av.getWrapAlignment());
1674 view.setTextCol1(av.getTextColour().getRGB());
1675 view.setTextCol2(av.getTextColour2().getRGB());
1676 view.setTextColThreshold(av.getThresholdTextColour());
1677 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1678 view.setShowSequenceLogo(av.isShowSequenceLogo());
1679 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1680 view.setShowGroupConsensus(av.isShowGroupConsensus());
1681 view.setShowGroupConservation(av.isShowGroupConservation());
1682 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1683 view.setShowDbRefTooltip(av.isShowDBRefs());
1684 view.setFollowHighlight(av.isFollowHighlight());
1685 view.setFollowSelection(av.followSelection);
1686 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1687 view.setShowComplementFeatures(av.isShowComplementFeatures());
1688 view.setShowComplementFeaturesOnTop(
1689 av.isShowComplementFeaturesOnTop());
1690 if (av.getFeaturesDisplayed() != null)
1692 FeatureSettings fs = new FeatureSettings();
1694 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1695 .getFeatureRenderer();
1696 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1698 Vector<String> settingsAdded = new Vector<>();
1699 if (renderOrder != null)
1701 for (String featureType : renderOrder)
1703 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1704 setting.setType(featureType);
1707 * save any filter for the feature type
1709 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1712 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1714 FeatureMatcherI firstFilter = filters.next();
1715 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1716 filters, filter.isAnded()));
1720 * save colour scheme for the feature type
1722 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1723 if (!fcol.isSimpleColour())
1725 setting.setColour(fcol.getMaxColour().getRGB());
1726 setting.setMincolour(fcol.getMinColour().getRGB());
1727 setting.setMin(fcol.getMin());
1728 setting.setMax(fcol.getMax());
1729 setting.setColourByLabel(fcol.isColourByLabel());
1730 if (fcol.isColourByAttribute())
1732 String[] attName = fcol.getAttributeName();
1733 setting.getAttributeName().add(attName[0]);
1734 if (attName.length > 1)
1736 setting.getAttributeName().add(attName[1]);
1739 setting.setAutoScale(fcol.isAutoScaled());
1740 setting.setThreshold(fcol.getThreshold());
1741 Color noColour = fcol.getNoColour();
1742 if (noColour == null)
1744 setting.setNoValueColour(NoValueColour.NONE);
1746 else if (noColour.equals(fcol.getMaxColour()))
1748 setting.setNoValueColour(NoValueColour.MAX);
1752 setting.setNoValueColour(NoValueColour.MIN);
1754 // -1 = No threshold, 0 = Below, 1 = Above
1755 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1756 : (fcol.isBelowThreshold() ? 0 : -1));
1760 setting.setColour(fcol.getColour().getRGB());
1764 av.getFeaturesDisplayed().isVisible(featureType));
1765 float rorder = fr.getOrder(featureType);
1768 setting.setOrder(rorder);
1770 /// fs.addSetting(setting);
1771 fs.getSetting().add(setting);
1772 settingsAdded.addElement(featureType);
1776 // is groups actually supposed to be a map here ?
1777 Iterator<String> en = fr.getFeatureGroups().iterator();
1778 Vector<String> groupsAdded = new Vector<>();
1779 while (en.hasNext())
1781 String grp = en.next();
1782 if (groupsAdded.contains(grp))
1786 Group g = new Group();
1788 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1791 fs.getGroup().add(g);
1792 groupsAdded.addElement(grp);
1794 // jms.setFeatureSettings(fs);
1795 object.setFeatureSettings(fs);
1798 if (av.hasHiddenColumns())
1800 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1801 .getHiddenColumns();
1805 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1809 Iterator<int[]> hiddenRegions = hidden.iterator();
1810 while (hiddenRegions.hasNext())
1812 int[] region = hiddenRegions.next();
1813 HiddenColumns hc = new HiddenColumns();
1814 hc.setStart(region[0]);
1815 hc.setEnd(region[1]);
1816 // view.addHiddenColumns(hc);
1817 view.getHiddenColumns().add(hc);
1821 if (calcIdSet.size() > 0)
1823 for (String calcId : calcIdSet)
1825 if (calcId.trim().length() > 0)
1827 CalcIdParam cidp = createCalcIdParam(calcId, av);
1828 // Some calcIds have no parameters.
1831 // view.addCalcIdParam(cidp);
1832 view.getCalcIdParam().add(cidp);
1838 // jms.addViewport(view);
1839 object.getViewport().add(view);
1844 // store matrices referenced by any views or annotation in this dataset
1845 if (xmlMatrices != null && xmlMatrices.size() > 0)
1848 "Adding " + xmlMatrices.size() + " matrices to dataset.");
1849 vamsasSet.getMatrix().addAll(xmlMatrices);
1850 xmlMatrices.clear();
1854 // object.setJalviewModelSequence(jms);
1855 // object.getVamsasModel().addSequenceSet(vamsasSet);
1856 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1858 if (jout != null && fileName != null)
1860 // We may not want to write the object to disk,
1861 // eg we can copy the alignViewport to a new view object
1862 // using save and then load
1865 fileName = fileName.replace('\\', '/');
1866 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1867 JarEntry entry = new JarEntry(fileName);
1868 jout.putNextEntry(entry);
1869 PrintWriter pout = new PrintWriter(
1870 new OutputStreamWriter(jout, UTF_8));
1871 JAXBContext jaxbContext = JAXBContext
1872 .newInstance(JalviewModel.class);
1873 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1875 // output pretty printed
1876 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1877 jaxbMarshaller.marshal(
1878 new ObjectFactory().createJalviewModel(object), pout);
1880 // jaxbMarshaller.marshal(object, pout);
1881 // marshaller.marshal(object);
1884 } catch (Exception ex)
1886 // TODO: raise error in GUI if marshalling failed.
1887 jalview.bin.Console.errPrintln("Error writing Jalview project");
1888 ex.printStackTrace();
1895 * Writes PCA viewer attributes and computed values to an XML model object and
1896 * adds it to the JalviewModel. Any exceptions are reported by logging.
1898 protected void savePCA(PCAPanel panel, JalviewModel object)
1902 PcaViewer viewer = new PcaViewer();
1903 viewer.setHeight(panel.getHeight());
1904 viewer.setWidth(panel.getWidth());
1905 viewer.setXpos(panel.getX());
1906 viewer.setYpos(panel.getY());
1907 viewer.setTitle(panel.getTitle());
1908 PCAModel pcaModel = panel.getPcaModel();
1909 viewer.setScoreModelName(pcaModel.getScoreModelName());
1910 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1911 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1912 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1914 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1915 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1916 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1917 SeqPointMin spmin = new SeqPointMin();
1918 spmin.setXPos(spMin[0]);
1919 spmin.setYPos(spMin[1]);
1920 spmin.setZPos(spMin[2]);
1921 viewer.setSeqPointMin(spmin);
1922 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1923 SeqPointMax spmax = new SeqPointMax();
1924 spmax.setXPos(spMax[0]);
1925 spmax.setYPos(spMax[1]);
1926 spmax.setZPos(spMax[2]);
1927 viewer.setSeqPointMax(spmax);
1928 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1929 viewer.setLinkToAllViews(
1930 panel.getRotatableCanvas().isApplyToAllViews());
1931 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1932 viewer.setIncludeGaps(sp.includeGaps());
1933 viewer.setMatchGaps(sp.matchGaps());
1934 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1935 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1938 * sequence points on display
1940 for (jalview.datamodel.SequencePoint spt : pcaModel
1941 .getSequencePoints())
1943 SequencePoint point = new SequencePoint();
1944 point.setSequenceRef(seqHash(spt.getSequence()));
1945 point.setXPos(spt.coord.x);
1946 point.setYPos(spt.coord.y);
1947 point.setZPos(spt.coord.z);
1948 viewer.getSequencePoint().add(point);
1952 * (end points of) axes on display
1954 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1957 Axis axis = new Axis();
1961 viewer.getAxis().add(axis);
1965 * raw PCA data (note we are not restoring PCA inputs here -
1966 * alignment view, score model, similarity parameters)
1968 PcaDataType data = new PcaDataType();
1969 viewer.setPcaData(data);
1970 PCA pca = pcaModel.getPcaData();
1972 DoubleMatrix pm = new DoubleMatrix();
1973 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1974 data.setPairwiseMatrix(pm);
1976 DoubleMatrix tm = new DoubleMatrix();
1977 saveDoubleMatrix(pca.getTridiagonal(), tm);
1978 data.setTridiagonalMatrix(tm);
1980 DoubleMatrix eigenMatrix = new DoubleMatrix();
1981 data.setEigenMatrix(eigenMatrix);
1982 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1984 object.getPcaViewer().add(viewer);
1985 } catch (Throwable t)
1987 Console.error("Error saving PCA: " + t.getMessage());
1992 * Writes PaSiMap viewer attributes and computed values to an XML model object and
1993 * adds it to the JalviewModel. Any exceptions are reported by logging.
1994 * uses the functions from PCA
1996 protected void savePaSiMap(PaSiMapPanel panel, JalviewModel object)
1998 // TODO: this should be merged with above savePCAPanel - otherwise it is essentially redundant code
2001 PcaViewer viewer = new PcaViewer();
2002 viewer.setHeight(panel.getHeight());
2003 viewer.setWidth(panel.getWidth());
2004 viewer.setXpos(panel.getX());
2005 viewer.setYpos(panel.getY());
2006 viewer.setTitle(panel.getTitle());
2007 PaSiMapModel pasimapModel = panel.getPasimapModel();
2008 viewer.setScoreModelName(pasimapModel.getScoreModelName());
2009 viewer.setXDim(panel.getSelectedDimensionIndex(X));
2010 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
2011 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
2013 panel.getRotatableCanvas().getBackgroundColour().getRGB());
2014 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
2015 float[] spMin = panel.getRotatableCanvas().getSeqMin();
2016 SeqPointMin spmin = new SeqPointMin();
2017 spmin.setXPos(spMin[0]);
2018 spmin.setYPos(spMin[1]);
2019 spmin.setZPos(spMin[2]);
2020 viewer.setSeqPointMin(spmin);
2021 float[] spMax = panel.getRotatableCanvas().getSeqMax();
2022 SeqPointMax spmax = new SeqPointMax();
2023 spmax.setXPos(spMax[0]);
2024 spmax.setYPos(spMax[1]);
2025 spmax.setZPos(spMax[2]);
2026 viewer.setSeqPointMax(spmax);
2027 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
2028 viewer.setLinkToAllViews(
2029 panel.getRotatableCanvas().isApplyToAllViews());
2030 /* NOT FOR PASIMAP CALCULATIONS
2032 SimilarityParamsI sp = pasimapModel.getSimilarityParameters();
2033 viewer.setIncludeGaps(sp.includeGaps());
2034 viewer.setMatchGaps(sp.matchGaps());
2035 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
2036 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
2040 * sequence points on display
2042 for (jalview.datamodel.SequencePoint spt : pasimapModel
2043 .getSequencePoints())
2045 SequencePoint point = new SequencePoint();
2046 point.setSequenceRef(seqHash(spt.getSequence()));
2047 point.setXPos(spt.coord.x);
2048 point.setYPos(spt.coord.y);
2049 point.setZPos(spt.coord.z);
2050 viewer.getSequencePoint().add(point);
2054 * (end points of) axes on display
2056 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
2059 Axis axis = new Axis();
2063 viewer.getAxis().add(axis);
2067 * raw PaSiMap data (note we are not restoring PaSiMap inputs here -
2068 * alignment view, score model, similarity parameters)
2070 PcaDataType data = new PcaDataType();
2071 viewer.setPcaData(data);
2072 PaSiMap pasimap = pasimapModel.getPasimapData();
2074 DoubleMatrix pm = new DoubleMatrix();
2075 saveDoubleMatrix(pasimap.getPairwiseScores(), pm);
2076 data.setPairwiseMatrix(pm);
2078 DoubleMatrix eigenMatrix = new DoubleMatrix();
2079 data.setEigenMatrix(eigenMatrix);
2080 saveDoubleMatrix(pasimap.getEigenmatrix(), eigenMatrix);
2082 object.getPcaViewer().add(viewer);
2083 } catch (Throwable t)
2085 Console.error("Error saving PaSiMap: " + t.getMessage());
2089 * Stores values from a matrix into an XML element, including (if present) the
2094 * @see #loadDoubleMatrix(DoubleMatrix)
2096 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
2098 xmlMatrix.setRows(m.height());
2099 xmlMatrix.setColumns(m.width());
2100 for (int i = 0; i < m.height(); i++)
2102 DoubleVector row = new DoubleVector();
2103 for (int j = 0; j < m.width(); j++)
2105 row.getV().add(m.getValue(i, j));
2107 xmlMatrix.getRow().add(row);
2109 if (m.getD() != null)
2111 DoubleVector dVector = new DoubleVector();
2112 for (double d : m.getD())
2114 dVector.getV().add(d);
2116 xmlMatrix.setD(dVector);
2118 if (m.getE() != null)
2120 DoubleVector eVector = new DoubleVector();
2121 for (double e : m.getE())
2123 eVector.getV().add(e);
2125 xmlMatrix.setE(eVector);
2130 * Loads XML matrix data into a new Matrix object, including the D and/or E
2131 * vectors (if present)
2135 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2137 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2139 int rows = mData.getRows();
2140 double[][] vals = new double[rows][];
2142 for (int i = 0; i < rows; i++)
2144 List<Double> dVector = mData.getRow().get(i).getV();
2145 vals[i] = new double[dVector.size()];
2147 for (Double d : dVector)
2153 MatrixI m = new Matrix(vals);
2155 if (mData.getD() != null)
2157 List<Double> dVector = mData.getD().getV();
2158 double[] vec = new double[dVector.size()];
2160 for (Double d : dVector)
2166 if (mData.getE() != null)
2168 List<Double> dVector = mData.getE().getV();
2169 double[] vec = new double[dVector.size()];
2171 for (Double d : dVector)
2182 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2183 * for each viewer, with
2185 * <li>viewer geometry (position, size, split pane divider location)</li>
2186 * <li>index of the selected structure in the viewer (currently shows gapped
2188 * <li>the id of the annotation holding RNA secondary structure</li>
2189 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2191 * Varna viewer state is also written out (in native Varna XML) to separate
2192 * project jar entries. A separate entry is written for each RNA structure
2193 * displayed, with the naming convention
2195 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2203 * @param storeDataset
2205 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2206 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2207 boolean storeDataset)
2209 if (Desktop.desktop == null)
2213 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2214 for (int f = frames.length - 1; f > -1; f--)
2216 if (frames[f] instanceof AppVarna)
2218 AppVarna varna = (AppVarna) frames[f];
2220 * link the sequence to every viewer that is showing it and is linked to
2221 * its alignment panel
2223 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2225 String viewId = varna.getViewId();
2226 RnaViewer rna = new RnaViewer();
2227 rna.setViewId(viewId);
2228 rna.setTitle(varna.getTitle());
2229 rna.setXpos(varna.getX());
2230 rna.setYpos(varna.getY());
2231 rna.setWidth(varna.getWidth());
2232 rna.setHeight(varna.getHeight());
2233 rna.setDividerLocation(varna.getDividerLocation());
2234 rna.setSelectedRna(varna.getSelectedIndex());
2235 // jseq.addRnaViewer(rna);
2236 jseq.getRnaViewer().add(rna);
2239 * Store each Varna panel's state once in the project per sequence.
2240 * First time through only (storeDataset==false)
2242 // boolean storeSessions = false;
2243 // String sequenceViewId = viewId + seqsToIds.get(jds);
2244 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2246 // viewIds.add(sequenceViewId);
2247 // storeSessions = true;
2249 for (RnaModel model : varna.getModels())
2251 if (model.seq == jds)
2254 * VARNA saves each view (sequence or alignment secondary
2255 * structure, gapped or trimmed) as a separate XML file
2257 String jarEntryName = rnaSessions.get(model);
2258 if (jarEntryName == null)
2261 String varnaStateFile = varna.getStateInfo(model.rna);
2262 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2263 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2264 rnaSessions.put(model, jarEntryName);
2266 SecondaryStructure ss = new SecondaryStructure();
2267 String annotationId = varna.getAnnotation(jds).annotationId;
2268 ss.setAnnotationId(annotationId);
2269 ss.setViewerState(jarEntryName);
2270 ss.setGapped(model.gapped);
2271 ss.setTitle(model.title);
2272 // rna.addSecondaryStructure(ss);
2273 rna.getSecondaryStructure().add(ss);
2282 * Copy the contents of a file to a new entry added to the output jar
2286 * @param jarEntryName
2288 * additional identifying info to log to the console
2290 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2291 String jarEntryName, String msg)
2293 try (InputStream is = new FileInputStream(infilePath))
2295 File file = new File(infilePath);
2296 if (file.exists() && jout != null)
2298 jalview.bin.Console.outPrintln(
2299 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2300 jout.putNextEntry(new JarEntry(jarEntryName));
2303 // dis = new DataInputStream(new FileInputStream(file));
2304 // byte[] data = new byte[(int) file.length()];
2305 // dis.readFully(data);
2306 // writeJarEntry(jout, jarEntryName, data);
2308 } catch (Exception ex)
2310 ex.printStackTrace();
2315 * Copies input to output, in 4K buffers; handles any data (text or binary)
2319 * @throws IOException
2321 protected void copyAll(InputStream in, OutputStream out)
2324 byte[] buffer = new byte[4096];
2326 while ((bytesRead = in.read(buffer)) != -1)
2328 out.write(buffer, 0, bytesRead);
2333 * Save the state of a structure viewer
2338 * the archive XML element under which to save the state
2341 * @param matchedFile
2345 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2346 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2347 String matchedFile, JalviewStructureDisplayI viewFrame)
2349 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2352 * Look for any bindings for this viewer to the PDB file of interest
2353 * (including part matches excluding chain id)
2355 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2357 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2358 final String pdbId = pdbentry.getId();
2359 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2360 && entry.getId().toLowerCase(Locale.ROOT)
2361 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2364 * not interested in a binding to a different PDB entry here
2368 if (matchedFile == null)
2370 matchedFile = pdbentry.getFile();
2372 else if (!matchedFile.equals(pdbentry.getFile()))
2375 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2376 + pdbentry.getFile());
2380 // can get at it if the ID
2381 // match is ambiguous (e.g.
2384 for (int smap = 0; smap < viewFrame.getBinding()
2385 .getSequence()[peid].length; smap++)
2387 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2388 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2390 StructureState state = new StructureState();
2391 state.setVisible(true);
2392 state.setXpos(viewFrame.getY());
2393 state.setYpos(viewFrame.getY());
2394 state.setWidth(viewFrame.getWidth());
2395 state.setHeight(viewFrame.getHeight());
2396 final String viewId = viewFrame.getViewId();
2397 state.setViewId(viewId);
2398 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2399 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2400 state.setColourByJmol(viewFrame.isColouredByViewer());
2401 state.setType(viewFrame.getViewerType().toString());
2402 // pdb.addStructureState(state);
2403 pdb.getStructureState().add(state);
2411 * Populates the AnnotationColourScheme xml for save. This captures the
2412 * settings of the options in the 'Colour by Annotation' dialog.
2415 * @param userColours
2419 private AnnotationColourScheme constructAnnotationColours(
2420 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2423 AnnotationColourScheme ac = new AnnotationColourScheme();
2424 ac.setAboveThreshold(acg.getAboveThreshold());
2425 ac.setThreshold(acg.getAnnotationThreshold());
2426 // 2.10.2 save annotationId (unique) not annotation label
2427 ac.setAnnotation(acg.getAnnotation().annotationId);
2428 if (acg.getBaseColour() instanceof UserColourScheme)
2431 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2436 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2439 ac.setMaxColour(acg.getMaxColour().getRGB());
2440 ac.setMinColour(acg.getMinColour().getRGB());
2441 ac.setPerSequence(acg.isSeqAssociated());
2442 ac.setPredefinedColours(acg.isPredefinedColours());
2446 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2447 IdentityHashMap<SequenceGroup, String> groupRefs,
2448 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2449 SequenceSet vamsasSet)
2452 for (int i = 0; i < aa.length; i++)
2454 Annotation an = new Annotation();
2456 AlignmentAnnotation annotation = aa[i];
2457 if (annotation.annotationId != null)
2459 annotationIds.put(annotation.annotationId, annotation);
2462 an.setId(annotation.annotationId);
2464 an.setVisible(annotation.visible);
2466 an.setDescription(annotation.description);
2468 if (annotation.sequenceRef != null)
2470 // 2.9 JAL-1781 xref on sequence id rather than name
2471 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2473 if (annotation.groupRef != null)
2475 String groupIdr = groupRefs.get(annotation.groupRef);
2476 if (groupIdr == null)
2478 // make a locally unique String
2479 groupRefs.put(annotation.groupRef,
2480 groupIdr = ("" + System.currentTimeMillis()
2481 + annotation.groupRef.getName()
2482 + groupRefs.size()));
2484 an.setGroupRef(groupIdr.toString());
2487 // store all visualization attributes for annotation
2488 an.setGraphHeight(annotation.graphHeight);
2489 an.setCentreColLabels(annotation.centreColLabels);
2490 an.setScaleColLabels(annotation.scaleColLabel);
2491 an.setShowAllColLabels(annotation.showAllColLabels);
2492 an.setBelowAlignment(annotation.belowAlignment);
2494 if (annotation.graph > 0)
2497 an.setGraphType(annotation.graph);
2498 an.setGraphGroup(annotation.graphGroup);
2499 if (annotation.getThreshold() != null)
2501 ThresholdLine line = new ThresholdLine();
2502 line.setLabel(annotation.getThreshold().label);
2503 line.setValue(annotation.getThreshold().value);
2504 line.setColour(annotation.getThreshold().colour.getRGB());
2505 an.setThresholdLine(line);
2507 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2509 if (annotation.sequenceRef.getContactMaps() != null)
2511 ContactMatrixI cm = annotation.sequenceRef
2512 .getContactMatrixFor(annotation);
2515 storeMatrixFor(vamsasSet, an, annotation, cm);
2525 an.setLabel(annotation.label);
2527 if (annotation == av.getAlignmentQualityAnnot()
2528 || annotation == av.getAlignmentConservationAnnotation()
2529 || annotation == av.getAlignmentConsensusAnnotation()
2530 || annotation.autoCalculated)
2532 // new way of indicating autocalculated annotation -
2533 an.setAutoCalculated(annotation.autoCalculated);
2535 if (annotation.hasScore())
2537 an.setScore(annotation.getScore());
2540 if (annotation.getCalcId() != null)
2542 calcIdSet.add(annotation.getCalcId());
2543 an.setCalcId(annotation.getCalcId());
2545 if (annotation.hasProperties())
2547 for (String pr : annotation.getProperties())
2549 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2551 prop.setValue(annotation.getProperty(pr));
2552 an.getProperty().add(prop);
2556 AnnotationElement ae;
2557 if (annotation.annotations != null)
2559 an.setScoreOnly(false);
2560 for (int a = 0; a < annotation.annotations.length; a++)
2562 if ((annotation == null) || (annotation.annotations[a] == null))
2567 ae = new AnnotationElement();
2568 if (annotation.annotations[a].description != null)
2570 ae.setDescription(annotation.annotations[a].description);
2572 if (annotation.annotations[a].displayCharacter != null)
2574 ae.setDisplayCharacter(
2575 annotation.annotations[a].displayCharacter);
2578 if (!Float.isNaN(annotation.annotations[a].value))
2580 ae.setValue(annotation.annotations[a].value);
2584 if (annotation.annotations[a].secondaryStructure > ' ')
2586 ae.setSecondaryStructure(
2587 annotation.annotations[a].secondaryStructure + "");
2590 if (annotation.annotations[a].colour != null
2591 && annotation.annotations[a].colour != java.awt.Color.black)
2593 ae.setColour(annotation.annotations[a].colour.getRGB());
2596 // an.addAnnotationElement(ae);
2597 an.getAnnotationElement().add(ae);
2598 if (annotation.autoCalculated)
2600 // only write one non-null entry into the annotation row -
2601 // sufficient to get the visualization attributes necessary to
2609 an.setScoreOnly(true);
2611 if (!storeDS || (storeDS && !annotation.autoCalculated))
2613 // skip autocalculated annotation - these are only provided for
2615 // vamsasSet.addAnnotation(an);
2616 vamsasSet.getAnnotation().add(an);
2622 private void storeMatrixFor(SequenceSet root, Annotation an,
2623 AlignmentAnnotation annotation, ContactMatrixI cm)
2625 String cmId = contactMatrices.get(cm);
2626 MatrixType xmlmat = null;
2628 // first create an xml ref for the matrix data, if none exist
2631 xmlmat = new MatrixType();
2632 xmlmat.setType(cm.getType());
2633 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2634 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2635 // consider using an opaque to/from -> allow instance to control
2636 // its representation ?
2637 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2640 for (BitSet gp : cm.getGroups())
2642 xmlmat.getGroups().add(stringifyBitset(gp));
2647 // provenance object for tree ?
2648 xmlmat.getNewick().add(cm.getNewick());
2649 xmlmat.setTreeMethod(cm.getTreeMethod());
2651 if (cm.hasCutHeight())
2653 xmlmat.setCutHeight(cm.getCutHeight());
2655 xmlmat.setId(cmId = "m" + contactMatrices.size()
2656 + System.currentTimeMillis());
2657 Console.trace("Matrix data stored :" + cmId);
2658 contactMatrices.put(cm, cmId);
2659 contactMatrixRefs.put(cmId, cm);
2660 xmlMatrices.add(xmlmat);
2664 Console.trace("Existing Matrix stored :" + cmId);
2667 // now store mapping
2669 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2670 xmlmatmapping.setMatrix(cmId);
2672 // Pretty much all matrices currently managed in this way are
2673 // mappableContactMatrixI implementations - but check anyway
2674 if (cm instanceof MappableContactMatrixI)
2676 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2677 .getMapFor(annotation.sequenceRef);
2680 MapListType mp = new MapListType();
2681 List<int[]> r = mlst.getFromRanges();
2682 for (int[] range : r)
2684 MapListFrom mfrom = new MapListFrom();
2685 mfrom.setStart(range[0]);
2686 mfrom.setEnd(range[1]);
2687 // mp.addMapListFrom(mfrom);
2688 mp.getMapListFrom().add(mfrom);
2690 r = mlst.getToRanges();
2691 for (int[] range : r)
2693 MapListTo mto = new MapListTo();
2694 mto.setStart(range[0]);
2695 mto.setEnd(range[1]);
2696 // mp.addMapListTo(mto);
2697 mp.getMapListTo().add(mto);
2699 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2700 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2701 xmlmatmapping.setMapping(mp);
2705 an.getContactmatrix().add(xmlmatmapping);
2708 private String stringifyBitset(BitSet gp)
2710 StringBuilder sb = new StringBuilder();
2711 for (long val : gp.toLongArray())
2713 if (sb.length() > 0)
2719 return sb.toString();
2722 private BitSet deStringifyBitset(String stringified)
2724 if ("".equals(stringified) || stringified == null)
2726 return new BitSet();
2728 String[] longvals = stringified.split(",");
2729 long[] newlongvals = new long[longvals.length];
2730 for (int lv = 0; lv < longvals.length; lv++)
2734 newlongvals[lv] = Long.valueOf(longvals[lv]);
2735 } catch (Exception x)
2737 errorMessage += "Couldn't destringify bitset from: '" + stringified
2739 newlongvals[lv] = 0;
2742 return BitSet.valueOf(newlongvals);
2746 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2748 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2749 if (settings != null)
2751 CalcIdParam vCalcIdParam = new CalcIdParam();
2752 vCalcIdParam.setCalcId(calcId);
2753 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2754 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2755 // generic URI allowing a third party to resolve another instance of the
2756 // service used for this calculation
2757 for (String url : settings.getServiceURLs())
2759 // vCalcIdParam.addServiceURL(urls);
2760 vCalcIdParam.getServiceURL().add(url);
2762 vCalcIdParam.setVersion("1.0");
2763 if (settings.getPreset() != null)
2765 WsParamSetI setting = settings.getPreset();
2766 vCalcIdParam.setName(setting.getName());
2767 vCalcIdParam.setDescription(setting.getDescription());
2771 vCalcIdParam.setName("");
2772 vCalcIdParam.setDescription("Last used parameters");
2774 // need to be able to recover 1) settings 2) user-defined presets or
2775 // recreate settings from preset 3) predefined settings provided by
2776 // service - or settings that can be transferred (or discarded)
2777 vCalcIdParam.setParameters(
2778 settings.getWsParamFile().replace("\n", "|\\n|"));
2779 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2780 // todo - decide if updateImmediately is needed for any projects.
2782 return vCalcIdParam;
2787 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2790 if (calcIdParam.getVersion().equals("1.0"))
2792 final String[] calcIds = calcIdParam.getServiceURL()
2793 .toArray(new String[0]);
2794 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2795 .getPreferredServiceFor(calcIds);
2796 if (service != null)
2798 WsParamSetI parmSet = null;
2801 parmSet = service.getParamStore().parseServiceParameterFile(
2802 calcIdParam.getName(), calcIdParam.getDescription(),
2804 calcIdParam.getParameters().replace("|\\n|", "\n"));
2805 } catch (IOException x)
2807 Console.warn("Couldn't parse parameter data for "
2808 + calcIdParam.getCalcId(), x);
2811 List<ArgumentI> argList = null;
2812 if (calcIdParam.getName().length() > 0)
2814 parmSet = service.getParamStore()
2815 .getPreset(calcIdParam.getName());
2816 if (parmSet != null)
2818 // TODO : check we have a good match with settings in AACon -
2819 // otherwise we'll need to create a new preset
2824 argList = parmSet.getArguments();
2827 AAConSettings settings = new AAConSettings(
2828 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2829 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2830 calcIdParam.isNeedsUpdate());
2836 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2840 throw new Error(MessageManager.formatMessage(
2841 "error.unsupported_version_calcIdparam", new Object[]
2842 { calcIdParam.toString() }));
2846 * External mapping between jalview objects and objects yielding a valid and
2847 * unique object ID string. This is null for normal Jalview project IO, but
2848 * non-null when a jalview project is being read or written as part of a
2851 IdentityHashMap jv2vobj = null;
2854 * Construct a unique ID for jvobj using either existing bindings or if none
2855 * exist, the result of the hashcode call for the object.
2858 * jalview data object
2859 * @return unique ID for referring to jvobj
2861 private String makeHashCode(Object jvobj, String altCode)
2863 if (jv2vobj != null)
2865 Object id = jv2vobj.get(jvobj);
2868 return id.toString();
2870 // check string ID mappings
2871 if (jvids2vobj != null && jvobj instanceof String)
2873 id = jvids2vobj.get(jvobj);
2877 return id.toString();
2879 // give up and warn that something has gone wrong
2881 "Cannot find ID for object in external mapping : " + jvobj);
2887 * return local jalview object mapped to ID, if it exists
2891 * @return null or object bound to idcode
2893 private Object retrieveExistingObj(String idcode)
2895 if (idcode != null && vobj2jv != null)
2897 return vobj2jv.get(idcode);
2903 * binding from ID strings from external mapping table to jalview data model
2906 private Hashtable vobj2jv;
2908 private Sequence createVamsasSequence(String id, SequenceI jds)
2910 return createVamsasSequence(true, id, jds, null);
2913 private Sequence createVamsasSequence(boolean recurse, String id,
2914 SequenceI jds, SequenceI parentseq)
2916 Sequence vamsasSeq = new Sequence();
2917 vamsasSeq.setId(id);
2918 vamsasSeq.setName(jds.getName());
2919 vamsasSeq.setSequence(jds.getSequenceAsString());
2920 vamsasSeq.setDescription(jds.getDescription());
2921 List<DBRefEntry> dbrefs = null;
2922 if (jds.getDatasetSequence() != null)
2924 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2928 // seqId==dsseqid so we can tell which sequences really are
2929 // dataset sequences only
2930 vamsasSeq.setDsseqid(id);
2931 dbrefs = jds.getDBRefs();
2932 if (parentseq == null)
2939 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2943 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2945 DBRef dbref = new DBRef();
2946 DBRefEntry ref = dbrefs.get(d);
2947 dbref.setSource(ref.getSource());
2948 dbref.setVersion(ref.getVersion());
2949 dbref.setAccessionId(ref.getAccessionId());
2950 dbref.setCanonical(ref.isCanonical());
2951 if (ref instanceof GeneLocus)
2953 dbref.setLocus(true);
2957 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2959 dbref.setMapping(mp);
2961 vamsasSeq.getDBRef().add(dbref);
2967 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2968 SequenceI parentseq, SequenceI jds, boolean recurse)
2971 if (jmp.getMap() != null)
2975 jalview.util.MapList mlst = jmp.getMap();
2976 List<int[]> r = mlst.getFromRanges();
2977 for (int[] range : r)
2979 MapListFrom mfrom = new MapListFrom();
2980 mfrom.setStart(range[0]);
2981 mfrom.setEnd(range[1]);
2982 // mp.addMapListFrom(mfrom);
2983 mp.getMapListFrom().add(mfrom);
2985 r = mlst.getToRanges();
2986 for (int[] range : r)
2988 MapListTo mto = new MapListTo();
2989 mto.setStart(range[0]);
2990 mto.setEnd(range[1]);
2991 // mp.addMapListTo(mto);
2992 mp.getMapListTo().add(mto);
2994 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2995 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2996 if (jmp.getTo() != null)
2998 // MappingChoice mpc = new MappingChoice();
3000 // check/create ID for the sequence referenced by getTo()
3003 SequenceI ps = null;
3004 if (parentseq != jmp.getTo()
3005 && parentseq.getDatasetSequence() != jmp.getTo())
3007 // chaining dbref rather than a handshaking one
3008 jmpid = seqHash(ps = jmp.getTo());
3012 jmpid = seqHash(ps = parentseq);
3014 // mpc.setDseqFor(jmpid);
3015 mp.setDseqFor(jmpid);
3016 if (!seqRefIds.containsKey(jmpid))
3018 Console.debug("creatign new DseqFor ID");
3019 seqRefIds.put(jmpid, ps);
3023 Console.debug("reusing DseqFor ID");
3026 // mp.setMappingChoice(mpc);
3032 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
3033 List<UserColourScheme> userColours, JalviewModel jm)
3036 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
3037 boolean newucs = false;
3038 if (!userColours.contains(ucs))
3040 userColours.add(ucs);
3043 id = "ucs" + userColours.indexOf(ucs);
3046 // actually create the scheme's entry in the XML model
3047 java.awt.Color[] colours = ucs.getColours();
3048 UserColours uc = new UserColours();
3049 // UserColourScheme jbucs = new UserColourScheme();
3050 JalviewUserColours jbucs = new JalviewUserColours();
3052 for (int i = 0; i < colours.length; i++)
3054 Colour col = new Colour();
3055 col.setName(ResidueProperties.aa[i]);
3056 col.setRGB(jalview.util.Format.getHexString(colours[i]));
3057 // jbucs.addColour(col);
3058 jbucs.getColour().add(col);
3060 if (ucs.getLowerCaseColours() != null)
3062 colours = ucs.getLowerCaseColours();
3063 for (int i = 0; i < colours.length; i++)
3065 Colour col = new Colour();
3066 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
3067 col.setRGB(jalview.util.Format.getHexString(colours[i]));
3068 // jbucs.addColour(col);
3069 jbucs.getColour().add(col);
3074 uc.setUserColourScheme(jbucs);
3075 // jm.addUserColours(uc);
3076 jm.getUserColours().add(uc);
3082 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
3085 List<UserColours> uc = jm.getUserColours();
3086 UserColours colours = null;
3088 for (int i = 0; i < uc.length; i++)
3090 if (uc[i].getId().equals(id))
3097 for (UserColours c : uc)
3099 if (c.getId().equals(id))
3106 java.awt.Color[] newColours = new java.awt.Color[24];
3108 for (int i = 0; i < 24; i++)
3110 newColours[i] = new java.awt.Color(Integer.parseInt(
3111 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
3112 colours.getUserColourScheme().getColour().get(i).getRGB(),
3116 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
3119 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3121 newColours = new java.awt.Color[23];
3122 for (int i = 0; i < 23; i++)
3124 newColours[i] = new java.awt.Color(
3125 Integer.parseInt(colours.getUserColourScheme().getColour()
3126 .get(i + 24).getRGB(), 16));
3128 ucs.setLowerCaseColours(newColours);
3135 * contains last error message (if any) encountered by XML loader.
3137 String errorMessage = null;
3140 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3141 * exceptions are raised during project XML parsing
3143 public boolean attemptversion1parse = false;
3146 * Load a jalview project archive from a jar file
3149 * - HTTP URL or filename
3151 public AlignFrame loadJalviewAlign(final Object file)
3154 jalview.gui.AlignFrame af = null;
3158 // create list to store references for any new Jmol viewers created
3159 newStructureViewers = new Vector<>();
3160 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3161 // Workaround is to make sure caller implements the JarInputStreamProvider
3163 // so we can re-open the jar input stream for each entry.
3165 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3166 af = loadJalviewAlign(jprovider);
3169 af.setMenusForViewport();
3171 } catch (MalformedURLException e)
3173 errorMessage = "Invalid URL format for '" + file + "'";
3179 SwingUtilities.invokeAndWait(new Runnable()
3184 setLoadingFinishedForNewStructureViewers();
3187 } catch (Exception x)
3190 .errPrintln("Error loading alignment: " + x.getMessage());
3196 @SuppressWarnings("unused")
3197 private jarInputStreamProvider createjarInputStreamProvider(
3198 final Object ofile) throws MalformedURLException
3201 // BH 2018 allow for bytes already attached to File object
3204 String file = (ofile instanceof File
3205 ? ((File) ofile).getCanonicalPath()
3206 : ofile.toString());
3207 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3210 errorMessage = null;
3211 uniqueSetSuffix = null;
3213 viewportsAdded.clear();
3214 frefedSequence = null;
3216 if (HttpUtils.startsWithHttpOrHttps(file))
3218 url = new URL(file);
3220 final URL _url = url;
3221 return new jarInputStreamProvider()
3225 public JarInputStream getJarInputStream() throws IOException
3229 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3230 // jarInputStream for
3231 // bytes.length=" + bytes.length);
3232 return new JarInputStream(new ByteArrayInputStream(bytes));
3236 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3237 // jarInputStream for "
3239 return new JarInputStream(HttpUtils.openStream(_url));
3243 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3244 // jarInputStream for
3246 return new JarInputStream(new FileInputStream(file));
3251 public String getFilename()
3256 } catch (IOException e)
3258 e.printStackTrace();
3264 * Recover jalview session from a jalview project archive. Caller may
3265 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3266 * themselves. Any null fields will be initialised with default values,
3267 * non-null fields are left alone.
3272 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3274 errorMessage = null;
3275 if (uniqueSetSuffix == null)
3277 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3279 if (seqRefIds == null)
3283 AlignFrame af = null, _af = null;
3284 List<AlignFrame> toRepaint = new ArrayList<AlignFrame>();
3285 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3286 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3287 final String file = jprovider.getFilename();
3290 JarInputStream jin = null;
3291 JarEntry jarentry = null;
3296 jin = jprovider.getJarInputStream();
3297 for (int i = 0; i < entryCount; i++)
3299 jarentry = jin.getNextJarEntry();
3302 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3304 JAXBContext jc = JAXBContext
3305 .newInstance("jalview.xml.binding.jalview");
3306 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3307 .createXMLStreamReader(jin);
3308 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3309 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3310 JalviewModel.class);
3311 JalviewModel object = jbe.getValue();
3313 if (true) // !skipViewport(object))
3315 _af = loadFromObject(object, file, true, jprovider);
3316 if (_af != null && object.getViewport().size() > 0)
3317 // getJalviewModelSequence().getViewportCount() > 0)
3322 // store a reference to the first view
3325 if (_af.getViewport().isGatherViewsHere())
3327 // if this is a gathered view, keep its reference since
3328 // after gathering views, only this frame will remain
3330 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3333 // Save dataset to register mappings once all resolved
3334 importedDatasets.put(
3335 af.getViewport().getAlignment().getDataset(),
3336 af.getViewport().getAlignment().getDataset());
3341 else if (jarentry != null)
3343 // Some other file here.
3346 } while (jarentry != null);
3348 resolveFrefedSequences();
3349 for (AlignFrame alignFrame : toRepaint)
3351 alignFrame.repaint();
3353 } catch (IOException ex)
3355 ex.printStackTrace();
3356 errorMessage = "Couldn't locate Jalview XML file : " + file;
3357 jalview.bin.Console.errPrintln(
3358 "Exception whilst loading jalview XML file : " + ex + "\n");
3359 } catch (Exception ex)
3362 .errPrintln("Parsing as Jalview Version 2 file failed.");
3363 ex.printStackTrace(System.err);
3364 if (attemptversion1parse)
3366 // used to attempt to parse as V1 castor-generated xml
3368 if (Desktop.instance != null)
3370 Desktop.instance.stopLoading();
3374 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3377 ex.printStackTrace();
3379 jalview.bin.Console.errPrintln(
3380 "Exception whilst loading jalview XML file : " + ex + "\n");
3381 } catch (OutOfMemoryError e)
3383 // Don't use the OOM Window here
3384 errorMessage = "Out of memory loading jalview XML file";
3386 .errPrintln("Out of memory whilst loading jalview XML file");
3387 e.printStackTrace();
3391 * Regather multiple views (with the same sequence set id) to the frame (if
3392 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3393 * views instead of separate frames. Note this doesn't restore a state where
3394 * some expanded views in turn have tabbed views - the last "first tab" read
3395 * in will play the role of gatherer for all.
3397 for (AlignFrame fr : gatherToThisFrame.values())
3399 Desktop.instance.gatherViews(fr);
3402 restoreSplitFrames();
3403 for (AlignmentI ds : importedDatasets.keySet())
3405 if (ds.getCodonFrames() != null)
3407 StructureSelectionManager
3408 .getStructureSelectionManager(Desktop.instance)
3409 .registerMappings(ds.getCodonFrames());
3412 if (errorMessage != null)
3417 if (Desktop.instance != null)
3419 Desktop.instance.stopLoading();
3426 * Try to reconstruct and display SplitFrame windows, where each contains
3427 * complementary dna and protein alignments. Done by pairing up AlignFrame
3428 * objects (created earlier) which have complementary viewport ids associated.
3430 protected void restoreSplitFrames()
3432 List<SplitFrame> gatherTo = new ArrayList<>();
3433 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3434 Map<String, AlignFrame> dna = new HashMap<>();
3437 * Identify the DNA alignments
3439 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3442 AlignFrame af = candidate.getValue();
3443 if (af.getViewport().getAlignment().isNucleotide())
3445 dna.put(candidate.getKey().getId(), af);
3450 * Try to match up the protein complements
3452 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3455 AlignFrame af = candidate.getValue();
3456 if (!af.getViewport().getAlignment().isNucleotide())
3458 String complementId = candidate.getKey().getComplementId();
3459 // only non-null complements should be in the Map
3460 if (complementId != null && dna.containsKey(complementId))
3462 final AlignFrame dnaFrame = dna.get(complementId);
3463 SplitFrame sf = createSplitFrame(dnaFrame, af);
3464 addedToSplitFrames.add(dnaFrame);
3465 addedToSplitFrames.add(af);
3466 dnaFrame.setMenusForViewport();
3467 af.setMenusForViewport();
3468 if (af.getViewport().isGatherViewsHere())
3477 * Open any that we failed to pair up (which shouldn't happen!) as
3478 * standalone AlignFrame's.
3480 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3483 AlignFrame af = candidate.getValue();
3484 if (!addedToSplitFrames.contains(af))
3486 Viewport view = candidate.getKey();
3487 Desktop.addInternalFrame(af, view.getTitle(),
3488 safeInt(view.getWidth()), safeInt(view.getHeight()));
3489 af.setMenusForViewport();
3490 jalview.bin.Console.errPrintln("Failed to restore view "
3491 + view.getTitle() + " to split frame");
3496 * Gather back into tabbed views as flagged.
3498 for (SplitFrame sf : gatherTo)
3500 Desktop.instance.gatherViews(sf);
3503 splitFrameCandidates.clear();
3507 * Construct and display one SplitFrame holding DNA and protein alignments.
3510 * @param proteinFrame
3513 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3514 AlignFrame proteinFrame)
3516 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3517 String title = MessageManager.getString("label.linked_view_title");
3518 int width = (int) dnaFrame.getBounds().getWidth();
3519 int height = (int) (dnaFrame.getBounds().getHeight()
3520 + proteinFrame.getBounds().getHeight() + 50);
3523 * SplitFrame location is saved to both enclosed frames
3525 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3526 Desktop.addInternalFrame(splitFrame, title, width, height);
3529 * And compute cDNA consensus (couldn't do earlier with consensus as
3530 * mappings were not yet present)
3532 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3538 * check errorMessage for a valid error message and raise an error box in the
3539 * GUI or write the current errorMessage to stderr and then clear the error
3542 protected void reportErrors()
3544 reportErrors(false);
3547 protected void reportErrors(final boolean saving)
3549 if (errorMessage != null)
3551 final String finalErrorMessage = errorMessage;
3554 javax.swing.SwingUtilities.invokeLater(new Runnable()
3559 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3561 "Error " + (saving ? "saving" : "loading")
3563 JvOptionPane.WARNING_MESSAGE);
3569 jalview.bin.Console.errPrintln(
3570 "Problem loading Jalview file: " + errorMessage);
3573 errorMessage = null;
3576 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3579 * when set, local views will be updated from view stored in JalviewXML
3580 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3581 * sync if this is set to true.
3583 private final boolean updateLocalViews = false;
3586 * Returns the path to a temporary file holding the PDB file for the given PDB
3587 * id. The first time of asking, searches for a file of that name in the
3588 * Jalview project jar, and copies it to a new temporary file. Any repeat
3589 * requests just return the path to the file previously created.
3595 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3598 if (alreadyLoadedPDB.containsKey(pdbId))
3600 return alreadyLoadedPDB.get(pdbId).toString();
3603 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3605 if (tempFile != null)
3607 alreadyLoadedPDB.put(pdbId, tempFile);
3613 * Copies the jar entry of given name to a new temporary file and returns the
3614 * path to the file, or null if the entry is not found.
3617 * @param jarEntryName
3619 * a prefix for the temporary file name, must be at least three
3621 * @param suffixModel
3622 * null or original file - so new file can be given the same suffix
3626 protected String copyJarEntry(jarInputStreamProvider jprovider,
3627 String jarEntryName, String prefix, String suffixModel)
3629 String suffix = ".tmp";
3630 if (suffixModel == null)
3632 suffixModel = jarEntryName;
3634 int sfpos = suffixModel.lastIndexOf(".");
3635 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3637 suffix = "." + suffixModel.substring(sfpos + 1);
3640 try (JarInputStream jin = jprovider.getJarInputStream())
3642 JarEntry entry = null;
3645 entry = jin.getNextJarEntry();
3646 } while (entry != null && !entry.getName().equals(jarEntryName));
3650 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3651 File outFile = File.createTempFile(prefix, suffix);
3652 outFile.deleteOnExit();
3653 try (OutputStream os = new FileOutputStream(outFile))
3657 String t = outFile.getAbsolutePath();
3663 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3665 } catch (Exception ex)
3667 ex.printStackTrace();
3673 private class JvAnnotRow
3675 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3682 * persisted version of annotation row from which to take vis properties
3684 public jalview.datamodel.AlignmentAnnotation template;
3687 * original position of the annotation row in the alignment
3693 * Load alignment frame from jalview XML DOM object
3695 * @param jalviewModel
3698 * filename source string
3699 * @param loadTreesAndStructures
3700 * when false only create Viewport
3702 * data source provider
3703 * @return alignment frame created from view stored in DOM
3705 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3706 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3708 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3710 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3712 // JalviewModelSequence jms = object.getJalviewModelSequence();
3714 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3716 Viewport view = (jalviewModel.getViewport().size() > 0)
3717 ? jalviewModel.getViewport().get(0)
3720 // ////////////////////////////////
3721 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3724 // If we just load in the same jar file again, the sequenceSetId
3725 // will be the same, and we end up with multiple references
3726 // to the same sequenceSet. We must modify this id on load
3727 // so that each load of the file gives a unique id
3730 * used to resolve correct alignment dataset for alignments with multiple
3733 String uniqueSeqSetId = null;
3734 String viewId = null;
3737 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3738 viewId = (view.getId() == null ? null
3739 : view.getId() + uniqueSetSuffix);
3742 // ////////////////////////////////
3743 // LOAD MATRICES (IF ANY)
3745 if (vamsasSet.getMatrix() != null && vamsasSet.getMatrix().size() > 0)
3747 importMatrixData(vamsasSet.getMatrix());
3750 // ////////////////////////////////
3753 List<SequenceI> hiddenSeqs = null;
3755 List<SequenceI> tmpseqs = new ArrayList<>();
3757 boolean multipleView = false;
3758 SequenceI referenceseqForView = null;
3759 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3760 List<JSeq> jseqs = jalviewModel.getJSeq();
3761 int vi = 0; // counter in vamsasSeq array
3762 for (int i = 0; i < jseqs.size(); i++)
3764 JSeq jseq = jseqs.get(i);
3765 String seqId = jseq.getId();
3767 SequenceI tmpSeq = seqRefIds.get(seqId);
3770 if (!incompleteSeqs.containsKey(seqId))
3772 // may not need this check, but keep it for at least 2.9,1 release
3773 if (tmpSeq.getStart() != jseq.getStart()
3774 || tmpSeq.getEnd() != jseq.getEnd())
3776 jalview.bin.Console.errPrintln(String.format(
3777 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3778 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3779 jseq.getStart(), jseq.getEnd()));
3784 incompleteSeqs.remove(seqId);
3786 if (vamsasSeqs.size() > vi
3787 && vamsasSeqs.get(vi).getId().equals(seqId))
3789 // most likely we are reading a dataset XML document so
3790 // update from vamsasSeq section of XML for this sequence
3791 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3792 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3793 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3798 // reading multiple views, so vamsasSeq set is a subset of JSeq
3799 multipleView = true;
3801 tmpSeq.setStart(jseq.getStart());
3802 tmpSeq.setEnd(jseq.getEnd());
3803 tmpseqs.add(tmpSeq);
3807 Sequence vamsasSeq = vamsasSeqs.get(vi);
3808 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3809 vamsasSeq.getSequence());
3810 tmpSeq.setDescription(vamsasSeq.getDescription());
3811 tmpSeq.setStart(jseq.getStart());
3812 tmpSeq.setEnd(jseq.getEnd());
3813 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3814 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3815 tmpseqs.add(tmpSeq);
3819 if (safeBoolean(jseq.isViewreference()))
3821 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3824 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3826 if (hiddenSeqs == null)
3828 hiddenSeqs = new ArrayList<>();
3831 hiddenSeqs.add(tmpSeq);
3836 // Create the alignment object from the sequence set
3837 // ///////////////////////////////
3838 SequenceI[] orderedSeqs = tmpseqs
3839 .toArray(new SequenceI[tmpseqs.size()]);
3841 AlignmentI al = null;
3842 // so we must create or recover the dataset alignment before going further
3843 // ///////////////////////////////
3844 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3846 // older jalview projects do not have a dataset - so creat alignment and
3848 al = new Alignment(orderedSeqs);
3849 al.setDataset(null);
3853 boolean isdsal = jalviewModel.getViewport().isEmpty();
3856 // we are importing a dataset record, so
3857 // recover reference to an alignment already materialsed as dataset
3858 al = getDatasetFor(vamsasSet.getDatasetId());
3862 // materialse the alignment
3863 al = new Alignment(orderedSeqs);
3867 addDatasetRef(vamsasSet.getDatasetId(), al);
3870 // finally, verify all data in vamsasSet is actually present in al
3871 // passing on flag indicating if it is actually a stored dataset
3872 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3875 if (referenceseqForView != null)
3877 al.setSeqrep(referenceseqForView);
3879 // / Add the alignment properties
3880 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3882 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3884 al.setProperty(ssp.getKey(), ssp.getValue());
3887 // ///////////////////////////////
3889 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3892 // load sequence features, database references and any associated PDB
3893 // structures for the alignment
3895 // prior to 2.10, this part would only be executed the first time a
3896 // sequence was encountered, but not afterwards.
3897 // now, for 2.10 projects, this is also done if the xml doc includes
3898 // dataset sequences not actually present in any particular view.
3900 for (int i = 0; i < vamsasSeqs.size(); i++)
3902 JSeq jseq = jseqs.get(i);
3903 if (jseq.getFeatures().size() > 0)
3905 List<Feature> features = jseq.getFeatures();
3906 for (int f = 0; f < features.size(); f++)
3908 Feature feat = features.get(f);
3909 SequenceFeature sf = new SequenceFeature(feat.getType(),
3910 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3911 safeFloat(feat.getScore()), feat.getFeatureGroup());
3912 sf.setStatus(feat.getStatus());
3915 * load any feature attributes - include map-valued attributes
3917 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3918 for (int od = 0; od < feat.getOtherData().size(); od++)
3920 OtherData keyValue = feat.getOtherData().get(od);
3921 String attributeName = keyValue.getKey();
3922 String attributeValue = keyValue.getValue();
3923 if (attributeName.startsWith("LINK"))
3925 sf.addLink(attributeValue);
3929 String subAttribute = keyValue.getKey2();
3930 if (subAttribute == null)
3932 // simple string-valued attribute
3933 sf.setValue(attributeName, attributeValue);
3937 // attribute 'key' has sub-attribute 'key2'
3938 if (!mapAttributes.containsKey(attributeName))
3940 mapAttributes.put(attributeName, new HashMap<>());
3942 mapAttributes.get(attributeName).put(subAttribute,
3947 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3950 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3953 // adds feature to datasequence's feature set (since Jalview 2.10)
3954 al.getSequenceAt(i).addSequenceFeature(sf);
3957 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3959 // adds dbrefs to datasequence's set (since Jalview 2.10)
3961 al.getSequenceAt(i).getDatasetSequence() == null
3962 ? al.getSequenceAt(i)
3963 : al.getSequenceAt(i).getDatasetSequence(),
3966 if (jseq.getPdbids().size() > 0)
3968 List<Pdbids> ids = jseq.getPdbids();
3969 for (int p = 0; p < ids.size(); p++)
3971 Pdbids pdbid = ids.get(p);
3972 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3973 entry.setId(pdbid.getId());
3974 if (pdbid.getType() != null)
3976 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3978 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3982 entry.setType(PDBEntry.Type.FILE);
3985 // jprovider is null when executing 'New View'
3986 if (pdbid.getFile() != null && jprovider != null)
3988 if (!pdbloaded.containsKey(pdbid.getFile()))
3990 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3995 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3999 if (pdbid.getPdbentryItem() != null)
4001 for (PdbentryItem item : pdbid.getPdbentryItem())
4003 for (Property pr : item.getProperty())
4005 entry.setProperty(pr.getName(), pr.getValue());
4010 for (Property prop : pdbid.getProperty())
4012 entry.setProperty(prop.getName(), prop.getValue());
4014 StructureSelectionManager
4015 .getStructureSelectionManager(Desktop.instance)
4016 .registerPDBEntry(entry);
4017 // adds PDBEntry to datasequence's set (since Jalview 2.10)
4018 if (al.getSequenceAt(i).getDatasetSequence() != null)
4020 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
4024 al.getSequenceAt(i).addPDBId(entry);
4029 } // end !multipleview
4031 // ///////////////////////////////
4032 // LOAD SEQUENCE MAPPINGS
4034 if (vamsasSet.getAlcodonFrame().size() > 0)
4036 // TODO Potentially this should only be done once for all views of an
4038 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
4039 for (int i = 0; i < alc.size(); i++)
4041 AlignedCodonFrame cf = new AlignedCodonFrame();
4042 if (alc.get(i).getAlcodMap().size() > 0)
4044 List<AlcodMap> maps = alc.get(i).getAlcodMap();
4045 for (int m = 0; m < maps.size(); m++)
4047 AlcodMap map = maps.get(m);
4048 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
4050 jalview.datamodel.Mapping mapping = null;
4051 // attach to dna sequence reference.
4052 if (map.getMapping() != null)
4054 mapping = addMapping(map.getMapping());
4055 if (dnaseq != null && mapping.getTo() != null)
4057 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
4063 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
4067 al.addCodonFrame(cf);
4072 // ////////////////////////////////
4074 List<JvAnnotRow> autoAlan = new ArrayList<>();
4077 * store any annotations which forward reference a group's ID
4079 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
4081 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
4083 List<Annotation> an = vamsasSet.getAnnotation();
4085 for (int i = 0; i < an.size(); i++)
4087 Annotation annotation = an.get(i);
4090 * test if annotation is automatically calculated for this view only
4092 boolean autoForView = false;
4093 if (annotation.getLabel().equals("Quality")
4094 || annotation.getLabel().equals("Conservation")
4095 || annotation.getLabel().equals("Consensus"))
4097 // Kludge for pre 2.5 projects which lacked the autocalculated flag
4099 // JAXB has no has() test; schema defaults value to false
4100 // if (!annotation.hasAutoCalculated())
4102 // annotation.setAutoCalculated(true);
4105 if (autoForView || annotation.isAutoCalculated())
4107 // remove ID - we don't recover annotation from other views for
4108 // view-specific annotation
4109 annotation.setId(null);
4112 // set visibility for other annotation in this view
4113 String annotationId = annotation.getId();
4114 if (annotationId != null && annotationIds.containsKey(annotationId))
4116 AlignmentAnnotation jda = annotationIds.get(annotationId);
4117 // in principle Visible should always be true for annotation displayed
4118 // in multiple views
4119 if (annotation.isVisible() != null)
4121 jda.visible = annotation.isVisible();
4124 al.addAnnotation(jda);
4128 // Construct new annotation from model.
4129 List<AnnotationElement> ae = annotation.getAnnotationElement();
4130 jalview.datamodel.Annotation[] anot = null;
4131 java.awt.Color firstColour = null;
4133 if (!annotation.isScoreOnly())
4135 anot = new jalview.datamodel.Annotation[al.getWidth()];
4136 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4138 AnnotationElement annElement = ae.get(aa);
4139 anpos = annElement.getPosition();
4141 if (anpos >= anot.length)
4146 float value = safeFloat(annElement.getValue());
4147 anot[anpos] = new jalview.datamodel.Annotation(
4148 annElement.getDisplayCharacter(),
4149 annElement.getDescription(),
4150 (annElement.getSecondaryStructure() == null
4151 || annElement.getSecondaryStructure()
4155 .getSecondaryStructure()
4158 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4159 if (firstColour == null)
4161 firstColour = anot[anpos].colour;
4165 jalview.datamodel.AlignmentAnnotation jaa = null;
4167 if (annotation.isGraph())
4169 float llim = 0, hlim = 0;
4170 // if (autoForView || an[i].isAutoCalculated()) {
4173 jaa = new jalview.datamodel.AlignmentAnnotation(
4174 annotation.getLabel(), annotation.getDescription(), anot,
4175 llim, hlim, safeInt(annotation.getGraphType()));
4177 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4178 jaa._linecolour = firstColour;
4179 if (annotation.getThresholdLine() != null)
4181 jaa.setThreshold(new jalview.datamodel.GraphLine(
4182 safeFloat(annotation.getThresholdLine().getValue()),
4183 annotation.getThresholdLine().getLabel(),
4184 new java.awt.Color(safeInt(
4185 annotation.getThresholdLine().getColour()))));
4187 if (autoForView || annotation.isAutoCalculated())
4189 // Hardwire the symbol display line to ensure that labels for
4190 // histograms are displayed
4196 jaa = new jalview.datamodel.AlignmentAnnotation(
4197 annotation.getLabel(), annotation.getDescription(), anot);
4198 jaa._linecolour = firstColour;
4200 // register new annotation
4201 if (annotation.getId() != null)
4203 annotationIds.put(annotation.getId(), jaa);
4204 jaa.annotationId = annotation.getId();
4206 // recover sequence association
4207 String sequenceRef = annotation.getSequenceRef();
4208 if (sequenceRef != null)
4210 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4211 SequenceI sequence = seqRefIds.get(sequenceRef);
4212 if (sequence == null)
4214 // in pre-2.9 projects sequence ref is to sequence name
4215 sequence = al.findName(sequenceRef);
4217 if (sequence != null)
4219 jaa.createSequenceMapping(sequence, 1, true);
4220 sequence.addAlignmentAnnotation(jaa);
4223 // and make a note of any group association
4224 if (annotation.getGroupRef() != null
4225 && annotation.getGroupRef().length() > 0)
4227 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4228 .get(annotation.getGroupRef());
4231 aal = new ArrayList<>();
4232 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4237 if (annotation.getScore() != null)
4239 jaa.setScore(annotation.getScore().doubleValue());
4241 if (annotation.isVisible() != null)
4243 jaa.visible = annotation.isVisible().booleanValue();
4246 if (annotation.isCentreColLabels() != null)
4248 jaa.centreColLabels = annotation.isCentreColLabels()
4252 if (annotation.isScaleColLabels() != null)
4254 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4256 if (annotation.isAutoCalculated())
4258 // newer files have an 'autoCalculated' flag and store calculation
4259 // state in viewport properties
4260 jaa.autoCalculated = true; // means annotation will be marked for
4261 // update at end of load.
4263 if (annotation.getGraphHeight() != null)
4265 jaa.graphHeight = annotation.getGraphHeight().intValue();
4267 jaa.belowAlignment = annotation.isBelowAlignment();
4268 jaa.setCalcId(annotation.getCalcId());
4269 if (annotation.getProperty().size() > 0)
4271 for (jalview.xml.binding.jalview.Property prop : annotation
4274 jaa.setProperty(prop.getName(), prop.getValue());
4277 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4279 if (annotation.getContactmatrix() != null
4280 && annotation.getContactmatrix().size() > 0)
4282 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4284 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4289 if (jaa.autoCalculated)
4291 autoAlan.add(new JvAnnotRow(i, jaa));
4294 // if (!autoForView)
4296 // add autocalculated group annotation and any user created annotation
4298 al.addAnnotation(jaa);
4302 // ///////////////////////
4304 // Create alignment markup and styles for this view
4305 if (jalviewModel.getJGroup().size() > 0)
4307 List<JGroup> groups = jalviewModel.getJGroup();
4308 boolean addAnnotSchemeGroup = false;
4309 for (int i = 0; i < groups.size(); i++)
4311 JGroup jGroup = groups.get(i);
4312 ColourSchemeI cs = null;
4313 if (jGroup.getColour() != null)
4315 if (jGroup.getColour().startsWith("ucs"))
4317 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4319 else if (jGroup.getColour().equals("AnnotationColourGradient")
4320 && jGroup.getAnnotationColours() != null)
4322 addAnnotSchemeGroup = true;
4326 cs = ColourSchemeProperty.getColourScheme(null, al,
4327 jGroup.getColour());
4330 int pidThreshold = safeInt(jGroup.getPidThreshold());
4332 Vector<SequenceI> seqs = new Vector<>();
4334 for (int s = 0; s < jGroup.getSeq().size(); s++)
4336 String seqId = jGroup.getSeq().get(s);
4337 SequenceI ts = seqRefIds.get(seqId);
4341 seqs.addElement(ts);
4345 if (seqs.size() < 1)
4350 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4351 safeBoolean(jGroup.isDisplayBoxes()),
4352 safeBoolean(jGroup.isDisplayText()),
4353 safeBoolean(jGroup.isColourText()),
4354 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4355 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4356 sg.getGroupColourScheme()
4357 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4358 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4360 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4361 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4362 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4363 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4364 // attributes with a default in the schema are never null
4365 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4366 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4367 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4368 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4369 if (jGroup.getConsThreshold() != null
4370 && jGroup.getConsThreshold().intValue() != 0)
4372 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4375 c.verdict(false, 25);
4376 sg.cs.setConservation(c);
4379 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4381 // re-instate unique group/annotation row reference
4382 List<AlignmentAnnotation> jaal = groupAnnotRefs
4383 .get(jGroup.getId());
4386 for (AlignmentAnnotation jaa : jaal)
4389 if (jaa.autoCalculated)
4391 // match up and try to set group autocalc alignment row for this
4393 if (jaa.label.startsWith("Consensus for "))
4395 sg.setConsensus(jaa);
4397 // match up and try to set group autocalc alignment row for this
4399 if (jaa.label.startsWith("Conservation for "))
4401 sg.setConservationRow(jaa);
4408 if (addAnnotSchemeGroup)
4410 // reconstruct the annotation colourscheme
4412 constructAnnotationColour(jGroup.getAnnotationColours(),
4413 null, al, jalviewModel, false));
4419 // only dataset in this model, so just return.
4422 // ///////////////////////////////
4425 AlignFrame af = null;
4426 AlignViewport av = null;
4427 // now check to see if we really need to create a new viewport.
4428 if (multipleView && viewportsAdded.size() == 0)
4430 // We recovered an alignment for which a viewport already exists.
4431 // TODO: fix up any settings necessary for overlaying stored state onto
4432 // state recovered from another document. (may not be necessary).
4433 // we may need a binding from a viewport in memory to one recovered from
4435 // and then recover its containing af to allow the settings to be applied.
4436 // TODO: fix for vamsas demo
4437 jalview.bin.Console.errPrintln(
4438 "About to recover a viewport for existing alignment: Sequence set ID is "
4440 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4441 if (seqsetobj != null)
4443 if (seqsetobj instanceof String)
4445 uniqueSeqSetId = (String) seqsetobj;
4446 jalview.bin.Console.errPrintln(
4447 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4452 jalview.bin.Console.errPrintln(
4453 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4459 * indicate that annotation colours are applied across all groups (pre
4460 * Jalview 2.8.1 behaviour)
4462 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4463 jalviewModel.getVersion());
4465 AlignmentPanel ap = null;
4466 boolean isnewview = true;
4469 // Check to see if this alignment already has a view id == viewId
4470 jalview.gui.AlignmentPanel views[] = Desktop
4471 .getAlignmentPanels(uniqueSeqSetId);
4472 if (views != null && views.length > 0)
4474 for (int v = 0; v < views.length; v++)
4476 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4478 // recover the existing alignpanel, alignframe, viewport
4479 af = views[v].alignFrame;
4482 // TODO: could even skip resetting view settings if we don't want to
4483 // change the local settings from other jalview processes
4492 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4493 uniqueSeqSetId, viewId, autoAlan);
4494 av = af.getViewport();
4499 * Load any trees, PDB structures and viewers, Overview
4501 * Not done if flag is false (when this method is used for New View)
4503 if (loadTreesAndStructures)
4505 loadTrees(jalviewModel, view, af, av, ap);
4506 loadPCAViewers(jalviewModel, ap);
4507 loadPaSiMapViewers(jalviewModel, ap);
4508 loadPDBStructures(jprovider, jseqs, af, ap);
4509 loadRnaViewers(jprovider, jseqs, ap);
4510 loadOverview(view, jalviewModel.getVersion(), af);
4512 // and finally return.
4516 private void importMatrixData(List<MatrixType> xmlmatrices)
4518 for (MatrixType xmlmat : xmlmatrices)
4520 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4522 Console.error("Ignoring matrix '" + xmlmat.getId() + "' of type '"
4523 + xmlmat.getType());
4527 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4529 Console.error("Can't handle non square matrices");
4533 float[][] elements = ContactMatrix.fromFloatStringToContacts(
4534 xmlmat.getElements(), xmlmat.getCols().intValue(),
4535 xmlmat.getRows().intValue());
4537 List<BitSet> newgroups = new ArrayList<BitSet>();
4538 if (xmlmat.getGroups().size() > 0)
4540 for (String sgroup : xmlmat.getGroups())
4542 newgroups.add(deStringifyBitset(sgroup));
4545 String nwk = xmlmat.getNewick().size() > 0 ? xmlmat.getNewick().get(0)
4547 if (xmlmat.getNewick().size() > 1)
4550 .info("Ignoring additional clusterings for contact matrix");
4552 String treeMethod = xmlmat.getTreeMethod();
4553 double thresh = xmlmat.getCutHeight() != null ? xmlmat.getCutHeight()
4555 GroupSet grpset = new GroupSet();
4556 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4558 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4559 contactMatrixRefs.put(xmlmat.getId(), newcm);
4560 Console.trace("Restored base contact matrix " + xmlmat.getId());
4564 private void restoreMatrixFor(SequenceI sequenceRef,
4565 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4567 // restore mapping data to matrix data
4568 jalview.util.MapList mapping = null;
4569 if (xmlmatmapping.getMapping() != null)
4571 MapListType m = xmlmatmapping.getMapping();
4572 // Mapping m = dr.getMapping();
4573 int fr[] = new int[m.getMapListFrom().size() * 2];
4574 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4575 for (int _i = 0; from.hasNext(); _i += 2)
4577 MapListFrom mf = from.next();
4578 fr[_i] = mf.getStart();
4579 fr[_i + 1] = mf.getEnd();
4581 int fto[] = new int[m.getMapListTo().size() * 2];
4582 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4583 for (int _i = 0; to.hasNext(); _i += 2)
4585 MapListTo mf = to.next();
4586 fto[_i] = mf.getStart();
4587 fto[_i + 1] = mf.getEnd();
4590 mapping = new jalview.util.MapList(fr, fto,
4591 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4594 // locate matrix data in project XML and import
4595 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4599 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4603 // create the PAEMatrix now
4604 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4607 jaa.sequenceRef.addContactListFor(jaa, newpae);
4614 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4615 * and geometry as saved
4620 protected void loadOverview(Viewport view, String version, AlignFrame af)
4622 if (!isVersionStringLaterThan("2.11.3", version)
4623 && view.getOverview() == null)
4628 * first close any Overview that was opened automatically
4629 * (if so configured in Preferences) so that the view is
4630 * restored in the same state as saved
4632 af.alignPanel.closeOverviewPanel();
4634 Overview overview = view.getOverview();
4635 if (overview != null)
4637 OverviewPanel overviewPanel = af
4638 .openOverviewPanel(overview.isShowHidden());
4639 overviewPanel.setTitle(overview.getTitle());
4640 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4641 overview.getWidth(), overview.getHeight());
4642 Color gap = new Color(overview.getGapColour());
4643 Color residue = new Color(overview.getResidueColour());
4644 Color hidden = new Color(overview.getHiddenColour());
4645 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4650 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4651 * panel is restored from separate jar entries, two (gapped and trimmed) per
4652 * sequence and secondary structure.
4654 * Currently each viewer shows just one sequence and structure (gapped and
4655 * trimmed), however this method is designed to support multiple sequences or
4656 * structures in viewers if wanted in future.
4662 private void loadRnaViewers(jarInputStreamProvider jprovider,
4663 List<JSeq> jseqs, AlignmentPanel ap)
4666 * scan the sequences for references to viewers; create each one the first
4667 * time it is referenced, add Rna models to existing viewers
4669 for (JSeq jseq : jseqs)
4671 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4673 RnaViewer viewer = jseq.getRnaViewer().get(i);
4674 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4677 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4679 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4680 SequenceI seq = seqRefIds.get(jseq.getId());
4681 AlignmentAnnotation ann = this.annotationIds
4682 .get(ss.getAnnotationId());
4685 * add the structure to the Varna display (with session state copied
4686 * from the jar to a temporary file)
4688 boolean gapped = safeBoolean(ss.isGapped());
4689 String rnaTitle = ss.getTitle();
4690 String sessionState = ss.getViewerState();
4691 String tempStateFile = copyJarEntry(jprovider, sessionState,
4693 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4694 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4696 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4702 * Locate and return an already instantiated matching AppVarna, or create one
4706 * @param viewIdSuffix
4710 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4711 String viewIdSuffix, AlignmentPanel ap)
4714 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4715 * if load is repeated
4717 String postLoadId = viewer.getViewId() + viewIdSuffix;
4718 for (JInternalFrame frame : getAllFrames())
4720 if (frame instanceof AppVarna)
4722 AppVarna varna = (AppVarna) frame;
4723 if (postLoadId.equals(varna.getViewId()))
4725 // this viewer is already instantiated
4726 // could in future here add ap as another 'parent' of the
4727 // AppVarna window; currently just 1-to-many
4734 * viewer not found - make it
4736 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4737 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4738 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4739 safeInt(viewer.getDividerLocation()));
4740 AppVarna varna = new AppVarna(model, ap);
4746 * Load any saved trees
4754 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4755 AlignViewport av, AlignmentPanel ap)
4757 // TODO result of automated refactoring - are all these parameters needed?
4760 for (int t = 0; t < jm.getTree().size(); t++)
4763 Tree tree = jm.getTree().get(t);
4765 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4768 if (tree.isColumnWise())
4770 AlignmentAnnotation aa = annotationIds
4771 .get(tree.getColumnReference());
4775 "Null alignment annotation when restoring columnwise tree");
4777 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4778 tree.getTitle(), safeInt(tree.getWidth()),
4779 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4780 safeInt(tree.getYpos()));
4785 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4786 tree.getTitle(), safeInt(tree.getWidth()),
4787 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4788 safeInt(tree.getYpos()));
4790 if (tree.getId() != null)
4792 // perhaps bind the tree id to something ?
4797 // update local tree attributes ?
4798 // TODO: should check if tp has been manipulated by user - if so its
4799 // settings shouldn't be modified
4800 tp.setTitle(tree.getTitle());
4801 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4802 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4803 safeInt(tree.getHeight())));
4804 tp.setViewport(av); // af.viewport;
4805 // TODO: verify 'associate with all views' works still
4806 tp.getTreeCanvas().setViewport(av); // af.viewport;
4807 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4809 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4813 "There was a problem recovering stored Newick tree: \n"
4814 + tree.getNewick());
4818 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4819 tp.fitToWindow_actionPerformed(null);
4821 if (tree.getFontName() != null)
4824 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4825 safeInt(tree.getFontSize())));
4830 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4831 safeInt(view.getFontSize())));
4834 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4835 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4836 tp.showDistances(safeBoolean(tree.isShowDistances()));
4838 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4840 if (safeBoolean(tree.isCurrentTree()))
4842 af.getViewport().setCurrentTree(tp.getTree());
4846 } catch (Exception ex)
4848 ex.printStackTrace();
4853 * Load and link any saved structure viewers.
4860 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4861 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4864 * Run through all PDB ids on the alignment, and collect mappings between
4865 * distinct view ids and all sequences referring to that view.
4867 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4869 for (int i = 0; i < jseqs.size(); i++)
4871 JSeq jseq = jseqs.get(i);
4872 if (jseq.getPdbids().size() > 0)
4874 List<Pdbids> ids = jseq.getPdbids();
4875 for (int p = 0; p < ids.size(); p++)
4877 Pdbids pdbid = ids.get(p);
4878 final int structureStateCount = pdbid.getStructureState().size();
4879 for (int s = 0; s < structureStateCount; s++)
4881 // check to see if we haven't already created this structure view
4882 final StructureState structureState = pdbid.getStructureState()
4884 String sviewid = (structureState.getViewId() == null) ? null
4885 : structureState.getViewId() + uniqueSetSuffix;
4886 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4887 // Originally : pdbid.getFile()
4888 // : TODO: verify external PDB file recovery still works in normal
4889 // jalview project load
4891 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4892 jpdb.setId(pdbid.getId());
4894 int x = safeInt(structureState.getXpos());
4895 int y = safeInt(structureState.getYpos());
4896 int width = safeInt(structureState.getWidth());
4897 int height = safeInt(structureState.getHeight());
4899 // Probably don't need to do this anymore...
4900 // Desktop.desktop.getComponentAt(x, y);
4901 // TODO: NOW: check that this recovers the PDB file correctly.
4902 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4904 jalview.datamodel.SequenceI seq = seqRefIds
4905 .get(jseq.getId() + "");
4906 if (sviewid == null)
4908 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4911 if (!structureViewers.containsKey(sviewid))
4913 String viewerType = structureState.getType();
4914 if (viewerType == null) // pre Jalview 2.9
4916 viewerType = ViewerType.JMOL.toString();
4918 structureViewers.put(sviewid,
4919 new StructureViewerModel(x, y, width, height, false,
4920 false, true, structureState.getViewId(),
4922 // Legacy pre-2.7 conversion JAL-823 :
4923 // do not assume any view has to be linked for colour by
4927 // assemble String[] { pdb files }, String[] { id for each
4928 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4929 // seqs_file 2}, boolean[] {
4930 // linkAlignPanel,superposeWithAlignpanel}} from hash
4931 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4932 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4933 || structureState.isAlignwithAlignPanel());
4936 * Default colour by linked panel to false if not specified (e.g.
4937 * for pre-2.7 projects)
4939 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4940 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4941 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4944 * Default colour by viewer to true if not specified (e.g. for
4947 boolean colourByViewer = jmoldat.isColourByViewer();
4948 colourByViewer &= structureState.isColourByJmol();
4949 jmoldat.setColourByViewer(colourByViewer);
4951 if (jmoldat.getStateData().length() < structureState.getValue()
4952 /*Content()*/.length())
4954 jmoldat.setStateData(structureState.getValue());// Content());
4956 if (pdbid.getFile() != null)
4958 File mapkey = new File(pdbid.getFile());
4959 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4960 if (seqstrmaps == null)
4962 jmoldat.getFileData().put(mapkey,
4963 seqstrmaps = jmoldat.new StructureData(pdbFile,
4966 if (!seqstrmaps.getSeqList().contains(seq))
4968 seqstrmaps.getSeqList().add(seq);
4974 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");
4975 Console.warn(errorMessage);
4981 // Instantiate the associated structure views
4982 for (Entry<String, StructureViewerModel> entry : structureViewers
4987 createOrLinkStructureViewer(entry, af, ap, jprovider);
4988 } catch (Exception e)
4990 jalview.bin.Console.errPrintln(
4991 "Error loading structure viewer: " + e.getMessage());
4992 // failed - try the next one
5004 protected void createOrLinkStructureViewer(
5005 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
5006 AlignmentPanel ap, jarInputStreamProvider jprovider)
5008 final StructureViewerModel stateData = viewerData.getValue();
5011 * Search for any viewer windows already open from other alignment views
5012 * that exactly match the stored structure state
5014 StructureViewerBase comp = findMatchingViewer(viewerData);
5018 linkStructureViewer(ap, comp, stateData);
5022 String type = stateData.getType();
5025 ViewerType viewerType = ViewerType.valueOf(type);
5026 createStructureViewer(viewerType, viewerData, af, jprovider);
5027 } catch (IllegalArgumentException | NullPointerException e)
5029 // TODO JAL-3619 show error dialog / offer an alternative viewer
5030 Console.error("Invalid structure viewer type: " + type);
5035 * Generates a name for the entry in the project jar file to hold state
5036 * information for a structure viewer
5041 protected String getViewerJarEntryName(String viewId)
5043 return VIEWER_PREFIX + viewId;
5047 * Returns any open frame that matches given structure viewer data. The match
5048 * is based on the unique viewId, or (for older project versions) the frame's
5054 protected StructureViewerBase findMatchingViewer(
5055 Entry<String, StructureViewerModel> viewerData)
5057 final String sviewid = viewerData.getKey();
5058 final StructureViewerModel svattrib = viewerData.getValue();
5059 StructureViewerBase comp = null;
5060 JInternalFrame[] frames = getAllFrames();
5061 for (JInternalFrame frame : frames)
5063 if (frame instanceof StructureViewerBase)
5066 * Post jalview 2.4 schema includes structure view id
5068 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
5071 comp = (StructureViewerBase) frame;
5072 break; // break added in 2.9
5075 * Otherwise test for matching position and size of viewer frame
5077 else if (frame.getX() == svattrib.getX()
5078 && frame.getY() == svattrib.getY()
5079 && frame.getHeight() == svattrib.getHeight()
5080 && frame.getWidth() == svattrib.getWidth())
5082 comp = (StructureViewerBase) frame;
5083 // no break in faint hope of an exact match on viewId
5091 * Link an AlignmentPanel to an existing structure viewer.
5096 * @param useinViewerSuperpos
5097 * @param usetoColourbyseq
5098 * @param viewerColouring
5100 protected void linkStructureViewer(AlignmentPanel ap,
5101 StructureViewerBase viewer, StructureViewerModel stateData)
5103 // NOTE: if the jalview project is part of a shared session then
5104 // view synchronization should/could be done here.
5106 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
5107 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
5108 final boolean viewerColouring = stateData.isColourByViewer();
5109 Map<File, StructureData> oldFiles = stateData.getFileData();
5112 * Add mapping for sequences in this view to an already open viewer
5114 final AAStructureBindingModel binding = viewer.getBinding();
5115 for (File id : oldFiles.keySet())
5117 // add this and any other pdb files that should be present in the
5119 StructureData filedat = oldFiles.get(id);
5120 String pdbFile = filedat.getFilePath();
5121 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5122 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5124 binding.addSequenceForStructFile(pdbFile, seq);
5126 // and add the AlignmentPanel's reference to the view panel
5127 viewer.addAlignmentPanel(ap);
5128 if (useinViewerSuperpos)
5130 viewer.useAlignmentPanelForSuperposition(ap);
5134 viewer.excludeAlignmentPanelForSuperposition(ap);
5136 if (usetoColourbyseq)
5138 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5142 viewer.excludeAlignmentPanelForColourbyseq(ap);
5147 * Get all frames within the Desktop.
5151 protected JInternalFrame[] getAllFrames()
5153 JInternalFrame[] frames = null;
5154 // TODO is this necessary - is it safe - risk of hanging?
5159 frames = Desktop.desktop.getAllFrames();
5160 } catch (ArrayIndexOutOfBoundsException e)
5162 // occasional No such child exceptions are thrown here...
5166 } catch (InterruptedException f)
5170 } while (frames == null);
5175 * Answers true if 'version' is equal to or later than 'supported', where each
5176 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5177 * changes. Development and test values for 'version' are leniently treated
5181 * - minimum version we are comparing against
5183 * - version of data being processsed
5184 * @return true if version is equal to or later than supported
5186 public static boolean isVersionStringLaterThan(String supported,
5189 if (supported == null || version == null
5190 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5191 || version.equalsIgnoreCase("Test")
5192 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5194 jalview.bin.Console.errPrintln("Assuming project file with "
5195 + (version == null ? "null" : version)
5196 + " is compatible with Jalview version " + supported);
5201 return StringUtils.compareVersions(version, supported, "b") >= 0;
5205 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5207 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5209 if (newStructureViewers != null)
5211 sview.getBinding().setFinishedLoadingFromArchive(false);
5212 newStructureViewers.add(sview);
5216 protected void setLoadingFinishedForNewStructureViewers()
5218 if (newStructureViewers != null)
5220 for (JalviewStructureDisplayI sview : newStructureViewers)
5222 sview.getBinding().setFinishedLoadingFromArchive(true);
5224 newStructureViewers.clear();
5225 newStructureViewers = null;
5229 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5230 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5231 Viewport view, String uniqueSeqSetId, String viewId,
5232 List<JvAnnotRow> autoAlan)
5234 AlignFrame af = null;
5235 af = new AlignFrame(al, safeInt(view.getWidth()),
5236 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5240 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5241 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5242 // super.processKeyEvent(e);
5249 af.setFileName(file, FileFormat.Jalview);
5251 final AlignViewport viewport = af.getViewport();
5252 for (int i = 0; i < JSEQ.size(); i++)
5254 int colour = safeInt(JSEQ.get(i).getColour());
5255 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5261 viewport.setColourByReferenceSeq(true);
5262 viewport.setDisplayReferenceSeq(true);
5265 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5267 if (view.getSequenceSetId() != null)
5269 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5271 viewport.setSequenceSetId(uniqueSeqSetId);
5274 // propagate shared settings to this new view
5275 viewport.setHistoryList(av.getHistoryList());
5276 viewport.setRedoList(av.getRedoList());
5280 viewportsAdded.put(uniqueSeqSetId, viewport);
5282 // TODO: check if this method can be called repeatedly without
5283 // side-effects if alignpanel already registered.
5284 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5286 // apply Hidden regions to view.
5287 if (hiddenSeqs != null)
5289 for (int s = 0; s < JSEQ.size(); s++)
5291 SequenceGroup hidden = new SequenceGroup();
5292 boolean isRepresentative = false;
5293 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5295 isRepresentative = true;
5296 SequenceI sequenceToHide = al
5297 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5298 hidden.addSequence(sequenceToHide, false);
5299 // remove from hiddenSeqs list so we don't try to hide it twice
5300 hiddenSeqs.remove(sequenceToHide);
5302 if (isRepresentative)
5304 SequenceI representativeSequence = al.getSequenceAt(s);
5305 hidden.addSequence(representativeSequence, false);
5306 viewport.hideRepSequences(representativeSequence, hidden);
5310 SequenceI[] hseqs = hiddenSeqs
5311 .toArray(new SequenceI[hiddenSeqs.size()]);
5312 viewport.hideSequence(hseqs);
5315 // recover view properties and display parameters
5317 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5318 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5319 final int pidThreshold = safeInt(view.getPidThreshold());
5320 viewport.setThreshold(pidThreshold);
5322 viewport.setColourText(safeBoolean(view.isShowColourText()));
5324 viewport.setConservationSelected(
5325 safeBoolean(view.isConservationSelected()));
5326 viewport.setIncrement(safeInt(view.getConsThreshold()));
5327 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5328 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5330 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5331 safeInt(view.getFontSize())),
5332 (view.getCharWidth() != null) ? false : true);
5333 if (view.getCharWidth() != null)
5335 viewport.setCharWidth(view.getCharWidth());
5336 viewport.setCharHeight(view.getCharHeight());
5338 ViewStyleI vs = viewport.getViewStyle();
5339 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5340 viewport.setViewStyle(vs);
5341 // TODO: allow custom charWidth/Heights to be restored by updating them
5342 // after setting font - which means set above to false
5343 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5344 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5345 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5347 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5349 viewport.setShowText(safeBoolean(view.isShowText()));
5351 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5352 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5353 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5354 viewport.setShowUnconserved(view.isShowUnconserved());
5355 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5357 if (view.getViewName() != null)
5359 viewport.setViewName(view.getViewName());
5360 af.setInitialTabVisible();
5362 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5363 safeInt(view.getWidth()), safeInt(view.getHeight()));
5365 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID
5367 if (view.getIdWidth() == null)
5369 if (!isVersionStringLaterThan("2.11.3", jm.getVersion()))
5371 // Pre 2.11.3 jalview projects do not store the id width
5372 // idWidth was also calculated in a different way.
5373 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5374 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5379 viewport.setIdWidth(view.getIdWidth());
5380 af.alignPanel.getIdPanel().getIdCanvas()
5381 .setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5384 // startSeq set in af.alignPanel.updateLayout below
5385 af.alignPanel.updateLayout();
5386 ColourSchemeI cs = null;
5387 // apply colourschemes
5388 if (view.getBgColour() != null)
5390 if (view.getBgColour().startsWith("ucs"))
5392 cs = getUserColourScheme(jm, view.getBgColour());
5394 else if (view.getBgColour().startsWith("Annotation"))
5396 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5397 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5404 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5405 view.getBgColour());
5410 * turn off 'alignment colour applies to all groups'
5411 * while restoring global colour scheme
5413 viewport.setColourAppliesToAllGroups(false);
5414 viewport.setGlobalColourScheme(cs);
5415 viewport.getResidueShading().setThreshold(pidThreshold,
5416 view.isIgnoreGapsinConsensus());
5417 viewport.getResidueShading()
5418 .setConsensus(viewport.getSequenceConsensusHash());
5419 viewport.getResidueShading()
5420 .setSsConsensus(viewport.getSequenceSSConsensusHash());
5421 if (safeBoolean(view.isConservationSelected()) && cs != null)
5423 viewport.getResidueShading()
5424 .setConservationInc(safeInt(view.getConsThreshold()));
5426 af.changeColour(cs);
5427 viewport.setColourAppliesToAllGroups(true);
5429 viewport.setShowSequenceFeatures(
5430 safeBoolean(view.isShowSequenceFeatures()));
5432 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5433 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5434 viewport.setFollowHighlight(view.isFollowHighlight());
5435 viewport.followSelection = view.isFollowSelection();
5436 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5437 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5438 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5439 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5440 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5441 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5442 viewport.setShowGroupConservation(view.isShowGroupConservation());
5443 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5444 viewport.setShowComplementFeaturesOnTop(
5445 view.isShowComplementFeaturesOnTop());
5447 // recover feature settings
5448 if (jm.getFeatureSettings() != null)
5450 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5451 .getFeatureRenderer();
5452 FeaturesDisplayed fdi;
5453 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5454 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5456 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5457 Map<String, Float> featureOrder = new Hashtable<>();
5459 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5462 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5463 String featureType = setting.getType();
5466 * restore feature filters (if any)
5468 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5470 if (filters != null)
5472 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5474 if (!filter.isEmpty())
5476 fr.setFeatureFilter(featureType, filter);
5481 * restore feature colour scheme
5483 Color maxColour = new Color(setting.getColour());
5484 if (setting.getMincolour() != null)
5487 * minColour is always set unless a simple colour
5488 * (including for colour by label though it doesn't use it)
5490 Color minColour = new Color(setting.getMincolour().intValue());
5491 Color noValueColour = minColour;
5492 NoValueColour noColour = setting.getNoValueColour();
5493 if (noColour == NoValueColour.NONE)
5495 noValueColour = null;
5497 else if (noColour == NoValueColour.MAX)
5499 noValueColour = maxColour;
5501 float min = safeFloat(safeFloat(setting.getMin()));
5502 float max = setting.getMax() == null ? 1f
5503 : setting.getMax().floatValue();
5504 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5505 maxColour, noValueColour, min, max);
5506 if (setting.getAttributeName().size() > 0)
5508 gc.setAttributeName(setting.getAttributeName().toArray(
5509 new String[setting.getAttributeName().size()]));
5511 if (setting.getThreshold() != null)
5513 gc.setThreshold(setting.getThreshold().floatValue());
5514 int threshstate = safeInt(setting.getThreshstate());
5515 // -1 = None, 0 = Below, 1 = Above threshold
5516 if (threshstate == 0)
5518 gc.setBelowThreshold(true);
5520 else if (threshstate == 1)
5522 gc.setAboveThreshold(true);
5525 gc.setAutoScaled(true); // default
5526 if (setting.isAutoScale() != null)
5528 gc.setAutoScaled(setting.isAutoScale());
5530 if (setting.isColourByLabel() != null)
5532 gc.setColourByLabel(setting.isColourByLabel());
5534 // and put in the feature colour table.
5535 featureColours.put(featureType, gc);
5539 featureColours.put(featureType, new FeatureColour(maxColour));
5541 renderOrder[fs] = featureType;
5542 if (setting.getOrder() != null)
5544 featureOrder.put(featureType, setting.getOrder().floatValue());
5548 featureOrder.put(featureType, Float.valueOf(
5549 fs / jm.getFeatureSettings().getSetting().size()));
5551 if (safeBoolean(setting.isDisplay()))
5553 fdi.setVisible(featureType);
5556 Map<String, Boolean> fgtable = new Hashtable<>();
5557 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5559 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5560 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5562 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5563 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5564 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5565 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5566 fgtable, featureColours, 1.0f, featureOrder);
5567 fr.transferSettings(frs);
5570 if (view.getHiddenColumns().size() > 0)
5572 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5574 final HiddenColumns hc = view.getHiddenColumns().get(c);
5575 viewport.hideColumns(safeInt(hc.getStart()),
5576 safeInt(hc.getEnd()) /* +1 */);
5579 if (view.getCalcIdParam() != null)
5581 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5583 if (calcIdParam != null)
5585 if (recoverCalcIdParam(calcIdParam, viewport))
5590 Console.warn("Couldn't recover parameters for "
5591 + calcIdParam.getCalcId());
5596 af.setMenusFromViewport(viewport);
5597 af.setTitle(view.getTitle());
5598 // TODO: we don't need to do this if the viewport is aready visible.
5600 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5601 * has a 'cdna/protein complement' view, in which case save it in order to
5602 * populate a SplitFrame once all views have been read in.
5604 String complementaryViewId = view.getComplementId();
5605 if (complementaryViewId == null)
5607 Desktop.addInternalFrame(af, view.getTitle(),
5608 safeInt(view.getWidth()), safeInt(view.getHeight()));
5609 // recompute any autoannotation
5610 af.alignPanel.updateAnnotation(false, true);
5611 reorderAutoannotation(af, al, autoAlan);
5612 af.alignPanel.alignmentChanged();
5616 splitFrameCandidates.put(view, af);
5623 * Reads saved data to restore Colour by Annotation settings
5625 * @param viewAnnColour
5629 * @param checkGroupAnnColour
5632 private ColourSchemeI constructAnnotationColour(
5633 AnnotationColourScheme viewAnnColour, AlignFrame af,
5634 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5636 boolean propagateAnnColour = false;
5637 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5639 if (checkGroupAnnColour && al.getGroups() != null
5640 && al.getGroups().size() > 0)
5642 // pre 2.8.1 behaviour
5643 // check to see if we should transfer annotation colours
5644 propagateAnnColour = true;
5645 for (SequenceGroup sg : al.getGroups())
5647 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5649 propagateAnnColour = false;
5655 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5657 String annotationId = viewAnnColour.getAnnotation();
5658 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5661 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5663 if (matchedAnnotation == null
5664 && annAlignment.getAlignmentAnnotation() != null)
5666 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5669 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5671 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5676 if (matchedAnnotation == null)
5679 .errPrintln("Failed to match annotation colour scheme for "
5683 // belt-and-braces create a threshold line if the
5684 // colourscheme needs one but the matchedAnnotation doesn't have one
5685 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5686 && matchedAnnotation.getThreshold() == null)
5688 matchedAnnotation.setThreshold(
5689 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5690 "Threshold", Color.black));
5693 AnnotationColourGradient cs = null;
5694 if (viewAnnColour.getColourScheme().equals("None"))
5696 cs = new AnnotationColourGradient(matchedAnnotation,
5697 new Color(safeInt(viewAnnColour.getMinColour())),
5698 new Color(safeInt(viewAnnColour.getMaxColour())),
5699 safeInt(viewAnnColour.getAboveThreshold()));
5701 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5703 cs = new AnnotationColourGradient(matchedAnnotation,
5704 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5705 safeInt(viewAnnColour.getAboveThreshold()));
5709 cs = new AnnotationColourGradient(matchedAnnotation,
5710 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5711 viewAnnColour.getColourScheme()),
5712 safeInt(viewAnnColour.getAboveThreshold()));
5715 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5716 boolean useOriginalColours = safeBoolean(
5717 viewAnnColour.isPredefinedColours());
5718 cs.setSeqAssociated(perSequenceOnly);
5719 cs.setPredefinedColours(useOriginalColours);
5721 if (propagateAnnColour && al.getGroups() != null)
5723 // Also use these settings for all the groups
5724 for (int g = 0; g < al.getGroups().size(); g++)
5726 SequenceGroup sg = al.getGroups().get(g);
5727 if (sg.getGroupColourScheme() == null)
5732 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5733 matchedAnnotation, sg.getColourScheme(),
5734 safeInt(viewAnnColour.getAboveThreshold()));
5735 sg.setColourScheme(groupScheme);
5736 groupScheme.setSeqAssociated(perSequenceOnly);
5737 groupScheme.setPredefinedColours(useOriginalColours);
5743 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5744 List<JvAnnotRow> autoAlan)
5746 // copy over visualization settings for autocalculated annotation in the
5748 if (al.getAlignmentAnnotation() != null)
5751 * Kludge for magic autoannotation names (see JAL-811)
5753 String[] magicNames = new String[] { "Consensus", "Quality",
5755 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5756 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5757 for (String nm : magicNames)
5759 visan.put(nm, nullAnnot);
5761 for (JvAnnotRow auan : autoAlan)
5763 visan.put(auan.template.label
5764 + (auan.template.getCalcId() == null ? ""
5765 : "\t" + auan.template.getCalcId()),
5768 int hSize = al.getAlignmentAnnotation().length;
5769 List<JvAnnotRow> reorder = new ArrayList<>();
5770 // work through any autoCalculated annotation already on the view
5771 // removing it if it should be placed in a different location on the
5772 // annotation panel.
5773 List<String> remains = new ArrayList<>(visan.keySet());
5774 for (int h = 0; h < hSize; h++)
5776 jalview.datamodel.AlignmentAnnotation jalan = al
5777 .getAlignmentAnnotation()[h];
5778 if (jalan.autoCalculated)
5781 JvAnnotRow valan = visan.get(k = jalan.label);
5782 if (jalan.getCalcId() != null)
5784 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5789 // delete the auto calculated row from the alignment
5790 al.deleteAnnotation(jalan, false);
5794 if (valan != nullAnnot)
5796 if (jalan != valan.template)
5798 // newly created autoannotation row instance
5799 // so keep a reference to the visible annotation row
5800 // and copy over all relevant attributes
5801 if (valan.template.graphHeight >= 0)
5804 jalan.graphHeight = valan.template.graphHeight;
5806 jalan.visible = valan.template.visible;
5808 reorder.add(new JvAnnotRow(valan.order, jalan));
5813 // Add any (possibly stale) autocalculated rows that were not appended to
5814 // the view during construction
5815 for (String other : remains)
5817 JvAnnotRow othera = visan.get(other);
5818 if (othera != nullAnnot && othera.template.getCalcId() != null
5819 && othera.template.getCalcId().length() > 0)
5821 reorder.add(othera);
5824 // now put the automatic annotation in its correct place
5825 int s = 0, srt[] = new int[reorder.size()];
5826 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5827 for (JvAnnotRow jvar : reorder)
5830 srt[s++] = jvar.order;
5833 jalview.util.QuickSort.sort(srt, rws);
5834 // and re-insert the annotation at its correct position
5835 for (JvAnnotRow jvar : rws)
5837 al.addAnnotation(jvar.template, jvar.order);
5839 af.alignPanel.adjustAnnotationHeight();
5843 Hashtable skipList = null;
5846 * TODO remove this method
5849 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5850 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5851 * throw new Error("Implementation Error. No skipList defined for this
5852 * Jalview2XML instance."); } return (AlignFrame)
5853 * skipList.get(view.getSequenceSetId()); }
5857 * Check if the Jalview view contained in object should be skipped or not.
5860 * @return true if view's sequenceSetId is a key in skipList
5862 private boolean skipViewport(JalviewModel object)
5864 if (skipList == null)
5868 String id = object.getViewport().get(0).getSequenceSetId();
5869 if (skipList.containsKey(id))
5871 Console.debug("Skipping seuqence set id " + id);
5877 public void addToSkipList(AlignFrame af)
5879 if (skipList == null)
5881 skipList = new Hashtable();
5883 skipList.put(af.getViewport().getSequenceSetId(), af);
5886 public void clearSkipList()
5888 if (skipList != null)
5895 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5896 boolean ignoreUnrefed, String uniqueSeqSetId)
5898 jalview.datamodel.AlignmentI ds = getDatasetFor(
5899 vamsasSet.getDatasetId());
5900 AlignmentI xtant_ds = ds;
5901 if (xtant_ds == null)
5903 // good chance we are about to create a new dataset, but check if we've
5904 // seen some of the dataset sequence IDs before.
5905 // TODO: skip this check if we are working with project generated by
5906 // version 2.11 or later
5907 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5908 if (xtant_ds != null)
5911 addDatasetRef(vamsasSet.getDatasetId(), ds);
5914 Vector<SequenceI> dseqs = null;
5917 // recovering an alignment View
5918 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5919 if (seqSetDS != null)
5921 if (ds != null && ds != seqSetDS)
5924 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5925 + " - CDS/Protein crossreference data may be lost");
5926 if (xtant_ds != null)
5928 // This can only happen if the unique sequence set ID was bound to a
5929 // dataset that did not contain any of the sequences in the view
5930 // currently being restored.
5932 "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.");
5936 addDatasetRef(vamsasSet.getDatasetId(), ds);
5941 // try even harder to restore dataset
5942 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5943 // create a list of new dataset sequences
5944 dseqs = new Vector<>();
5946 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5948 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5949 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5951 // create a new dataset
5954 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5955 dseqs.copyInto(dsseqs);
5956 ds = new jalview.datamodel.Alignment(dsseqs);
5957 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5958 + " for alignment " + System.identityHashCode(al));
5959 addDatasetRef(vamsasSet.getDatasetId(), ds);
5961 // set the dataset for the newly imported alignment.
5962 if (al.getDataset() == null && !ignoreUnrefed)
5965 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5966 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5968 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5972 * XML dataset sequence ID to materialised dataset reference
5974 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5977 * @return the first materialised dataset reference containing a dataset
5978 * sequence referenced in the given view
5980 * - sequences from the view
5982 AlignmentI checkIfHasDataset(List<Sequence> list)
5984 for (Sequence restoredSeq : list)
5986 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5987 if (datasetFor != null)
5996 * Register ds as the containing dataset for the dataset sequences referenced
5997 * by sequences in list
6000 * - sequences in a view
6003 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
6005 for (Sequence restoredSeq : list)
6007 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
6008 if (prevDS != null && prevDS != ds)
6010 Console.warn("Dataset sequence appears in many datasets: "
6011 + restoredSeq.getDsseqid());
6012 // TODO: try to merge!
6020 * sequence definition to create/merge dataset sequence for
6024 * vector to add new dataset sequence to
6025 * @param ignoreUnrefed
6026 * - when true, don't create new sequences from vamsasSeq if it's id
6027 * doesn't already have an asssociated Jalview sequence.
6029 * - used to reorder the sequence in the alignment according to the
6030 * vamsasSeq array ordering, to preserve ordering of dataset
6032 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
6033 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
6036 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
6038 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
6039 boolean reorder = false;
6040 SequenceI dsq = null;
6041 if (sq != null && sq.getDatasetSequence() != null)
6043 dsq = sq.getDatasetSequence();
6049 if (sq == null && ignoreUnrefed)
6053 String sqid = vamsasSeq.getDsseqid();
6056 // need to create or add a new dataset sequence reference to this sequence
6059 dsq = seqRefIds.get(sqid);
6064 // make a new dataset sequence
6065 dsq = sq.createDatasetSequence();
6068 // make up a new dataset reference for this sequence
6069 sqid = seqHash(dsq);
6071 dsq.setVamsasId(uniqueSetSuffix + sqid);
6072 seqRefIds.put(sqid, dsq);
6077 dseqs.addElement(dsq);
6082 ds.addSequence(dsq);
6088 { // make this dataset sequence sq's dataset sequence
6089 sq.setDatasetSequence(dsq);
6090 // and update the current dataset alignment
6095 if (!dseqs.contains(dsq))
6102 if (ds.findIndex(dsq) < 0)
6104 ds.addSequence(dsq);
6111 // TODO: refactor this as a merge dataset sequence function
6112 // now check that sq (the dataset sequence) sequence really is the union of
6113 // all references to it
6114 // boolean pre = sq.getStart() < dsq.getStart();
6115 // boolean post = sq.getEnd() > dsq.getEnd();
6119 // StringBuffer sb = new StringBuffer();
6120 String newres = jalview.analysis.AlignSeq.extractGaps(
6121 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
6122 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
6123 && newres.length() > dsq.getLength())
6125 // Update with the longer sequence.
6129 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
6130 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
6131 * sb.append(newres.substring(newres.length() - sq.getEnd() -
6132 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
6134 dsq.setSequence(newres);
6136 // TODO: merges will never happen if we 'know' we have the real dataset
6137 // sequence - this should be detected when id==dssid
6138 jalview.bin.Console.errPrintln(
6139 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
6140 // + (pre ? "prepended" : "") + " "
6141 // + (post ? "appended" : ""));
6146 // sequence refs are identical. We may need to update the existing dataset
6147 // alignment with this one, though.
6148 if (ds != null && dseqs == null)
6150 int opos = ds.findIndex(dsq);
6151 SequenceI tseq = null;
6152 if (opos != -1 && vseqpos != opos)
6154 // remove from old position
6155 ds.deleteSequence(dsq);
6157 if (vseqpos < ds.getHeight())
6159 if (vseqpos != opos)
6161 // save sequence at destination position
6162 tseq = ds.getSequenceAt(vseqpos);
6163 ds.replaceSequenceAt(vseqpos, dsq);
6164 ds.addSequence(tseq);
6169 ds.addSequence(dsq);
6176 * TODO use AlignmentI here and in related methods - needs
6177 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6179 Hashtable<String, AlignmentI> datasetIds = null;
6181 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6183 private AlignmentI getDatasetFor(String datasetId)
6185 if (datasetIds == null)
6187 datasetIds = new Hashtable<>();
6190 if (datasetIds.containsKey(datasetId))
6192 return datasetIds.get(datasetId);
6197 private void addDatasetRef(String datasetId, AlignmentI dataset)
6199 if (datasetIds == null)
6201 datasetIds = new Hashtable<>();
6203 datasetIds.put(datasetId, dataset);
6207 * make a new dataset ID for this jalview dataset alignment
6212 private String getDatasetIdRef(AlignmentI dataset)
6214 if (dataset.getDataset() != null)
6217 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6219 String datasetId = makeHashCode(dataset, null);
6220 if (datasetId == null)
6222 // make a new datasetId and record it
6223 if (dataset2Ids == null)
6225 dataset2Ids = new IdentityHashMap<>();
6229 datasetId = dataset2Ids.get(dataset);
6231 if (datasetId == null)
6233 datasetId = "ds" + dataset2Ids.size() + 1;
6234 dataset2Ids.put(dataset, datasetId);
6241 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6242 * constructed as a special subclass GeneLocus.
6244 * @param datasetSequence
6247 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6249 for (int d = 0; d < sequence.getDBRef().size(); d++)
6251 DBRef dr = sequence.getDBRef().get(d);
6255 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6256 dr.getAccessionId());
6260 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6261 dr.getAccessionId());
6263 if (dr.getMapping() != null)
6265 entry.setMap(addMapping(dr.getMapping()));
6267 entry.setCanonical(dr.isCanonical());
6268 datasetSequence.addDBRef(entry);
6272 private jalview.datamodel.Mapping addMapping(Mapping m)
6274 SequenceI dsto = null;
6275 // Mapping m = dr.getMapping();
6276 int fr[] = new int[m.getMapListFrom().size() * 2];
6277 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6278 for (int _i = 0; from.hasNext(); _i += 2)
6280 MapListFrom mf = from.next();
6281 fr[_i] = mf.getStart();
6282 fr[_i + 1] = mf.getEnd();
6284 int fto[] = new int[m.getMapListTo().size() * 2];
6285 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6286 for (int _i = 0; to.hasNext(); _i += 2)
6288 MapListTo mf = to.next();
6289 fto[_i] = mf.getStart();
6290 fto[_i + 1] = mf.getEnd();
6292 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6293 fto, m.getMapFromUnit().intValue(),
6294 m.getMapToUnit().intValue());
6297 * (optional) choice of dseqFor or Sequence
6299 if (m.getDseqFor() != null)
6301 String dsfor = m.getDseqFor();
6302 if (seqRefIds.containsKey(dsfor))
6307 jmap.setTo(seqRefIds.get(dsfor));
6311 frefedSequence.add(newMappingRef(dsfor, jmap));
6314 else if (m.getSequence() != null)
6317 * local sequence definition
6319 Sequence ms = m.getSequence();
6320 SequenceI djs = null;
6321 String sqid = ms.getDsseqid();
6322 if (sqid != null && sqid.length() > 0)
6325 * recover dataset sequence
6327 djs = seqRefIds.get(sqid);
6331 jalview.bin.Console.errPrintln(
6332 "Warning - making up dataset sequence id for DbRef sequence map reference");
6333 sqid = ((Object) ms).toString(); // make up a new hascode for
6334 // undefined dataset sequence hash
6335 // (unlikely to happen)
6341 * make a new dataset sequence and add it to refIds hash
6343 djs = new jalview.datamodel.Sequence(ms.getName(),
6345 djs.setStart(jmap.getMap().getToLowest());
6346 djs.setEnd(jmap.getMap().getToHighest());
6347 djs.setVamsasId(uniqueSetSuffix + sqid);
6349 incompleteSeqs.put(sqid, djs);
6350 seqRefIds.put(sqid, djs);
6353 Console.debug("about to recurse on addDBRefs.");
6362 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6363 * view as XML (but not to file), and then reloading it
6368 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6371 JalviewModel jm = saveState(ap, null, null, null);
6374 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6375 ap.getAlignment().getDataset());
6377 uniqueSetSuffix = "";
6378 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6379 jm.getViewport().get(0).setId(null);
6380 // we don't overwrite the view we just copied
6382 if (this.frefedSequence == null)
6384 frefedSequence = new Vector<>();
6387 viewportsAdded.clear();
6389 AlignFrame af = loadFromObject(jm, null, false, null);
6390 af.getAlignPanels().clear();
6391 af.closeMenuItem_actionPerformed(true);
6394 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6395 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6396 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6397 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6398 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6401 return af.alignPanel;
6404 private Hashtable jvids2vobj;
6407 * set the object to ID mapping tables used to write/recover objects and XML
6408 * ID strings for the jalview project. If external tables are provided then
6409 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6410 * object goes out of scope. - also populates the datasetIds hashtable with
6411 * alignment objects containing dataset sequences
6414 * Map from ID strings to jalview datamodel
6416 * Map from jalview datamodel to ID strings
6420 public void setObjectMappingTables(Hashtable vobj2jv,
6421 IdentityHashMap jv2vobj)
6423 this.jv2vobj = jv2vobj;
6424 this.vobj2jv = vobj2jv;
6425 Iterator ds = jv2vobj.keySet().iterator();
6427 while (ds.hasNext())
6429 Object jvobj = ds.next();
6430 id = jv2vobj.get(jvobj).toString();
6431 if (jvobj instanceof jalview.datamodel.Alignment)
6433 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6435 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6438 else if (jvobj instanceof jalview.datamodel.Sequence)
6440 // register sequence object so the XML parser can recover it.
6441 if (seqRefIds == null)
6443 seqRefIds = new HashMap<>();
6445 if (seqsToIds == null)
6447 seqsToIds = new IdentityHashMap<>();
6449 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6450 seqsToIds.put((SequenceI) jvobj, id);
6452 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6455 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6456 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6457 if (jvann.annotationId == null)
6459 jvann.annotationId = anid;
6461 if (!jvann.annotationId.equals(anid))
6463 // TODO verify that this is the correct behaviour
6464 Console.warn("Overriding Annotation ID for " + anid
6465 + " from different id : " + jvann.annotationId);
6466 jvann.annotationId = anid;
6469 else if (jvobj instanceof String)
6471 if (jvids2vobj == null)
6473 jvids2vobj = new Hashtable();
6474 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6479 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6485 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6486 * objects created from the project archive. If string is null (default for
6487 * construction) then suffix will be set automatically.
6491 public void setUniqueSetSuffix(String string)
6493 uniqueSetSuffix = string;
6498 * uses skipList2 as the skipList for skipping views on sequence sets
6499 * associated with keys in the skipList
6503 public void setSkipList(Hashtable skipList2)
6505 skipList = skipList2;
6509 * Reads the jar entry of given name and returns its contents, or null if the
6510 * entry is not found.
6513 * @param jarEntryName
6516 protected String readJarEntry(jarInputStreamProvider jprovider,
6517 String jarEntryName)
6519 String result = null;
6520 BufferedReader in = null;
6525 * Reopen the jar input stream and traverse its entries to find a matching
6528 JarInputStream jin = jprovider.getJarInputStream();
6529 JarEntry entry = null;
6532 entry = jin.getNextJarEntry();
6533 } while (entry != null && !entry.getName().equals(jarEntryName));
6537 StringBuilder out = new StringBuilder(256);
6538 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6541 while ((data = in.readLine()) != null)
6545 result = out.toString();
6550 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6552 } catch (Exception ex)
6554 ex.printStackTrace();
6562 } catch (IOException e)
6573 * Returns an incrementing counter (0, 1, 2...)
6577 private synchronized int nextCounter()
6583 * Loads any saved PCA viewers
6588 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6592 List<PcaViewer> pcaviewers = model.getPcaViewer();
6593 for (PcaViewer viewer : pcaviewers)
6595 if (isPasimap(viewer))
6599 String modelName = viewer.getScoreModelName();
6600 SimilarityParamsI params = new SimilarityParams(
6601 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6602 viewer.isIncludeGaps(),
6603 viewer.isDenominateByShortestLength());
6606 * create the panel (without computing the PCA)
6608 PCAPanel panel = new PCAPanel(ap, modelName, params);
6610 panel.setTitle(viewer.getTitle());
6611 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6612 viewer.getWidth(), viewer.getHeight()));
6614 boolean showLabels = viewer.isShowLabels();
6615 panel.setShowLabels(showLabels);
6616 panel.getRotatableCanvas().setShowLabels(showLabels);
6617 panel.getRotatableCanvas()
6618 .setBgColour(new Color(viewer.getBgColour()));
6619 panel.getRotatableCanvas()
6620 .setApplyToAllViews(viewer.isLinkToAllViews());
6623 * load PCA output data
6625 ScoreModelI scoreModel = ScoreModels.getInstance()
6626 .getScoreModel(modelName, ap);
6627 PCA pca = new PCA(null, scoreModel, params);
6628 PcaDataType pcaData = viewer.getPcaData();
6630 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6631 pca.setPairwiseScores(pairwise);
6633 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6634 pca.setTridiagonal(triDiag);
6636 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6637 pca.setEigenmatrix(result);
6639 panel.getPcaModel().setPCA(pca);
6642 * we haven't saved the input data! (JAL-2647 to do)
6644 panel.setInputData(null);
6647 * add the sequence points for the PCA display
6649 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6650 for (SequencePoint sp : viewer.getSequencePoint())
6652 String seqId = sp.getSequenceRef();
6653 SequenceI seq = seqRefIds.get(seqId);
6656 throw new IllegalStateException(
6657 "Unmatched seqref for PCA: " + seqId);
6659 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6660 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6662 seqPoints.add(seqPoint);
6664 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6667 * set min-max ranges and scale after setPoints (which recomputes them)
6669 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6670 SeqPointMin spMin = viewer.getSeqPointMin();
6671 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6673 SeqPointMax spMax = viewer.getSeqPointMax();
6674 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6676 panel.getRotatableCanvas().setSeqMinMax(min, max);
6678 // todo: hold points list in PCAModel only
6679 panel.getPcaModel().setSequencePoints(seqPoints);
6681 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6682 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6683 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6685 // is this duplication needed?
6686 panel.setTop(seqPoints.size() - 1);
6687 panel.getPcaModel().setTop(seqPoints.size() - 1);
6690 * add the axes' end points for the display
6692 for (int i = 0; i < 3; i++)
6694 Axis axis = viewer.getAxis().get(i);
6695 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6696 axis.getXPos(), axis.getYPos(), axis.getZPos());
6699 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6700 "label.calc_title", "PCA", modelName), 475, 450);
6702 } catch (Exception ex)
6704 Console.error("Error loading PCA: " + ex.toString());
6708 private boolean isPasimap(PcaViewer viewer)
6710 return viewer.getTitle().toLowerCase(Locale.ROOT)
6711 .startsWith("pasimap");
6714 * Loads any saved PaSiMAp viewers using the function from PCA
6719 protected void loadPaSiMapViewers(JalviewModel model, AlignmentPanel ap)
6723 List<PcaViewer> pcaviewers = model.getPcaViewer();
6724 for (PcaViewer viewer : pcaviewers)
6726 if (!isPasimap(viewer))
6730 String modelName = viewer.getScoreModelName();
6732 SimilarityParamsI params = new SimilarityParams(
6733 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6734 viewer.isIncludeGaps(),
6735 viewer.isDenominateByShortestLength());
6739 * create the panel (without computing the PaSiMAp)
6741 PaSiMapPanel panel = new PaSiMapPanel(ap, modelName);
6743 panel.setTitle(viewer.getTitle());
6744 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6745 viewer.getWidth(), viewer.getHeight()));
6747 boolean showLabels = viewer.isShowLabels();
6748 panel.setShowLabels(showLabels);
6749 panel.getRotatableCanvas().setShowLabels(showLabels);
6750 panel.getRotatableCanvas()
6751 .setBgColour(new Color(viewer.getBgColour()));
6752 panel.getRotatableCanvas()
6753 .setApplyToAllViews(viewer.isLinkToAllViews());
6756 * load PaSiMap output data
6758 ScoreModelI scoreModel = ScoreModels.getInstance()
6759 .getScoreModel(modelName, ap);
6760 PaSiMap pasimap = new PaSiMap(null, scoreModel, null);
6761 PcaDataType pasimapData = viewer.getPcaData();
6763 MatrixI pairwise = loadDoubleMatrix(pasimapData.getPairwiseMatrix());
6764 pasimap.setPairwiseScores(pairwise);
6766 MatrixI result = loadDoubleMatrix(pasimapData.getEigenMatrix());
6767 pasimap.setEigenmatrix(result);
6769 panel.getPasimapModel().setPaSiMap(pasimap);
6772 * we haven't saved the input data! (JAL-2647 to do)
6774 panel.setInputData(null);
6777 * add the sequence points for the PCA display
6779 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6780 for (SequencePoint sp : viewer.getSequencePoint())
6782 String seqId = sp.getSequenceRef();
6783 SequenceI seq = seqRefIds.get(seqId);
6786 throw new IllegalStateException(
6787 "Unmatched seqref for PaSiMap: " + seqId);
6789 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6790 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6792 seqPoints.add(seqPoint);
6794 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6797 * set min-max ranges and scale after setPoints (which recomputes them)
6799 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6800 SeqPointMin spMin = viewer.getSeqPointMin();
6801 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6803 SeqPointMax spMax = viewer.getSeqPointMax();
6804 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6806 panel.getRotatableCanvas().setSeqMinMax(min, max);
6808 // todo: hold points list in PCAModel only
6809 panel.getPasimapModel().setSequencePoints(seqPoints);
6811 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6812 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6813 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6815 // is this duplication needed?
6816 panel.setTop(seqPoints.size() - 1);
6817 panel.getPasimapModel().setTop(seqPoints.size() - 1);
6820 * add the axes' end points for the display
6822 for (int i = 0; i < 3; i++)
6824 Axis axis = viewer.getAxis().get(i);
6825 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6826 axis.getXPos(), axis.getYPos(), axis.getZPos());
6829 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6830 "label.calc_title", "PaSiMap", modelName), 475, 450);
6832 } catch (Exception ex)
6834 Console.error("Error loading PaSiMap: " + ex.toString());
6839 * Creates a new structure viewer window
6846 protected void createStructureViewer(ViewerType viewerType,
6847 final Entry<String, StructureViewerModel> viewerData,
6848 AlignFrame af, jarInputStreamProvider jprovider)
6850 final StructureViewerModel viewerModel = viewerData.getValue();
6851 String sessionFilePath = null;
6853 if (viewerType == ViewerType.JMOL)
6855 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6859 String viewerJarEntryName = getViewerJarEntryName(
6860 viewerModel.getViewId());
6861 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6862 "viewerSession", ".tmp");
6864 final String sessionPath = sessionFilePath;
6865 final String sviewid = viewerData.getKey();
6868 SwingUtilities.invokeAndWait(new Runnable()
6873 JalviewStructureDisplayI sview = null;
6876 sview = StructureViewer.createView(viewerType, af.alignPanel,
6877 viewerModel, sessionPath, sviewid);
6878 addNewStructureViewer(sview);
6879 } catch (OutOfMemoryError ex)
6881 new OOMWarning("Restoring structure view for " + viewerType,
6882 (OutOfMemoryError) ex.getCause());
6883 if (sview != null && sview.isVisible())
6885 sview.closeViewer(false);
6886 sview.setVisible(false);
6892 } catch (InvocationTargetException | InterruptedException ex)
6894 Console.warn("Unexpected error when opening " + viewerType
6895 + " structure viewer", ex);
6900 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6901 * the path of the file. "load file" commands are rewritten to change the
6902 * original PDB file names to those created as the Jalview project is loaded.
6908 private String rewriteJmolSession(StructureViewerModel svattrib,
6909 jarInputStreamProvider jprovider)
6911 String state = svattrib.getStateData(); // Jalview < 2.9
6912 if (state == null || state.isEmpty()) // Jalview >= 2.9
6914 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6915 state = readJarEntry(jprovider, jarEntryName);
6917 // TODO or simpler? for each key in oldFiles,
6918 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6919 // (allowing for different path escapings)
6920 StringBuilder rewritten = new StringBuilder(state.length());
6921 int cp = 0, ncp, ecp;
6922 Map<File, StructureData> oldFiles = svattrib.getFileData();
6923 while ((ncp = state.indexOf("load ", cp)) > -1)
6927 // look for next filename in load statement
6928 rewritten.append(state.substring(cp,
6929 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6930 String oldfilenam = state.substring(ncp,
6931 ecp = state.indexOf("\"", ncp));
6932 // recover the new mapping data for this old filename
6933 // have to normalize filename - since Jmol and jalview do
6934 // filename translation differently.
6935 StructureData filedat = oldFiles.get(new File(oldfilenam));
6936 if (filedat == null)
6938 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6939 filedat = oldFiles.get(new File(reformatedOldFilename));
6941 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6942 rewritten.append("\"");
6943 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6944 // look for next file statement.
6945 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6949 // just append rest of state
6950 rewritten.append(state.substring(cp));
6954 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6955 rewritten = new StringBuilder(state);
6956 rewritten.append("; load append ");
6957 for (File id : oldFiles.keySet())
6959 // add pdb files that should be present in the viewer
6960 StructureData filedat = oldFiles.get(id);
6961 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6963 rewritten.append(";");
6966 if (rewritten.length() == 0)
6970 final String history = "history = ";
6971 int historyIndex = rewritten.indexOf(history);
6972 if (historyIndex > -1)
6975 * change "history = [true|false];" to "history = [1|0];"
6977 historyIndex += history.length();
6978 String val = rewritten.substring(historyIndex, historyIndex + 5);
6979 if (val.startsWith("true"))
6981 rewritten.replace(historyIndex, historyIndex + 4, "1");
6983 else if (val.startsWith("false"))
6985 rewritten.replace(historyIndex, historyIndex + 5, "0");
6991 File tmp = File.createTempFile("viewerSession", ".tmp");
6992 try (OutputStream os = new FileOutputStream(tmp))
6994 InputStream is = new ByteArrayInputStream(
6995 rewritten.toString().getBytes());
6997 return tmp.getAbsolutePath();
6999 } catch (IOException e)
7001 Console.error("Error restoring Jmol session: " + e.toString());
7007 * Populates an XML model of the feature colour scheme for one feature type
7009 * @param featureType
7013 public static Colour marshalColour(String featureType,
7014 FeatureColourI fcol)
7016 Colour col = new Colour();
7017 if (fcol.isSimpleColour())
7019 col.setRGB(Format.getHexString(fcol.getColour()));
7023 col.setRGB(Format.getHexString(fcol.getMaxColour()));
7024 col.setMin(fcol.getMin());
7025 col.setMax(fcol.getMax());
7026 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
7027 col.setAutoScale(fcol.isAutoScaled());
7028 col.setThreshold(fcol.getThreshold());
7029 col.setColourByLabel(fcol.isColourByLabel());
7030 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
7031 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
7032 : ThresholdType.NONE));
7033 if (fcol.isColourByAttribute())
7035 final String[] attName = fcol.getAttributeName();
7036 col.getAttributeName().add(attName[0]);
7037 if (attName.length > 1)
7039 col.getAttributeName().add(attName[1]);
7042 Color noColour = fcol.getNoColour();
7043 if (noColour == null)
7045 col.setNoValueColour(NoValueColour.NONE);
7047 else if (noColour == fcol.getMaxColour())
7049 col.setNoValueColour(NoValueColour.MAX);
7053 col.setNoValueColour(NoValueColour.MIN);
7056 col.setName(featureType);
7061 * Populates an XML model of the feature filter(s) for one feature type
7063 * @param firstMatcher
7064 * the first (or only) match condition)
7066 * remaining match conditions (if any)
7068 * if true, conditions are and-ed, else or-ed
7070 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
7071 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
7074 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
7076 if (filters.hasNext())
7081 CompoundMatcher compound = new CompoundMatcher();
7082 compound.setAnd(and);
7083 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
7084 firstMatcher, Collections.emptyIterator(), and);
7085 // compound.addMatcherSet(matcher1);
7086 compound.getMatcherSet().add(matcher1);
7087 FeatureMatcherI nextMatcher = filters.next();
7088 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
7089 nextMatcher, filters, and);
7090 // compound.addMatcherSet(matcher2);
7091 compound.getMatcherSet().add(matcher2);
7092 result.setCompoundMatcher(compound);
7097 * single condition matcher
7099 // MatchCondition matcherModel = new MatchCondition();
7100 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
7101 matcherModel.setCondition(
7102 firstMatcher.getMatcher().getCondition().getStableName());
7103 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
7104 if (firstMatcher.isByAttribute())
7106 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
7107 // matcherModel.setAttributeName(firstMatcher.getAttribute());
7108 String[] attName = firstMatcher.getAttribute();
7109 matcherModel.getAttributeName().add(attName[0]); // attribute
7110 if (attName.length > 1)
7112 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
7115 else if (firstMatcher.isByLabel())
7117 matcherModel.setBy(FilterBy.BY_LABEL);
7119 else if (firstMatcher.isByScore())
7121 matcherModel.setBy(FilterBy.BY_SCORE);
7123 result.setMatchCondition(matcherModel);
7130 * Loads one XML model of a feature filter to a Jalview object
7132 * @param featureType
7133 * @param matcherSetModel
7136 public static FeatureMatcherSetI parseFilter(String featureType,
7137 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
7139 FeatureMatcherSetI result = new FeatureMatcherSet();
7142 parseFilterConditions(result, matcherSetModel, true);
7143 } catch (IllegalStateException e)
7145 // mixing AND and OR conditions perhaps
7146 jalview.bin.Console.errPrintln(
7147 String.format("Error reading filter conditions for '%s': %s",
7148 featureType, e.getMessage()));
7149 // return as much as was parsed up to the error
7156 * Adds feature match conditions to matcherSet as unmarshalled from XML
7157 * (possibly recursively for compound conditions)
7160 * @param matcherSetModel
7162 * if true, multiple conditions are AND-ed, else they are OR-ed
7163 * @throws IllegalStateException
7164 * if AND and OR conditions are mixed
7166 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
7167 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
7170 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
7171 .getMatchCondition();
7177 FilterBy filterBy = mc.getBy();
7178 Condition cond = Condition.fromString(mc.getCondition());
7179 String pattern = mc.getValue();
7180 FeatureMatcherI matchCondition = null;
7181 if (filterBy == FilterBy.BY_LABEL)
7183 matchCondition = FeatureMatcher.byLabel(cond, pattern);
7185 else if (filterBy == FilterBy.BY_SCORE)
7187 matchCondition = FeatureMatcher.byScore(cond, pattern);
7190 else if (filterBy == FilterBy.BY_ATTRIBUTE)
7192 final List<String> attributeName = mc.getAttributeName();
7193 String[] attNames = attributeName
7194 .toArray(new String[attributeName.size()]);
7195 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
7200 * note this throws IllegalStateException if AND-ing to a
7201 * previously OR-ed compound condition, or vice versa
7205 matcherSet.and(matchCondition);
7209 matcherSet.or(matchCondition);
7215 * compound condition
7217 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
7218 .getCompoundMatcher().getMatcherSet();
7219 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
7220 if (matchers.size() == 2)
7222 parseFilterConditions(matcherSet, matchers.get(0), anded);
7223 parseFilterConditions(matcherSet, matchers.get(1), anded);
7228 .errPrintln("Malformed compound filter condition");
7234 * Loads one XML model of a feature colour to a Jalview object
7236 * @param colourModel
7239 public static FeatureColourI parseColour(Colour colourModel)
7241 FeatureColourI colour = null;
7243 if (colourModel.getMax() != null)
7245 Color mincol = null;
7246 Color maxcol = null;
7247 Color noValueColour = null;
7251 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
7252 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7253 } catch (Exception e)
7255 Console.warn("Couldn't parse out graduated feature color.", e);
7258 NoValueColour noCol = colourModel.getNoValueColour();
7259 if (noCol == NoValueColour.MIN)
7261 noValueColour = mincol;
7263 else if (noCol == NoValueColour.MAX)
7265 noValueColour = maxcol;
7268 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
7269 safeFloat(colourModel.getMin()),
7270 safeFloat(colourModel.getMax()));
7271 final List<String> attributeName = colourModel.getAttributeName();
7272 String[] attributes = attributeName
7273 .toArray(new String[attributeName.size()]);
7274 if (attributes != null && attributes.length > 0)
7276 colour.setAttributeName(attributes);
7278 if (colourModel.isAutoScale() != null)
7280 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7282 if (colourModel.isColourByLabel() != null)
7284 colour.setColourByLabel(
7285 colourModel.isColourByLabel().booleanValue());
7287 if (colourModel.getThreshold() != null)
7289 colour.setThreshold(colourModel.getThreshold().floatValue());
7291 ThresholdType ttyp = colourModel.getThreshType();
7292 if (ttyp == ThresholdType.ABOVE)
7294 colour.setAboveThreshold(true);
7296 else if (ttyp == ThresholdType.BELOW)
7298 colour.setBelowThreshold(true);
7303 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7304 colour = new FeatureColour(color);
7310 public static void setStateSavedUpToDate(boolean s)
7312 Console.debug("Setting overall stateSavedUpToDate to " + s);
7313 stateSavedUpToDate = s;
7316 public static boolean stateSavedUpToDate()
7318 Console.debug("Returning overall stateSavedUpToDate value: "
7319 + stateSavedUpToDate);
7320 return stateSavedUpToDate;
7323 public static boolean allSavedUpToDate()
7325 if (stateSavedUpToDate()) // nothing happened since last project save
7328 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7331 for (int i = 0; i < frames.length; i++)
7333 if (frames[i] == null)
7335 if (!frames[i].getViewport().savedUpToDate())
7336 return false; // at least one alignment is not individually saved
7342 // used for debugging and tests
7343 private static int debugDelaySave = 20;
7345 public static void setDebugDelaySave(int n)