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.scoremodels.ScoreModels;
81 import jalview.analysis.scoremodels.SimilarityParams;
82 import jalview.api.FeatureColourI;
83 import jalview.api.ViewStyleI;
84 import jalview.api.analysis.ScoreModelI;
85 import jalview.api.analysis.SimilarityParamsI;
86 import jalview.api.structures.JalviewStructureDisplayI;
87 import jalview.bin.Cache;
88 import jalview.bin.Console;
89 import jalview.bin.Jalview;
90 import jalview.datamodel.AlignedCodonFrame;
91 import jalview.datamodel.Alignment;
92 import jalview.datamodel.AlignmentAnnotation;
93 import jalview.datamodel.AlignmentI;
94 import jalview.datamodel.ContactListI;
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.GroupSetI;
103 import jalview.datamodel.PDBEntry;
104 import jalview.datamodel.Point;
105 import jalview.datamodel.RnaViewerModel;
106 import jalview.datamodel.SequenceFeature;
107 import jalview.datamodel.SequenceGroup;
108 import jalview.datamodel.SequenceI;
109 import jalview.datamodel.StructureViewerModel;
110 import jalview.datamodel.StructureViewerModel.StructureData;
111 import jalview.datamodel.features.FeatureMatcher;
112 import jalview.datamodel.features.FeatureMatcherI;
113 import jalview.datamodel.features.FeatureMatcherSet;
114 import jalview.datamodel.features.FeatureMatcherSetI;
115 import jalview.ext.varna.RnaModel;
116 import jalview.gui.AlignFrame;
117 import jalview.gui.AlignViewport;
118 import jalview.gui.AlignmentPanel;
119 import jalview.gui.AppVarna;
120 import jalview.gui.Desktop;
121 import jalview.gui.JvOptionPane;
122 import jalview.gui.OOMWarning;
123 import jalview.gui.OverviewPanel;
124 import jalview.gui.PCAPanel;
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.ViewportRanges;
156 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
157 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
158 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
159 import jalview.ws.datamodel.MappableContactMatrixI;
160 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
161 import jalview.ws.jws2.Jws2Discoverer;
162 import jalview.ws.jws2.dm.AAConSettings;
163 import jalview.ws.jws2.jabaws2.Jws2Instance;
164 import jalview.ws.params.ArgumentI;
165 import jalview.ws.params.AutoCalcSetting;
166 import jalview.ws.params.WsParamSetI;
167 import jalview.xml.binding.jalview.AlcodonFrame;
168 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
169 import jalview.xml.binding.jalview.Annotation;
170 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
171 import jalview.xml.binding.jalview.AnnotationColourScheme;
172 import jalview.xml.binding.jalview.AnnotationElement;
173 import jalview.xml.binding.jalview.DoubleMatrix;
174 import jalview.xml.binding.jalview.DoubleVector;
175 import jalview.xml.binding.jalview.Feature;
176 import jalview.xml.binding.jalview.Feature.OtherData;
177 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
178 import jalview.xml.binding.jalview.FilterBy;
179 import jalview.xml.binding.jalview.JalviewModel;
180 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
181 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
182 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
183 import jalview.xml.binding.jalview.JalviewModel.JGroup;
184 import jalview.xml.binding.jalview.JalviewModel.JSeq;
185 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
186 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
187 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
188 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
189 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
190 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
191 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
192 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
193 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
194 import jalview.xml.binding.jalview.JalviewModel.Tree;
195 import jalview.xml.binding.jalview.JalviewModel.UserColours;
196 import jalview.xml.binding.jalview.JalviewModel.Viewport;
197 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
198 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
199 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
200 import jalview.xml.binding.jalview.JalviewUserColours;
201 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
202 import jalview.xml.binding.jalview.MapListType;
203 import jalview.xml.binding.jalview.MapListType.MapListFrom;
204 import jalview.xml.binding.jalview.MapListType.MapListTo;
205 import jalview.xml.binding.jalview.MapOnAMatrixType;
206 import jalview.xml.binding.jalview.Mapping;
207 import jalview.xml.binding.jalview.MatrixType;
208 import jalview.xml.binding.jalview.NoValueColour;
209 import jalview.xml.binding.jalview.ObjectFactory;
210 import jalview.xml.binding.jalview.PcaDataType;
211 import jalview.xml.binding.jalview.Pdbentry.Property;
212 import jalview.xml.binding.jalview.Sequence;
213 import jalview.xml.binding.jalview.Sequence.DBRef;
214 import jalview.xml.binding.jalview.SequenceSet;
215 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
216 import jalview.xml.binding.jalview.ThresholdType;
217 import jalview.xml.binding.jalview.VAMSAS;
220 * Write out the current jalview desktop state as a Jalview XML stream.
222 * Note: the vamsas objects referred to here are primitive versions of the
223 * VAMSAS project schema elements - they are not the same and most likely never
227 * @version $Revision: 1.134 $
229 public class Jalview2XML
232 // BH 2018 we add the .jvp binary extension to J2S so that
233 // it will declare that binary when we do the file save from the browser
237 Platform.addJ2SBinaryType(".jvp?");
240 private static final String VIEWER_PREFIX = "viewer_";
242 private static final String RNA_PREFIX = "rna_";
244 private static final String UTF_8 = "UTF-8";
247 * used in decision if quit confirmation should be issued
249 private static boolean stateSavedUpToDate = false;
252 * prefix for recovering datasets for alignments with multiple views where
253 * non-existent dataset IDs were written for some views
255 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
257 // use this with nextCounter() to make unique names for entities
258 private int counter = 0;
261 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
262 * of sequence objects are created.
264 IdentityHashMap<SequenceI, String> seqsToIds = null;
267 * jalview XML Sequence ID to jalview sequence object reference (both dataset
268 * and alignment sequences. Populated as XML reps of sequence objects are
271 Map<String, SequenceI> seqRefIds = null;
273 Map<String, SequenceI> incompleteSeqs = null;
275 List<forwardRef> frefedSequence = null;
277 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
280 * Map of reconstructed AlignFrame objects that appear to have come from
281 * SplitFrame objects (have a dna/protein complement view).
283 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
286 * Map from displayed rna structure models to their saved session state jar
289 private Map<RnaModel, String> rnaSessions = new HashMap<>();
292 * map from contact matrices to their XML ids
294 private Map<ContactMatrixI,String> contactMatrices = new HashMap<>();
295 private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
296 private List<jalview.xml.binding.jalview.MatrixType> xmlMatrices= new ArrayList<>();
299 * A helper method for safely using the value of an optional attribute that
300 * may be null if not present in the XML. Answers the boolean value, or false
306 public static boolean safeBoolean(Boolean b)
308 return b == null ? false : b.booleanValue();
312 * A helper method for safely using the value of an optional attribute that
313 * may be null if not present in the XML. Answers the integer value, or zero
319 public static int safeInt(Integer i)
321 return i == null ? 0 : i.intValue();
325 * A helper method for safely using the value of an optional attribute that
326 * may be null if not present in the XML. Answers the float value, or zero if
332 public static float safeFloat(Float f)
334 return f == null ? 0f : f.floatValue();
338 * create/return unique hash string for sq
341 * @return new or existing unique string for sq
343 String seqHash(SequenceI sq)
345 if (seqsToIds == null)
349 if (seqsToIds.containsKey(sq))
351 return seqsToIds.get(sq);
355 // create sequential key
356 String key = "sq" + (seqsToIds.size() + 1);
357 key = makeHashCode(sq, key); // check we don't have an external reference
359 seqsToIds.put(sq, key);
366 if (seqsToIds == null)
368 seqsToIds = new IdentityHashMap<>();
370 if (seqRefIds == null)
372 seqRefIds = new HashMap<>();
374 if (incompleteSeqs == null)
376 incompleteSeqs = new HashMap<>();
378 if (frefedSequence == null)
380 frefedSequence = new ArrayList<>();
388 public Jalview2XML(boolean raiseGUI)
390 this.raiseGUI = raiseGUI;
394 * base class for resolving forward references to an as-yet unmarshalled object referenced by already unmarshalled objects
399 abstract class forwardRef {
404 public forwardRef(String _sref, String type)
410 public String getSref()
415 public abstract boolean isResolvable();
417 * @return true if the forward reference was fully resolved
419 abstract boolean resolve();
422 public String toString()
424 return type + " reference to " + sref;
428 * resolve forward references to sequences by their ID
431 abstract class SeqFref extends forwardRef
433 public SeqFref(String _sref, String type)
437 public SequenceI getSrefSeq()
439 return seqRefIds.get(sref);
442 public boolean isResolvable()
444 return seqRefIds.get(sref) != null;
447 public SequenceI getSrefDatasetSeq()
449 SequenceI sq = seqRefIds.get(sref);
452 while (sq.getDatasetSequence() != null)
454 sq = sq.getDatasetSequence();
462 * create forward reference for a mapping
468 public SeqFref newMappingRef(final String sref,
469 final jalview.datamodel.Mapping _jmap)
471 SeqFref fref = new SeqFref(sref, "Mapping")
473 public jalview.datamodel.Mapping jmap = _jmap;
478 SequenceI seq = getSrefDatasetSeq();
490 public SeqFref newAlcodMapRef(final String sref,
491 final AlignedCodonFrame _cf,
492 final jalview.datamodel.Mapping _jmap)
495 SeqFref fref = new SeqFref(sref, "Codon Frame")
497 AlignedCodonFrame cf = _cf;
499 public jalview.datamodel.Mapping mp = _jmap;
502 public boolean isResolvable()
504 return super.isResolvable() && mp.getTo() != null;
510 SequenceI seq = getSrefDatasetSeq();
515 cf.addMap(seq, mp.getTo(), mp.getMap());
522 public forwardRef newMatrixFref(final String matRef,
523 final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
525 forwardRef fref = new forwardRef(matRef,
526 "Matrix Reference for sequence and annotation")
532 ContactMatrixI cm = contactMatrixRefs.get(matRef);
533 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
536 jaa.sequenceRef.addContactListFor(jaa, newpae);
541 public boolean isResolvable()
543 return (contactMatrixRefs.get(matRef) != null);
549 public void resolveFrefedSequences()
551 Iterator<forwardRef> nextFref = frefedSequence.iterator();
552 int toresolve = frefedSequence.size();
553 int unresolved = 0, failedtoresolve = 0;
554 while (nextFref.hasNext())
556 forwardRef ref = nextFref.next();
557 if (ref.isResolvable())
569 } catch (Exception x)
571 jalview.bin.Console.errPrintln(
572 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
585 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
587 + " forward references left unresolved on the stack.");
589 if (failedtoresolve > 0)
591 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
592 + " resolvable forward references failed to resolve.");
594 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
596 jalview.bin.Console.errPrintln(
597 "Jalview Project Import: There are " + incompleteSeqs.size()
598 + " sequences which may have incomplete metadata.");
599 if (incompleteSeqs.size() < 10)
601 for (SequenceI s : incompleteSeqs.values())
603 jalview.bin.Console.errPrintln(s.toString());
608 jalview.bin.Console.errPrintln(
609 "Too many to report. Skipping output of incomplete sequences.");
615 * This maintains a map of viewports, the key being the seqSetId. Important to
616 * set historyItem and redoList for multiple views
618 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
620 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
622 String uniqueSetSuffix = "";
625 * List of pdbfiles added to Jar
627 List<String> pdbfiles = null;
629 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
630 public void saveState(File statefile)
632 FileOutputStream fos = null;
637 fos = new FileOutputStream(statefile);
639 JarOutputStream jout = new JarOutputStream(fos);
643 } catch (Exception e)
645 Console.error("Couln't write Jalview state to " + statefile, e);
646 // TODO: inform user of the problem - they need to know if their data was
648 if (errorMessage == null)
650 errorMessage = "Did't write Jalview Archive to output file '"
651 + statefile + "' - See console error log for details";
655 errorMessage += "(Didn't write Jalview Archive to output file '"
666 } catch (IOException e)
676 * Writes a jalview project archive to the given Jar output stream.
680 public void saveState(JarOutputStream jout)
682 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
684 setStateSavedUpToDate(true);
686 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
688 int n = debugDelaySave;
692 Console.debug("***** debugging save sleep " + i + "/" + n);
696 } catch (InterruptedException e)
698 // TODO Auto-generated catch block
709 saveAllFrames(Arrays.asList(frames), jout);
713 * core method for storing state for a set of AlignFrames.
716 * - frames involving all data to be exported (including containing
719 * - project output stream
721 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
723 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
726 * ensure cached data is clear before starting
728 // todo tidy up seqRefIds, seqsToIds initialisation / reset
730 splitFrameCandidates.clear();
735 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
736 // //////////////////////////////////////////////////
738 List<String> shortNames = new ArrayList<>();
739 List<String> viewIds = new ArrayList<>();
742 for (int i = frames.size() - 1; i > -1; i--)
744 AlignFrame af = frames.get(i);
746 if (skipList != null && skipList
747 .containsKey(af.getViewport().getSequenceSetId()))
752 String shortName = makeFilename(af, shortNames);
754 int apSize = af.getAlignPanels().size();
756 for (int ap = 0; ap < apSize; ap++)
758 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
760 String fileName = apSize == 1 ? shortName : ap + shortName;
761 if (!fileName.endsWith(".xml"))
763 fileName = fileName + ".xml";
766 saveState(apanel, fileName, jout, viewIds);
768 String dssid = getDatasetIdRef(
769 af.getViewport().getAlignment().getDataset());
770 if (!dsses.containsKey(dssid))
772 dsses.put(dssid, af);
777 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
783 } catch (Exception foo)
787 } catch (Exception ex)
789 // TODO: inform user of the problem - they need to know if their data was
791 if (errorMessage == null)
793 errorMessage = "Couldn't write Jalview Archive - see error output for details";
795 ex.printStackTrace();
800 * Generates a distinct file name, based on the title of the AlignFrame, by
801 * appending _n for increasing n until an unused name is generated. The new
802 * name (without its extension) is added to the list.
806 * @return the generated name, with .xml extension
808 protected String makeFilename(AlignFrame af, List<String> namesUsed)
810 String shortName = af.getTitle();
812 if (shortName.indexOf(File.separatorChar) > -1)
814 shortName = shortName
815 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
820 while (namesUsed.contains(shortName))
822 if (shortName.endsWith("_" + (count - 1)))
824 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
827 shortName = shortName.concat("_" + count);
831 namesUsed.add(shortName);
833 if (!shortName.endsWith(".xml"))
835 shortName = shortName + ".xml";
840 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
841 public boolean saveAlignment(AlignFrame af, String jarFile,
846 // create backupfiles object and get new temp filename destination
847 boolean doBackup = BackupFiles.getEnabled();
848 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
849 FileOutputStream fos = new FileOutputStream(
850 doBackup ? backupfiles.getTempFilePath() : jarFile);
852 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
854 int n = debugDelaySave;
858 Console.debug("***** debugging save sleep " + i + "/" + n);
862 } catch (InterruptedException e)
864 // TODO Auto-generated catch block
871 JarOutputStream jout = new JarOutputStream(fos);
872 List<AlignFrame> frames = new ArrayList<>();
874 // resolve splitframes
875 if (af.getViewport().getCodingComplement() != null)
877 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
883 saveAllFrames(frames, jout);
887 } catch (Exception foo)
891 boolean success = true;
895 backupfiles.setWriteSuccess(success);
896 success = backupfiles.rollBackupsAndRenameTempFile();
900 } catch (Exception ex)
902 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
903 ex.printStackTrace();
908 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
909 String fileName, JarOutputStream jout)
912 for (String dssids : dsses.keySet())
914 AlignFrame _af = dsses.get(dssids);
915 String jfileName = fileName + " Dataset for " + _af.getTitle();
916 if (!jfileName.endsWith(".xml"))
918 jfileName = jfileName + ".xml";
920 saveState(_af.alignPanel, jfileName, true, jout, null);
925 * create a JalviewModel from an alignment view and marshall it to a
929 * panel to create jalview model for
931 * name of alignment panel written to output stream
938 public JalviewModel saveState(AlignmentPanel ap, String fileName,
939 JarOutputStream jout, List<String> viewIds)
941 return saveState(ap, fileName, false, jout, viewIds);
945 * create a JalviewModel from an alignment view and marshall it to a
949 * panel to create jalview model for
951 * name of alignment panel written to output stream
953 * when true, only write the dataset for the alignment, not the data
954 * associated with the view.
960 public JalviewModel saveState(AlignmentPanel ap, String fileName,
961 boolean storeDS, JarOutputStream jout, List<String> viewIds)
965 viewIds = new ArrayList<>();
970 List<UserColourScheme> userColours = new ArrayList<>();
972 AlignViewport av = ap.av;
973 ViewportRanges vpRanges = av.getRanges();
975 final ObjectFactory objectFactory = new ObjectFactory();
976 JalviewModel object = objectFactory.createJalviewModel();
977 object.setVamsasModel(new VAMSAS());
979 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
982 GregorianCalendar c = new GregorianCalendar();
983 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
984 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
985 object.setCreationDate(now);
986 } catch (DatatypeConfigurationException e)
988 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
990 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
993 * rjal is full height alignment, jal is actual alignment with full metadata
994 * but excludes hidden sequences.
996 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
998 if (av.hasHiddenRows())
1000 rjal = jal.getHiddenSequences().getFullAlignment();
1003 SequenceSet vamsasSet = new SequenceSet();
1005 // JalviewModelSequence jms = new JalviewModelSequence();
1007 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1009 if (jal.getDataset() != null)
1011 // dataset id is the dataset's hashcode
1012 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1015 // switch jal and the dataset
1016 jal = jal.getDataset();
1020 if (jal.getProperties() != null)
1022 Enumeration en = jal.getProperties().keys();
1023 while (en.hasMoreElements())
1025 String key = en.nextElement().toString();
1026 SequenceSetProperties ssp = new SequenceSetProperties();
1028 ssp.setValue(jal.getProperties().get(key).toString());
1029 // vamsasSet.addSequenceSetProperties(ssp);
1030 vamsasSet.getSequenceSetProperties().add(ssp);
1035 Set<String> calcIdSet = new HashSet<>();
1036 // record the set of vamsas sequence XML POJO we create.
1037 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1039 for (final SequenceI jds : rjal.getSequences())
1041 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1042 : jds.getDatasetSequence();
1043 String id = seqHash(jds);
1044 if (vamsasSetIds.get(id) == null)
1046 if (seqRefIds.get(id) != null && !storeDS)
1048 // This happens for two reasons: 1. multiple views are being
1050 // 2. the hashCode has collided with another sequence's code. This
1052 // HAPPEN! (PF00072.15.stk does this)
1053 // JBPNote: Uncomment to debug writing out of files that do not read
1054 // back in due to ArrayOutOfBoundExceptions.
1055 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1056 // jalview.bin.Console.errPrintln(jds.getName()+"
1057 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1058 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1059 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1060 // jalview.bin.Console.errPrintln(rsq.getName()+"
1061 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1062 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1066 vamsasSeq = createVamsasSequence(id, jds);
1067 // vamsasSet.addSequence(vamsasSeq);
1068 vamsasSet.getSequence().add(vamsasSeq);
1069 vamsasSetIds.put(id, vamsasSeq);
1070 seqRefIds.put(id, jds);
1074 jseq.setStart(jds.getStart());
1075 jseq.setEnd(jds.getEnd());
1076 jseq.setColour(av.getSequenceColour(jds).getRGB());
1078 jseq.setId(id); // jseq id should be a string not a number
1081 // Store any sequences this sequence represents
1082 if (av.hasHiddenRows())
1084 // use rjal, contains the full height alignment
1086 av.getAlignment().getHiddenSequences().isHidden(jds));
1088 if (av.isHiddenRepSequence(jds))
1090 jalview.datamodel.SequenceI[] reps = av
1091 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1093 for (int h = 0; h < reps.length; h++)
1097 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1098 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1103 // mark sequence as reference - if it is the reference for this view
1104 if (jal.hasSeqrep())
1106 jseq.setViewreference(jds == jal.getSeqrep());
1110 // TODO: omit sequence features from each alignment view's XML dump if we
1111 // are storing dataset
1112 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1113 for (SequenceFeature sf : sfs)
1115 // Features features = new Features();
1116 Feature features = new Feature();
1118 features.setBegin(sf.getBegin());
1119 features.setEnd(sf.getEnd());
1120 features.setDescription(sf.getDescription());
1121 features.setType(sf.getType());
1122 features.setFeatureGroup(sf.getFeatureGroup());
1123 features.setScore(sf.getScore());
1124 if (sf.links != null)
1126 for (int l = 0; l < sf.links.size(); l++)
1128 OtherData keyValue = new OtherData();
1129 keyValue.setKey("LINK_" + l);
1130 keyValue.setValue(sf.links.elementAt(l).toString());
1131 // features.addOtherData(keyValue);
1132 features.getOtherData().add(keyValue);
1135 if (sf.otherDetails != null)
1138 * save feature attributes, which may be simple strings or
1139 * map valued (have sub-attributes)
1141 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1143 String key = entry.getKey();
1144 Object value = entry.getValue();
1145 if (value instanceof Map<?, ?>)
1147 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1150 OtherData otherData = new OtherData();
1151 otherData.setKey(key);
1152 otherData.setKey2(subAttribute.getKey());
1153 otherData.setValue(subAttribute.getValue().toString());
1154 // features.addOtherData(otherData);
1155 features.getOtherData().add(otherData);
1160 OtherData otherData = new OtherData();
1161 otherData.setKey(key);
1162 otherData.setValue(value.toString());
1163 // features.addOtherData(otherData);
1164 features.getOtherData().add(otherData);
1169 // jseq.addFeatures(features);
1170 jseq.getFeatures().add(features);
1173 if (jdatasq.getAllPDBEntries() != null)
1175 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1176 while (en.hasMoreElements())
1178 Pdbids pdb = new Pdbids();
1179 jalview.datamodel.PDBEntry entry = en.nextElement();
1181 String pdbId = entry.getId();
1183 pdb.setType(entry.getType());
1186 * Store any structure views associated with this sequence. This
1187 * section copes with duplicate entries in the project, so a dataset
1188 * only view *should* be coped with sensibly.
1190 // This must have been loaded, is it still visible?
1191 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1192 if (Desktop.desktop != null)
1194 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1197 for (JInternalFrame jif : jifs)
1199 if (jif instanceof JalviewStructureDisplayI)
1201 viewFrames.add((JalviewStructureDisplayI) jif);
1206 else if (Jalview.isHeadlessMode()
1207 && Jalview.getInstance().getCommands() != null)
1210 StructureViewerBase.getAllStructureViewerBases());
1213 String matchedFile = null;
1214 for (JalviewStructureDisplayI viewFrame : viewFrames)
1216 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1217 matchedFile, viewFrame);
1219 * Only store each structure viewer's state once in the project
1220 * jar. First time through only (storeDS==false)
1222 String viewId = viewFrame.getViewId();
1223 String viewerType = viewFrame.getViewerType().toString();
1224 if (!storeDS && !viewIds.contains(viewId))
1226 viewIds.add(viewId);
1227 File viewerState = viewFrame.saveSession();
1228 if (viewerState != null)
1230 copyFileToJar(jout, viewerState.getPath(),
1231 getViewerJarEntryName(viewId), viewerType);
1236 "Failed to save viewer state for " + viewerType);
1241 if (matchedFile != null || entry.getFile() != null)
1243 if (entry.getFile() != null)
1246 matchedFile = entry.getFile();
1248 pdb.setFile(matchedFile); // entry.getFile());
1249 if (pdbfiles == null)
1251 pdbfiles = new ArrayList<>();
1254 if (!pdbfiles.contains(pdbId))
1256 pdbfiles.add(pdbId);
1257 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1261 Enumeration<String> props = entry.getProperties();
1262 if (props.hasMoreElements())
1264 // PdbentryItem item = new PdbentryItem();
1265 while (props.hasMoreElements())
1267 Property prop = new Property();
1268 String key = props.nextElement();
1270 prop.setValue(entry.getProperty(key).toString());
1271 // item.addProperty(prop);
1272 pdb.getProperty().add(prop);
1274 // pdb.addPdbentryItem(item);
1277 // jseq.addPdbids(pdb);
1278 jseq.getPdbids().add(pdb);
1282 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1284 // jms.addJSeq(jseq);
1285 object.getJSeq().add(jseq);
1288 if (!storeDS && av.hasHiddenRows())
1290 jal = av.getAlignment();
1294 if (storeDS && jal.getCodonFrames() != null)
1296 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1297 for (AlignedCodonFrame acf : jac)
1299 AlcodonFrame alc = new AlcodonFrame();
1300 if (acf.getProtMappings() != null
1301 && acf.getProtMappings().length > 0)
1303 boolean hasMap = false;
1304 SequenceI[] dnas = acf.getdnaSeqs();
1305 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1306 for (int m = 0; m < pmaps.length; m++)
1308 AlcodMap alcmap = new AlcodMap();
1309 alcmap.setDnasq(seqHash(dnas[m]));
1311 createVamsasMapping(pmaps[m], dnas[m], null, false));
1312 // alc.addAlcodMap(alcmap);
1313 alc.getAlcodMap().add(alcmap);
1318 // vamsasSet.addAlcodonFrame(alc);
1319 vamsasSet.getAlcodonFrame().add(alc);
1322 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1324 // AlcodonFrame alc = new AlcodonFrame();
1325 // vamsasSet.addAlcodonFrame(alc);
1326 // for (int p = 0; p < acf.aaWidth; p++)
1328 // Alcodon cmap = new Alcodon();
1329 // if (acf.codons[p] != null)
1331 // // Null codons indicate a gapped column in the translated peptide
1333 // cmap.setPos1(acf.codons[p][0]);
1334 // cmap.setPos2(acf.codons[p][1]);
1335 // cmap.setPos3(acf.codons[p][2]);
1337 // alc.addAlcodon(cmap);
1339 // if (acf.getProtMappings() != null
1340 // && acf.getProtMappings().length > 0)
1342 // SequenceI[] dnas = acf.getdnaSeqs();
1343 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1344 // for (int m = 0; m < pmaps.length; m++)
1346 // AlcodMap alcmap = new AlcodMap();
1347 // alcmap.setDnasq(seqHash(dnas[m]));
1348 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1350 // alc.addAlcodMap(alcmap);
1357 // /////////////////////////////////
1358 if (!storeDS && av.getCurrentTree() != null)
1360 // FIND ANY ASSOCIATED TREES
1361 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1362 if (Desktop.desktop != null)
1364 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1366 for (int t = 0; t < frames.length; t++)
1368 if (frames[t] instanceof TreePanel)
1370 TreePanel tp = (TreePanel) frames[t];
1372 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1374 JalviewModel.Tree tree = new JalviewModel.Tree();
1375 tree.setTitle(tp.getTitle());
1376 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1377 tree.setNewick(tp.getTree().print());
1378 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1380 tree.setFitToWindow(tp.fitToWindow.getState());
1381 tree.setFontName(tp.getTreeFont().getName());
1382 tree.setFontSize(tp.getTreeFont().getSize());
1383 tree.setFontStyle(tp.getTreeFont().getStyle());
1384 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1386 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1387 tree.setShowDistances(tp.distanceMenu.getState());
1389 tree.setHeight(tp.getHeight());
1390 tree.setWidth(tp.getWidth());
1391 tree.setXpos(tp.getX());
1392 tree.setYpos(tp.getY());
1393 tree.setId(makeHashCode(tp, null));
1394 tree.setLinkToAllViews(
1395 tp.getTreeCanvas().isApplyToAllViews());
1398 if (tp.isColumnWise())
1400 tree.setColumnWise(true);
1401 String annId = tp.getAssocAnnotation().annotationId;
1402 tree.setColumnReference(annId);
1404 // jms.addTree(tree);
1405 object.getTree().add(tree);
1415 if (!storeDS && Desktop.desktop != null)
1417 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1419 if (frame instanceof PCAPanel)
1421 PCAPanel panel = (PCAPanel) frame;
1422 if (panel.getAlignViewport().getAlignment() == jal)
1424 savePCA(panel, object);
1432 * store forward refs from an annotationRow to any groups
1434 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1437 for (SequenceI sq : jal.getSequences())
1439 // Store annotation on dataset sequences only
1440 AlignmentAnnotation[] aa = sq.getAnnotation();
1441 if (aa != null && aa.length > 0)
1443 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1450 if (jal.getAlignmentAnnotation() != null)
1452 // Store the annotation shown on the alignment.
1453 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1454 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1459 if (jal.getGroups() != null)
1461 JGroup[] groups = new JGroup[jal.getGroups().size()];
1463 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1465 JGroup jGroup = new JGroup();
1466 groups[++i] = jGroup;
1468 jGroup.setStart(sg.getStartRes());
1469 jGroup.setEnd(sg.getEndRes());
1470 jGroup.setName(sg.getName());
1471 if (groupRefs.containsKey(sg))
1473 // group has references so set its ID field
1474 jGroup.setId(groupRefs.get(sg));
1476 ColourSchemeI colourScheme = sg.getColourScheme();
1477 if (colourScheme != null)
1479 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1480 if (groupColourScheme.conservationApplied())
1482 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1484 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1486 jGroup.setColour(setUserColourScheme(colourScheme,
1487 userColours, object));
1491 jGroup.setColour(colourScheme.getSchemeName());
1494 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1496 jGroup.setColour("AnnotationColourGradient");
1497 jGroup.setAnnotationColours(constructAnnotationColours(
1498 (jalview.schemes.AnnotationColourGradient) colourScheme,
1499 userColours, object));
1501 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1504 setUserColourScheme(colourScheme, userColours, object));
1508 jGroup.setColour(colourScheme.getSchemeName());
1511 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1514 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1515 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1516 jGroup.setDisplayText(sg.getDisplayText());
1517 jGroup.setColourText(sg.getColourText());
1518 jGroup.setTextCol1(sg.textColour.getRGB());
1519 jGroup.setTextCol2(sg.textColour2.getRGB());
1520 jGroup.setTextColThreshold(sg.thresholdTextColour);
1521 jGroup.setShowUnconserved(sg.getShowNonconserved());
1522 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1523 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1524 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1525 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1526 for (SequenceI seq : sg.getSequences())
1528 // jGroup.addSeq(seqHash(seq));
1529 jGroup.getSeq().add(seqHash(seq));
1533 // jms.setJGroup(groups);
1535 for (JGroup grp : groups)
1537 object.getJGroup().add(grp);
1542 // /////////SAVE VIEWPORT
1543 Viewport view = new Viewport();
1544 view.setTitle(ap.alignFrame.getTitle());
1545 view.setSequenceSetId(
1546 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1547 view.setId(av.getViewId());
1548 if (av.getCodingComplement() != null)
1550 view.setComplementId(av.getCodingComplement().getViewId());
1552 view.setViewName(av.getViewName());
1553 view.setGatheredViews(av.isGatherViewsHere());
1555 Rectangle size = ap.av.getExplodedGeometry();
1556 Rectangle position = size;
1559 size = ap.alignFrame.getBounds();
1560 if (av.getCodingComplement() != null)
1562 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1570 view.setXpos(position.x);
1571 view.setYpos(position.y);
1573 view.setWidth(size.width);
1574 view.setHeight(size.height);
1576 view.setStartRes(vpRanges.getStartRes());
1577 view.setStartSeq(vpRanges.getStartSeq());
1579 OverviewPanel ov = ap.getOverviewPanel();
1582 Overview overview = new Overview();
1583 overview.setTitle(ov.getTitle());
1584 Rectangle bounds = ov.getFrameBounds();
1585 overview.setXpos(bounds.x);
1586 overview.setYpos(bounds.y);
1587 overview.setWidth(bounds.width);
1588 overview.setHeight(bounds.height);
1589 overview.setShowHidden(ov.isShowHiddenRegions());
1590 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1591 overview.setResidueColour(
1592 ov.getCanvas().getResidueColour().getRGB());
1593 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1594 view.setOverview(overview);
1596 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1598 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1599 userColours, object));
1602 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1604 AnnotationColourScheme ac = constructAnnotationColours(
1605 (jalview.schemes.AnnotationColourGradient) av
1606 .getGlobalColourScheme(),
1607 userColours, object);
1609 view.setAnnotationColours(ac);
1610 view.setBgColour("AnnotationColourGradient");
1614 view.setBgColour(ColourSchemeProperty
1615 .getColourName(av.getGlobalColourScheme()));
1618 ResidueShaderI vcs = av.getResidueShading();
1619 ColourSchemeI cs = av.getGlobalColourScheme();
1623 if (vcs.conservationApplied())
1625 view.setConsThreshold(vcs.getConservationInc());
1626 if (cs instanceof jalview.schemes.UserColourScheme)
1628 view.setBgColour(setUserColourScheme(cs, userColours, object));
1631 view.setPidThreshold(vcs.getThreshold());
1634 view.setConservationSelected(av.getConservationSelected());
1635 view.setPidSelected(av.getAbovePIDThreshold());
1636 view.setCharHeight(av.getCharHeight());
1637 view.setCharWidth(av.getCharWidth());
1638 final Font font = av.getFont();
1639 view.setFontName(font.getName());
1640 view.setFontSize(font.getSize());
1641 view.setFontStyle(font.getStyle());
1642 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1643 view.setRenderGaps(av.isRenderGaps());
1644 view.setShowAnnotation(av.isShowAnnotation());
1645 view.setShowBoxes(av.getShowBoxes());
1646 view.setShowColourText(av.getColourText());
1647 view.setShowFullId(av.getShowJVSuffix());
1648 view.setRightAlignIds(av.isRightAlignIds());
1649 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1650 view.setShowText(av.getShowText());
1651 view.setShowUnconserved(av.getShowUnconserved());
1652 view.setWrapAlignment(av.getWrapAlignment());
1653 view.setTextCol1(av.getTextColour().getRGB());
1654 view.setTextCol2(av.getTextColour2().getRGB());
1655 view.setTextColThreshold(av.getThresholdTextColour());
1656 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1657 view.setShowSequenceLogo(av.isShowSequenceLogo());
1658 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1659 view.setShowGroupConsensus(av.isShowGroupConsensus());
1660 view.setShowGroupConservation(av.isShowGroupConservation());
1661 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1662 view.setShowDbRefTooltip(av.isShowDBRefs());
1663 view.setFollowHighlight(av.isFollowHighlight());
1664 view.setFollowSelection(av.followSelection);
1665 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1666 view.setShowComplementFeatures(av.isShowComplementFeatures());
1667 view.setShowComplementFeaturesOnTop(
1668 av.isShowComplementFeaturesOnTop());
1669 if (av.getFeaturesDisplayed() != null)
1671 FeatureSettings fs = new FeatureSettings();
1673 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1674 .getFeatureRenderer();
1675 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1677 Vector<String> settingsAdded = new Vector<>();
1678 if (renderOrder != null)
1680 for (String featureType : renderOrder)
1682 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1683 setting.setType(featureType);
1686 * save any filter for the feature type
1688 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1691 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1693 FeatureMatcherI firstFilter = filters.next();
1694 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1695 filters, filter.isAnded()));
1699 * save colour scheme for the feature type
1701 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1702 if (!fcol.isSimpleColour())
1704 setting.setColour(fcol.getMaxColour().getRGB());
1705 setting.setMincolour(fcol.getMinColour().getRGB());
1706 setting.setMin(fcol.getMin());
1707 setting.setMax(fcol.getMax());
1708 setting.setColourByLabel(fcol.isColourByLabel());
1709 if (fcol.isColourByAttribute())
1711 String[] attName = fcol.getAttributeName();
1712 setting.getAttributeName().add(attName[0]);
1713 if (attName.length > 1)
1715 setting.getAttributeName().add(attName[1]);
1718 setting.setAutoScale(fcol.isAutoScaled());
1719 setting.setThreshold(fcol.getThreshold());
1720 Color noColour = fcol.getNoColour();
1721 if (noColour == null)
1723 setting.setNoValueColour(NoValueColour.NONE);
1725 else if (noColour.equals(fcol.getMaxColour()))
1727 setting.setNoValueColour(NoValueColour.MAX);
1731 setting.setNoValueColour(NoValueColour.MIN);
1733 // -1 = No threshold, 0 = Below, 1 = Above
1734 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1735 : (fcol.isBelowThreshold() ? 0 : -1));
1739 setting.setColour(fcol.getColour().getRGB());
1743 av.getFeaturesDisplayed().isVisible(featureType));
1744 float rorder = fr.getOrder(featureType);
1747 setting.setOrder(rorder);
1749 /// fs.addSetting(setting);
1750 fs.getSetting().add(setting);
1751 settingsAdded.addElement(featureType);
1755 // is groups actually supposed to be a map here ?
1756 Iterator<String> en = fr.getFeatureGroups().iterator();
1757 Vector<String> groupsAdded = new Vector<>();
1758 while (en.hasNext())
1760 String grp = en.next();
1761 if (groupsAdded.contains(grp))
1765 Group g = new Group();
1767 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1770 fs.getGroup().add(g);
1771 groupsAdded.addElement(grp);
1773 // jms.setFeatureSettings(fs);
1774 object.setFeatureSettings(fs);
1777 if (av.hasHiddenColumns())
1779 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1780 .getHiddenColumns();
1784 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1788 Iterator<int[]> hiddenRegions = hidden.iterator();
1789 while (hiddenRegions.hasNext())
1791 int[] region = hiddenRegions.next();
1792 HiddenColumns hc = new HiddenColumns();
1793 hc.setStart(region[0]);
1794 hc.setEnd(region[1]);
1795 // view.addHiddenColumns(hc);
1796 view.getHiddenColumns().add(hc);
1800 if (calcIdSet.size() > 0)
1802 for (String calcId : calcIdSet)
1804 if (calcId.trim().length() > 0)
1806 CalcIdParam cidp = createCalcIdParam(calcId, av);
1807 // Some calcIds have no parameters.
1810 // view.addCalcIdParam(cidp);
1811 view.getCalcIdParam().add(cidp);
1817 // jms.addViewport(view);
1818 object.getViewport().add(view);
1824 // store matrices referenced by any views or annotation in this dataset
1825 if (xmlMatrices!=null && xmlMatrices.size()>0)
1827 Console.debug("Adding "+xmlMatrices.size()+" matrices to dataset.");
1828 vamsasSet.getMatrix().addAll(xmlMatrices);
1829 xmlMatrices.clear();
1834 // object.setJalviewModelSequence(jms);
1835 // object.getVamsasModel().addSequenceSet(vamsasSet);
1836 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1838 if (jout != null && fileName != null)
1840 // We may not want to write the object to disk,
1841 // eg we can copy the alignViewport to a new view object
1842 // using save and then load
1845 fileName = fileName.replace('\\', '/');
1846 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1847 JarEntry entry = new JarEntry(fileName);
1848 jout.putNextEntry(entry);
1849 PrintWriter pout = new PrintWriter(
1850 new OutputStreamWriter(jout, UTF_8));
1851 JAXBContext jaxbContext = JAXBContext
1852 .newInstance(JalviewModel.class);
1853 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1855 // output pretty printed
1856 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1857 jaxbMarshaller.marshal(
1858 new ObjectFactory().createJalviewModel(object), pout);
1860 // jaxbMarshaller.marshal(object, pout);
1861 // marshaller.marshal(object);
1864 } catch (Exception ex)
1866 // TODO: raise error in GUI if marshalling failed.
1867 jalview.bin.Console.errPrintln("Error writing Jalview project");
1868 ex.printStackTrace();
1875 * Writes PCA viewer attributes and computed values to an XML model object and
1876 * adds it to the JalviewModel. Any exceptions are reported by logging.
1878 protected void savePCA(PCAPanel panel, JalviewModel object)
1882 PcaViewer viewer = new PcaViewer();
1883 viewer.setHeight(panel.getHeight());
1884 viewer.setWidth(panel.getWidth());
1885 viewer.setXpos(panel.getX());
1886 viewer.setYpos(panel.getY());
1887 viewer.setTitle(panel.getTitle());
1888 PCAModel pcaModel = panel.getPcaModel();
1889 viewer.setScoreModelName(pcaModel.getScoreModelName());
1890 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1891 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1892 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1894 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1895 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1896 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1897 SeqPointMin spmin = new SeqPointMin();
1898 spmin.setXPos(spMin[0]);
1899 spmin.setYPos(spMin[1]);
1900 spmin.setZPos(spMin[2]);
1901 viewer.setSeqPointMin(spmin);
1902 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1903 SeqPointMax spmax = new SeqPointMax();
1904 spmax.setXPos(spMax[0]);
1905 spmax.setYPos(spMax[1]);
1906 spmax.setZPos(spMax[2]);
1907 viewer.setSeqPointMax(spmax);
1908 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1909 viewer.setLinkToAllViews(
1910 panel.getRotatableCanvas().isApplyToAllViews());
1911 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1912 viewer.setIncludeGaps(sp.includeGaps());
1913 viewer.setMatchGaps(sp.matchGaps());
1914 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1915 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1918 * sequence points on display
1920 for (jalview.datamodel.SequencePoint spt : pcaModel
1921 .getSequencePoints())
1923 SequencePoint point = new SequencePoint();
1924 point.setSequenceRef(seqHash(spt.getSequence()));
1925 point.setXPos(spt.coord.x);
1926 point.setYPos(spt.coord.y);
1927 point.setZPos(spt.coord.z);
1928 viewer.getSequencePoint().add(point);
1932 * (end points of) axes on display
1934 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1937 Axis axis = new Axis();
1941 viewer.getAxis().add(axis);
1945 * raw PCA data (note we are not restoring PCA inputs here -
1946 * alignment view, score model, similarity parameters)
1948 PcaDataType data = new PcaDataType();
1949 viewer.setPcaData(data);
1950 PCA pca = pcaModel.getPcaData();
1952 DoubleMatrix pm = new DoubleMatrix();
1953 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1954 data.setPairwiseMatrix(pm);
1956 DoubleMatrix tm = new DoubleMatrix();
1957 saveDoubleMatrix(pca.getTridiagonal(), tm);
1958 data.setTridiagonalMatrix(tm);
1960 DoubleMatrix eigenMatrix = new DoubleMatrix();
1961 data.setEigenMatrix(eigenMatrix);
1962 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1964 object.getPcaViewer().add(viewer);
1965 } catch (Throwable t)
1967 Console.error("Error saving PCA: " + t.getMessage());
1972 * Stores values from a matrix into an XML element, including (if present) the
1977 * @see #loadDoubleMatrix(DoubleMatrix)
1979 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1981 xmlMatrix.setRows(m.height());
1982 xmlMatrix.setColumns(m.width());
1983 for (int i = 0; i < m.height(); i++)
1985 DoubleVector row = new DoubleVector();
1986 for (int j = 0; j < m.width(); j++)
1988 row.getV().add(m.getValue(i, j));
1990 xmlMatrix.getRow().add(row);
1992 if (m.getD() != null)
1994 DoubleVector dVector = new DoubleVector();
1995 for (double d : m.getD())
1997 dVector.getV().add(d);
1999 xmlMatrix.setD(dVector);
2001 if (m.getE() != null)
2003 DoubleVector eVector = new DoubleVector();
2004 for (double e : m.getE())
2006 eVector.getV().add(e);
2008 xmlMatrix.setE(eVector);
2013 * Loads XML matrix data into a new Matrix object, including the D and/or E
2014 * vectors (if present)
2018 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2020 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2022 int rows = mData.getRows();
2023 double[][] vals = new double[rows][];
2025 for (int i = 0; i < rows; i++)
2027 List<Double> dVector = mData.getRow().get(i).getV();
2028 vals[i] = new double[dVector.size()];
2030 for (Double d : dVector)
2036 MatrixI m = new Matrix(vals);
2038 if (mData.getD() != null)
2040 List<Double> dVector = mData.getD().getV();
2041 double[] vec = new double[dVector.size()];
2043 for (Double d : dVector)
2049 if (mData.getE() != null)
2051 List<Double> dVector = mData.getE().getV();
2052 double[] vec = new double[dVector.size()];
2054 for (Double d : dVector)
2065 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2066 * for each viewer, with
2068 * <li>viewer geometry (position, size, split pane divider location)</li>
2069 * <li>index of the selected structure in the viewer (currently shows gapped
2071 * <li>the id of the annotation holding RNA secondary structure</li>
2072 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2074 * Varna viewer state is also written out (in native Varna XML) to separate
2075 * project jar entries. A separate entry is written for each RNA structure
2076 * displayed, with the naming convention
2078 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2086 * @param storeDataset
2088 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2089 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2090 boolean storeDataset)
2092 if (Desktop.desktop == null)
2096 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2097 for (int f = frames.length - 1; f > -1; f--)
2099 if (frames[f] instanceof AppVarna)
2101 AppVarna varna = (AppVarna) frames[f];
2103 * link the sequence to every viewer that is showing it and is linked to
2104 * its alignment panel
2106 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2108 String viewId = varna.getViewId();
2109 RnaViewer rna = new RnaViewer();
2110 rna.setViewId(viewId);
2111 rna.setTitle(varna.getTitle());
2112 rna.setXpos(varna.getX());
2113 rna.setYpos(varna.getY());
2114 rna.setWidth(varna.getWidth());
2115 rna.setHeight(varna.getHeight());
2116 rna.setDividerLocation(varna.getDividerLocation());
2117 rna.setSelectedRna(varna.getSelectedIndex());
2118 // jseq.addRnaViewer(rna);
2119 jseq.getRnaViewer().add(rna);
2122 * Store each Varna panel's state once in the project per sequence.
2123 * First time through only (storeDataset==false)
2125 // boolean storeSessions = false;
2126 // String sequenceViewId = viewId + seqsToIds.get(jds);
2127 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2129 // viewIds.add(sequenceViewId);
2130 // storeSessions = true;
2132 for (RnaModel model : varna.getModels())
2134 if (model.seq == jds)
2137 * VARNA saves each view (sequence or alignment secondary
2138 * structure, gapped or trimmed) as a separate XML file
2140 String jarEntryName = rnaSessions.get(model);
2141 if (jarEntryName == null)
2144 String varnaStateFile = varna.getStateInfo(model.rna);
2145 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2146 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2147 rnaSessions.put(model, jarEntryName);
2149 SecondaryStructure ss = new SecondaryStructure();
2150 String annotationId = varna.getAnnotation(jds).annotationId;
2151 ss.setAnnotationId(annotationId);
2152 ss.setViewerState(jarEntryName);
2153 ss.setGapped(model.gapped);
2154 ss.setTitle(model.title);
2155 // rna.addSecondaryStructure(ss);
2156 rna.getSecondaryStructure().add(ss);
2165 * Copy the contents of a file to a new entry added to the output jar
2169 * @param jarEntryName
2171 * additional identifying info to log to the console
2173 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2174 String jarEntryName, String msg)
2176 try (InputStream is = new FileInputStream(infilePath))
2178 File file = new File(infilePath);
2179 if (file.exists() && jout != null)
2181 jalview.bin.Console.outPrintln(
2182 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2183 jout.putNextEntry(new JarEntry(jarEntryName));
2186 // dis = new DataInputStream(new FileInputStream(file));
2187 // byte[] data = new byte[(int) file.length()];
2188 // dis.readFully(data);
2189 // writeJarEntry(jout, jarEntryName, data);
2191 } catch (Exception ex)
2193 ex.printStackTrace();
2198 * Copies input to output, in 4K buffers; handles any data (text or binary)
2202 * @throws IOException
2204 protected void copyAll(InputStream in, OutputStream out)
2207 byte[] buffer = new byte[4096];
2209 while ((bytesRead = in.read(buffer)) != -1)
2211 out.write(buffer, 0, bytesRead);
2216 * Save the state of a structure viewer
2221 * the archive XML element under which to save the state
2224 * @param matchedFile
2228 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2229 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2230 String matchedFile, JalviewStructureDisplayI viewFrame)
2232 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2235 * Look for any bindings for this viewer to the PDB file of interest
2236 * (including part matches excluding chain id)
2238 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2240 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2241 final String pdbId = pdbentry.getId();
2242 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2243 && entry.getId().toLowerCase(Locale.ROOT)
2244 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2247 * not interested in a binding to a different PDB entry here
2251 if (matchedFile == null)
2253 matchedFile = pdbentry.getFile();
2255 else if (!matchedFile.equals(pdbentry.getFile()))
2258 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2259 + pdbentry.getFile());
2263 // can get at it if the ID
2264 // match is ambiguous (e.g.
2267 for (int smap = 0; smap < viewFrame.getBinding()
2268 .getSequence()[peid].length; smap++)
2270 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2271 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2273 StructureState state = new StructureState();
2274 state.setVisible(true);
2275 state.setXpos(viewFrame.getY());
2276 state.setYpos(viewFrame.getY());
2277 state.setWidth(viewFrame.getWidth());
2278 state.setHeight(viewFrame.getHeight());
2279 final String viewId = viewFrame.getViewId();
2280 state.setViewId(viewId);
2281 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2282 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2283 state.setColourByJmol(viewFrame.isColouredByViewer());
2284 state.setType(viewFrame.getViewerType().toString());
2285 // pdb.addStructureState(state);
2286 pdb.getStructureState().add(state);
2294 * Populates the AnnotationColourScheme xml for save. This captures the
2295 * settings of the options in the 'Colour by Annotation' dialog.
2298 * @param userColours
2302 private AnnotationColourScheme constructAnnotationColours(
2303 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2306 AnnotationColourScheme ac = new AnnotationColourScheme();
2307 ac.setAboveThreshold(acg.getAboveThreshold());
2308 ac.setThreshold(acg.getAnnotationThreshold());
2309 // 2.10.2 save annotationId (unique) not annotation label
2310 ac.setAnnotation(acg.getAnnotation().annotationId);
2311 if (acg.getBaseColour() instanceof UserColourScheme)
2314 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2319 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2322 ac.setMaxColour(acg.getMaxColour().getRGB());
2323 ac.setMinColour(acg.getMinColour().getRGB());
2324 ac.setPerSequence(acg.isSeqAssociated());
2325 ac.setPredefinedColours(acg.isPredefinedColours());
2329 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2330 IdentityHashMap<SequenceGroup, String> groupRefs,
2331 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2332 SequenceSet vamsasSet)
2335 for (int i = 0; i < aa.length; i++)
2337 Annotation an = new Annotation();
2339 AlignmentAnnotation annotation = aa[i];
2340 if (annotation.annotationId != null)
2342 annotationIds.put(annotation.annotationId, annotation);
2345 an.setId(annotation.annotationId);
2347 an.setVisible(annotation.visible);
2349 an.setDescription(annotation.description);
2351 if (annotation.sequenceRef != null)
2353 // 2.9 JAL-1781 xref on sequence id rather than name
2354 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2356 if (annotation.groupRef != null)
2358 String groupIdr = groupRefs.get(annotation.groupRef);
2359 if (groupIdr == null)
2361 // make a locally unique String
2362 groupRefs.put(annotation.groupRef,
2363 groupIdr = ("" + System.currentTimeMillis()
2364 + annotation.groupRef.getName()
2365 + groupRefs.size()));
2367 an.setGroupRef(groupIdr.toString());
2370 // store all visualization attributes for annotation
2371 an.setGraphHeight(annotation.graphHeight);
2372 an.setCentreColLabels(annotation.centreColLabels);
2373 an.setScaleColLabels(annotation.scaleColLabel);
2374 an.setShowAllColLabels(annotation.showAllColLabels);
2375 an.setBelowAlignment(annotation.belowAlignment);
2377 if (annotation.graph > 0)
2380 an.setGraphType(annotation.graph);
2381 an.setGraphGroup(annotation.graphGroup);
2382 if (annotation.getThreshold() != null)
2384 ThresholdLine line = new ThresholdLine();
2385 line.setLabel(annotation.getThreshold().label);
2386 line.setValue(annotation.getThreshold().value);
2387 line.setColour(annotation.getThreshold().colour.getRGB());
2388 an.setThresholdLine(line);
2390 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2392 if (annotation.sequenceRef.getContactMaps() != null)
2394 ContactMatrixI cm = annotation.sequenceRef
2395 .getContactMatrixFor(annotation);
2398 storeMatrixFor(vamsasSet, an,annotation, cm);
2408 an.setLabel(annotation.label);
2410 if (annotation == av.getAlignmentQualityAnnot()
2411 || annotation == av.getAlignmentConservationAnnotation()
2412 || annotation == av.getAlignmentConsensusAnnotation()
2413 || annotation.autoCalculated)
2415 // new way of indicating autocalculated annotation -
2416 an.setAutoCalculated(annotation.autoCalculated);
2418 if (annotation.hasScore())
2420 an.setScore(annotation.getScore());
2423 if (annotation.getCalcId() != null)
2425 calcIdSet.add(annotation.getCalcId());
2426 an.setCalcId(annotation.getCalcId());
2428 if (annotation.hasProperties())
2430 for (String pr : annotation.getProperties())
2432 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2434 prop.setValue(annotation.getProperty(pr));
2435 an.getProperty().add(prop);
2439 AnnotationElement ae;
2440 if (annotation.annotations != null)
2442 an.setScoreOnly(false);
2443 for (int a = 0; a < annotation.annotations.length; a++)
2445 if ((annotation == null) || (annotation.annotations[a] == null))
2450 ae = new AnnotationElement();
2451 if (annotation.annotations[a].description != null)
2453 ae.setDescription(annotation.annotations[a].description);
2455 if (annotation.annotations[a].displayCharacter != null)
2457 ae.setDisplayCharacter(
2458 annotation.annotations[a].displayCharacter);
2461 if (!Float.isNaN(annotation.annotations[a].value))
2463 ae.setValue(annotation.annotations[a].value);
2467 if (annotation.annotations[a].secondaryStructure > ' ')
2469 ae.setSecondaryStructure(
2470 annotation.annotations[a].secondaryStructure + "");
2473 if (annotation.annotations[a].colour != null
2474 && annotation.annotations[a].colour != java.awt.Color.black)
2476 ae.setColour(annotation.annotations[a].colour.getRGB());
2479 // an.addAnnotationElement(ae);
2480 an.getAnnotationElement().add(ae);
2481 if (annotation.autoCalculated)
2483 // only write one non-null entry into the annotation row -
2484 // sufficient to get the visualization attributes necessary to
2492 an.setScoreOnly(true);
2494 if (!storeDS || (storeDS && !annotation.autoCalculated))
2496 // skip autocalculated annotation - these are only provided for
2498 // vamsasSet.addAnnotation(an);
2499 vamsasSet.getAnnotation().add(an);
2505 private void storeMatrixFor(SequenceSet root, Annotation an, AlignmentAnnotation annotation, ContactMatrixI cm)
2507 String cmId = contactMatrices.get(cm);
2508 MatrixType xmlmat=null;
2510 // first create an xml ref for the matrix data, if none exist
2513 xmlmat = new MatrixType();
2514 xmlmat.setType(cm.getType());
2515 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2516 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2517 // consider using an opaque to/from -> allow instance to control
2518 // its representation ?
2519 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2522 for (BitSet gp : cm.getGroups())
2524 xmlmat.getGroups().add(stringifyBitset(gp));
2529 // provenance object for tree ?
2530 xmlmat.getNewick().add(cm.getNewick());
2531 xmlmat.setTreeMethod(cm.getTreeMethod());
2533 if (cm.hasCutHeight())
2535 xmlmat.setCutHeight(cm.getCutHeight());
2537 xmlmat.setId(cmId = "m"+contactMatrices.size()+System.currentTimeMillis());
2538 Console.trace("Matrix data stored :"+cmId);
2539 contactMatrices.put(cm, cmId);
2540 contactMatrixRefs.put(cmId, cm);
2541 xmlMatrices.add(xmlmat);
2543 Console.trace("Existing Matrix stored :"+cmId);
2546 // now store mapping
2548 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2549 xmlmatmapping.setMatrix(cmId);
2551 // Pretty much all matrices currently managed in this way are
2552 // mappableContactMatrixI implementations - but check anyway
2553 if (cm instanceof MappableContactMatrixI)
2555 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2556 .getMapFor(annotation.sequenceRef);
2559 MapListType mp = new MapListType();
2560 List<int[]> r = mlst.getFromRanges();
2561 for (int[] range : r)
2563 MapListFrom mfrom = new MapListFrom();
2564 mfrom.setStart(range[0]);
2565 mfrom.setEnd(range[1]);
2566 // mp.addMapListFrom(mfrom);
2567 mp.getMapListFrom().add(mfrom);
2569 r = mlst.getToRanges();
2570 for (int[] range : r)
2572 MapListTo mto = new MapListTo();
2573 mto.setStart(range[0]);
2574 mto.setEnd(range[1]);
2575 // mp.addMapListTo(mto);
2576 mp.getMapListTo().add(mto);
2578 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2579 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2580 xmlmatmapping.setMapping(mp);
2584 an.getContactmatrix().add(xmlmatmapping);
2587 private String stringifyBitset(BitSet gp)
2589 StringBuilder sb = new StringBuilder();
2590 for (long val : gp.toLongArray())
2592 if (sb.length() > 0)
2598 return sb.toString();
2601 private BitSet deStringifyBitset(String stringified)
2603 if ("".equals(stringified) || stringified == null)
2605 return new BitSet();
2607 String[] longvals = stringified.split(",");
2608 long[] newlongvals = new long[longvals.length];
2609 for (int lv = 0; lv < longvals.length; lv++)
2613 newlongvals[lv] = Long.valueOf(longvals[lv]);
2614 } catch (Exception x)
2616 errorMessage += "Couldn't destringify bitset from: '" + stringified
2618 newlongvals[lv] = 0;
2621 return BitSet.valueOf(newlongvals);
2625 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2627 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2628 if (settings != null)
2630 CalcIdParam vCalcIdParam = new CalcIdParam();
2631 vCalcIdParam.setCalcId(calcId);
2632 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2633 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2634 // generic URI allowing a third party to resolve another instance of the
2635 // service used for this calculation
2636 for (String url : settings.getServiceURLs())
2638 // vCalcIdParam.addServiceURL(urls);
2639 vCalcIdParam.getServiceURL().add(url);
2641 vCalcIdParam.setVersion("1.0");
2642 if (settings.getPreset() != null)
2644 WsParamSetI setting = settings.getPreset();
2645 vCalcIdParam.setName(setting.getName());
2646 vCalcIdParam.setDescription(setting.getDescription());
2650 vCalcIdParam.setName("");
2651 vCalcIdParam.setDescription("Last used parameters");
2653 // need to be able to recover 1) settings 2) user-defined presets or
2654 // recreate settings from preset 3) predefined settings provided by
2655 // service - or settings that can be transferred (or discarded)
2656 vCalcIdParam.setParameters(
2657 settings.getWsParamFile().replace("\n", "|\\n|"));
2658 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2659 // todo - decide if updateImmediately is needed for any projects.
2661 return vCalcIdParam;
2666 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2669 if (calcIdParam.getVersion().equals("1.0"))
2671 final String[] calcIds = calcIdParam.getServiceURL()
2672 .toArray(new String[0]);
2673 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2674 .getPreferredServiceFor(calcIds);
2675 if (service != null)
2677 WsParamSetI parmSet = null;
2680 parmSet = service.getParamStore().parseServiceParameterFile(
2681 calcIdParam.getName(), calcIdParam.getDescription(),
2683 calcIdParam.getParameters().replace("|\\n|", "\n"));
2684 } catch (IOException x)
2686 Console.warn("Couldn't parse parameter data for "
2687 + calcIdParam.getCalcId(), x);
2690 List<ArgumentI> argList = null;
2691 if (calcIdParam.getName().length() > 0)
2693 parmSet = service.getParamStore()
2694 .getPreset(calcIdParam.getName());
2695 if (parmSet != null)
2697 // TODO : check we have a good match with settings in AACon -
2698 // otherwise we'll need to create a new preset
2703 argList = parmSet.getArguments();
2706 AAConSettings settings = new AAConSettings(
2707 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2708 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2709 calcIdParam.isNeedsUpdate());
2715 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2719 throw new Error(MessageManager.formatMessage(
2720 "error.unsupported_version_calcIdparam", new Object[]
2721 { calcIdParam.toString() }));
2725 * External mapping between jalview objects and objects yielding a valid and
2726 * unique object ID string. This is null for normal Jalview project IO, but
2727 * non-null when a jalview project is being read or written as part of a
2730 IdentityHashMap jv2vobj = null;
2733 * Construct a unique ID for jvobj using either existing bindings or if none
2734 * exist, the result of the hashcode call for the object.
2737 * jalview data object
2738 * @return unique ID for referring to jvobj
2740 private String makeHashCode(Object jvobj, String altCode)
2742 if (jv2vobj != null)
2744 Object id = jv2vobj.get(jvobj);
2747 return id.toString();
2749 // check string ID mappings
2750 if (jvids2vobj != null && jvobj instanceof String)
2752 id = jvids2vobj.get(jvobj);
2756 return id.toString();
2758 // give up and warn that something has gone wrong
2760 "Cannot find ID for object in external mapping : " + jvobj);
2766 * return local jalview object mapped to ID, if it exists
2770 * @return null or object bound to idcode
2772 private Object retrieveExistingObj(String idcode)
2774 if (idcode != null && vobj2jv != null)
2776 return vobj2jv.get(idcode);
2782 * binding from ID strings from external mapping table to jalview data model
2785 private Hashtable vobj2jv;
2787 private Sequence createVamsasSequence(String id, SequenceI jds)
2789 return createVamsasSequence(true, id, jds, null);
2792 private Sequence createVamsasSequence(boolean recurse, String id,
2793 SequenceI jds, SequenceI parentseq)
2795 Sequence vamsasSeq = new Sequence();
2796 vamsasSeq.setId(id);
2797 vamsasSeq.setName(jds.getName());
2798 vamsasSeq.setSequence(jds.getSequenceAsString());
2799 vamsasSeq.setDescription(jds.getDescription());
2800 List<DBRefEntry> dbrefs = null;
2801 if (jds.getDatasetSequence() != null)
2803 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2807 // seqId==dsseqid so we can tell which sequences really are
2808 // dataset sequences only
2809 vamsasSeq.setDsseqid(id);
2810 dbrefs = jds.getDBRefs();
2811 if (parentseq == null)
2818 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2822 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2824 DBRef dbref = new DBRef();
2825 DBRefEntry ref = dbrefs.get(d);
2826 dbref.setSource(ref.getSource());
2827 dbref.setVersion(ref.getVersion());
2828 dbref.setAccessionId(ref.getAccessionId());
2829 dbref.setCanonical(ref.isCanonical());
2830 if (ref instanceof GeneLocus)
2832 dbref.setLocus(true);
2836 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2838 dbref.setMapping(mp);
2840 vamsasSeq.getDBRef().add(dbref);
2846 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2847 SequenceI parentseq, SequenceI jds, boolean recurse)
2850 if (jmp.getMap() != null)
2854 jalview.util.MapList mlst = jmp.getMap();
2855 List<int[]> r = mlst.getFromRanges();
2856 for (int[] range : r)
2858 MapListFrom mfrom = new MapListFrom();
2859 mfrom.setStart(range[0]);
2860 mfrom.setEnd(range[1]);
2861 // mp.addMapListFrom(mfrom);
2862 mp.getMapListFrom().add(mfrom);
2864 r = mlst.getToRanges();
2865 for (int[] range : r)
2867 MapListTo mto = new MapListTo();
2868 mto.setStart(range[0]);
2869 mto.setEnd(range[1]);
2870 // mp.addMapListTo(mto);
2871 mp.getMapListTo().add(mto);
2873 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2874 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2875 if (jmp.getTo() != null)
2877 // MappingChoice mpc = new MappingChoice();
2879 // check/create ID for the sequence referenced by getTo()
2882 SequenceI ps = null;
2883 if (parentseq != jmp.getTo()
2884 && parentseq.getDatasetSequence() != jmp.getTo())
2886 // chaining dbref rather than a handshaking one
2887 jmpid = seqHash(ps = jmp.getTo());
2891 jmpid = seqHash(ps = parentseq);
2893 // mpc.setDseqFor(jmpid);
2894 mp.setDseqFor(jmpid);
2895 if (!seqRefIds.containsKey(jmpid))
2897 Console.debug("creatign new DseqFor ID");
2898 seqRefIds.put(jmpid, ps);
2902 Console.debug("reusing DseqFor ID");
2905 // mp.setMappingChoice(mpc);
2911 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2912 List<UserColourScheme> userColours, JalviewModel jm)
2915 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2916 boolean newucs = false;
2917 if (!userColours.contains(ucs))
2919 userColours.add(ucs);
2922 id = "ucs" + userColours.indexOf(ucs);
2925 // actually create the scheme's entry in the XML model
2926 java.awt.Color[] colours = ucs.getColours();
2927 UserColours uc = new UserColours();
2928 // UserColourScheme jbucs = new UserColourScheme();
2929 JalviewUserColours jbucs = new JalviewUserColours();
2931 for (int i = 0; i < colours.length; i++)
2933 Colour col = new Colour();
2934 col.setName(ResidueProperties.aa[i]);
2935 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2936 // jbucs.addColour(col);
2937 jbucs.getColour().add(col);
2939 if (ucs.getLowerCaseColours() != null)
2941 colours = ucs.getLowerCaseColours();
2942 for (int i = 0; i < colours.length; i++)
2944 Colour col = new Colour();
2945 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2946 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2947 // jbucs.addColour(col);
2948 jbucs.getColour().add(col);
2953 uc.setUserColourScheme(jbucs);
2954 // jm.addUserColours(uc);
2955 jm.getUserColours().add(uc);
2961 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2964 List<UserColours> uc = jm.getUserColours();
2965 UserColours colours = null;
2967 for (int i = 0; i < uc.length; i++)
2969 if (uc[i].getId().equals(id))
2976 for (UserColours c : uc)
2978 if (c.getId().equals(id))
2985 java.awt.Color[] newColours = new java.awt.Color[24];
2987 for (int i = 0; i < 24; i++)
2989 newColours[i] = new java.awt.Color(Integer.parseInt(
2990 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2991 colours.getUserColourScheme().getColour().get(i).getRGB(),
2995 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2998 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3000 newColours = new java.awt.Color[23];
3001 for (int i = 0; i < 23; i++)
3003 newColours[i] = new java.awt.Color(
3004 Integer.parseInt(colours.getUserColourScheme().getColour()
3005 .get(i + 24).getRGB(), 16));
3007 ucs.setLowerCaseColours(newColours);
3014 * contains last error message (if any) encountered by XML loader.
3016 String errorMessage = null;
3019 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3020 * exceptions are raised during project XML parsing
3022 public boolean attemptversion1parse = false;
3025 * Load a jalview project archive from a jar file
3028 * - HTTP URL or filename
3030 public AlignFrame loadJalviewAlign(final Object file)
3033 jalview.gui.AlignFrame af = null;
3037 // create list to store references for any new Jmol viewers created
3038 newStructureViewers = new Vector<>();
3039 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3040 // Workaround is to make sure caller implements the JarInputStreamProvider
3042 // so we can re-open the jar input stream for each entry.
3044 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3045 af = loadJalviewAlign(jprovider);
3048 af.setMenusForViewport();
3050 } catch (MalformedURLException e)
3052 errorMessage = "Invalid URL format for '" + file + "'";
3058 SwingUtilities.invokeAndWait(new Runnable()
3063 setLoadingFinishedForNewStructureViewers();
3066 } catch (Exception x)
3069 .errPrintln("Error loading alignment: " + x.getMessage());
3075 @SuppressWarnings("unused")
3076 private jarInputStreamProvider createjarInputStreamProvider(
3077 final Object ofile) throws MalformedURLException
3080 // BH 2018 allow for bytes already attached to File object
3083 String file = (ofile instanceof File
3084 ? ((File) ofile).getCanonicalPath()
3085 : ofile.toString());
3086 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3089 errorMessage = null;
3090 uniqueSetSuffix = null;
3092 viewportsAdded.clear();
3093 frefedSequence = null;
3095 if (HttpUtils.startsWithHttpOrHttps(file))
3097 url = new URL(file);
3099 final URL _url = url;
3100 return new jarInputStreamProvider()
3104 public JarInputStream getJarInputStream() throws IOException
3108 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3109 // jarInputStream for
3110 // bytes.length=" + bytes.length);
3111 return new JarInputStream(new ByteArrayInputStream(bytes));
3115 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3116 // jarInputStream for "
3118 return new JarInputStream(_url.openStream());
3122 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3123 // jarInputStream for
3125 return new JarInputStream(new FileInputStream(file));
3130 public String getFilename()
3135 } catch (IOException e)
3137 e.printStackTrace();
3143 * Recover jalview session from a jalview project archive. Caller may
3144 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3145 * themselves. Any null fields will be initialised with default values,
3146 * non-null fields are left alone.
3151 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3153 errorMessage = null;
3154 if (uniqueSetSuffix == null)
3156 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3158 if (seqRefIds == null)
3162 AlignFrame af = null, _af = null;
3163 List<AlignFrame> toRepaint=new ArrayList<AlignFrame>();
3164 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3165 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3166 final String file = jprovider.getFilename();
3169 JarInputStream jin = null;
3170 JarEntry jarentry = null;
3175 jin = jprovider.getJarInputStream();
3176 for (int i = 0; i < entryCount; i++)
3178 jarentry = jin.getNextJarEntry();
3181 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3183 JAXBContext jc = JAXBContext
3184 .newInstance("jalview.xml.binding.jalview");
3185 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3186 .createXMLStreamReader(jin);
3187 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3188 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3189 JalviewModel.class);
3190 JalviewModel object = jbe.getValue();
3192 if (true) // !skipViewport(object))
3194 _af = loadFromObject(object, file, true, jprovider);
3195 if (_af != null && object.getViewport().size() > 0)
3196 // getJalviewModelSequence().getViewportCount() > 0)
3201 // store a reference to the first view
3204 if (_af.getViewport().isGatherViewsHere())
3206 // if this is a gathered view, keep its reference since
3207 // after gathering views, only this frame will remain
3209 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3212 // Save dataset to register mappings once all resolved
3213 importedDatasets.put(
3214 af.getViewport().getAlignment().getDataset(),
3215 af.getViewport().getAlignment().getDataset());
3220 else if (jarentry != null)
3222 // Some other file here.
3225 } while (jarentry != null);
3227 resolveFrefedSequences();
3228 for (AlignFrame alignFrame:toRepaint)
3230 alignFrame.repaint();
3232 } catch (IOException ex)
3234 ex.printStackTrace();
3235 errorMessage = "Couldn't locate Jalview XML file : " + file;
3236 jalview.bin.Console.errPrintln(
3237 "Exception whilst loading jalview XML file : " + ex + "\n");
3238 } catch (Exception ex)
3241 .errPrintln("Parsing as Jalview Version 2 file failed.");
3242 ex.printStackTrace(System.err);
3243 if (attemptversion1parse)
3245 // used to attempt to parse as V1 castor-generated xml
3247 if (Desktop.instance != null)
3249 Desktop.instance.stopLoading();
3253 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3256 ex.printStackTrace();
3258 jalview.bin.Console.errPrintln(
3259 "Exception whilst loading jalview XML file : " + ex + "\n");
3260 } catch (OutOfMemoryError e)
3262 // Don't use the OOM Window here
3263 errorMessage = "Out of memory loading jalview XML file";
3265 .errPrintln("Out of memory whilst loading jalview XML file");
3266 e.printStackTrace();
3270 * Regather multiple views (with the same sequence set id) to the frame (if
3271 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3272 * views instead of separate frames. Note this doesn't restore a state where
3273 * some expanded views in turn have tabbed views - the last "first tab" read
3274 * in will play the role of gatherer for all.
3276 for (AlignFrame fr : gatherToThisFrame.values())
3278 Desktop.instance.gatherViews(fr);
3281 restoreSplitFrames();
3282 for (AlignmentI ds : importedDatasets.keySet())
3284 if (ds.getCodonFrames() != null)
3286 StructureSelectionManager
3287 .getStructureSelectionManager(Desktop.instance)
3288 .registerMappings(ds.getCodonFrames());
3291 if (errorMessage != null)
3296 if (Desktop.instance != null)
3298 Desktop.instance.stopLoading();
3305 * Try to reconstruct and display SplitFrame windows, where each contains
3306 * complementary dna and protein alignments. Done by pairing up AlignFrame
3307 * objects (created earlier) which have complementary viewport ids associated.
3309 protected void restoreSplitFrames()
3311 List<SplitFrame> gatherTo = new ArrayList<>();
3312 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3313 Map<String, AlignFrame> dna = new HashMap<>();
3316 * Identify the DNA alignments
3318 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3321 AlignFrame af = candidate.getValue();
3322 if (af.getViewport().getAlignment().isNucleotide())
3324 dna.put(candidate.getKey().getId(), af);
3329 * Try to match up the protein complements
3331 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3334 AlignFrame af = candidate.getValue();
3335 if (!af.getViewport().getAlignment().isNucleotide())
3337 String complementId = candidate.getKey().getComplementId();
3338 // only non-null complements should be in the Map
3339 if (complementId != null && dna.containsKey(complementId))
3341 final AlignFrame dnaFrame = dna.get(complementId);
3342 SplitFrame sf = createSplitFrame(dnaFrame, af);
3343 addedToSplitFrames.add(dnaFrame);
3344 addedToSplitFrames.add(af);
3345 dnaFrame.setMenusForViewport();
3346 af.setMenusForViewport();
3347 if (af.getViewport().isGatherViewsHere())
3356 * Open any that we failed to pair up (which shouldn't happen!) as
3357 * standalone AlignFrame's.
3359 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3362 AlignFrame af = candidate.getValue();
3363 if (!addedToSplitFrames.contains(af))
3365 Viewport view = candidate.getKey();
3366 Desktop.addInternalFrame(af, view.getTitle(),
3367 safeInt(view.getWidth()), safeInt(view.getHeight()));
3368 af.setMenusForViewport();
3369 jalview.bin.Console.errPrintln("Failed to restore view "
3370 + view.getTitle() + " to split frame");
3375 * Gather back into tabbed views as flagged.
3377 for (SplitFrame sf : gatherTo)
3379 Desktop.instance.gatherViews(sf);
3382 splitFrameCandidates.clear();
3386 * Construct and display one SplitFrame holding DNA and protein alignments.
3389 * @param proteinFrame
3392 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3393 AlignFrame proteinFrame)
3395 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3396 String title = MessageManager.getString("label.linked_view_title");
3397 int width = (int) dnaFrame.getBounds().getWidth();
3398 int height = (int) (dnaFrame.getBounds().getHeight()
3399 + proteinFrame.getBounds().getHeight() + 50);
3402 * SplitFrame location is saved to both enclosed frames
3404 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3405 Desktop.addInternalFrame(splitFrame, title, width, height);
3408 * And compute cDNA consensus (couldn't do earlier with consensus as
3409 * mappings were not yet present)
3411 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3417 * check errorMessage for a valid error message and raise an error box in the
3418 * GUI or write the current errorMessage to stderr and then clear the error
3421 protected void reportErrors()
3423 reportErrors(false);
3426 protected void reportErrors(final boolean saving)
3428 if (errorMessage != null)
3430 final String finalErrorMessage = errorMessage;
3433 javax.swing.SwingUtilities.invokeLater(new Runnable()
3438 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3440 "Error " + (saving ? "saving" : "loading")
3442 JvOptionPane.WARNING_MESSAGE);
3448 jalview.bin.Console.errPrintln(
3449 "Problem loading Jalview file: " + errorMessage);
3452 errorMessage = null;
3455 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3458 * when set, local views will be updated from view stored in JalviewXML
3459 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3460 * sync if this is set to true.
3462 private final boolean updateLocalViews = false;
3465 * Returns the path to a temporary file holding the PDB file for the given PDB
3466 * id. The first time of asking, searches for a file of that name in the
3467 * Jalview project jar, and copies it to a new temporary file. Any repeat
3468 * requests just return the path to the file previously created.
3474 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3477 if (alreadyLoadedPDB.containsKey(pdbId))
3479 return alreadyLoadedPDB.get(pdbId).toString();
3482 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3484 if (tempFile != null)
3486 alreadyLoadedPDB.put(pdbId, tempFile);
3492 * Copies the jar entry of given name to a new temporary file and returns the
3493 * path to the file, or null if the entry is not found.
3496 * @param jarEntryName
3498 * a prefix for the temporary file name, must be at least three
3500 * @param suffixModel
3501 * null or original file - so new file can be given the same suffix
3505 protected String copyJarEntry(jarInputStreamProvider jprovider,
3506 String jarEntryName, String prefix, String suffixModel)
3508 String suffix = ".tmp";
3509 if (suffixModel == null)
3511 suffixModel = jarEntryName;
3513 int sfpos = suffixModel.lastIndexOf(".");
3514 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3516 suffix = "." + suffixModel.substring(sfpos + 1);
3519 try (JarInputStream jin = jprovider.getJarInputStream())
3521 JarEntry entry = null;
3524 entry = jin.getNextJarEntry();
3525 } while (entry != null && !entry.getName().equals(jarEntryName));
3529 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3530 File outFile = File.createTempFile(prefix, suffix);
3531 outFile.deleteOnExit();
3532 try (OutputStream os = new FileOutputStream(outFile))
3536 String t = outFile.getAbsolutePath();
3542 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3544 } catch (Exception ex)
3546 ex.printStackTrace();
3552 private class JvAnnotRow
3554 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3561 * persisted version of annotation row from which to take vis properties
3563 public jalview.datamodel.AlignmentAnnotation template;
3566 * original position of the annotation row in the alignment
3572 * Load alignment frame from jalview XML DOM object
3574 * @param jalviewModel
3577 * filename source string
3578 * @param loadTreesAndStructures
3579 * when false only create Viewport
3581 * data source provider
3582 * @return alignment frame created from view stored in DOM
3584 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3585 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3587 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3589 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3591 // JalviewModelSequence jms = object.getJalviewModelSequence();
3593 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3595 Viewport view = (jalviewModel.getViewport().size() > 0)
3596 ? jalviewModel.getViewport().get(0)
3599 // ////////////////////////////////
3600 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3603 // If we just load in the same jar file again, the sequenceSetId
3604 // will be the same, and we end up with multiple references
3605 // to the same sequenceSet. We must modify this id on load
3606 // so that each load of the file gives a unique id
3609 * used to resolve correct alignment dataset for alignments with multiple
3612 String uniqueSeqSetId = null;
3613 String viewId = null;
3616 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3617 viewId = (view.getId() == null ? null
3618 : view.getId() + uniqueSetSuffix);
3621 // ////////////////////////////////
3622 // LOAD MATRICES (IF ANY)
3624 if (vamsasSet.getMatrix()!=null && vamsasSet.getMatrix().size()>0)
3626 importMatrixData(vamsasSet.getMatrix());
3629 // ////////////////////////////////
3632 List<SequenceI> hiddenSeqs = null;
3634 List<SequenceI> tmpseqs = new ArrayList<>();
3636 boolean multipleView = false;
3637 SequenceI referenceseqForView = null;
3638 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3639 List<JSeq> jseqs = jalviewModel.getJSeq();
3640 int vi = 0; // counter in vamsasSeq array
3641 for (int i = 0; i < jseqs.size(); i++)
3643 JSeq jseq = jseqs.get(i);
3644 String seqId = jseq.getId();
3646 SequenceI tmpSeq = seqRefIds.get(seqId);
3649 if (!incompleteSeqs.containsKey(seqId))
3651 // may not need this check, but keep it for at least 2.9,1 release
3652 if (tmpSeq.getStart() != jseq.getStart()
3653 || tmpSeq.getEnd() != jseq.getEnd())
3655 jalview.bin.Console.errPrintln(String.format(
3656 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3657 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3658 jseq.getStart(), jseq.getEnd()));
3663 incompleteSeqs.remove(seqId);
3665 if (vamsasSeqs.size() > vi
3666 && vamsasSeqs.get(vi).getId().equals(seqId))
3668 // most likely we are reading a dataset XML document so
3669 // update from vamsasSeq section of XML for this sequence
3670 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3671 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3672 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3677 // reading multiple views, so vamsasSeq set is a subset of JSeq
3678 multipleView = true;
3680 tmpSeq.setStart(jseq.getStart());
3681 tmpSeq.setEnd(jseq.getEnd());
3682 tmpseqs.add(tmpSeq);
3686 Sequence vamsasSeq = vamsasSeqs.get(vi);
3687 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3688 vamsasSeq.getSequence());
3689 tmpSeq.setDescription(vamsasSeq.getDescription());
3690 tmpSeq.setStart(jseq.getStart());
3691 tmpSeq.setEnd(jseq.getEnd());
3692 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3693 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3694 tmpseqs.add(tmpSeq);
3698 if (safeBoolean(jseq.isViewreference()))
3700 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3703 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3705 if (hiddenSeqs == null)
3707 hiddenSeqs = new ArrayList<>();
3710 hiddenSeqs.add(tmpSeq);
3715 // Create the alignment object from the sequence set
3716 // ///////////////////////////////
3717 SequenceI[] orderedSeqs = tmpseqs
3718 .toArray(new SequenceI[tmpseqs.size()]);
3720 AlignmentI al = null;
3721 // so we must create or recover the dataset alignment before going further
3722 // ///////////////////////////////
3723 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3725 // older jalview projects do not have a dataset - so creat alignment and
3727 al = new Alignment(orderedSeqs);
3728 al.setDataset(null);
3732 boolean isdsal = jalviewModel.getViewport().isEmpty();
3735 // we are importing a dataset record, so
3736 // recover reference to an alignment already materialsed as dataset
3737 al = getDatasetFor(vamsasSet.getDatasetId());
3741 // materialse the alignment
3742 al = new Alignment(orderedSeqs);
3746 addDatasetRef(vamsasSet.getDatasetId(), al);
3749 // finally, verify all data in vamsasSet is actually present in al
3750 // passing on flag indicating if it is actually a stored dataset
3751 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3754 if (referenceseqForView != null)
3756 al.setSeqrep(referenceseqForView);
3758 // / Add the alignment properties
3759 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3761 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3763 al.setProperty(ssp.getKey(), ssp.getValue());
3766 // ///////////////////////////////
3768 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3771 // load sequence features, database references and any associated PDB
3772 // structures for the alignment
3774 // prior to 2.10, this part would only be executed the first time a
3775 // sequence was encountered, but not afterwards.
3776 // now, for 2.10 projects, this is also done if the xml doc includes
3777 // dataset sequences not actually present in any particular view.
3779 for (int i = 0; i < vamsasSeqs.size(); i++)
3781 JSeq jseq = jseqs.get(i);
3782 if (jseq.getFeatures().size() > 0)
3784 List<Feature> features = jseq.getFeatures();
3785 for (int f = 0; f < features.size(); f++)
3787 Feature feat = features.get(f);
3788 SequenceFeature sf = new SequenceFeature(feat.getType(),
3789 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3790 safeFloat(feat.getScore()), feat.getFeatureGroup());
3791 sf.setStatus(feat.getStatus());
3794 * load any feature attributes - include map-valued attributes
3796 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3797 for (int od = 0; od < feat.getOtherData().size(); od++)
3799 OtherData keyValue = feat.getOtherData().get(od);
3800 String attributeName = keyValue.getKey();
3801 String attributeValue = keyValue.getValue();
3802 if (attributeName.startsWith("LINK"))
3804 sf.addLink(attributeValue);
3808 String subAttribute = keyValue.getKey2();
3809 if (subAttribute == null)
3811 // simple string-valued attribute
3812 sf.setValue(attributeName, attributeValue);
3816 // attribute 'key' has sub-attribute 'key2'
3817 if (!mapAttributes.containsKey(attributeName))
3819 mapAttributes.put(attributeName, new HashMap<>());
3821 mapAttributes.get(attributeName).put(subAttribute,
3826 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3829 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3832 // adds feature to datasequence's feature set (since Jalview 2.10)
3833 al.getSequenceAt(i).addSequenceFeature(sf);
3836 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3838 // adds dbrefs to datasequence's set (since Jalview 2.10)
3840 al.getSequenceAt(i).getDatasetSequence() == null
3841 ? al.getSequenceAt(i)
3842 : al.getSequenceAt(i).getDatasetSequence(),
3845 if (jseq.getPdbids().size() > 0)
3847 List<Pdbids> ids = jseq.getPdbids();
3848 for (int p = 0; p < ids.size(); p++)
3850 Pdbids pdbid = ids.get(p);
3851 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3852 entry.setId(pdbid.getId());
3853 if (pdbid.getType() != null)
3855 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3857 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3861 entry.setType(PDBEntry.Type.FILE);
3864 // jprovider is null when executing 'New View'
3865 if (pdbid.getFile() != null && jprovider != null)
3867 if (!pdbloaded.containsKey(pdbid.getFile()))
3869 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3874 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3878 if (pdbid.getPdbentryItem() != null)
3880 for (PdbentryItem item : pdbid.getPdbentryItem())
3882 for (Property pr : item.getProperty())
3884 entry.setProperty(pr.getName(), pr.getValue());
3889 for (Property prop : pdbid.getProperty())
3891 entry.setProperty(prop.getName(), prop.getValue());
3893 StructureSelectionManager
3894 .getStructureSelectionManager(Desktop.instance)
3895 .registerPDBEntry(entry);
3896 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3897 if (al.getSequenceAt(i).getDatasetSequence() != null)
3899 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3903 al.getSequenceAt(i).addPDBId(entry);
3908 } // end !multipleview
3910 // ///////////////////////////////
3911 // LOAD SEQUENCE MAPPINGS
3913 if (vamsasSet.getAlcodonFrame().size() > 0)
3915 // TODO Potentially this should only be done once for all views of an
3917 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3918 for (int i = 0; i < alc.size(); i++)
3920 AlignedCodonFrame cf = new AlignedCodonFrame();
3921 if (alc.get(i).getAlcodMap().size() > 0)
3923 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3924 for (int m = 0; m < maps.size(); m++)
3926 AlcodMap map = maps.get(m);
3927 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3929 jalview.datamodel.Mapping mapping = null;
3930 // attach to dna sequence reference.
3931 if (map.getMapping() != null)
3933 mapping = addMapping(map.getMapping());
3934 if (dnaseq != null && mapping.getTo() != null)
3936 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3942 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3946 al.addCodonFrame(cf);
3951 // ////////////////////////////////
3953 List<JvAnnotRow> autoAlan = new ArrayList<>();
3956 * store any annotations which forward reference a group's ID
3958 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3960 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3962 List<Annotation> an = vamsasSet.getAnnotation();
3964 for (int i = 0; i < an.size(); i++)
3966 Annotation annotation = an.get(i);
3969 * test if annotation is automatically calculated for this view only
3971 boolean autoForView = false;
3972 if (annotation.getLabel().equals("Quality")
3973 || annotation.getLabel().equals("Conservation")
3974 || annotation.getLabel().equals("Consensus"))
3976 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3978 // JAXB has no has() test; schema defaults value to false
3979 // if (!annotation.hasAutoCalculated())
3981 // annotation.setAutoCalculated(true);
3984 if (autoForView || annotation.isAutoCalculated())
3986 // remove ID - we don't recover annotation from other views for
3987 // view-specific annotation
3988 annotation.setId(null);
3991 // set visibility for other annotation in this view
3992 String annotationId = annotation.getId();
3993 if (annotationId != null && annotationIds.containsKey(annotationId))
3995 AlignmentAnnotation jda = annotationIds.get(annotationId);
3996 // in principle Visible should always be true for annotation displayed
3997 // in multiple views
3998 if (annotation.isVisible() != null)
4000 jda.visible = annotation.isVisible();
4003 al.addAnnotation(jda);
4007 // Construct new annotation from model.
4008 List<AnnotationElement> ae = annotation.getAnnotationElement();
4009 jalview.datamodel.Annotation[] anot = null;
4010 java.awt.Color firstColour = null;
4012 if (!annotation.isScoreOnly())
4014 anot = new jalview.datamodel.Annotation[al.getWidth()];
4015 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4017 AnnotationElement annElement = ae.get(aa);
4018 anpos = annElement.getPosition();
4020 if (anpos >= anot.length)
4025 float value = safeFloat(annElement.getValue());
4026 anot[anpos] = new jalview.datamodel.Annotation(
4027 annElement.getDisplayCharacter(),
4028 annElement.getDescription(),
4029 (annElement.getSecondaryStructure() == null
4030 || annElement.getSecondaryStructure()
4034 .getSecondaryStructure()
4037 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4038 if (firstColour == null)
4040 firstColour = anot[anpos].colour;
4044 jalview.datamodel.AlignmentAnnotation jaa = null;
4046 if (annotation.isGraph())
4048 float llim = 0, hlim = 0;
4049 // if (autoForView || an[i].isAutoCalculated()) {
4052 jaa = new jalview.datamodel.AlignmentAnnotation(
4053 annotation.getLabel(), annotation.getDescription(), anot,
4054 llim, hlim, safeInt(annotation.getGraphType()));
4056 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4057 jaa._linecolour = firstColour;
4058 if (annotation.getThresholdLine() != null)
4060 jaa.setThreshold(new jalview.datamodel.GraphLine(
4061 safeFloat(annotation.getThresholdLine().getValue()),
4062 annotation.getThresholdLine().getLabel(),
4063 new java.awt.Color(safeInt(
4064 annotation.getThresholdLine().getColour()))));
4066 if (autoForView || annotation.isAutoCalculated())
4068 // Hardwire the symbol display line to ensure that labels for
4069 // histograms are displayed
4075 jaa = new jalview.datamodel.AlignmentAnnotation(
4076 annotation.getLabel(), annotation.getDescription(), anot);
4077 jaa._linecolour = firstColour;
4079 // register new annotation
4080 if (annotation.getId() != null)
4082 annotationIds.put(annotation.getId(), jaa);
4083 jaa.annotationId = annotation.getId();
4085 // recover sequence association
4086 String sequenceRef = annotation.getSequenceRef();
4087 if (sequenceRef != null)
4089 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4090 SequenceI sequence = seqRefIds.get(sequenceRef);
4091 if (sequence == null)
4093 // in pre-2.9 projects sequence ref is to sequence name
4094 sequence = al.findName(sequenceRef);
4096 if (sequence != null)
4098 jaa.createSequenceMapping(sequence, 1, true);
4099 sequence.addAlignmentAnnotation(jaa);
4102 // and make a note of any group association
4103 if (annotation.getGroupRef() != null
4104 && annotation.getGroupRef().length() > 0)
4106 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4107 .get(annotation.getGroupRef());
4110 aal = new ArrayList<>();
4111 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4116 if (annotation.getScore() != null)
4118 jaa.setScore(annotation.getScore().doubleValue());
4120 if (annotation.isVisible() != null)
4122 jaa.visible = annotation.isVisible().booleanValue();
4125 if (annotation.isCentreColLabels() != null)
4127 jaa.centreColLabels = annotation.isCentreColLabels()
4131 if (annotation.isScaleColLabels() != null)
4133 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4135 if (annotation.isAutoCalculated())
4137 // newer files have an 'autoCalculated' flag and store calculation
4138 // state in viewport properties
4139 jaa.autoCalculated = true; // means annotation will be marked for
4140 // update at end of load.
4142 if (annotation.getGraphHeight() != null)
4144 jaa.graphHeight = annotation.getGraphHeight().intValue();
4146 jaa.belowAlignment = annotation.isBelowAlignment();
4147 jaa.setCalcId(annotation.getCalcId());
4148 if (annotation.getProperty().size() > 0)
4150 for (jalview.xml.binding.jalview.Property prop : annotation
4153 jaa.setProperty(prop.getName(), prop.getValue());
4156 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4158 if (annotation.getContactmatrix() != null
4159 && annotation.getContactmatrix().size() > 0)
4161 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4163 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4168 if (jaa.autoCalculated)
4170 autoAlan.add(new JvAnnotRow(i, jaa));
4173 // if (!autoForView)
4175 // add autocalculated group annotation and any user created annotation
4177 al.addAnnotation(jaa);
4181 // ///////////////////////
4183 // Create alignment markup and styles for this view
4184 if (jalviewModel.getJGroup().size() > 0)
4186 List<JGroup> groups = jalviewModel.getJGroup();
4187 boolean addAnnotSchemeGroup = false;
4188 for (int i = 0; i < groups.size(); i++)
4190 JGroup jGroup = groups.get(i);
4191 ColourSchemeI cs = null;
4192 if (jGroup.getColour() != null)
4194 if (jGroup.getColour().startsWith("ucs"))
4196 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4198 else if (jGroup.getColour().equals("AnnotationColourGradient")
4199 && jGroup.getAnnotationColours() != null)
4201 addAnnotSchemeGroup = true;
4205 cs = ColourSchemeProperty.getColourScheme(null, al,
4206 jGroup.getColour());
4209 int pidThreshold = safeInt(jGroup.getPidThreshold());
4211 Vector<SequenceI> seqs = new Vector<>();
4213 for (int s = 0; s < jGroup.getSeq().size(); s++)
4215 String seqId = jGroup.getSeq().get(s);
4216 SequenceI ts = seqRefIds.get(seqId);
4220 seqs.addElement(ts);
4224 if (seqs.size() < 1)
4229 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4230 safeBoolean(jGroup.isDisplayBoxes()),
4231 safeBoolean(jGroup.isDisplayText()),
4232 safeBoolean(jGroup.isColourText()),
4233 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4234 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4235 sg.getGroupColourScheme()
4236 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4237 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4239 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4240 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4241 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4242 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4243 // attributes with a default in the schema are never null
4244 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4245 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4246 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4247 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4248 if (jGroup.getConsThreshold() != null
4249 && jGroup.getConsThreshold().intValue() != 0)
4251 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4254 c.verdict(false, 25);
4255 sg.cs.setConservation(c);
4258 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4260 // re-instate unique group/annotation row reference
4261 List<AlignmentAnnotation> jaal = groupAnnotRefs
4262 .get(jGroup.getId());
4265 for (AlignmentAnnotation jaa : jaal)
4268 if (jaa.autoCalculated)
4270 // match up and try to set group autocalc alignment row for this
4272 if (jaa.label.startsWith("Consensus for "))
4274 sg.setConsensus(jaa);
4276 // match up and try to set group autocalc alignment row for this
4278 if (jaa.label.startsWith("Conservation for "))
4280 sg.setConservationRow(jaa);
4287 if (addAnnotSchemeGroup)
4289 // reconstruct the annotation colourscheme
4291 constructAnnotationColour(jGroup.getAnnotationColours(),
4292 null, al, jalviewModel, false));
4298 // only dataset in this model, so just return.
4301 // ///////////////////////////////
4304 AlignFrame af = null;
4305 AlignViewport av = null;
4306 // now check to see if we really need to create a new viewport.
4307 if (multipleView && viewportsAdded.size() == 0)
4309 // We recovered an alignment for which a viewport already exists.
4310 // TODO: fix up any settings necessary for overlaying stored state onto
4311 // state recovered from another document. (may not be necessary).
4312 // we may need a binding from a viewport in memory to one recovered from
4314 // and then recover its containing af to allow the settings to be applied.
4315 // TODO: fix for vamsas demo
4316 jalview.bin.Console.errPrintln(
4317 "About to recover a viewport for existing alignment: Sequence set ID is "
4319 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4320 if (seqsetobj != null)
4322 if (seqsetobj instanceof String)
4324 uniqueSeqSetId = (String) seqsetobj;
4325 jalview.bin.Console.errPrintln(
4326 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4331 jalview.bin.Console.errPrintln(
4332 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4338 * indicate that annotation colours are applied across all groups (pre
4339 * Jalview 2.8.1 behaviour)
4341 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4342 jalviewModel.getVersion());
4344 AlignmentPanel ap = null;
4345 boolean isnewview = true;
4348 // Check to see if this alignment already has a view id == viewId
4349 jalview.gui.AlignmentPanel views[] = Desktop
4350 .getAlignmentPanels(uniqueSeqSetId);
4351 if (views != null && views.length > 0)
4353 for (int v = 0; v < views.length; v++)
4355 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4357 // recover the existing alignpanel, alignframe, viewport
4358 af = views[v].alignFrame;
4361 // TODO: could even skip resetting view settings if we don't want to
4362 // change the local settings from other jalview processes
4371 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4372 uniqueSeqSetId, viewId, autoAlan);
4373 av = af.getViewport();
4378 * Load any trees, PDB structures and viewers, Overview
4380 * Not done if flag is false (when this method is used for New View)
4382 if (loadTreesAndStructures)
4384 loadTrees(jalviewModel, view, af, av, ap);
4385 loadPCAViewers(jalviewModel, ap);
4386 loadPDBStructures(jprovider, jseqs, af, ap);
4387 loadRnaViewers(jprovider, jseqs, ap);
4388 loadOverview(view, jalviewModel.getVersion(), af);
4390 // and finally return.
4394 private void importMatrixData(List<MatrixType> xmlmatrices)
4396 for (MatrixType xmlmat:xmlmatrices)
4398 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4400 Console.error("Ignoring matrix '"+xmlmat.getId()+"' of type '"+xmlmat.getType());
4404 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4406 Console.error("Can't handle non square matrices");
4410 float[][] elements = ContactMatrix
4411 .fromFloatStringToContacts(xmlmat.getElements(),
4412 xmlmat.getCols().intValue(),
4413 xmlmat.getRows().intValue());
4415 List<BitSet> newgroups = new ArrayList<BitSet>();
4416 if (xmlmat.getGroups().size() > 0)
4418 for (String sgroup : xmlmat.getGroups())
4420 newgroups.add(deStringifyBitset(sgroup));
4423 String nwk = xmlmat.getNewick().size() > 0
4424 ? xmlmat.getNewick().get(0)
4426 if (xmlmat.getNewick().size() > 1)
4429 "Ignoring additional clusterings for contact matrix");
4431 String treeMethod = xmlmat.getTreeMethod();
4432 double thresh = xmlmat.getCutHeight() != null
4433 ? xmlmat.getCutHeight()
4435 GroupSet grpset = new GroupSet();
4436 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4438 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4439 contactMatrixRefs.put(xmlmat.getId(), newcm);
4440 Console.trace("Restored base contact matrix "+xmlmat.getId());
4444 private void restoreMatrixFor(SequenceI sequenceRef,
4445 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4447 // restore mapping data to matrix data
4448 jalview.util.MapList mapping = null;
4449 if (xmlmatmapping.getMapping() != null)
4451 MapListType m = xmlmatmapping.getMapping();
4452 // Mapping m = dr.getMapping();
4453 int fr[] = new int[m.getMapListFrom().size() * 2];
4454 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4455 for (int _i = 0; from.hasNext(); _i += 2)
4457 MapListFrom mf = from.next();
4458 fr[_i] = mf.getStart();
4459 fr[_i + 1] = mf.getEnd();
4461 int fto[] = new int[m.getMapListTo().size() * 2];
4462 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4463 for (int _i = 0; to.hasNext(); _i += 2)
4465 MapListTo mf = to.next();
4466 fto[_i] = mf.getStart();
4467 fto[_i + 1] = mf.getEnd();
4470 mapping = new jalview.util.MapList(fr, fto,
4471 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4474 // locate matrix data in project XML and import
4475 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4479 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4483 // create the PAEMatrix now
4484 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4487 jaa.sequenceRef.addContactListFor(jaa, newpae);
4494 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4495 * and geometry as saved
4500 protected void loadOverview(Viewport view, String version, AlignFrame af)
4502 if (!isVersionStringLaterThan("2.11.3", version)
4503 && view.getOverview() == null)
4508 * first close any Overview that was opened automatically
4509 * (if so configured in Preferences) so that the view is
4510 * restored in the same state as saved
4512 af.alignPanel.closeOverviewPanel();
4514 Overview overview = view.getOverview();
4515 if (overview != null)
4517 OverviewPanel overviewPanel = af
4518 .openOverviewPanel(overview.isShowHidden());
4519 overviewPanel.setTitle(overview.getTitle());
4520 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4521 overview.getWidth(), overview.getHeight());
4522 Color gap = new Color(overview.getGapColour());
4523 Color residue = new Color(overview.getResidueColour());
4524 Color hidden = new Color(overview.getHiddenColour());
4525 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4530 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4531 * panel is restored from separate jar entries, two (gapped and trimmed) per
4532 * sequence and secondary structure.
4534 * Currently each viewer shows just one sequence and structure (gapped and
4535 * trimmed), however this method is designed to support multiple sequences or
4536 * structures in viewers if wanted in future.
4542 private void loadRnaViewers(jarInputStreamProvider jprovider,
4543 List<JSeq> jseqs, AlignmentPanel ap)
4546 * scan the sequences for references to viewers; create each one the first
4547 * time it is referenced, add Rna models to existing viewers
4549 for (JSeq jseq : jseqs)
4551 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4553 RnaViewer viewer = jseq.getRnaViewer().get(i);
4554 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4557 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4559 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4560 SequenceI seq = seqRefIds.get(jseq.getId());
4561 AlignmentAnnotation ann = this.annotationIds
4562 .get(ss.getAnnotationId());
4565 * add the structure to the Varna display (with session state copied
4566 * from the jar to a temporary file)
4568 boolean gapped = safeBoolean(ss.isGapped());
4569 String rnaTitle = ss.getTitle();
4570 String sessionState = ss.getViewerState();
4571 String tempStateFile = copyJarEntry(jprovider, sessionState,
4573 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4574 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4576 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4582 * Locate and return an already instantiated matching AppVarna, or create one
4586 * @param viewIdSuffix
4590 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4591 String viewIdSuffix, AlignmentPanel ap)
4594 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4595 * if load is repeated
4597 String postLoadId = viewer.getViewId() + viewIdSuffix;
4598 for (JInternalFrame frame : getAllFrames())
4600 if (frame instanceof AppVarna)
4602 AppVarna varna = (AppVarna) frame;
4603 if (postLoadId.equals(varna.getViewId()))
4605 // this viewer is already instantiated
4606 // could in future here add ap as another 'parent' of the
4607 // AppVarna window; currently just 1-to-many
4614 * viewer not found - make it
4616 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4617 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4618 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4619 safeInt(viewer.getDividerLocation()));
4620 AppVarna varna = new AppVarna(model, ap);
4626 * Load any saved trees
4634 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4635 AlignViewport av, AlignmentPanel ap)
4637 // TODO result of automated refactoring - are all these parameters needed?
4640 for (int t = 0; t < jm.getTree().size(); t++)
4643 Tree tree = jm.getTree().get(t);
4645 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4648 if (tree.isColumnWise())
4650 AlignmentAnnotation aa = annotationIds
4651 .get(tree.getColumnReference());
4655 "Null alignment annotation when restoring columnwise tree");
4657 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4658 tree.getTitle(), safeInt(tree.getWidth()),
4659 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4660 safeInt(tree.getYpos()));
4665 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4666 tree.getTitle(), safeInt(tree.getWidth()),
4667 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4668 safeInt(tree.getYpos()));
4670 if (tree.getId() != null)
4672 // perhaps bind the tree id to something ?
4677 // update local tree attributes ?
4678 // TODO: should check if tp has been manipulated by user - if so its
4679 // settings shouldn't be modified
4680 tp.setTitle(tree.getTitle());
4681 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4682 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4683 safeInt(tree.getHeight())));
4684 tp.setViewport(av); // af.viewport;
4685 // TODO: verify 'associate with all views' works still
4686 tp.getTreeCanvas().setViewport(av); // af.viewport;
4687 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4689 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4693 "There was a problem recovering stored Newick tree: \n"
4694 + tree.getNewick());
4698 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4699 tp.fitToWindow_actionPerformed(null);
4701 if (tree.getFontName() != null)
4704 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4705 safeInt(tree.getFontSize())));
4710 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4711 safeInt(view.getFontSize())));
4714 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4715 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4716 tp.showDistances(safeBoolean(tree.isShowDistances()));
4718 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4720 if (safeBoolean(tree.isCurrentTree()))
4722 af.getViewport().setCurrentTree(tp.getTree());
4726 } catch (Exception ex)
4728 ex.printStackTrace();
4733 * Load and link any saved structure viewers.
4740 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4741 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4744 * Run through all PDB ids on the alignment, and collect mappings between
4745 * distinct view ids and all sequences referring to that view.
4747 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4749 for (int i = 0; i < jseqs.size(); i++)
4751 JSeq jseq = jseqs.get(i);
4752 if (jseq.getPdbids().size() > 0)
4754 List<Pdbids> ids = jseq.getPdbids();
4755 for (int p = 0; p < ids.size(); p++)
4757 Pdbids pdbid = ids.get(p);
4758 final int structureStateCount = pdbid.getStructureState().size();
4759 for (int s = 0; s < structureStateCount; s++)
4761 // check to see if we haven't already created this structure view
4762 final StructureState structureState = pdbid.getStructureState()
4764 String sviewid = (structureState.getViewId() == null) ? null
4765 : structureState.getViewId() + uniqueSetSuffix;
4766 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4767 // Originally : pdbid.getFile()
4768 // : TODO: verify external PDB file recovery still works in normal
4769 // jalview project load
4771 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4772 jpdb.setId(pdbid.getId());
4774 int x = safeInt(structureState.getXpos());
4775 int y = safeInt(structureState.getYpos());
4776 int width = safeInt(structureState.getWidth());
4777 int height = safeInt(structureState.getHeight());
4779 // Probably don't need to do this anymore...
4780 // Desktop.desktop.getComponentAt(x, y);
4781 // TODO: NOW: check that this recovers the PDB file correctly.
4782 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4784 jalview.datamodel.SequenceI seq = seqRefIds
4785 .get(jseq.getId() + "");
4786 if (sviewid == null)
4788 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4791 if (!structureViewers.containsKey(sviewid))
4793 String viewerType = structureState.getType();
4794 if (viewerType == null) // pre Jalview 2.9
4796 viewerType = ViewerType.JMOL.toString();
4798 structureViewers.put(sviewid,
4799 new StructureViewerModel(x, y, width, height, false,
4800 false, true, structureState.getViewId(),
4802 // Legacy pre-2.7 conversion JAL-823 :
4803 // do not assume any view has to be linked for colour by
4807 // assemble String[] { pdb files }, String[] { id for each
4808 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4809 // seqs_file 2}, boolean[] {
4810 // linkAlignPanel,superposeWithAlignpanel}} from hash
4811 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4812 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4813 || structureState.isAlignwithAlignPanel());
4816 * Default colour by linked panel to false if not specified (e.g.
4817 * for pre-2.7 projects)
4819 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4820 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4821 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4824 * Default colour by viewer to true if not specified (e.g. for
4827 boolean colourByViewer = jmoldat.isColourByViewer();
4828 colourByViewer &= structureState.isColourByJmol();
4829 jmoldat.setColourByViewer(colourByViewer);
4831 if (jmoldat.getStateData().length() < structureState.getValue()
4832 /*Content()*/.length())
4834 jmoldat.setStateData(structureState.getValue());// Content());
4836 if (pdbid.getFile() != null)
4838 File mapkey = new File(pdbid.getFile());
4839 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4840 if (seqstrmaps == null)
4842 jmoldat.getFileData().put(mapkey,
4843 seqstrmaps = jmoldat.new StructureData(pdbFile,
4846 if (!seqstrmaps.getSeqList().contains(seq))
4848 seqstrmaps.getSeqList().add(seq);
4854 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");
4855 Console.warn(errorMessage);
4861 // Instantiate the associated structure views
4862 for (Entry<String, StructureViewerModel> entry : structureViewers
4867 createOrLinkStructureViewer(entry, af, ap, jprovider);
4868 } catch (Exception e)
4870 jalview.bin.Console.errPrintln(
4871 "Error loading structure viewer: " + e.getMessage());
4872 // failed - try the next one
4884 protected void createOrLinkStructureViewer(
4885 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4886 AlignmentPanel ap, jarInputStreamProvider jprovider)
4888 final StructureViewerModel stateData = viewerData.getValue();
4891 * Search for any viewer windows already open from other alignment views
4892 * that exactly match the stored structure state
4894 StructureViewerBase comp = findMatchingViewer(viewerData);
4898 linkStructureViewer(ap, comp, stateData);
4902 String type = stateData.getType();
4905 ViewerType viewerType = ViewerType.valueOf(type);
4906 createStructureViewer(viewerType, viewerData, af, jprovider);
4907 } catch (IllegalArgumentException | NullPointerException e)
4909 // TODO JAL-3619 show error dialog / offer an alternative viewer
4910 Console.error("Invalid structure viewer type: " + type);
4915 * Generates a name for the entry in the project jar file to hold state
4916 * information for a structure viewer
4921 protected String getViewerJarEntryName(String viewId)
4923 return VIEWER_PREFIX + viewId;
4927 * Returns any open frame that matches given structure viewer data. The match
4928 * is based on the unique viewId, or (for older project versions) the frame's
4934 protected StructureViewerBase findMatchingViewer(
4935 Entry<String, StructureViewerModel> viewerData)
4937 final String sviewid = viewerData.getKey();
4938 final StructureViewerModel svattrib = viewerData.getValue();
4939 StructureViewerBase comp = null;
4940 JInternalFrame[] frames = getAllFrames();
4941 for (JInternalFrame frame : frames)
4943 if (frame instanceof StructureViewerBase)
4946 * Post jalview 2.4 schema includes structure view id
4948 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4951 comp = (StructureViewerBase) frame;
4952 break; // break added in 2.9
4955 * Otherwise test for matching position and size of viewer frame
4957 else if (frame.getX() == svattrib.getX()
4958 && frame.getY() == svattrib.getY()
4959 && frame.getHeight() == svattrib.getHeight()
4960 && frame.getWidth() == svattrib.getWidth())
4962 comp = (StructureViewerBase) frame;
4963 // no break in faint hope of an exact match on viewId
4971 * Link an AlignmentPanel to an existing structure viewer.
4976 * @param useinViewerSuperpos
4977 * @param usetoColourbyseq
4978 * @param viewerColouring
4980 protected void linkStructureViewer(AlignmentPanel ap,
4981 StructureViewerBase viewer, StructureViewerModel stateData)
4983 // NOTE: if the jalview project is part of a shared session then
4984 // view synchronization should/could be done here.
4986 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4987 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4988 final boolean viewerColouring = stateData.isColourByViewer();
4989 Map<File, StructureData> oldFiles = stateData.getFileData();
4992 * Add mapping for sequences in this view to an already open viewer
4994 final AAStructureBindingModel binding = viewer.getBinding();
4995 for (File id : oldFiles.keySet())
4997 // add this and any other pdb files that should be present in the
4999 StructureData filedat = oldFiles.get(id);
5000 String pdbFile = filedat.getFilePath();
5001 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5002 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5004 binding.addSequenceForStructFile(pdbFile, seq);
5006 // and add the AlignmentPanel's reference to the view panel
5007 viewer.addAlignmentPanel(ap);
5008 if (useinViewerSuperpos)
5010 viewer.useAlignmentPanelForSuperposition(ap);
5014 viewer.excludeAlignmentPanelForSuperposition(ap);
5016 if (usetoColourbyseq)
5018 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5022 viewer.excludeAlignmentPanelForColourbyseq(ap);
5027 * Get all frames within the Desktop.
5031 protected JInternalFrame[] getAllFrames()
5033 JInternalFrame[] frames = null;
5034 // TODO is this necessary - is it safe - risk of hanging?
5039 frames = Desktop.desktop.getAllFrames();
5040 } catch (ArrayIndexOutOfBoundsException e)
5042 // occasional No such child exceptions are thrown here...
5046 } catch (InterruptedException f)
5050 } while (frames == null);
5055 * Answers true if 'version' is equal to or later than 'supported', where each
5056 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5057 * changes. Development and test values for 'version' are leniently treated
5061 * - minimum version we are comparing against
5063 * - version of data being processsed
5064 * @return true if version is equal to or later than supported
5066 public static boolean isVersionStringLaterThan(String supported,
5069 if (supported == null || version == null
5070 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5071 || version.equalsIgnoreCase("Test")
5072 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5074 jalview.bin.Console.errPrintln("Assuming project file with "
5075 + (version == null ? "null" : version)
5076 + " is compatible with Jalview version " + supported);
5081 return StringUtils.compareVersions(version, supported, "b") >= 0;
5085 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5087 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5089 if (newStructureViewers != null)
5091 sview.getBinding().setFinishedLoadingFromArchive(false);
5092 newStructureViewers.add(sview);
5096 protected void setLoadingFinishedForNewStructureViewers()
5098 if (newStructureViewers != null)
5100 for (JalviewStructureDisplayI sview : newStructureViewers)
5102 sview.getBinding().setFinishedLoadingFromArchive(true);
5104 newStructureViewers.clear();
5105 newStructureViewers = null;
5109 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5110 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5111 Viewport view, String uniqueSeqSetId, String viewId,
5112 List<JvAnnotRow> autoAlan)
5114 AlignFrame af = null;
5115 af = new AlignFrame(al, safeInt(view.getWidth()),
5116 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5120 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5121 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5122 // super.processKeyEvent(e);
5129 af.setFileName(file, FileFormat.Jalview);
5131 final AlignViewport viewport = af.getViewport();
5132 for (int i = 0; i < JSEQ.size(); i++)
5134 int colour = safeInt(JSEQ.get(i).getColour());
5135 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5141 viewport.setColourByReferenceSeq(true);
5142 viewport.setDisplayReferenceSeq(true);
5145 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5147 if (view.getSequenceSetId() != null)
5149 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5151 viewport.setSequenceSetId(uniqueSeqSetId);
5154 // propagate shared settings to this new view
5155 viewport.setHistoryList(av.getHistoryList());
5156 viewport.setRedoList(av.getRedoList());
5160 viewportsAdded.put(uniqueSeqSetId, viewport);
5162 // TODO: check if this method can be called repeatedly without
5163 // side-effects if alignpanel already registered.
5164 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5166 // apply Hidden regions to view.
5167 if (hiddenSeqs != null)
5169 for (int s = 0; s < JSEQ.size(); s++)
5171 SequenceGroup hidden = new SequenceGroup();
5172 boolean isRepresentative = false;
5173 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5175 isRepresentative = true;
5176 SequenceI sequenceToHide = al
5177 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5178 hidden.addSequence(sequenceToHide, false);
5179 // remove from hiddenSeqs list so we don't try to hide it twice
5180 hiddenSeqs.remove(sequenceToHide);
5182 if (isRepresentative)
5184 SequenceI representativeSequence = al.getSequenceAt(s);
5185 hidden.addSequence(representativeSequence, false);
5186 viewport.hideRepSequences(representativeSequence, hidden);
5190 SequenceI[] hseqs = hiddenSeqs
5191 .toArray(new SequenceI[hiddenSeqs.size()]);
5192 viewport.hideSequence(hseqs);
5195 // recover view properties and display parameters
5197 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5198 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5199 final int pidThreshold = safeInt(view.getPidThreshold());
5200 viewport.setThreshold(pidThreshold);
5202 viewport.setColourText(safeBoolean(view.isShowColourText()));
5204 viewport.setConservationSelected(
5205 safeBoolean(view.isConservationSelected()));
5206 viewport.setIncrement(safeInt(view.getConsThreshold()));
5207 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5208 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5210 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5211 safeInt(view.getFontSize())),
5212 (view.getCharWidth() != null) ? false : true);
5213 if (view.getCharWidth() != null)
5215 viewport.setCharWidth(view.getCharWidth());
5216 viewport.setCharHeight(view.getCharHeight());
5218 ViewStyleI vs = viewport.getViewStyle();
5219 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5220 viewport.setViewStyle(vs);
5221 // TODO: allow custom charWidth/Heights to be restored by updating them
5222 // after setting font - which means set above to false
5223 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5224 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5225 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5227 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5229 viewport.setShowText(safeBoolean(view.isShowText()));
5231 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5232 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5233 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5234 viewport.setShowUnconserved(view.isShowUnconserved());
5235 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5237 if (view.getViewName() != null)
5239 viewport.setViewName(view.getViewName());
5240 af.setInitialTabVisible();
5242 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5243 safeInt(view.getWidth()), safeInt(view.getHeight()));
5244 // startSeq set in af.alignPanel.updateLayout below
5245 af.alignPanel.updateLayout();
5246 ColourSchemeI cs = null;
5247 // apply colourschemes
5248 if (view.getBgColour() != null)
5250 if (view.getBgColour().startsWith("ucs"))
5252 cs = getUserColourScheme(jm, view.getBgColour());
5254 else if (view.getBgColour().startsWith("Annotation"))
5256 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5257 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5264 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5265 view.getBgColour());
5270 * turn off 'alignment colour applies to all groups'
5271 * while restoring global colour scheme
5273 viewport.setColourAppliesToAllGroups(false);
5274 viewport.setGlobalColourScheme(cs);
5275 viewport.getResidueShading().setThreshold(pidThreshold,
5276 view.isIgnoreGapsinConsensus());
5277 viewport.getResidueShading()
5278 .setConsensus(viewport.getSequenceConsensusHash());
5279 if (safeBoolean(view.isConservationSelected()) && cs != null)
5281 viewport.getResidueShading()
5282 .setConservationInc(safeInt(view.getConsThreshold()));
5284 af.changeColour(cs);
5285 viewport.setColourAppliesToAllGroups(true);
5287 viewport.setShowSequenceFeatures(
5288 safeBoolean(view.isShowSequenceFeatures()));
5290 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5291 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5292 viewport.setFollowHighlight(view.isFollowHighlight());
5293 viewport.followSelection = view.isFollowSelection();
5294 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5295 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5296 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5297 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5298 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5299 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5300 viewport.setShowGroupConservation(view.isShowGroupConservation());
5301 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5302 viewport.setShowComplementFeaturesOnTop(
5303 view.isShowComplementFeaturesOnTop());
5305 // recover feature settings
5306 if (jm.getFeatureSettings() != null)
5308 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5309 .getFeatureRenderer();
5310 FeaturesDisplayed fdi;
5311 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5312 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5314 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5315 Map<String, Float> featureOrder = new Hashtable<>();
5317 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5320 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5321 String featureType = setting.getType();
5324 * restore feature filters (if any)
5326 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5328 if (filters != null)
5330 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5332 if (!filter.isEmpty())
5334 fr.setFeatureFilter(featureType, filter);
5339 * restore feature colour scheme
5341 Color maxColour = new Color(setting.getColour());
5342 if (setting.getMincolour() != null)
5345 * minColour is always set unless a simple colour
5346 * (including for colour by label though it doesn't use it)
5348 Color minColour = new Color(setting.getMincolour().intValue());
5349 Color noValueColour = minColour;
5350 NoValueColour noColour = setting.getNoValueColour();
5351 if (noColour == NoValueColour.NONE)
5353 noValueColour = null;
5355 else if (noColour == NoValueColour.MAX)
5357 noValueColour = maxColour;
5359 float min = safeFloat(safeFloat(setting.getMin()));
5360 float max = setting.getMax() == null ? 1f
5361 : setting.getMax().floatValue();
5362 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5363 maxColour, noValueColour, min, max);
5364 if (setting.getAttributeName().size() > 0)
5366 gc.setAttributeName(setting.getAttributeName().toArray(
5367 new String[setting.getAttributeName().size()]));
5369 if (setting.getThreshold() != null)
5371 gc.setThreshold(setting.getThreshold().floatValue());
5372 int threshstate = safeInt(setting.getThreshstate());
5373 // -1 = None, 0 = Below, 1 = Above threshold
5374 if (threshstate == 0)
5376 gc.setBelowThreshold(true);
5378 else if (threshstate == 1)
5380 gc.setAboveThreshold(true);
5383 gc.setAutoScaled(true); // default
5384 if (setting.isAutoScale() != null)
5386 gc.setAutoScaled(setting.isAutoScale());
5388 if (setting.isColourByLabel() != null)
5390 gc.setColourByLabel(setting.isColourByLabel());
5392 // and put in the feature colour table.
5393 featureColours.put(featureType, gc);
5397 featureColours.put(featureType, new FeatureColour(maxColour));
5399 renderOrder[fs] = featureType;
5400 if (setting.getOrder() != null)
5402 featureOrder.put(featureType, setting.getOrder().floatValue());
5406 featureOrder.put(featureType, Float.valueOf(
5407 fs / jm.getFeatureSettings().getSetting().size()));
5409 if (safeBoolean(setting.isDisplay()))
5411 fdi.setVisible(featureType);
5414 Map<String, Boolean> fgtable = new Hashtable<>();
5415 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5417 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5418 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5420 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5421 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5422 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5423 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5424 fgtable, featureColours, 1.0f, featureOrder);
5425 fr.transferSettings(frs);
5428 if (view.getHiddenColumns().size() > 0)
5430 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5432 final HiddenColumns hc = view.getHiddenColumns().get(c);
5433 viewport.hideColumns(safeInt(hc.getStart()),
5434 safeInt(hc.getEnd()) /* +1 */);
5437 if (view.getCalcIdParam() != null)
5439 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5441 if (calcIdParam != null)
5443 if (recoverCalcIdParam(calcIdParam, viewport))
5448 Console.warn("Couldn't recover parameters for "
5449 + calcIdParam.getCalcId());
5454 af.setMenusFromViewport(viewport);
5455 af.setTitle(view.getTitle());
5456 // TODO: we don't need to do this if the viewport is aready visible.
5458 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5459 * has a 'cdna/protein complement' view, in which case save it in order to
5460 * populate a SplitFrame once all views have been read in.
5462 String complementaryViewId = view.getComplementId();
5463 if (complementaryViewId == null)
5465 Desktop.addInternalFrame(af, view.getTitle(),
5466 safeInt(view.getWidth()), safeInt(view.getHeight()));
5467 // recompute any autoannotation
5468 af.alignPanel.updateAnnotation(false, true);
5469 reorderAutoannotation(af, al, autoAlan);
5470 af.alignPanel.alignmentChanged();
5474 splitFrameCandidates.put(view, af);
5481 * Reads saved data to restore Colour by Annotation settings
5483 * @param viewAnnColour
5487 * @param checkGroupAnnColour
5490 private ColourSchemeI constructAnnotationColour(
5491 AnnotationColourScheme viewAnnColour, AlignFrame af,
5492 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5494 boolean propagateAnnColour = false;
5495 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5497 if (checkGroupAnnColour && al.getGroups() != null
5498 && al.getGroups().size() > 0)
5500 // pre 2.8.1 behaviour
5501 // check to see if we should transfer annotation colours
5502 propagateAnnColour = true;
5503 for (SequenceGroup sg : al.getGroups())
5505 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5507 propagateAnnColour = false;
5513 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5515 String annotationId = viewAnnColour.getAnnotation();
5516 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5519 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5521 if (matchedAnnotation == null
5522 && annAlignment.getAlignmentAnnotation() != null)
5524 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5527 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5529 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5534 if (matchedAnnotation == null)
5537 .errPrintln("Failed to match annotation colour scheme for "
5541 // belt-and-braces create a threshold line if the
5542 // colourscheme needs one but the matchedAnnotation doesn't have one
5543 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5544 && matchedAnnotation.getThreshold() == null)
5546 matchedAnnotation.setThreshold(
5547 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5548 "Threshold", Color.black));
5551 AnnotationColourGradient cs = null;
5552 if (viewAnnColour.getColourScheme().equals("None"))
5554 cs = new AnnotationColourGradient(matchedAnnotation,
5555 new Color(safeInt(viewAnnColour.getMinColour())),
5556 new Color(safeInt(viewAnnColour.getMaxColour())),
5557 safeInt(viewAnnColour.getAboveThreshold()));
5559 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5561 cs = new AnnotationColourGradient(matchedAnnotation,
5562 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5563 safeInt(viewAnnColour.getAboveThreshold()));
5567 cs = new AnnotationColourGradient(matchedAnnotation,
5568 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5569 viewAnnColour.getColourScheme()),
5570 safeInt(viewAnnColour.getAboveThreshold()));
5573 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5574 boolean useOriginalColours = safeBoolean(
5575 viewAnnColour.isPredefinedColours());
5576 cs.setSeqAssociated(perSequenceOnly);
5577 cs.setPredefinedColours(useOriginalColours);
5579 if (propagateAnnColour && al.getGroups() != null)
5581 // Also use these settings for all the groups
5582 for (int g = 0; g < al.getGroups().size(); g++)
5584 SequenceGroup sg = al.getGroups().get(g);
5585 if (sg.getGroupColourScheme() == null)
5590 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5591 matchedAnnotation, sg.getColourScheme(),
5592 safeInt(viewAnnColour.getAboveThreshold()));
5593 sg.setColourScheme(groupScheme);
5594 groupScheme.setSeqAssociated(perSequenceOnly);
5595 groupScheme.setPredefinedColours(useOriginalColours);
5601 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5602 List<JvAnnotRow> autoAlan)
5604 // copy over visualization settings for autocalculated annotation in the
5606 if (al.getAlignmentAnnotation() != null)
5609 * Kludge for magic autoannotation names (see JAL-811)
5611 String[] magicNames = new String[] { "Consensus", "Quality",
5613 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5614 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5615 for (String nm : magicNames)
5617 visan.put(nm, nullAnnot);
5619 for (JvAnnotRow auan : autoAlan)
5621 visan.put(auan.template.label
5622 + (auan.template.getCalcId() == null ? ""
5623 : "\t" + auan.template.getCalcId()),
5626 int hSize = al.getAlignmentAnnotation().length;
5627 List<JvAnnotRow> reorder = new ArrayList<>();
5628 // work through any autoCalculated annotation already on the view
5629 // removing it if it should be placed in a different location on the
5630 // annotation panel.
5631 List<String> remains = new ArrayList<>(visan.keySet());
5632 for (int h = 0; h < hSize; h++)
5634 jalview.datamodel.AlignmentAnnotation jalan = al
5635 .getAlignmentAnnotation()[h];
5636 if (jalan.autoCalculated)
5639 JvAnnotRow valan = visan.get(k = jalan.label);
5640 if (jalan.getCalcId() != null)
5642 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5647 // delete the auto calculated row from the alignment
5648 al.deleteAnnotation(jalan, false);
5652 if (valan != nullAnnot)
5654 if (jalan != valan.template)
5656 // newly created autoannotation row instance
5657 // so keep a reference to the visible annotation row
5658 // and copy over all relevant attributes
5659 if (valan.template.graphHeight >= 0)
5662 jalan.graphHeight = valan.template.graphHeight;
5664 jalan.visible = valan.template.visible;
5666 reorder.add(new JvAnnotRow(valan.order, jalan));
5671 // Add any (possibly stale) autocalculated rows that were not appended to
5672 // the view during construction
5673 for (String other : remains)
5675 JvAnnotRow othera = visan.get(other);
5676 if (othera != nullAnnot && othera.template.getCalcId() != null
5677 && othera.template.getCalcId().length() > 0)
5679 reorder.add(othera);
5682 // now put the automatic annotation in its correct place
5683 int s = 0, srt[] = new int[reorder.size()];
5684 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5685 for (JvAnnotRow jvar : reorder)
5688 srt[s++] = jvar.order;
5691 jalview.util.QuickSort.sort(srt, rws);
5692 // and re-insert the annotation at its correct position
5693 for (JvAnnotRow jvar : rws)
5695 al.addAnnotation(jvar.template, jvar.order);
5697 af.alignPanel.adjustAnnotationHeight();
5701 Hashtable skipList = null;
5704 * TODO remove this method
5707 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5708 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5709 * throw new Error("Implementation Error. No skipList defined for this
5710 * Jalview2XML instance."); } return (AlignFrame)
5711 * skipList.get(view.getSequenceSetId()); }
5715 * Check if the Jalview view contained in object should be skipped or not.
5718 * @return true if view's sequenceSetId is a key in skipList
5720 private boolean skipViewport(JalviewModel object)
5722 if (skipList == null)
5726 String id = object.getViewport().get(0).getSequenceSetId();
5727 if (skipList.containsKey(id))
5729 Console.debug("Skipping seuqence set id " + id);
5735 public void addToSkipList(AlignFrame af)
5737 if (skipList == null)
5739 skipList = new Hashtable();
5741 skipList.put(af.getViewport().getSequenceSetId(), af);
5744 public void clearSkipList()
5746 if (skipList != null)
5753 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5754 boolean ignoreUnrefed, String uniqueSeqSetId)
5756 jalview.datamodel.AlignmentI ds = getDatasetFor(
5757 vamsasSet.getDatasetId());
5758 AlignmentI xtant_ds = ds;
5759 if (xtant_ds == null)
5761 // good chance we are about to create a new dataset, but check if we've
5762 // seen some of the dataset sequence IDs before.
5763 // TODO: skip this check if we are working with project generated by
5764 // version 2.11 or later
5765 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5766 if (xtant_ds != null)
5769 addDatasetRef(vamsasSet.getDatasetId(), ds);
5772 Vector<SequenceI> dseqs = null;
5775 // recovering an alignment View
5776 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5777 if (seqSetDS != null)
5779 if (ds != null && ds != seqSetDS)
5782 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5783 + " - CDS/Protein crossreference data may be lost");
5784 if (xtant_ds != null)
5786 // This can only happen if the unique sequence set ID was bound to a
5787 // dataset that did not contain any of the sequences in the view
5788 // currently being restored.
5790 "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.");
5794 addDatasetRef(vamsasSet.getDatasetId(), ds);
5799 // try even harder to restore dataset
5800 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5801 // create a list of new dataset sequences
5802 dseqs = new Vector<>();
5804 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5806 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5807 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5809 // create a new dataset
5812 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5813 dseqs.copyInto(dsseqs);
5814 ds = new jalview.datamodel.Alignment(dsseqs);
5815 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5816 + " for alignment " + System.identityHashCode(al));
5817 addDatasetRef(vamsasSet.getDatasetId(), ds);
5819 // set the dataset for the newly imported alignment.
5820 if (al.getDataset() == null && !ignoreUnrefed)
5823 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5824 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5826 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5830 * XML dataset sequence ID to materialised dataset reference
5832 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5835 * @return the first materialised dataset reference containing a dataset
5836 * sequence referenced in the given view
5838 * - sequences from the view
5840 AlignmentI checkIfHasDataset(List<Sequence> list)
5842 for (Sequence restoredSeq : list)
5844 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5845 if (datasetFor != null)
5854 * Register ds as the containing dataset for the dataset sequences referenced
5855 * by sequences in list
5858 * - sequences in a view
5861 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5863 for (Sequence restoredSeq : list)
5865 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5866 if (prevDS != null && prevDS != ds)
5868 Console.warn("Dataset sequence appears in many datasets: "
5869 + restoredSeq.getDsseqid());
5870 // TODO: try to merge!
5878 * sequence definition to create/merge dataset sequence for
5882 * vector to add new dataset sequence to
5883 * @param ignoreUnrefed
5884 * - when true, don't create new sequences from vamsasSeq if it's id
5885 * doesn't already have an asssociated Jalview sequence.
5887 * - used to reorder the sequence in the alignment according to the
5888 * vamsasSeq array ordering, to preserve ordering of dataset
5890 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5891 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5894 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5896 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5897 boolean reorder = false;
5898 SequenceI dsq = null;
5899 if (sq != null && sq.getDatasetSequence() != null)
5901 dsq = sq.getDatasetSequence();
5907 if (sq == null && ignoreUnrefed)
5911 String sqid = vamsasSeq.getDsseqid();
5914 // need to create or add a new dataset sequence reference to this sequence
5917 dsq = seqRefIds.get(sqid);
5922 // make a new dataset sequence
5923 dsq = sq.createDatasetSequence();
5926 // make up a new dataset reference for this sequence
5927 sqid = seqHash(dsq);
5929 dsq.setVamsasId(uniqueSetSuffix + sqid);
5930 seqRefIds.put(sqid, dsq);
5935 dseqs.addElement(dsq);
5940 ds.addSequence(dsq);
5946 { // make this dataset sequence sq's dataset sequence
5947 sq.setDatasetSequence(dsq);
5948 // and update the current dataset alignment
5953 if (!dseqs.contains(dsq))
5960 if (ds.findIndex(dsq) < 0)
5962 ds.addSequence(dsq);
5969 // TODO: refactor this as a merge dataset sequence function
5970 // now check that sq (the dataset sequence) sequence really is the union of
5971 // all references to it
5972 // boolean pre = sq.getStart() < dsq.getStart();
5973 // boolean post = sq.getEnd() > dsq.getEnd();
5977 // StringBuffer sb = new StringBuffer();
5978 String newres = jalview.analysis.AlignSeq.extractGaps(
5979 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5980 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5981 && newres.length() > dsq.getLength())
5983 // Update with the longer sequence.
5987 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5988 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5989 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5990 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5992 dsq.setSequence(newres);
5994 // TODO: merges will never happen if we 'know' we have the real dataset
5995 // sequence - this should be detected when id==dssid
5996 jalview.bin.Console.errPrintln(
5997 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5998 // + (pre ? "prepended" : "") + " "
5999 // + (post ? "appended" : ""));
6004 // sequence refs are identical. We may need to update the existing dataset
6005 // alignment with this one, though.
6006 if (ds != null && dseqs == null)
6008 int opos = ds.findIndex(dsq);
6009 SequenceI tseq = null;
6010 if (opos != -1 && vseqpos != opos)
6012 // remove from old position
6013 ds.deleteSequence(dsq);
6015 if (vseqpos < ds.getHeight())
6017 if (vseqpos != opos)
6019 // save sequence at destination position
6020 tseq = ds.getSequenceAt(vseqpos);
6021 ds.replaceSequenceAt(vseqpos, dsq);
6022 ds.addSequence(tseq);
6027 ds.addSequence(dsq);
6034 * TODO use AlignmentI here and in related methods - needs
6035 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6037 Hashtable<String, AlignmentI> datasetIds = null;
6039 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6041 private AlignmentI getDatasetFor(String datasetId)
6043 if (datasetIds == null)
6045 datasetIds = new Hashtable<>();
6048 if (datasetIds.containsKey(datasetId))
6050 return datasetIds.get(datasetId);
6055 private void addDatasetRef(String datasetId, AlignmentI dataset)
6057 if (datasetIds == null)
6059 datasetIds = new Hashtable<>();
6061 datasetIds.put(datasetId, dataset);
6065 * make a new dataset ID for this jalview dataset alignment
6070 private String getDatasetIdRef(AlignmentI dataset)
6072 if (dataset.getDataset() != null)
6075 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6077 String datasetId = makeHashCode(dataset, null);
6078 if (datasetId == null)
6080 // make a new datasetId and record it
6081 if (dataset2Ids == null)
6083 dataset2Ids = new IdentityHashMap<>();
6087 datasetId = dataset2Ids.get(dataset);
6089 if (datasetId == null)
6091 datasetId = "ds" + dataset2Ids.size() + 1;
6092 dataset2Ids.put(dataset, datasetId);
6099 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6100 * constructed as a special subclass GeneLocus.
6102 * @param datasetSequence
6105 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6107 for (int d = 0; d < sequence.getDBRef().size(); d++)
6109 DBRef dr = sequence.getDBRef().get(d);
6113 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6114 dr.getAccessionId());
6118 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6119 dr.getAccessionId());
6121 if (dr.getMapping() != null)
6123 entry.setMap(addMapping(dr.getMapping()));
6125 entry.setCanonical(dr.isCanonical());
6126 datasetSequence.addDBRef(entry);
6130 private jalview.datamodel.Mapping addMapping(Mapping m)
6132 SequenceI dsto = null;
6133 // Mapping m = dr.getMapping();
6134 int fr[] = new int[m.getMapListFrom().size() * 2];
6135 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6136 for (int _i = 0; from.hasNext(); _i += 2)
6138 MapListFrom mf = from.next();
6139 fr[_i] = mf.getStart();
6140 fr[_i + 1] = mf.getEnd();
6142 int fto[] = new int[m.getMapListTo().size() * 2];
6143 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6144 for (int _i = 0; to.hasNext(); _i += 2)
6146 MapListTo mf = to.next();
6147 fto[_i] = mf.getStart();
6148 fto[_i + 1] = mf.getEnd();
6150 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6151 fto, m.getMapFromUnit().intValue(),
6152 m.getMapToUnit().intValue());
6155 * (optional) choice of dseqFor or Sequence
6157 if (m.getDseqFor() != null)
6159 String dsfor = m.getDseqFor();
6160 if (seqRefIds.containsKey(dsfor))
6165 jmap.setTo(seqRefIds.get(dsfor));
6169 frefedSequence.add(newMappingRef(dsfor, jmap));
6172 else if (m.getSequence() != null)
6175 * local sequence definition
6177 Sequence ms = m.getSequence();
6178 SequenceI djs = null;
6179 String sqid = ms.getDsseqid();
6180 if (sqid != null && sqid.length() > 0)
6183 * recover dataset sequence
6185 djs = seqRefIds.get(sqid);
6189 jalview.bin.Console.errPrintln(
6190 "Warning - making up dataset sequence id for DbRef sequence map reference");
6191 sqid = ((Object) ms).toString(); // make up a new hascode for
6192 // undefined dataset sequence hash
6193 // (unlikely to happen)
6199 * make a new dataset sequence and add it to refIds hash
6201 djs = new jalview.datamodel.Sequence(ms.getName(),
6203 djs.setStart(jmap.getMap().getToLowest());
6204 djs.setEnd(jmap.getMap().getToHighest());
6205 djs.setVamsasId(uniqueSetSuffix + sqid);
6207 incompleteSeqs.put(sqid, djs);
6208 seqRefIds.put(sqid, djs);
6211 Console.debug("about to recurse on addDBRefs.");
6220 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6221 * view as XML (but not to file), and then reloading it
6226 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6229 JalviewModel jm = saveState(ap, null, null, null);
6232 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6233 ap.getAlignment().getDataset());
6235 uniqueSetSuffix = "";
6236 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6237 jm.getViewport().get(0).setId(null);
6238 // we don't overwrite the view we just copied
6240 if (this.frefedSequence == null)
6242 frefedSequence = new Vector<>();
6245 viewportsAdded.clear();
6247 AlignFrame af = loadFromObject(jm, null, false, null);
6248 af.getAlignPanels().clear();
6249 af.closeMenuItem_actionPerformed(true);
6252 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6253 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6254 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6255 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6256 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6259 return af.alignPanel;
6262 private Hashtable jvids2vobj;
6265 * set the object to ID mapping tables used to write/recover objects and XML
6266 * ID strings for the jalview project. If external tables are provided then
6267 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6268 * object goes out of scope. - also populates the datasetIds hashtable with
6269 * alignment objects containing dataset sequences
6272 * Map from ID strings to jalview datamodel
6274 * Map from jalview datamodel to ID strings
6278 public void setObjectMappingTables(Hashtable vobj2jv,
6279 IdentityHashMap jv2vobj)
6281 this.jv2vobj = jv2vobj;
6282 this.vobj2jv = vobj2jv;
6283 Iterator ds = jv2vobj.keySet().iterator();
6285 while (ds.hasNext())
6287 Object jvobj = ds.next();
6288 id = jv2vobj.get(jvobj).toString();
6289 if (jvobj instanceof jalview.datamodel.Alignment)
6291 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6293 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6296 else if (jvobj instanceof jalview.datamodel.Sequence)
6298 // register sequence object so the XML parser can recover it.
6299 if (seqRefIds == null)
6301 seqRefIds = new HashMap<>();
6303 if (seqsToIds == null)
6305 seqsToIds = new IdentityHashMap<>();
6307 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6308 seqsToIds.put((SequenceI) jvobj, id);
6310 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6313 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6314 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6315 if (jvann.annotationId == null)
6317 jvann.annotationId = anid;
6319 if (!jvann.annotationId.equals(anid))
6321 // TODO verify that this is the correct behaviour
6322 Console.warn("Overriding Annotation ID for " + anid
6323 + " from different id : " + jvann.annotationId);
6324 jvann.annotationId = anid;
6327 else if (jvobj instanceof String)
6329 if (jvids2vobj == null)
6331 jvids2vobj = new Hashtable();
6332 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6337 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6343 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6344 * objects created from the project archive. If string is null (default for
6345 * construction) then suffix will be set automatically.
6349 public void setUniqueSetSuffix(String string)
6351 uniqueSetSuffix = string;
6356 * uses skipList2 as the skipList for skipping views on sequence sets
6357 * associated with keys in the skipList
6361 public void setSkipList(Hashtable skipList2)
6363 skipList = skipList2;
6367 * Reads the jar entry of given name and returns its contents, or null if the
6368 * entry is not found.
6371 * @param jarEntryName
6374 protected String readJarEntry(jarInputStreamProvider jprovider,
6375 String jarEntryName)
6377 String result = null;
6378 BufferedReader in = null;
6383 * Reopen the jar input stream and traverse its entries to find a matching
6386 JarInputStream jin = jprovider.getJarInputStream();
6387 JarEntry entry = null;
6390 entry = jin.getNextJarEntry();
6391 } while (entry != null && !entry.getName().equals(jarEntryName));
6395 StringBuilder out = new StringBuilder(256);
6396 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6399 while ((data = in.readLine()) != null)
6403 result = out.toString();
6408 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6410 } catch (Exception ex)
6412 ex.printStackTrace();
6420 } catch (IOException e)
6431 * Returns an incrementing counter (0, 1, 2...)
6435 private synchronized int nextCounter()
6441 * Loads any saved PCA viewers
6446 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6450 List<PcaViewer> pcaviewers = model.getPcaViewer();
6451 for (PcaViewer viewer : pcaviewers)
6453 String modelName = viewer.getScoreModelName();
6454 SimilarityParamsI params = new SimilarityParams(
6455 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6456 viewer.isIncludeGaps(),
6457 viewer.isDenominateByShortestLength());
6460 * create the panel (without computing the PCA)
6462 PCAPanel panel = new PCAPanel(ap, modelName, params);
6464 panel.setTitle(viewer.getTitle());
6465 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6466 viewer.getWidth(), viewer.getHeight()));
6468 boolean showLabels = viewer.isShowLabels();
6469 panel.setShowLabels(showLabels);
6470 panel.getRotatableCanvas().setShowLabels(showLabels);
6471 panel.getRotatableCanvas()
6472 .setBgColour(new Color(viewer.getBgColour()));
6473 panel.getRotatableCanvas()
6474 .setApplyToAllViews(viewer.isLinkToAllViews());
6477 * load PCA output data
6479 ScoreModelI scoreModel = ScoreModels.getInstance()
6480 .getScoreModel(modelName, ap);
6481 PCA pca = new PCA(null, scoreModel, params);
6482 PcaDataType pcaData = viewer.getPcaData();
6484 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6485 pca.setPairwiseScores(pairwise);
6487 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6488 pca.setTridiagonal(triDiag);
6490 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6491 pca.setEigenmatrix(result);
6493 panel.getPcaModel().setPCA(pca);
6496 * we haven't saved the input data! (JAL-2647 to do)
6498 panel.setInputData(null);
6501 * add the sequence points for the PCA display
6503 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6504 for (SequencePoint sp : viewer.getSequencePoint())
6506 String seqId = sp.getSequenceRef();
6507 SequenceI seq = seqRefIds.get(seqId);
6510 throw new IllegalStateException(
6511 "Unmatched seqref for PCA: " + seqId);
6513 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6514 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6516 seqPoints.add(seqPoint);
6518 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6521 * set min-max ranges and scale after setPoints (which recomputes them)
6523 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6524 SeqPointMin spMin = viewer.getSeqPointMin();
6525 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6527 SeqPointMax spMax = viewer.getSeqPointMax();
6528 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6530 panel.getRotatableCanvas().setSeqMinMax(min, max);
6532 // todo: hold points list in PCAModel only
6533 panel.getPcaModel().setSequencePoints(seqPoints);
6535 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6536 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6537 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6539 // is this duplication needed?
6540 panel.setTop(seqPoints.size() - 1);
6541 panel.getPcaModel().setTop(seqPoints.size() - 1);
6544 * add the axes' end points for the display
6546 for (int i = 0; i < 3; i++)
6548 Axis axis = viewer.getAxis().get(i);
6549 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6550 axis.getXPos(), axis.getYPos(), axis.getZPos());
6553 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6554 "label.calc_title", "PCA", modelName), 475, 450);
6556 } catch (Exception ex)
6558 Console.error("Error loading PCA: " + ex.toString());
6563 * Creates a new structure viewer window
6570 protected void createStructureViewer(ViewerType viewerType,
6571 final Entry<String, StructureViewerModel> viewerData,
6572 AlignFrame af, jarInputStreamProvider jprovider)
6574 final StructureViewerModel viewerModel = viewerData.getValue();
6575 String sessionFilePath = null;
6577 if (viewerType == ViewerType.JMOL)
6579 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6583 String viewerJarEntryName = getViewerJarEntryName(
6584 viewerModel.getViewId());
6585 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6586 "viewerSession", ".tmp");
6588 final String sessionPath = sessionFilePath;
6589 final String sviewid = viewerData.getKey();
6592 SwingUtilities.invokeAndWait(new Runnable()
6597 JalviewStructureDisplayI sview = null;
6600 sview = StructureViewer.createView(viewerType, af.alignPanel,
6601 viewerModel, sessionPath, sviewid);
6602 addNewStructureViewer(sview);
6603 } catch (OutOfMemoryError ex)
6605 new OOMWarning("Restoring structure view for " + viewerType,
6606 (OutOfMemoryError) ex.getCause());
6607 if (sview != null && sview.isVisible())
6609 sview.closeViewer(false);
6610 sview.setVisible(false);
6616 } catch (InvocationTargetException | InterruptedException ex)
6618 Console.warn("Unexpected error when opening " + viewerType
6619 + " structure viewer", ex);
6624 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6625 * the path of the file. "load file" commands are rewritten to change the
6626 * original PDB file names to those created as the Jalview project is loaded.
6632 private String rewriteJmolSession(StructureViewerModel svattrib,
6633 jarInputStreamProvider jprovider)
6635 String state = svattrib.getStateData(); // Jalview < 2.9
6636 if (state == null || state.isEmpty()) // Jalview >= 2.9
6638 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6639 state = readJarEntry(jprovider, jarEntryName);
6641 // TODO or simpler? for each key in oldFiles,
6642 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6643 // (allowing for different path escapings)
6644 StringBuilder rewritten = new StringBuilder(state.length());
6645 int cp = 0, ncp, ecp;
6646 Map<File, StructureData> oldFiles = svattrib.getFileData();
6647 while ((ncp = state.indexOf("load ", cp)) > -1)
6651 // look for next filename in load statement
6652 rewritten.append(state.substring(cp,
6653 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6654 String oldfilenam = state.substring(ncp,
6655 ecp = state.indexOf("\"", ncp));
6656 // recover the new mapping data for this old filename
6657 // have to normalize filename - since Jmol and jalview do
6658 // filename translation differently.
6659 StructureData filedat = oldFiles.get(new File(oldfilenam));
6660 if (filedat == null)
6662 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6663 filedat = oldFiles.get(new File(reformatedOldFilename));
6665 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6666 rewritten.append("\"");
6667 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6668 // look for next file statement.
6669 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6673 // just append rest of state
6674 rewritten.append(state.substring(cp));
6678 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6679 rewritten = new StringBuilder(state);
6680 rewritten.append("; load append ");
6681 for (File id : oldFiles.keySet())
6683 // add pdb files that should be present in the viewer
6684 StructureData filedat = oldFiles.get(id);
6685 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6687 rewritten.append(";");
6690 if (rewritten.length() == 0)
6694 final String history = "history = ";
6695 int historyIndex = rewritten.indexOf(history);
6696 if (historyIndex > -1)
6699 * change "history = [true|false];" to "history = [1|0];"
6701 historyIndex += history.length();
6702 String val = rewritten.substring(historyIndex, historyIndex + 5);
6703 if (val.startsWith("true"))
6705 rewritten.replace(historyIndex, historyIndex + 4, "1");
6707 else if (val.startsWith("false"))
6709 rewritten.replace(historyIndex, historyIndex + 5, "0");
6715 File tmp = File.createTempFile("viewerSession", ".tmp");
6716 try (OutputStream os = new FileOutputStream(tmp))
6718 InputStream is = new ByteArrayInputStream(
6719 rewritten.toString().getBytes());
6721 return tmp.getAbsolutePath();
6723 } catch (IOException e)
6725 Console.error("Error restoring Jmol session: " + e.toString());
6731 * Populates an XML model of the feature colour scheme for one feature type
6733 * @param featureType
6737 public static Colour marshalColour(String featureType,
6738 FeatureColourI fcol)
6740 Colour col = new Colour();
6741 if (fcol.isSimpleColour())
6743 col.setRGB(Format.getHexString(fcol.getColour()));
6747 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6748 col.setMin(fcol.getMin());
6749 col.setMax(fcol.getMax());
6750 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6751 col.setAutoScale(fcol.isAutoScaled());
6752 col.setThreshold(fcol.getThreshold());
6753 col.setColourByLabel(fcol.isColourByLabel());
6754 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6755 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6756 : ThresholdType.NONE));
6757 if (fcol.isColourByAttribute())
6759 final String[] attName = fcol.getAttributeName();
6760 col.getAttributeName().add(attName[0]);
6761 if (attName.length > 1)
6763 col.getAttributeName().add(attName[1]);
6766 Color noColour = fcol.getNoColour();
6767 if (noColour == null)
6769 col.setNoValueColour(NoValueColour.NONE);
6771 else if (noColour == fcol.getMaxColour())
6773 col.setNoValueColour(NoValueColour.MAX);
6777 col.setNoValueColour(NoValueColour.MIN);
6780 col.setName(featureType);
6785 * Populates an XML model of the feature filter(s) for one feature type
6787 * @param firstMatcher
6788 * the first (or only) match condition)
6790 * remaining match conditions (if any)
6792 * if true, conditions are and-ed, else or-ed
6794 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6795 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6798 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6800 if (filters.hasNext())
6805 CompoundMatcher compound = new CompoundMatcher();
6806 compound.setAnd(and);
6807 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6808 firstMatcher, Collections.emptyIterator(), and);
6809 // compound.addMatcherSet(matcher1);
6810 compound.getMatcherSet().add(matcher1);
6811 FeatureMatcherI nextMatcher = filters.next();
6812 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6813 nextMatcher, filters, and);
6814 // compound.addMatcherSet(matcher2);
6815 compound.getMatcherSet().add(matcher2);
6816 result.setCompoundMatcher(compound);
6821 * single condition matcher
6823 // MatchCondition matcherModel = new MatchCondition();
6824 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6825 matcherModel.setCondition(
6826 firstMatcher.getMatcher().getCondition().getStableName());
6827 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6828 if (firstMatcher.isByAttribute())
6830 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6831 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6832 String[] attName = firstMatcher.getAttribute();
6833 matcherModel.getAttributeName().add(attName[0]); // attribute
6834 if (attName.length > 1)
6836 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6839 else if (firstMatcher.isByLabel())
6841 matcherModel.setBy(FilterBy.BY_LABEL);
6843 else if (firstMatcher.isByScore())
6845 matcherModel.setBy(FilterBy.BY_SCORE);
6847 result.setMatchCondition(matcherModel);
6854 * Loads one XML model of a feature filter to a Jalview object
6856 * @param featureType
6857 * @param matcherSetModel
6860 public static FeatureMatcherSetI parseFilter(String featureType,
6861 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6863 FeatureMatcherSetI result = new FeatureMatcherSet();
6866 parseFilterConditions(result, matcherSetModel, true);
6867 } catch (IllegalStateException e)
6869 // mixing AND and OR conditions perhaps
6870 jalview.bin.Console.errPrintln(
6871 String.format("Error reading filter conditions for '%s': %s",
6872 featureType, e.getMessage()));
6873 // return as much as was parsed up to the error
6880 * Adds feature match conditions to matcherSet as unmarshalled from XML
6881 * (possibly recursively for compound conditions)
6884 * @param matcherSetModel
6886 * if true, multiple conditions are AND-ed, else they are OR-ed
6887 * @throws IllegalStateException
6888 * if AND and OR conditions are mixed
6890 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6891 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6894 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6895 .getMatchCondition();
6901 FilterBy filterBy = mc.getBy();
6902 Condition cond = Condition.fromString(mc.getCondition());
6903 String pattern = mc.getValue();
6904 FeatureMatcherI matchCondition = null;
6905 if (filterBy == FilterBy.BY_LABEL)
6907 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6909 else if (filterBy == FilterBy.BY_SCORE)
6911 matchCondition = FeatureMatcher.byScore(cond, pattern);
6914 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6916 final List<String> attributeName = mc.getAttributeName();
6917 String[] attNames = attributeName
6918 .toArray(new String[attributeName.size()]);
6919 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6924 * note this throws IllegalStateException if AND-ing to a
6925 * previously OR-ed compound condition, or vice versa
6929 matcherSet.and(matchCondition);
6933 matcherSet.or(matchCondition);
6939 * compound condition
6941 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6942 .getCompoundMatcher().getMatcherSet();
6943 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6944 if (matchers.size() == 2)
6946 parseFilterConditions(matcherSet, matchers.get(0), anded);
6947 parseFilterConditions(matcherSet, matchers.get(1), anded);
6952 .errPrintln("Malformed compound filter condition");
6958 * Loads one XML model of a feature colour to a Jalview object
6960 * @param colourModel
6963 public static FeatureColourI parseColour(Colour colourModel)
6965 FeatureColourI colour = null;
6967 if (colourModel.getMax() != null)
6969 Color mincol = null;
6970 Color maxcol = null;
6971 Color noValueColour = null;
6975 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6976 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6977 } catch (Exception e)
6979 Console.warn("Couldn't parse out graduated feature color.", e);
6982 NoValueColour noCol = colourModel.getNoValueColour();
6983 if (noCol == NoValueColour.MIN)
6985 noValueColour = mincol;
6987 else if (noCol == NoValueColour.MAX)
6989 noValueColour = maxcol;
6992 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6993 safeFloat(colourModel.getMin()),
6994 safeFloat(colourModel.getMax()));
6995 final List<String> attributeName = colourModel.getAttributeName();
6996 String[] attributes = attributeName
6997 .toArray(new String[attributeName.size()]);
6998 if (attributes != null && attributes.length > 0)
7000 colour.setAttributeName(attributes);
7002 if (colourModel.isAutoScale() != null)
7004 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7006 if (colourModel.isColourByLabel() != null)
7008 colour.setColourByLabel(
7009 colourModel.isColourByLabel().booleanValue());
7011 if (colourModel.getThreshold() != null)
7013 colour.setThreshold(colourModel.getThreshold().floatValue());
7015 ThresholdType ttyp = colourModel.getThreshType();
7016 if (ttyp == ThresholdType.ABOVE)
7018 colour.setAboveThreshold(true);
7020 else if (ttyp == ThresholdType.BELOW)
7022 colour.setBelowThreshold(true);
7027 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7028 colour = new FeatureColour(color);
7034 public static void setStateSavedUpToDate(boolean s)
7036 Console.debug("Setting overall stateSavedUpToDate to " + s);
7037 stateSavedUpToDate = s;
7040 public static boolean stateSavedUpToDate()
7042 Console.debug("Returning overall stateSavedUpToDate value: "
7043 + stateSavedUpToDate);
7044 return stateSavedUpToDate;
7047 public static boolean allSavedUpToDate()
7049 if (stateSavedUpToDate()) // nothing happened since last project save
7052 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7055 for (int i = 0; i < frames.length; i++)
7057 if (frames[i] == null)
7059 if (!frames[i].getViewport().savedUpToDate())
7060 return false; // at least one alignment is not individually saved
7066 // used for debugging and tests
7067 private static int debugDelaySave = 20;
7069 public static void setDebugDelaySave(int n)