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.FontMetrics;
30 import java.awt.Rectangle;
31 import java.io.BufferedReader;
32 import java.io.ByteArrayInputStream;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.OutputStream;
40 import java.io.OutputStreamWriter;
41 import java.io.PrintWriter;
42 import java.lang.reflect.InvocationTargetException;
43 import java.math.BigInteger;
44 import java.net.MalformedURLException;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.BitSet;
49 import java.util.Collections;
50 import java.util.Enumeration;
51 import java.util.GregorianCalendar;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Hashtable;
55 import java.util.IdentityHashMap;
56 import java.util.Iterator;
57 import java.util.LinkedHashMap;
58 import java.util.List;
59 import java.util.Locale;
61 import java.util.Map.Entry;
63 import java.util.Vector;
64 import java.util.jar.JarEntry;
65 import java.util.jar.JarInputStream;
66 import java.util.jar.JarOutputStream;
68 import javax.swing.JInternalFrame;
69 import javax.swing.SwingUtilities;
70 import javax.xml.bind.JAXBContext;
71 import javax.xml.bind.JAXBElement;
72 import javax.xml.bind.Marshaller;
73 import javax.xml.datatype.DatatypeConfigurationException;
74 import javax.xml.datatype.DatatypeFactory;
75 import javax.xml.datatype.XMLGregorianCalendar;
76 import javax.xml.stream.XMLInputFactory;
77 import javax.xml.stream.XMLStreamReader;
79 import jalview.analysis.Conservation;
80 import jalview.analysis.PCA;
81 import jalview.analysis.scoremodels.ScoreModels;
82 import jalview.analysis.scoremodels.SimilarityParams;
83 import jalview.api.FeatureColourI;
84 import jalview.api.ViewStyleI;
85 import jalview.api.analysis.ScoreModelI;
86 import jalview.api.analysis.SimilarityParamsI;
87 import jalview.api.structures.JalviewStructureDisplayI;
88 import jalview.bin.Cache;
89 import jalview.bin.Console;
90 import jalview.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)
572 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
585 System.err.println("Jalview Project Import: There were " + unresolved
586 + " forward references left unresolved on the stack.");
588 if (failedtoresolve > 0)
590 System.err.println("SERIOUS! " + failedtoresolve
591 + " resolvable forward references failed to resolve.");
593 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
596 "Jalview Project Import: There are " + incompleteSeqs.size()
597 + " sequences which may have incomplete metadata.");
598 if (incompleteSeqs.size() < 10)
600 for (SequenceI s : incompleteSeqs.values())
602 System.err.println(s.toString());
608 "Too many to report. Skipping output of incomplete sequences.");
614 * This maintains a map of viewports, the key being the seqSetId. Important to
615 * set historyItem and redoList for multiple views
617 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
619 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
621 String uniqueSetSuffix = "";
624 * List of pdbfiles added to Jar
626 List<String> pdbfiles = null;
628 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
629 public void saveState(File statefile)
631 FileOutputStream fos = null;
636 fos = new FileOutputStream(statefile);
638 JarOutputStream jout = new JarOutputStream(fos);
642 } catch (Exception e)
644 Console.error("Couln't write Jalview state to " + statefile, e);
645 // TODO: inform user of the problem - they need to know if their data was
647 if (errorMessage == null)
649 errorMessage = "Did't write Jalview Archive to output file '"
650 + statefile + "' - See console error log for details";
654 errorMessage += "(Didn't write Jalview Archive to output file '"
665 } catch (IOException e)
675 * Writes a jalview project archive to the given Jar output stream.
679 public void saveState(JarOutputStream jout)
681 AlignFrame[] frames = Desktop.getAlignFrames();
683 setStateSavedUpToDate(true);
685 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
687 int n = debugDelaySave;
691 Console.debug("***** debugging save sleep " + i + "/" + n);
695 } catch (InterruptedException e)
697 // TODO Auto-generated catch block
708 saveAllFrames(Arrays.asList(frames), jout);
712 * core method for storing state for a set of AlignFrames.
715 * - frames involving all data to be exported (including containing
718 * - project output stream
720 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
722 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
725 * ensure cached data is clear before starting
727 // todo tidy up seqRefIds, seqsToIds initialisation / reset
729 splitFrameCandidates.clear();
734 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
735 // //////////////////////////////////////////////////
737 List<String> shortNames = new ArrayList<>();
738 List<String> viewIds = new ArrayList<>();
741 for (int i = frames.size() - 1; i > -1; i--)
743 AlignFrame af = frames.get(i);
745 if (skipList != null && skipList
746 .containsKey(af.getViewport().getSequenceSetId()))
751 String shortName = makeFilename(af, shortNames);
753 int apSize = af.getAlignPanels().size();
755 for (int ap = 0; ap < apSize; ap++)
757 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
759 String fileName = apSize == 1 ? shortName : ap + shortName;
760 if (!fileName.endsWith(".xml"))
762 fileName = fileName + ".xml";
765 saveState(apanel, fileName, jout, viewIds);
767 String dssid = getDatasetIdRef(
768 af.getViewport().getAlignment().getDataset());
769 if (!dsses.containsKey(dssid))
771 dsses.put(dssid, af);
776 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
782 } catch (Exception foo)
786 } catch (Exception ex)
788 // TODO: inform user of the problem - they need to know if their data was
790 if (errorMessage == null)
792 errorMessage = "Couldn't write Jalview Archive - see error output for details";
794 ex.printStackTrace();
799 * Generates a distinct file name, based on the title of the AlignFrame, by
800 * appending _n for increasing n until an unused name is generated. The new
801 * name (without its extension) is added to the list.
805 * @return the generated name, with .xml extension
807 protected String makeFilename(AlignFrame af, List<String> namesUsed)
809 String shortName = af.getTitle();
811 if (shortName.indexOf(File.separatorChar) > -1)
813 shortName = shortName
814 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
819 while (namesUsed.contains(shortName))
821 if (shortName.endsWith("_" + (count - 1)))
823 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
826 shortName = shortName.concat("_" + count);
830 namesUsed.add(shortName);
832 if (!shortName.endsWith(".xml"))
834 shortName = shortName + ".xml";
839 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
840 public boolean saveAlignment(AlignFrame af, String jarFile,
845 // create backupfiles object and get new temp filename destination
846 boolean doBackup = BackupFiles.getEnabled();
847 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
848 FileOutputStream fos = new FileOutputStream(
849 doBackup ? backupfiles.getTempFilePath() : jarFile);
851 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
853 int n = debugDelaySave;
857 Console.debug("***** debugging save sleep " + i + "/" + n);
861 } catch (InterruptedException e)
863 // TODO Auto-generated catch block
870 JarOutputStream jout = new JarOutputStream(fos);
871 List<AlignFrame> frames = new ArrayList<>();
873 // resolve splitframes
874 if (af.getViewport().getCodingComplement() != null)
876 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
882 saveAllFrames(frames, jout);
886 } catch (Exception foo)
890 boolean success = true;
894 backupfiles.setWriteSuccess(success);
895 success = backupfiles.rollBackupsAndRenameTempFile();
899 } catch (Exception ex)
901 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
902 ex.printStackTrace();
907 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
908 String fileName, JarOutputStream jout)
911 for (String dssids : dsses.keySet())
913 AlignFrame _af = dsses.get(dssids);
914 String jfileName = fileName + " Dataset for " + _af.getTitle();
915 if (!jfileName.endsWith(".xml"))
917 jfileName = jfileName + ".xml";
919 saveState(_af.alignPanel, jfileName, true, jout, null);
924 * create a JalviewModel from an alignment view and marshall it to a
928 * panel to create jalview model for
930 * name of alignment panel written to output stream
937 public JalviewModel saveState(AlignmentPanel ap, String fileName,
938 JarOutputStream jout, List<String> viewIds)
940 return saveState(ap, fileName, false, jout, viewIds);
944 * create a JalviewModel from an alignment view and marshall it to a
948 * panel to create jalview model for
950 * name of alignment panel written to output stream
952 * when true, only write the dataset for the alignment, not the data
953 * associated with the view.
959 public JalviewModel saveState(AlignmentPanel ap, String fileName,
960 boolean storeDS, JarOutputStream jout, List<String> viewIds)
964 viewIds = new ArrayList<>();
969 List<UserColourScheme> userColours = new ArrayList<>();
971 AlignViewport av = ap.av;
972 ViewportRanges vpRanges = av.getRanges();
974 final ObjectFactory objectFactory = new ObjectFactory();
975 JalviewModel object = objectFactory.createJalviewModel();
976 object.setVamsasModel(new VAMSAS());
978 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
981 GregorianCalendar c = new GregorianCalendar();
982 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
983 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
984 object.setCreationDate(now);
985 } catch (DatatypeConfigurationException e)
987 System.err.println("error writing date: " + e.toString());
989 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
992 * rjal is full height alignment, jal is actual alignment with full metadata
993 * but excludes hidden sequences.
995 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
997 if (av.hasHiddenRows())
999 rjal = jal.getHiddenSequences().getFullAlignment();
1002 SequenceSet vamsasSet = new SequenceSet();
1004 // JalviewModelSequence jms = new JalviewModelSequence();
1006 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1008 if (jal.getDataset() != null)
1010 // dataset id is the dataset's hashcode
1011 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1014 // switch jal and the dataset
1015 jal = jal.getDataset();
1019 if (jal.getProperties() != null)
1021 Enumeration en = jal.getProperties().keys();
1022 while (en.hasMoreElements())
1024 String key = en.nextElement().toString();
1025 SequenceSetProperties ssp = new SequenceSetProperties();
1027 ssp.setValue(jal.getProperties().get(key).toString());
1028 // vamsasSet.addSequenceSetProperties(ssp);
1029 vamsasSet.getSequenceSetProperties().add(ssp);
1034 Set<String> calcIdSet = new HashSet<>();
1035 // record the set of vamsas sequence XML POJO we create.
1036 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1038 for (final SequenceI jds : rjal.getSequences())
1040 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1041 : jds.getDatasetSequence();
1042 String id = seqHash(jds);
1043 if (vamsasSetIds.get(id) == null)
1045 if (seqRefIds.get(id) != null && !storeDS)
1047 // This happens for two reasons: 1. multiple views are being
1049 // 2. the hashCode has collided with another sequence's code. This
1051 // HAPPEN! (PF00072.15.stk does this)
1052 // JBPNote: Uncomment to debug writing out of files that do not read
1053 // back in due to ArrayOutOfBoundExceptions.
1054 // System.err.println("vamsasSeq backref: "+id+"");
1055 // System.err.println(jds.getName()+"
1056 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1057 // System.err.println("Hashcode: "+seqHash(jds));
1058 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1059 // System.err.println(rsq.getName()+"
1060 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1061 // System.err.println("Hashcode: "+seqHash(rsq));
1065 vamsasSeq = createVamsasSequence(id, jds);
1066 // vamsasSet.addSequence(vamsasSeq);
1067 vamsasSet.getSequence().add(vamsasSeq);
1068 vamsasSetIds.put(id, vamsasSeq);
1069 seqRefIds.put(id, jds);
1073 jseq.setStart(jds.getStart());
1074 jseq.setEnd(jds.getEnd());
1075 jseq.setColour(av.getSequenceColour(jds).getRGB());
1077 jseq.setId(id); // jseq id should be a string not a number
1080 // Store any sequences this sequence represents
1081 if (av.hasHiddenRows())
1083 // use rjal, contains the full height alignment
1085 av.getAlignment().getHiddenSequences().isHidden(jds));
1087 if (av.isHiddenRepSequence(jds))
1089 jalview.datamodel.SequenceI[] reps = av
1090 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1092 for (int h = 0; h < reps.length; h++)
1096 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1097 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1102 // mark sequence as reference - if it is the reference for this view
1103 if (jal.hasSeqrep())
1105 jseq.setViewreference(jds == jal.getSeqrep());
1109 // TODO: omit sequence features from each alignment view's XML dump if we
1110 // are storing dataset
1111 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1112 for (SequenceFeature sf : sfs)
1114 // Features features = new Features();
1115 Feature features = new Feature();
1117 features.setBegin(sf.getBegin());
1118 features.setEnd(sf.getEnd());
1119 features.setDescription(sf.getDescription());
1120 features.setType(sf.getType());
1121 features.setFeatureGroup(sf.getFeatureGroup());
1122 features.setScore(sf.getScore());
1123 if (sf.links != null)
1125 for (int l = 0; l < sf.links.size(); l++)
1127 OtherData keyValue = new OtherData();
1128 keyValue.setKey("LINK_" + l);
1129 keyValue.setValue(sf.links.elementAt(l).toString());
1130 // features.addOtherData(keyValue);
1131 features.getOtherData().add(keyValue);
1134 if (sf.otherDetails != null)
1137 * save feature attributes, which may be simple strings or
1138 * map valued (have sub-attributes)
1140 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1142 String key = entry.getKey();
1143 Object value = entry.getValue();
1144 if (value instanceof Map<?, ?>)
1146 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1149 OtherData otherData = new OtherData();
1150 otherData.setKey(key);
1151 otherData.setKey2(subAttribute.getKey());
1152 otherData.setValue(subAttribute.getValue().toString());
1153 // features.addOtherData(otherData);
1154 features.getOtherData().add(otherData);
1159 OtherData otherData = new OtherData();
1160 otherData.setKey(key);
1161 otherData.setValue(value.toString());
1162 // features.addOtherData(otherData);
1163 features.getOtherData().add(otherData);
1168 // jseq.addFeatures(features);
1169 jseq.getFeatures().add(features);
1172 if (jdatasq.getAllPDBEntries() != null)
1174 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1175 while (en.hasMoreElements())
1177 Pdbids pdb = new Pdbids();
1178 jalview.datamodel.PDBEntry entry = en.nextElement();
1180 String pdbId = entry.getId();
1182 pdb.setType(entry.getType());
1185 * Store any structure views associated with this sequence. This
1186 * section copes with duplicate entries in the project, so a dataset
1187 * only view *should* be coped with sensibly.
1189 // This must have been loaded, is it still visible?
1190 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1191 String matchedFile = null;
1192 for (int f = frames.length - 1; f > -1; f--)
1194 if (frames[f] instanceof StructureViewerBase)
1196 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1197 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1198 viewIds, matchedFile, viewFrame);
1200 * Only store each structure viewer's state once in the project
1201 * jar. First time through only (storeDS==false)
1203 String viewId = viewFrame.getViewId();
1204 String viewerType = viewFrame.getViewerType().toString();
1205 if (!storeDS && !viewIds.contains(viewId))
1207 viewIds.add(viewId);
1208 File viewerState = viewFrame.saveSession();
1209 if (viewerState != null)
1211 copyFileToJar(jout, viewerState.getPath(),
1212 getViewerJarEntryName(viewId), viewerType);
1217 "Failed to save viewer state for " + viewerType);
1223 if (matchedFile != null || entry.getFile() != null)
1225 if (entry.getFile() != null)
1228 matchedFile = entry.getFile();
1230 pdb.setFile(matchedFile); // entry.getFile());
1231 if (pdbfiles == null)
1233 pdbfiles = new ArrayList<>();
1236 if (!pdbfiles.contains(pdbId))
1238 pdbfiles.add(pdbId);
1239 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1243 Enumeration<String> props = entry.getProperties();
1244 if (props.hasMoreElements())
1246 // PdbentryItem item = new PdbentryItem();
1247 while (props.hasMoreElements())
1249 Property prop = new Property();
1250 String key = props.nextElement();
1252 prop.setValue(entry.getProperty(key).toString());
1253 // item.addProperty(prop);
1254 pdb.getProperty().add(prop);
1256 // pdb.addPdbentryItem(item);
1259 // jseq.addPdbids(pdb);
1260 jseq.getPdbids().add(pdb);
1264 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1266 // jms.addJSeq(jseq);
1267 object.getJSeq().add(jseq);
1270 if (!storeDS && av.hasHiddenRows())
1272 jal = av.getAlignment();
1276 if (storeDS && jal.getCodonFrames() != null)
1278 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1279 for (AlignedCodonFrame acf : jac)
1281 AlcodonFrame alc = new AlcodonFrame();
1282 if (acf.getProtMappings() != null
1283 && acf.getProtMappings().length > 0)
1285 boolean hasMap = false;
1286 SequenceI[] dnas = acf.getdnaSeqs();
1287 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1288 for (int m = 0; m < pmaps.length; m++)
1290 AlcodMap alcmap = new AlcodMap();
1291 alcmap.setDnasq(seqHash(dnas[m]));
1293 createVamsasMapping(pmaps[m], dnas[m], null, false));
1294 // alc.addAlcodMap(alcmap);
1295 alc.getAlcodMap().add(alcmap);
1300 // vamsasSet.addAlcodonFrame(alc);
1301 vamsasSet.getAlcodonFrame().add(alc);
1304 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1306 // AlcodonFrame alc = new AlcodonFrame();
1307 // vamsasSet.addAlcodonFrame(alc);
1308 // for (int p = 0; p < acf.aaWidth; p++)
1310 // Alcodon cmap = new Alcodon();
1311 // if (acf.codons[p] != null)
1313 // // Null codons indicate a gapped column in the translated peptide
1315 // cmap.setPos1(acf.codons[p][0]);
1316 // cmap.setPos2(acf.codons[p][1]);
1317 // cmap.setPos3(acf.codons[p][2]);
1319 // alc.addAlcodon(cmap);
1321 // if (acf.getProtMappings() != null
1322 // && acf.getProtMappings().length > 0)
1324 // SequenceI[] dnas = acf.getdnaSeqs();
1325 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1326 // for (int m = 0; m < pmaps.length; m++)
1328 // AlcodMap alcmap = new AlcodMap();
1329 // alcmap.setDnasq(seqHash(dnas[m]));
1330 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1332 // alc.addAlcodMap(alcmap);
1339 // /////////////////////////////////
1340 if (!storeDS && av.getCurrentTree() != null)
1342 // FIND ANY ASSOCIATED TREES
1343 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1344 if (Desktop.desktop != null)
1346 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1348 for (int t = 0; t < frames.length; t++)
1350 if (frames[t] instanceof TreePanel)
1352 TreePanel tp = (TreePanel) frames[t];
1354 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1356 JalviewModel.Tree tree = new JalviewModel.Tree();
1357 tree.setTitle(tp.getTitle());
1358 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1359 tree.setNewick(tp.getTree().print());
1360 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1362 tree.setFitToWindow(tp.fitToWindow.getState());
1363 tree.setFontName(tp.getTreeFont().getName());
1364 tree.setFontSize(tp.getTreeFont().getSize());
1365 tree.setFontStyle(tp.getTreeFont().getStyle());
1366 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1368 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1369 tree.setShowDistances(tp.distanceMenu.getState());
1371 tree.setHeight(tp.getHeight());
1372 tree.setWidth(tp.getWidth());
1373 tree.setXpos(tp.getX());
1374 tree.setYpos(tp.getY());
1375 tree.setId(makeHashCode(tp, null));
1376 tree.setLinkToAllViews(
1377 tp.getTreeCanvas().isApplyToAllViews());
1380 if (tp.isColumnWise())
1382 tree.setColumnWise(true);
1383 String annId = tp.getAssocAnnotation().annotationId;
1384 tree.setColumnReference(annId);
1386 // jms.addTree(tree);
1387 object.getTree().add(tree);
1397 if (!storeDS && Desktop.desktop != null)
1399 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1401 if (frame instanceof PCAPanel)
1403 PCAPanel panel = (PCAPanel) frame;
1404 if (panel.getAlignViewport().getAlignment() == jal)
1406 savePCA(panel, object);
1414 * store forward refs from an annotationRow to any groups
1416 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1419 for (SequenceI sq : jal.getSequences())
1421 // Store annotation on dataset sequences only
1422 AlignmentAnnotation[] aa = sq.getAnnotation();
1423 if (aa != null && aa.length > 0)
1425 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1432 if (jal.getAlignmentAnnotation() != null)
1434 // Store the annotation shown on the alignment.
1435 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1436 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1441 if (jal.getGroups() != null)
1443 JGroup[] groups = new JGroup[jal.getGroups().size()];
1445 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1447 JGroup jGroup = new JGroup();
1448 groups[++i] = jGroup;
1450 jGroup.setStart(sg.getStartRes());
1451 jGroup.setEnd(sg.getEndRes());
1452 jGroup.setName(sg.getName());
1453 if (groupRefs.containsKey(sg))
1455 // group has references so set its ID field
1456 jGroup.setId(groupRefs.get(sg));
1458 ColourSchemeI colourScheme = sg.getColourScheme();
1459 if (colourScheme != null)
1461 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1462 if (groupColourScheme.conservationApplied())
1464 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1466 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1468 jGroup.setColour(setUserColourScheme(colourScheme,
1469 userColours, object));
1473 jGroup.setColour(colourScheme.getSchemeName());
1476 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1478 jGroup.setColour("AnnotationColourGradient");
1479 jGroup.setAnnotationColours(constructAnnotationColours(
1480 (jalview.schemes.AnnotationColourGradient) colourScheme,
1481 userColours, object));
1483 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1486 setUserColourScheme(colourScheme, userColours, object));
1490 jGroup.setColour(colourScheme.getSchemeName());
1493 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1496 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1497 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1498 jGroup.setDisplayText(sg.getDisplayText());
1499 jGroup.setColourText(sg.getColourText());
1500 jGroup.setTextCol1(sg.textColour.getRGB());
1501 jGroup.setTextCol2(sg.textColour2.getRGB());
1502 jGroup.setTextColThreshold(sg.thresholdTextColour);
1503 jGroup.setShowUnconserved(sg.getShowNonconserved());
1504 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1505 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1506 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1507 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1508 for (SequenceI seq : sg.getSequences())
1510 // jGroup.addSeq(seqHash(seq));
1511 jGroup.getSeq().add(seqHash(seq));
1515 // jms.setJGroup(groups);
1517 for (JGroup grp : groups)
1519 object.getJGroup().add(grp);
1524 // /////////SAVE VIEWPORT
1525 Viewport view = new Viewport();
1526 view.setTitle(ap.alignFrame.getTitle());
1527 view.setSequenceSetId(
1528 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1529 view.setId(av.getViewId());
1530 if (av.getCodingComplement() != null)
1532 view.setComplementId(av.getCodingComplement().getViewId());
1534 view.setViewName(av.getViewName());
1535 view.setGatheredViews(av.isGatherViewsHere());
1537 Rectangle size = ap.av.getExplodedGeometry();
1538 Rectangle position = size;
1541 size = ap.alignFrame.getBounds();
1542 if (av.getCodingComplement() != null)
1544 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1552 view.setXpos(position.x);
1553 view.setYpos(position.y);
1555 view.setWidth(size.width);
1556 view.setHeight(size.height);
1558 view.setStartRes(vpRanges.getStartRes());
1559 view.setStartSeq(vpRanges.getStartSeq());
1561 OverviewPanel ov = ap.getOverviewPanel();
1564 Overview overview = new Overview();
1565 overview.setTitle(ov.getTitle());
1566 Rectangle bounds = ov.getFrameBounds();
1567 overview.setXpos(bounds.x);
1568 overview.setYpos(bounds.y);
1569 overview.setWidth(bounds.width);
1570 overview.setHeight(bounds.height);
1571 overview.setShowHidden(ov.isShowHiddenRegions());
1572 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1573 overview.setResidueColour(
1574 ov.getCanvas().getResidueColour().getRGB());
1575 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1576 view.setOverview(overview);
1578 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1580 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1581 userColours, object));
1584 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1586 AnnotationColourScheme ac = constructAnnotationColours(
1587 (jalview.schemes.AnnotationColourGradient) av
1588 .getGlobalColourScheme(),
1589 userColours, object);
1591 view.setAnnotationColours(ac);
1592 view.setBgColour("AnnotationColourGradient");
1596 view.setBgColour(ColourSchemeProperty
1597 .getColourName(av.getGlobalColourScheme()));
1600 ResidueShaderI vcs = av.getResidueShading();
1601 ColourSchemeI cs = av.getGlobalColourScheme();
1605 if (vcs.conservationApplied())
1607 view.setConsThreshold(vcs.getConservationInc());
1608 if (cs instanceof jalview.schemes.UserColourScheme)
1610 view.setBgColour(setUserColourScheme(cs, userColours, object));
1613 view.setPidThreshold(vcs.getThreshold());
1616 view.setConservationSelected(av.getConservationSelected());
1617 view.setPidSelected(av.getAbovePIDThreshold());
1618 view.setCharHeight(av.getCharHeight());
1619 view.setCharWidth(av.getCharWidth());
1620 final Font font = av.getFont();
1621 view.setFontName(font.getName());
1622 view.setFontSize(font.getSize());
1623 view.setFontStyle(font.getStyle());
1624 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1625 view.setRenderGaps(av.isRenderGaps());
1626 view.setShowAnnotation(av.isShowAnnotation());
1627 view.setShowBoxes(av.getShowBoxes());
1628 view.setShowColourText(av.getColourText());
1629 view.setShowFullId(av.getShowJVSuffix());
1630 view.setRightAlignIds(av.isRightAlignIds());
1631 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1632 view.setShowText(av.getShowText());
1633 view.setShowUnconserved(av.getShowUnconserved());
1634 view.setWrapAlignment(av.getWrapAlignment());
1635 view.setTextCol1(av.getTextColour().getRGB());
1636 view.setTextCol2(av.getTextColour2().getRGB());
1637 view.setTextColThreshold(av.getThresholdTextColour());
1638 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1639 view.setShowSequenceLogo(av.isShowSequenceLogo());
1640 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1641 view.setShowGroupConsensus(av.isShowGroupConsensus());
1642 view.setShowGroupConservation(av.isShowGroupConservation());
1643 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1644 view.setShowDbRefTooltip(av.isShowDBRefs());
1645 view.setFollowHighlight(av.isFollowHighlight());
1646 view.setFollowSelection(av.followSelection);
1647 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1648 view.setShowComplementFeatures(av.isShowComplementFeatures());
1649 view.setShowComplementFeaturesOnTop(
1650 av.isShowComplementFeaturesOnTop());
1651 if (av.getFeaturesDisplayed() != null)
1653 FeatureSettings fs = new FeatureSettings();
1655 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1656 .getFeatureRenderer();
1657 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1659 Vector<String> settingsAdded = new Vector<>();
1660 if (renderOrder != null)
1662 for (String featureType : renderOrder)
1664 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1665 setting.setType(featureType);
1668 * save any filter for the feature type
1670 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1673 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1675 FeatureMatcherI firstFilter = filters.next();
1676 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1677 filters, filter.isAnded()));
1681 * save colour scheme for the feature type
1683 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1684 if (!fcol.isSimpleColour())
1686 setting.setColour(fcol.getMaxColour().getRGB());
1687 setting.setMincolour(fcol.getMinColour().getRGB());
1688 setting.setMin(fcol.getMin());
1689 setting.setMax(fcol.getMax());
1690 setting.setColourByLabel(fcol.isColourByLabel());
1691 if (fcol.isColourByAttribute())
1693 String[] attName = fcol.getAttributeName();
1694 setting.getAttributeName().add(attName[0]);
1695 if (attName.length > 1)
1697 setting.getAttributeName().add(attName[1]);
1700 setting.setAutoScale(fcol.isAutoScaled());
1701 setting.setThreshold(fcol.getThreshold());
1702 Color noColour = fcol.getNoColour();
1703 if (noColour == null)
1705 setting.setNoValueColour(NoValueColour.NONE);
1707 else if (noColour.equals(fcol.getMaxColour()))
1709 setting.setNoValueColour(NoValueColour.MAX);
1713 setting.setNoValueColour(NoValueColour.MIN);
1715 // -1 = No threshold, 0 = Below, 1 = Above
1716 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1717 : (fcol.isBelowThreshold() ? 0 : -1));
1721 setting.setColour(fcol.getColour().getRGB());
1725 av.getFeaturesDisplayed().isVisible(featureType));
1726 float rorder = fr.getOrder(featureType);
1729 setting.setOrder(rorder);
1731 /// fs.addSetting(setting);
1732 fs.getSetting().add(setting);
1733 settingsAdded.addElement(featureType);
1737 // is groups actually supposed to be a map here ?
1738 Iterator<String> en = fr.getFeatureGroups().iterator();
1739 Vector<String> groupsAdded = new Vector<>();
1740 while (en.hasNext())
1742 String grp = en.next();
1743 if (groupsAdded.contains(grp))
1747 Group g = new Group();
1749 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1752 fs.getGroup().add(g);
1753 groupsAdded.addElement(grp);
1755 // jms.setFeatureSettings(fs);
1756 object.setFeatureSettings(fs);
1759 if (av.hasHiddenColumns())
1761 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1762 .getHiddenColumns();
1766 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1770 Iterator<int[]> hiddenRegions = hidden.iterator();
1771 while (hiddenRegions.hasNext())
1773 int[] region = hiddenRegions.next();
1774 HiddenColumns hc = new HiddenColumns();
1775 hc.setStart(region[0]);
1776 hc.setEnd(region[1]);
1777 // view.addHiddenColumns(hc);
1778 view.getHiddenColumns().add(hc);
1782 if (calcIdSet.size() > 0)
1784 for (String calcId : calcIdSet)
1786 if (calcId.trim().length() > 0)
1788 CalcIdParam cidp = createCalcIdParam(calcId, av);
1789 // Some calcIds have no parameters.
1792 // view.addCalcIdParam(cidp);
1793 view.getCalcIdParam().add(cidp);
1799 // jms.addViewport(view);
1800 object.getViewport().add(view);
1806 // store matrices referenced by any views or annotation in this dataset
1807 if (xmlMatrices!=null && xmlMatrices.size()>0)
1809 Console.debug("Adding "+xmlMatrices.size()+" matrices to dataset.");
1810 vamsasSet.getMatrix().addAll(xmlMatrices);
1811 xmlMatrices.clear();
1816 // object.setJalviewModelSequence(jms);
1817 // object.getVamsasModel().addSequenceSet(vamsasSet);
1818 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1820 if (jout != null && fileName != null)
1822 // We may not want to write the object to disk,
1823 // eg we can copy the alignViewport to a new view object
1824 // using save and then load
1827 fileName = fileName.replace('\\', '/');
1828 System.out.println("Writing jar entry " + fileName);
1829 JarEntry entry = new JarEntry(fileName);
1830 jout.putNextEntry(entry);
1831 PrintWriter pout = new PrintWriter(
1832 new OutputStreamWriter(jout, UTF_8));
1833 JAXBContext jaxbContext = JAXBContext
1834 .newInstance(JalviewModel.class);
1835 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1837 // output pretty printed
1838 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1839 jaxbMarshaller.marshal(
1840 new ObjectFactory().createJalviewModel(object), pout);
1842 // jaxbMarshaller.marshal(object, pout);
1843 // marshaller.marshal(object);
1846 } catch (Exception ex)
1848 // TODO: raise error in GUI if marshalling failed.
1849 System.err.println("Error writing Jalview project");
1850 ex.printStackTrace();
1857 * Writes PCA viewer attributes and computed values to an XML model object and
1858 * adds it to the JalviewModel. Any exceptions are reported by logging.
1860 protected void savePCA(PCAPanel panel, JalviewModel object)
1864 PcaViewer viewer = new PcaViewer();
1865 viewer.setHeight(panel.getHeight());
1866 viewer.setWidth(panel.getWidth());
1867 viewer.setXpos(panel.getX());
1868 viewer.setYpos(panel.getY());
1869 viewer.setTitle(panel.getTitle());
1870 PCAModel pcaModel = panel.getPcaModel();
1871 viewer.setScoreModelName(pcaModel.getScoreModelName());
1872 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1873 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1874 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1876 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1877 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1878 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1879 SeqPointMin spmin = new SeqPointMin();
1880 spmin.setXPos(spMin[0]);
1881 spmin.setYPos(spMin[1]);
1882 spmin.setZPos(spMin[2]);
1883 viewer.setSeqPointMin(spmin);
1884 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1885 SeqPointMax spmax = new SeqPointMax();
1886 spmax.setXPos(spMax[0]);
1887 spmax.setYPos(spMax[1]);
1888 spmax.setZPos(spMax[2]);
1889 viewer.setSeqPointMax(spmax);
1890 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1891 viewer.setLinkToAllViews(
1892 panel.getRotatableCanvas().isApplyToAllViews());
1893 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1894 viewer.setIncludeGaps(sp.includeGaps());
1895 viewer.setMatchGaps(sp.matchGaps());
1896 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1897 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1900 * sequence points on display
1902 for (jalview.datamodel.SequencePoint spt : pcaModel
1903 .getSequencePoints())
1905 SequencePoint point = new SequencePoint();
1906 point.setSequenceRef(seqHash(spt.getSequence()));
1907 point.setXPos(spt.coord.x);
1908 point.setYPos(spt.coord.y);
1909 point.setZPos(spt.coord.z);
1910 viewer.getSequencePoint().add(point);
1914 * (end points of) axes on display
1916 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1919 Axis axis = new Axis();
1923 viewer.getAxis().add(axis);
1927 * raw PCA data (note we are not restoring PCA inputs here -
1928 * alignment view, score model, similarity parameters)
1930 PcaDataType data = new PcaDataType();
1931 viewer.setPcaData(data);
1932 PCA pca = pcaModel.getPcaData();
1934 DoubleMatrix pm = new DoubleMatrix();
1935 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1936 data.setPairwiseMatrix(pm);
1938 DoubleMatrix tm = new DoubleMatrix();
1939 saveDoubleMatrix(pca.getTridiagonal(), tm);
1940 data.setTridiagonalMatrix(tm);
1942 DoubleMatrix eigenMatrix = new DoubleMatrix();
1943 data.setEigenMatrix(eigenMatrix);
1944 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1946 object.getPcaViewer().add(viewer);
1947 } catch (Throwable t)
1949 Console.error("Error saving PCA: " + t.getMessage());
1954 * Stores values from a matrix into an XML element, including (if present) the
1959 * @see #loadDoubleMatrix(DoubleMatrix)
1961 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1963 xmlMatrix.setRows(m.height());
1964 xmlMatrix.setColumns(m.width());
1965 for (int i = 0; i < m.height(); i++)
1967 DoubleVector row = new DoubleVector();
1968 for (int j = 0; j < m.width(); j++)
1970 row.getV().add(m.getValue(i, j));
1972 xmlMatrix.getRow().add(row);
1974 if (m.getD() != null)
1976 DoubleVector dVector = new DoubleVector();
1977 for (double d : m.getD())
1979 dVector.getV().add(d);
1981 xmlMatrix.setD(dVector);
1983 if (m.getE() != null)
1985 DoubleVector eVector = new DoubleVector();
1986 for (double e : m.getE())
1988 eVector.getV().add(e);
1990 xmlMatrix.setE(eVector);
1995 * Loads XML matrix data into a new Matrix object, including the D and/or E
1996 * vectors (if present)
2000 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2002 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2004 int rows = mData.getRows();
2005 double[][] vals = new double[rows][];
2007 for (int i = 0; i < rows; i++)
2009 List<Double> dVector = mData.getRow().get(i).getV();
2010 vals[i] = new double[dVector.size()];
2012 for (Double d : dVector)
2018 MatrixI m = new Matrix(vals);
2020 if (mData.getD() != null)
2022 List<Double> dVector = mData.getD().getV();
2023 double[] vec = new double[dVector.size()];
2025 for (Double d : dVector)
2031 if (mData.getE() != null)
2033 List<Double> dVector = mData.getE().getV();
2034 double[] vec = new double[dVector.size()];
2036 for (Double d : dVector)
2047 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2048 * for each viewer, with
2050 * <li>viewer geometry (position, size, split pane divider location)</li>
2051 * <li>index of the selected structure in the viewer (currently shows gapped
2053 * <li>the id of the annotation holding RNA secondary structure</li>
2054 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2056 * Varna viewer state is also written out (in native Varna XML) to separate
2057 * project jar entries. A separate entry is written for each RNA structure
2058 * displayed, with the naming convention
2060 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2068 * @param storeDataset
2070 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2071 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2072 boolean storeDataset)
2074 if (Desktop.desktop == null)
2078 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2079 for (int f = frames.length - 1; f > -1; f--)
2081 if (frames[f] instanceof AppVarna)
2083 AppVarna varna = (AppVarna) frames[f];
2085 * link the sequence to every viewer that is showing it and is linked to
2086 * its alignment panel
2088 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2090 String viewId = varna.getViewId();
2091 RnaViewer rna = new RnaViewer();
2092 rna.setViewId(viewId);
2093 rna.setTitle(varna.getTitle());
2094 rna.setXpos(varna.getX());
2095 rna.setYpos(varna.getY());
2096 rna.setWidth(varna.getWidth());
2097 rna.setHeight(varna.getHeight());
2098 rna.setDividerLocation(varna.getDividerLocation());
2099 rna.setSelectedRna(varna.getSelectedIndex());
2100 // jseq.addRnaViewer(rna);
2101 jseq.getRnaViewer().add(rna);
2104 * Store each Varna panel's state once in the project per sequence.
2105 * First time through only (storeDataset==false)
2107 // boolean storeSessions = false;
2108 // String sequenceViewId = viewId + seqsToIds.get(jds);
2109 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2111 // viewIds.add(sequenceViewId);
2112 // storeSessions = true;
2114 for (RnaModel model : varna.getModels())
2116 if (model.seq == jds)
2119 * VARNA saves each view (sequence or alignment secondary
2120 * structure, gapped or trimmed) as a separate XML file
2122 String jarEntryName = rnaSessions.get(model);
2123 if (jarEntryName == null)
2126 String varnaStateFile = varna.getStateInfo(model.rna);
2127 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2128 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2129 rnaSessions.put(model, jarEntryName);
2131 SecondaryStructure ss = new SecondaryStructure();
2132 String annotationId = varna.getAnnotation(jds).annotationId;
2133 ss.setAnnotationId(annotationId);
2134 ss.setViewerState(jarEntryName);
2135 ss.setGapped(model.gapped);
2136 ss.setTitle(model.title);
2137 // rna.addSecondaryStructure(ss);
2138 rna.getSecondaryStructure().add(ss);
2147 * Copy the contents of a file to a new entry added to the output jar
2151 * @param jarEntryName
2153 * additional identifying info to log to the console
2155 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2156 String jarEntryName, String msg)
2158 try (InputStream is = new FileInputStream(infilePath))
2160 File file = new File(infilePath);
2161 if (file.exists() && jout != null)
2164 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2165 jout.putNextEntry(new JarEntry(jarEntryName));
2168 // dis = new DataInputStream(new FileInputStream(file));
2169 // byte[] data = new byte[(int) file.length()];
2170 // dis.readFully(data);
2171 // writeJarEntry(jout, jarEntryName, data);
2173 } catch (Exception ex)
2175 ex.printStackTrace();
2180 * Copies input to output, in 4K buffers; handles any data (text or binary)
2184 * @throws IOException
2186 protected void copyAll(InputStream in, OutputStream out)
2189 byte[] buffer = new byte[4096];
2191 while ((bytesRead = in.read(buffer)) != -1)
2193 out.write(buffer, 0, bytesRead);
2198 * Save the state of a structure viewer
2203 * the archive XML element under which to save the state
2206 * @param matchedFile
2210 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2211 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2212 String matchedFile, StructureViewerBase viewFrame)
2214 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2217 * Look for any bindings for this viewer to the PDB file of interest
2218 * (including part matches excluding chain id)
2220 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2222 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2223 final String pdbId = pdbentry.getId();
2224 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2225 && entry.getId().toLowerCase(Locale.ROOT)
2226 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2229 * not interested in a binding to a different PDB entry here
2233 if (matchedFile == null)
2235 matchedFile = pdbentry.getFile();
2237 else if (!matchedFile.equals(pdbentry.getFile()))
2240 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2241 + pdbentry.getFile());
2245 // can get at it if the ID
2246 // match is ambiguous (e.g.
2249 for (int smap = 0; smap < viewFrame.getBinding()
2250 .getSequence()[peid].length; smap++)
2252 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2253 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2255 StructureState state = new StructureState();
2256 state.setVisible(true);
2257 state.setXpos(viewFrame.getX());
2258 state.setYpos(viewFrame.getY());
2259 state.setWidth(viewFrame.getWidth());
2260 state.setHeight(viewFrame.getHeight());
2261 final String viewId = viewFrame.getViewId();
2262 state.setViewId(viewId);
2263 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2264 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2265 state.setColourByJmol(viewFrame.isColouredByViewer());
2266 state.setType(viewFrame.getViewerType().toString());
2267 // pdb.addStructureState(state);
2268 pdb.getStructureState().add(state);
2276 * Populates the AnnotationColourScheme xml for save. This captures the
2277 * settings of the options in the 'Colour by Annotation' dialog.
2280 * @param userColours
2284 private AnnotationColourScheme constructAnnotationColours(
2285 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2288 AnnotationColourScheme ac = new AnnotationColourScheme();
2289 ac.setAboveThreshold(acg.getAboveThreshold());
2290 ac.setThreshold(acg.getAnnotationThreshold());
2291 // 2.10.2 save annotationId (unique) not annotation label
2292 ac.setAnnotation(acg.getAnnotation().annotationId);
2293 if (acg.getBaseColour() instanceof UserColourScheme)
2296 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2301 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2304 ac.setMaxColour(acg.getMaxColour().getRGB());
2305 ac.setMinColour(acg.getMinColour().getRGB());
2306 ac.setPerSequence(acg.isSeqAssociated());
2307 ac.setPredefinedColours(acg.isPredefinedColours());
2311 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2312 IdentityHashMap<SequenceGroup, String> groupRefs,
2313 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2314 SequenceSet vamsasSet)
2317 for (int i = 0; i < aa.length; i++)
2319 Annotation an = new Annotation();
2321 AlignmentAnnotation annotation = aa[i];
2322 if (annotation.annotationId != null)
2324 annotationIds.put(annotation.annotationId, annotation);
2327 an.setId(annotation.annotationId);
2329 an.setVisible(annotation.visible);
2331 an.setDescription(annotation.description);
2333 if (annotation.sequenceRef != null)
2335 // 2.9 JAL-1781 xref on sequence id rather than name
2336 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2338 if (annotation.groupRef != null)
2340 String groupIdr = groupRefs.get(annotation.groupRef);
2341 if (groupIdr == null)
2343 // make a locally unique String
2344 groupRefs.put(annotation.groupRef,
2345 groupIdr = ("" + System.currentTimeMillis()
2346 + annotation.groupRef.getName()
2347 + groupRefs.size()));
2349 an.setGroupRef(groupIdr.toString());
2352 // store all visualization attributes for annotation
2353 an.setGraphHeight(annotation.graphHeight);
2354 an.setCentreColLabels(annotation.centreColLabels);
2355 an.setScaleColLabels(annotation.scaleColLabel);
2356 an.setShowAllColLabels(annotation.showAllColLabels);
2357 an.setBelowAlignment(annotation.belowAlignment);
2359 if (annotation.graph > 0)
2362 an.setGraphType(annotation.graph);
2363 an.setGraphGroup(annotation.graphGroup);
2364 if (annotation.getThreshold() != null)
2366 ThresholdLine line = new ThresholdLine();
2367 line.setLabel(annotation.getThreshold().label);
2368 line.setValue(annotation.getThreshold().value);
2369 line.setColour(annotation.getThreshold().colour.getRGB());
2370 an.setThresholdLine(line);
2372 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2374 if (annotation.sequenceRef.getContactMaps() != null)
2376 ContactMatrixI cm = annotation.sequenceRef
2377 .getContactMatrixFor(annotation);
2380 storeMatrixFor(vamsasSet, an,annotation, cm);
2390 an.setLabel(annotation.label);
2392 if (annotation == av.getAlignmentQualityAnnot()
2393 || annotation == av.getAlignmentConservationAnnotation()
2394 || annotation == av.getAlignmentConsensusAnnotation()
2395 || annotation.autoCalculated)
2397 // new way of indicating autocalculated annotation -
2398 an.setAutoCalculated(annotation.autoCalculated);
2400 if (annotation.hasScore())
2402 an.setScore(annotation.getScore());
2405 if (annotation.getCalcId() != null)
2407 calcIdSet.add(annotation.getCalcId());
2408 an.setCalcId(annotation.getCalcId());
2410 if (annotation.hasProperties())
2412 for (String pr : annotation.getProperties())
2414 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2416 prop.setValue(annotation.getProperty(pr));
2417 an.getProperty().add(prop);
2421 AnnotationElement ae;
2422 if (annotation.annotations != null)
2424 an.setScoreOnly(false);
2425 for (int a = 0; a < annotation.annotations.length; a++)
2427 if ((annotation == null) || (annotation.annotations[a] == null))
2432 ae = new AnnotationElement();
2433 if (annotation.annotations[a].description != null)
2435 ae.setDescription(annotation.annotations[a].description);
2437 if (annotation.annotations[a].displayCharacter != null)
2439 ae.setDisplayCharacter(
2440 annotation.annotations[a].displayCharacter);
2443 if (!Float.isNaN(annotation.annotations[a].value))
2445 ae.setValue(annotation.annotations[a].value);
2449 if (annotation.annotations[a].secondaryStructure > ' ')
2451 ae.setSecondaryStructure(
2452 annotation.annotations[a].secondaryStructure + "");
2455 if (annotation.annotations[a].colour != null
2456 && annotation.annotations[a].colour != java.awt.Color.black)
2458 ae.setColour(annotation.annotations[a].colour.getRGB());
2461 // an.addAnnotationElement(ae);
2462 an.getAnnotationElement().add(ae);
2463 if (annotation.autoCalculated)
2465 // only write one non-null entry into the annotation row -
2466 // sufficient to get the visualization attributes necessary to
2474 an.setScoreOnly(true);
2476 if (!storeDS || (storeDS && !annotation.autoCalculated))
2478 // skip autocalculated annotation - these are only provided for
2480 // vamsasSet.addAnnotation(an);
2481 vamsasSet.getAnnotation().add(an);
2487 private void storeMatrixFor(SequenceSet root, Annotation an, AlignmentAnnotation annotation, ContactMatrixI cm)
2489 String cmId = contactMatrices.get(cm);
2490 MatrixType xmlmat=null;
2492 // first create an xml ref for the matrix data, if none exist
2495 xmlmat = new MatrixType();
2496 xmlmat.setType(cm.getType());
2497 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2498 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2499 // consider using an opaque to/from -> allow instance to control
2500 // its representation ?
2501 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2504 for (BitSet gp : cm.getGroups())
2506 xmlmat.getGroups().add(stringifyBitset(gp));
2511 // provenance object for tree ?
2512 xmlmat.getNewick().add(cm.getNewick());
2513 xmlmat.setTreeMethod(cm.getTreeMethod());
2515 if (cm.hasCutHeight())
2517 xmlmat.setCutHeight(cm.getCutHeight());
2519 xmlmat.setId(cmId = "m"+contactMatrices.size()+System.currentTimeMillis());
2520 Console.trace("Matrix data stored :"+cmId);
2521 contactMatrices.put(cm, cmId);
2522 contactMatrixRefs.put(cmId, cm);
2523 xmlMatrices.add(xmlmat);
2525 Console.trace("Existing Matrix stored :"+cmId);
2528 // now store mapping
2530 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2531 xmlmatmapping.setMatrix(cmId);
2533 // Pretty much all matrices currently managed in this way are
2534 // mappableContactMatrixI implementations - but check anyway
2535 if (cm instanceof MappableContactMatrixI)
2537 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2538 .getMapFor(annotation.sequenceRef);
2541 MapListType mp = new MapListType();
2542 List<int[]> r = mlst.getFromRanges();
2543 for (int[] range : r)
2545 MapListFrom mfrom = new MapListFrom();
2546 mfrom.setStart(range[0]);
2547 mfrom.setEnd(range[1]);
2548 // mp.addMapListFrom(mfrom);
2549 mp.getMapListFrom().add(mfrom);
2551 r = mlst.getToRanges();
2552 for (int[] range : r)
2554 MapListTo mto = new MapListTo();
2555 mto.setStart(range[0]);
2556 mto.setEnd(range[1]);
2557 // mp.addMapListTo(mto);
2558 mp.getMapListTo().add(mto);
2560 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2561 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2562 xmlmatmapping.setMapping(mp);
2566 an.getContactmatrix().add(xmlmatmapping);
2569 private String stringifyBitset(BitSet gp)
2571 StringBuilder sb = new StringBuilder();
2572 for (long val : gp.toLongArray())
2574 if (sb.length() > 0)
2580 return sb.toString();
2583 private BitSet deStringifyBitset(String stringified)
2585 if ("".equals(stringified) || stringified == null)
2587 return new BitSet();
2589 String[] longvals = stringified.split(",");
2590 long[] newlongvals = new long[longvals.length];
2591 for (int lv = 0; lv < longvals.length; lv++)
2595 newlongvals[lv] = Long.valueOf(longvals[lv]);
2596 } catch (Exception x)
2598 errorMessage += "Couldn't destringify bitset from: '" + stringified
2600 newlongvals[lv] = 0;
2603 return BitSet.valueOf(newlongvals);
2606 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2608 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2609 if (settings != null)
2611 CalcIdParam vCalcIdParam = new CalcIdParam();
2612 vCalcIdParam.setCalcId(calcId);
2613 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2614 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2615 // generic URI allowing a third party to resolve another instance of the
2616 // service used for this calculation
2617 for (String url : settings.getServiceURLs())
2619 // vCalcIdParam.addServiceURL(urls);
2620 vCalcIdParam.getServiceURL().add(url);
2622 vCalcIdParam.setVersion("1.0");
2623 if (settings.getPreset() != null)
2625 WsParamSetI setting = settings.getPreset();
2626 vCalcIdParam.setName(setting.getName());
2627 vCalcIdParam.setDescription(setting.getDescription());
2631 vCalcIdParam.setName("");
2632 vCalcIdParam.setDescription("Last used parameters");
2634 // need to be able to recover 1) settings 2) user-defined presets or
2635 // recreate settings from preset 3) predefined settings provided by
2636 // service - or settings that can be transferred (or discarded)
2637 vCalcIdParam.setParameters(
2638 settings.getWsParamFile().replace("\n", "|\\n|"));
2639 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2640 // todo - decide if updateImmediately is needed for any projects.
2642 return vCalcIdParam;
2647 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2650 if (calcIdParam.getVersion().equals("1.0"))
2652 final String[] calcIds = calcIdParam.getServiceURL()
2653 .toArray(new String[0]);
2654 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2655 .getPreferredServiceFor(calcIds);
2656 if (service != null)
2658 WsParamSetI parmSet = null;
2661 parmSet = service.getParamStore().parseServiceParameterFile(
2662 calcIdParam.getName(), calcIdParam.getDescription(),
2664 calcIdParam.getParameters().replace("|\\n|", "\n"));
2665 } catch (IOException x)
2667 Console.warn("Couldn't parse parameter data for "
2668 + calcIdParam.getCalcId(), x);
2671 List<ArgumentI> argList = null;
2672 if (calcIdParam.getName().length() > 0)
2674 parmSet = service.getParamStore()
2675 .getPreset(calcIdParam.getName());
2676 if (parmSet != null)
2678 // TODO : check we have a good match with settings in AACon -
2679 // otherwise we'll need to create a new preset
2684 argList = parmSet.getArguments();
2687 AAConSettings settings = new AAConSettings(
2688 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2689 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2690 calcIdParam.isNeedsUpdate());
2696 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2700 throw new Error(MessageManager.formatMessage(
2701 "error.unsupported_version_calcIdparam", new Object[]
2702 { calcIdParam.toString() }));
2706 * External mapping between jalview objects and objects yielding a valid and
2707 * unique object ID string. This is null for normal Jalview project IO, but
2708 * non-null when a jalview project is being read or written as part of a
2711 IdentityHashMap jv2vobj = null;
2714 * Construct a unique ID for jvobj using either existing bindings or if none
2715 * exist, the result of the hashcode call for the object.
2718 * jalview data object
2719 * @return unique ID for referring to jvobj
2721 private String makeHashCode(Object jvobj, String altCode)
2723 if (jv2vobj != null)
2725 Object id = jv2vobj.get(jvobj);
2728 return id.toString();
2730 // check string ID mappings
2731 if (jvids2vobj != null && jvobj instanceof String)
2733 id = jvids2vobj.get(jvobj);
2737 return id.toString();
2739 // give up and warn that something has gone wrong
2741 "Cannot find ID for object in external mapping : " + jvobj);
2747 * return local jalview object mapped to ID, if it exists
2751 * @return null or object bound to idcode
2753 private Object retrieveExistingObj(String idcode)
2755 if (idcode != null && vobj2jv != null)
2757 return vobj2jv.get(idcode);
2763 * binding from ID strings from external mapping table to jalview data model
2766 private Hashtable vobj2jv;
2768 private Sequence createVamsasSequence(String id, SequenceI jds)
2770 return createVamsasSequence(true, id, jds, null);
2773 private Sequence createVamsasSequence(boolean recurse, String id,
2774 SequenceI jds, SequenceI parentseq)
2776 Sequence vamsasSeq = new Sequence();
2777 vamsasSeq.setId(id);
2778 vamsasSeq.setName(jds.getName());
2779 vamsasSeq.setSequence(jds.getSequenceAsString());
2780 vamsasSeq.setDescription(jds.getDescription());
2781 List<DBRefEntry> dbrefs = null;
2782 if (jds.getDatasetSequence() != null)
2784 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2788 // seqId==dsseqid so we can tell which sequences really are
2789 // dataset sequences only
2790 vamsasSeq.setDsseqid(id);
2791 dbrefs = jds.getDBRefs();
2792 if (parentseq == null)
2799 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2803 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2805 DBRef dbref = new DBRef();
2806 DBRefEntry ref = dbrefs.get(d);
2807 dbref.setSource(ref.getSource());
2808 dbref.setVersion(ref.getVersion());
2809 dbref.setAccessionId(ref.getAccessionId());
2810 dbref.setCanonical(ref.isCanonical());
2811 if (ref instanceof GeneLocus)
2813 dbref.setLocus(true);
2817 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2819 dbref.setMapping(mp);
2821 vamsasSeq.getDBRef().add(dbref);
2827 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2828 SequenceI parentseq, SequenceI jds, boolean recurse)
2831 if (jmp.getMap() != null)
2835 jalview.util.MapList mlst = jmp.getMap();
2836 List<int[]> r = mlst.getFromRanges();
2837 for (int[] range : r)
2839 MapListFrom mfrom = new MapListFrom();
2840 mfrom.setStart(range[0]);
2841 mfrom.setEnd(range[1]);
2842 // mp.addMapListFrom(mfrom);
2843 mp.getMapListFrom().add(mfrom);
2845 r = mlst.getToRanges();
2846 for (int[] range : r)
2848 MapListTo mto = new MapListTo();
2849 mto.setStart(range[0]);
2850 mto.setEnd(range[1]);
2851 // mp.addMapListTo(mto);
2852 mp.getMapListTo().add(mto);
2854 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2855 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2856 if (jmp.getTo() != null)
2858 // MappingChoice mpc = new MappingChoice();
2860 // check/create ID for the sequence referenced by getTo()
2863 SequenceI ps = null;
2864 if (parentseq != jmp.getTo()
2865 && parentseq.getDatasetSequence() != jmp.getTo())
2867 // chaining dbref rather than a handshaking one
2868 jmpid = seqHash(ps = jmp.getTo());
2872 jmpid = seqHash(ps = parentseq);
2874 // mpc.setDseqFor(jmpid);
2875 mp.setDseqFor(jmpid);
2876 if (!seqRefIds.containsKey(jmpid))
2878 Console.debug("creatign new DseqFor ID");
2879 seqRefIds.put(jmpid, ps);
2883 Console.debug("reusing DseqFor ID");
2886 // mp.setMappingChoice(mpc);
2892 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2893 List<UserColourScheme> userColours, JalviewModel jm)
2896 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2897 boolean newucs = false;
2898 if (!userColours.contains(ucs))
2900 userColours.add(ucs);
2903 id = "ucs" + userColours.indexOf(ucs);
2906 // actually create the scheme's entry in the XML model
2907 java.awt.Color[] colours = ucs.getColours();
2908 UserColours uc = new UserColours();
2909 // UserColourScheme jbucs = new UserColourScheme();
2910 JalviewUserColours jbucs = new JalviewUserColours();
2912 for (int i = 0; i < colours.length; i++)
2914 Colour col = new Colour();
2915 col.setName(ResidueProperties.aa[i]);
2916 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2917 // jbucs.addColour(col);
2918 jbucs.getColour().add(col);
2920 if (ucs.getLowerCaseColours() != null)
2922 colours = ucs.getLowerCaseColours();
2923 for (int i = 0; i < colours.length; i++)
2925 Colour col = new Colour();
2926 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2927 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2928 // jbucs.addColour(col);
2929 jbucs.getColour().add(col);
2934 uc.setUserColourScheme(jbucs);
2935 // jm.addUserColours(uc);
2936 jm.getUserColours().add(uc);
2942 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2945 List<UserColours> uc = jm.getUserColours();
2946 UserColours colours = null;
2948 for (int i = 0; i < uc.length; i++)
2950 if (uc[i].getId().equals(id))
2957 for (UserColours c : uc)
2959 if (c.getId().equals(id))
2966 java.awt.Color[] newColours = new java.awt.Color[24];
2968 for (int i = 0; i < 24; i++)
2970 newColours[i] = new java.awt.Color(Integer.parseInt(
2971 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2972 colours.getUserColourScheme().getColour().get(i).getRGB(),
2976 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2979 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2981 newColours = new java.awt.Color[23];
2982 for (int i = 0; i < 23; i++)
2984 newColours[i] = new java.awt.Color(
2985 Integer.parseInt(colours.getUserColourScheme().getColour()
2986 .get(i + 24).getRGB(), 16));
2988 ucs.setLowerCaseColours(newColours);
2995 * contains last error message (if any) encountered by XML loader.
2997 String errorMessage = null;
3000 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3001 * exceptions are raised during project XML parsing
3003 public boolean attemptversion1parse = false;
3006 * Load a jalview project archive from a jar file
3009 * - HTTP URL or filename
3011 public AlignFrame loadJalviewAlign(final Object file)
3014 jalview.gui.AlignFrame af = null;
3018 // create list to store references for any new Jmol viewers created
3019 newStructureViewers = new Vector<>();
3020 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3021 // Workaround is to make sure caller implements the JarInputStreamProvider
3023 // so we can re-open the jar input stream for each entry.
3025 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3026 af = loadJalviewAlign(jprovider);
3029 af.setMenusForViewport();
3031 } catch (MalformedURLException e)
3033 errorMessage = "Invalid URL format for '" + file + "'";
3039 SwingUtilities.invokeAndWait(new Runnable()
3044 setLoadingFinishedForNewStructureViewers();
3047 } catch (Exception x)
3049 System.err.println("Error loading alignment: " + x.getMessage());
3055 @SuppressWarnings("unused")
3056 private jarInputStreamProvider createjarInputStreamProvider(
3057 final Object ofile) throws MalformedURLException
3060 // BH 2018 allow for bytes already attached to File object
3063 String file = (ofile instanceof File
3064 ? ((File) ofile).getCanonicalPath()
3065 : ofile.toString());
3066 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3069 errorMessage = null;
3070 uniqueSetSuffix = null;
3072 viewportsAdded.clear();
3073 frefedSequence = null;
3075 if (HttpUtils.startsWithHttpOrHttps(file))
3077 url = new URL(file);
3079 final URL _url = url;
3080 return new jarInputStreamProvider()
3084 public JarInputStream getJarInputStream() throws IOException
3088 // System.out.println("Jalview2XML: opening byte jarInputStream for
3089 // bytes.length=" + bytes.length);
3090 return new JarInputStream(new ByteArrayInputStream(bytes));
3094 // System.out.println("Jalview2XML: opening url jarInputStream for "
3096 return new JarInputStream(_url.openStream());
3100 // System.out.println("Jalview2XML: opening file jarInputStream for
3102 return new JarInputStream(new FileInputStream(file));
3107 public String getFilename()
3112 } catch (IOException e)
3114 e.printStackTrace();
3120 * Recover jalview session from a jalview project archive. Caller may
3121 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3122 * themselves. Any null fields will be initialised with default values,
3123 * non-null fields are left alone.
3128 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3130 errorMessage = null;
3131 if (uniqueSetSuffix == null)
3133 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3135 if (seqRefIds == null)
3139 AlignFrame af = null, _af = null;
3140 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3141 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3142 final String file = jprovider.getFilename();
3145 JarInputStream jin = null;
3146 JarEntry jarentry = null;
3151 jin = jprovider.getJarInputStream();
3152 for (int i = 0; i < entryCount; i++)
3154 jarentry = jin.getNextJarEntry();
3157 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3159 JAXBContext jc = JAXBContext
3160 .newInstance("jalview.xml.binding.jalview");
3161 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3162 .createXMLStreamReader(jin);
3163 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3164 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3165 JalviewModel.class);
3166 JalviewModel object = jbe.getValue();
3168 if (true) // !skipViewport(object))
3170 _af = loadFromObject(object, file, true, jprovider);
3171 if (_af != null && object.getViewport().size() > 0)
3172 // getJalviewModelSequence().getViewportCount() > 0)
3176 // store a reference to the first view
3179 if (_af.getViewport().isGatherViewsHere())
3181 // if this is a gathered view, keep its reference since
3182 // after gathering views, only this frame will remain
3184 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3187 // Save dataset to register mappings once all resolved
3188 importedDatasets.put(
3189 af.getViewport().getAlignment().getDataset(),
3190 af.getViewport().getAlignment().getDataset());
3195 else if (jarentry != null)
3197 // Some other file here.
3200 } while (jarentry != null);
3202 resolveFrefedSequences();
3203 } catch (IOException ex)
3205 ex.printStackTrace();
3206 errorMessage = "Couldn't locate Jalview XML file : " + file;
3208 "Exception whilst loading jalview XML file : " + ex + "\n");
3209 } catch (Exception ex)
3211 System.err.println("Parsing as Jalview Version 2 file failed.");
3212 ex.printStackTrace(System.err);
3213 if (attemptversion1parse)
3215 // used to attempt to parse as V1 castor-generated xml
3217 if (Desktop.instance != null)
3219 Desktop.instance.stopLoading();
3223 System.out.println("Successfully loaded archive file");
3226 ex.printStackTrace();
3229 "Exception whilst loading jalview XML file : " + ex + "\n");
3230 } catch (OutOfMemoryError e)
3232 // Don't use the OOM Window here
3233 errorMessage = "Out of memory loading jalview XML file";
3234 System.err.println("Out of memory whilst loading jalview XML file");
3235 e.printStackTrace();
3239 * Regather multiple views (with the same sequence set id) to the frame (if
3240 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3241 * views instead of separate frames. Note this doesn't restore a state where
3242 * some expanded views in turn have tabbed views - the last "first tab" read
3243 * in will play the role of gatherer for all.
3245 for (AlignFrame fr : gatherToThisFrame.values())
3247 Desktop.instance.gatherViews(fr);
3250 restoreSplitFrames();
3251 for (AlignmentI ds : importedDatasets.keySet())
3253 if (ds.getCodonFrames() != null)
3255 StructureSelectionManager
3256 .getStructureSelectionManager(Desktop.instance)
3257 .registerMappings(ds.getCodonFrames());
3260 if (errorMessage != null)
3265 if (Desktop.instance != null)
3267 Desktop.instance.stopLoading();
3274 * Try to reconstruct and display SplitFrame windows, where each contains
3275 * complementary dna and protein alignments. Done by pairing up AlignFrame
3276 * objects (created earlier) which have complementary viewport ids associated.
3278 protected void restoreSplitFrames()
3280 List<SplitFrame> gatherTo = new ArrayList<>();
3281 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3282 Map<String, AlignFrame> dna = new HashMap<>();
3285 * Identify the DNA alignments
3287 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3290 AlignFrame af = candidate.getValue();
3291 if (af.getViewport().getAlignment().isNucleotide())
3293 dna.put(candidate.getKey().getId(), af);
3298 * Try to match up the protein complements
3300 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3303 AlignFrame af = candidate.getValue();
3304 if (!af.getViewport().getAlignment().isNucleotide())
3306 String complementId = candidate.getKey().getComplementId();
3307 // only non-null complements should be in the Map
3308 if (complementId != null && dna.containsKey(complementId))
3310 final AlignFrame dnaFrame = dna.get(complementId);
3311 SplitFrame sf = createSplitFrame(dnaFrame, af);
3312 addedToSplitFrames.add(dnaFrame);
3313 addedToSplitFrames.add(af);
3314 dnaFrame.setMenusForViewport();
3315 af.setMenusForViewport();
3316 if (af.getViewport().isGatherViewsHere())
3325 * Open any that we failed to pair up (which shouldn't happen!) as
3326 * standalone AlignFrame's.
3328 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3331 AlignFrame af = candidate.getValue();
3332 if (!addedToSplitFrames.contains(af))
3334 Viewport view = candidate.getKey();
3335 Desktop.addInternalFrame(af, view.getTitle(),
3336 safeInt(view.getWidth()), safeInt(view.getHeight()));
3337 af.setMenusForViewport();
3338 System.err.println("Failed to restore view " + view.getTitle()
3339 + " to split frame");
3344 * Gather back into tabbed views as flagged.
3346 for (SplitFrame sf : gatherTo)
3348 Desktop.instance.gatherViews(sf);
3351 splitFrameCandidates.clear();
3355 * Construct and display one SplitFrame holding DNA and protein alignments.
3358 * @param proteinFrame
3361 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3362 AlignFrame proteinFrame)
3364 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3365 String title = MessageManager.getString("label.linked_view_title");
3366 int width = (int) dnaFrame.getBounds().getWidth();
3367 int height = (int) (dnaFrame.getBounds().getHeight()
3368 + proteinFrame.getBounds().getHeight() + 50);
3371 * SplitFrame location is saved to both enclosed frames
3373 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3374 Desktop.addInternalFrame(splitFrame, title, width, height);
3377 * And compute cDNA consensus (couldn't do earlier with consensus as
3378 * mappings were not yet present)
3380 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3386 * check errorMessage for a valid error message and raise an error box in the
3387 * GUI or write the current errorMessage to stderr and then clear the error
3390 protected void reportErrors()
3392 reportErrors(false);
3395 protected void reportErrors(final boolean saving)
3397 if (errorMessage != null)
3399 final String finalErrorMessage = errorMessage;
3402 javax.swing.SwingUtilities.invokeLater(new Runnable()
3407 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3409 "Error " + (saving ? "saving" : "loading")
3411 JvOptionPane.WARNING_MESSAGE);
3417 System.err.println("Problem loading Jalview file: " + errorMessage);
3420 errorMessage = null;
3423 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3426 * when set, local views will be updated from view stored in JalviewXML
3427 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3428 * sync if this is set to true.
3430 private final boolean updateLocalViews = false;
3433 * Returns the path to a temporary file holding the PDB file for the given PDB
3434 * id. The first time of asking, searches for a file of that name in the
3435 * Jalview project jar, and copies it to a new temporary file. Any repeat
3436 * requests just return the path to the file previously created.
3442 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3445 if (alreadyLoadedPDB.containsKey(pdbId))
3447 return alreadyLoadedPDB.get(pdbId).toString();
3450 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3452 if (tempFile != null)
3454 alreadyLoadedPDB.put(pdbId, tempFile);
3460 * Copies the jar entry of given name to a new temporary file and returns the
3461 * path to the file, or null if the entry is not found.
3464 * @param jarEntryName
3466 * a prefix for the temporary file name, must be at least three
3468 * @param suffixModel
3469 * null or original file - so new file can be given the same suffix
3473 protected String copyJarEntry(jarInputStreamProvider jprovider,
3474 String jarEntryName, String prefix, String suffixModel)
3476 String suffix = ".tmp";
3477 if (suffixModel == null)
3479 suffixModel = jarEntryName;
3481 int sfpos = suffixModel.lastIndexOf(".");
3482 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3484 suffix = "." + suffixModel.substring(sfpos + 1);
3487 try (JarInputStream jin = jprovider.getJarInputStream())
3489 JarEntry entry = null;
3492 entry = jin.getNextJarEntry();
3493 } while (entry != null && !entry.getName().equals(jarEntryName));
3497 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3498 File outFile = File.createTempFile(prefix, suffix);
3499 outFile.deleteOnExit();
3500 try (OutputStream os = new FileOutputStream(outFile))
3504 String t = outFile.getAbsolutePath();
3510 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3512 } catch (Exception ex)
3514 ex.printStackTrace();
3520 private class JvAnnotRow
3522 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3529 * persisted version of annotation row from which to take vis properties
3531 public jalview.datamodel.AlignmentAnnotation template;
3534 * original position of the annotation row in the alignment
3540 * Load alignment frame from jalview XML DOM object
3542 * @param jalviewModel
3545 * filename source string
3546 * @param loadTreesAndStructures
3547 * when false only create Viewport
3549 * data source provider
3550 * @return alignment frame created from view stored in DOM
3552 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3553 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3555 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3557 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3559 // JalviewModelSequence jms = object.getJalviewModelSequence();
3561 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3563 Viewport view = (jalviewModel.getViewport().size() > 0)
3564 ? jalviewModel.getViewport().get(0)
3567 // ////////////////////////////////
3568 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3571 // If we just load in the same jar file again, the sequenceSetId
3572 // will be the same, and we end up with multiple references
3573 // to the same sequenceSet. We must modify this id on load
3574 // so that each load of the file gives a unique id
3577 * used to resolve correct alignment dataset for alignments with multiple
3580 String uniqueSeqSetId = null;
3581 String viewId = null;
3584 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3585 viewId = (view.getId() == null ? null
3586 : view.getId() + uniqueSetSuffix);
3589 // ////////////////////////////////
3590 // LOAD MATRICES (IF ANY)
3592 if (vamsasSet.getMatrix()!=null && vamsasSet.getMatrix().size()>0)
3594 importMatrixData(vamsasSet.getMatrix());
3597 // ////////////////////////////////
3600 List<SequenceI> hiddenSeqs = null;
3602 List<SequenceI> tmpseqs = new ArrayList<>();
3604 boolean multipleView = false;
3605 SequenceI referenceseqForView = null;
3606 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3607 List<JSeq> jseqs = jalviewModel.getJSeq();
3608 int vi = 0; // counter in vamsasSeq array
3609 for (int i = 0; i < jseqs.size(); i++)
3611 JSeq jseq = jseqs.get(i);
3612 String seqId = jseq.getId();
3614 SequenceI tmpSeq = seqRefIds.get(seqId);
3617 if (!incompleteSeqs.containsKey(seqId))
3619 // may not need this check, but keep it for at least 2.9,1 release
3620 if (tmpSeq.getStart() != jseq.getStart()
3621 || tmpSeq.getEnd() != jseq.getEnd())
3623 System.err.println(String.format(
3624 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3625 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3626 jseq.getStart(), jseq.getEnd()));
3631 incompleteSeqs.remove(seqId);
3633 if (vamsasSeqs.size() > vi
3634 && vamsasSeqs.get(vi).getId().equals(seqId))
3636 // most likely we are reading a dataset XML document so
3637 // update from vamsasSeq section of XML for this sequence
3638 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3639 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3640 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3645 // reading multiple views, so vamsasSeq set is a subset of JSeq
3646 multipleView = true;
3648 tmpSeq.setStart(jseq.getStart());
3649 tmpSeq.setEnd(jseq.getEnd());
3650 tmpseqs.add(tmpSeq);
3654 Sequence vamsasSeq = vamsasSeqs.get(vi);
3655 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3656 vamsasSeq.getSequence());
3657 tmpSeq.setDescription(vamsasSeq.getDescription());
3658 tmpSeq.setStart(jseq.getStart());
3659 tmpSeq.setEnd(jseq.getEnd());
3660 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3661 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3662 tmpseqs.add(tmpSeq);
3666 if (safeBoolean(jseq.isViewreference()))
3668 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3671 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3673 if (hiddenSeqs == null)
3675 hiddenSeqs = new ArrayList<>();
3678 hiddenSeqs.add(tmpSeq);
3683 // Create the alignment object from the sequence set
3684 // ///////////////////////////////
3685 SequenceI[] orderedSeqs = tmpseqs
3686 .toArray(new SequenceI[tmpseqs.size()]);
3688 AlignmentI al = null;
3689 // so we must create or recover the dataset alignment before going further
3690 // ///////////////////////////////
3691 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3693 // older jalview projects do not have a dataset - so creat alignment and
3695 al = new Alignment(orderedSeqs);
3696 al.setDataset(null);
3700 boolean isdsal = jalviewModel.getViewport().isEmpty();
3703 // we are importing a dataset record, so
3704 // recover reference to an alignment already materialsed as dataset
3705 al = getDatasetFor(vamsasSet.getDatasetId());
3709 // materialse the alignment
3710 al = new Alignment(orderedSeqs);
3714 addDatasetRef(vamsasSet.getDatasetId(), al);
3717 // finally, verify all data in vamsasSet is actually present in al
3718 // passing on flag indicating if it is actually a stored dataset
3719 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3722 if (referenceseqForView != null)
3724 al.setSeqrep(referenceseqForView);
3726 // / Add the alignment properties
3727 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3729 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3731 al.setProperty(ssp.getKey(), ssp.getValue());
3734 // ///////////////////////////////
3736 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3739 // load sequence features, database references and any associated PDB
3740 // structures for the alignment
3742 // prior to 2.10, this part would only be executed the first time a
3743 // sequence was encountered, but not afterwards.
3744 // now, for 2.10 projects, this is also done if the xml doc includes
3745 // dataset sequences not actually present in any particular view.
3747 for (int i = 0; i < vamsasSeqs.size(); i++)
3749 JSeq jseq = jseqs.get(i);
3750 if (jseq.getFeatures().size() > 0)
3752 List<Feature> features = jseq.getFeatures();
3753 for (int f = 0; f < features.size(); f++)
3755 Feature feat = features.get(f);
3756 SequenceFeature sf = new SequenceFeature(feat.getType(),
3757 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3758 safeFloat(feat.getScore()), feat.getFeatureGroup());
3759 sf.setStatus(feat.getStatus());
3762 * load any feature attributes - include map-valued attributes
3764 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3765 for (int od = 0; od < feat.getOtherData().size(); od++)
3767 OtherData keyValue = feat.getOtherData().get(od);
3768 String attributeName = keyValue.getKey();
3769 String attributeValue = keyValue.getValue();
3770 if (attributeName.startsWith("LINK"))
3772 sf.addLink(attributeValue);
3776 String subAttribute = keyValue.getKey2();
3777 if (subAttribute == null)
3779 // simple string-valued attribute
3780 sf.setValue(attributeName, attributeValue);
3784 // attribute 'key' has sub-attribute 'key2'
3785 if (!mapAttributes.containsKey(attributeName))
3787 mapAttributes.put(attributeName, new HashMap<>());
3789 mapAttributes.get(attributeName).put(subAttribute,
3794 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3797 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3800 // adds feature to datasequence's feature set (since Jalview 2.10)
3801 al.getSequenceAt(i).addSequenceFeature(sf);
3804 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3806 // adds dbrefs to datasequence's set (since Jalview 2.10)
3808 al.getSequenceAt(i).getDatasetSequence() == null
3809 ? al.getSequenceAt(i)
3810 : al.getSequenceAt(i).getDatasetSequence(),
3813 if (jseq.getPdbids().size() > 0)
3815 List<Pdbids> ids = jseq.getPdbids();
3816 for (int p = 0; p < ids.size(); p++)
3818 Pdbids pdbid = ids.get(p);
3819 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3820 entry.setId(pdbid.getId());
3821 if (pdbid.getType() != null)
3823 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3825 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3829 entry.setType(PDBEntry.Type.FILE);
3832 // jprovider is null when executing 'New View'
3833 if (pdbid.getFile() != null && jprovider != null)
3835 if (!pdbloaded.containsKey(pdbid.getFile()))
3837 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3842 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3846 if (pdbid.getPdbentryItem() != null)
3848 for (PdbentryItem item : pdbid.getPdbentryItem())
3850 for (Property pr : item.getProperty())
3852 entry.setProperty(pr.getName(), pr.getValue());
3857 for (Property prop : pdbid.getProperty())
3859 entry.setProperty(prop.getName(), prop.getValue());
3861 StructureSelectionManager
3862 .getStructureSelectionManager(Desktop.instance)
3863 .registerPDBEntry(entry);
3864 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3865 if (al.getSequenceAt(i).getDatasetSequence() != null)
3867 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3871 al.getSequenceAt(i).addPDBId(entry);
3876 } // end !multipleview
3878 // ///////////////////////////////
3879 // LOAD SEQUENCE MAPPINGS
3881 if (vamsasSet.getAlcodonFrame().size() > 0)
3883 // TODO Potentially this should only be done once for all views of an
3885 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3886 for (int i = 0; i < alc.size(); i++)
3888 AlignedCodonFrame cf = new AlignedCodonFrame();
3889 if (alc.get(i).getAlcodMap().size() > 0)
3891 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3892 for (int m = 0; m < maps.size(); m++)
3894 AlcodMap map = maps.get(m);
3895 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3897 jalview.datamodel.Mapping mapping = null;
3898 // attach to dna sequence reference.
3899 if (map.getMapping() != null)
3901 mapping = addMapping(map.getMapping());
3902 if (dnaseq != null && mapping.getTo() != null)
3904 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3910 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3914 al.addCodonFrame(cf);
3919 // ////////////////////////////////
3921 List<JvAnnotRow> autoAlan = new ArrayList<>();
3924 * store any annotations which forward reference a group's ID
3926 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3928 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3930 List<Annotation> an = vamsasSet.getAnnotation();
3932 for (int i = 0; i < an.size(); i++)
3934 Annotation annotation = an.get(i);
3937 * test if annotation is automatically calculated for this view only
3939 boolean autoForView = false;
3940 if (annotation.getLabel().equals("Quality")
3941 || annotation.getLabel().equals("Conservation")
3942 || annotation.getLabel().equals("Consensus"))
3944 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3946 // JAXB has no has() test; schema defaults value to false
3947 // if (!annotation.hasAutoCalculated())
3949 // annotation.setAutoCalculated(true);
3952 if (autoForView || annotation.isAutoCalculated())
3954 // remove ID - we don't recover annotation from other views for
3955 // view-specific annotation
3956 annotation.setId(null);
3959 // set visibility for other annotation in this view
3960 String annotationId = annotation.getId();
3961 if (annotationId != null && annotationIds.containsKey(annotationId))
3963 AlignmentAnnotation jda = annotationIds.get(annotationId);
3964 // in principle Visible should always be true for annotation displayed
3965 // in multiple views
3966 if (annotation.isVisible() != null)
3968 jda.visible = annotation.isVisible();
3971 al.addAnnotation(jda);
3975 // Construct new annotation from model.
3976 List<AnnotationElement> ae = annotation.getAnnotationElement();
3977 jalview.datamodel.Annotation[] anot = null;
3978 java.awt.Color firstColour = null;
3980 if (!annotation.isScoreOnly())
3982 anot = new jalview.datamodel.Annotation[al.getWidth()];
3983 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3985 AnnotationElement annElement = ae.get(aa);
3986 anpos = annElement.getPosition();
3988 if (anpos >= anot.length)
3993 float value = safeFloat(annElement.getValue());
3994 anot[anpos] = new jalview.datamodel.Annotation(
3995 annElement.getDisplayCharacter(),
3996 annElement.getDescription(),
3997 (annElement.getSecondaryStructure() == null
3998 || annElement.getSecondaryStructure()
4002 .getSecondaryStructure()
4005 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4006 if (firstColour == null)
4008 firstColour = anot[anpos].colour;
4012 jalview.datamodel.AlignmentAnnotation jaa = null;
4014 if (annotation.isGraph())
4016 float llim = 0, hlim = 0;
4017 // if (autoForView || an[i].isAutoCalculated()) {
4020 jaa = new jalview.datamodel.AlignmentAnnotation(
4021 annotation.getLabel(), annotation.getDescription(), anot,
4022 llim, hlim, safeInt(annotation.getGraphType()));
4024 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4025 jaa._linecolour = firstColour;
4026 if (annotation.getThresholdLine() != null)
4028 jaa.setThreshold(new jalview.datamodel.GraphLine(
4029 safeFloat(annotation.getThresholdLine().getValue()),
4030 annotation.getThresholdLine().getLabel(),
4031 new java.awt.Color(safeInt(
4032 annotation.getThresholdLine().getColour()))));
4034 if (autoForView || annotation.isAutoCalculated())
4036 // Hardwire the symbol display line to ensure that labels for
4037 // histograms are displayed
4043 jaa = new jalview.datamodel.AlignmentAnnotation(
4044 annotation.getLabel(), annotation.getDescription(), anot);
4045 jaa._linecolour = firstColour;
4047 // register new annotation
4048 if (annotation.getId() != null)
4050 annotationIds.put(annotation.getId(), jaa);
4051 jaa.annotationId = annotation.getId();
4053 // recover sequence association
4054 String sequenceRef = annotation.getSequenceRef();
4055 if (sequenceRef != null)
4057 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4058 SequenceI sequence = seqRefIds.get(sequenceRef);
4059 if (sequence == null)
4061 // in pre-2.9 projects sequence ref is to sequence name
4062 sequence = al.findName(sequenceRef);
4064 if (sequence != null)
4066 jaa.createSequenceMapping(sequence, 1, true);
4067 sequence.addAlignmentAnnotation(jaa);
4070 // and make a note of any group association
4071 if (annotation.getGroupRef() != null
4072 && annotation.getGroupRef().length() > 0)
4074 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4075 .get(annotation.getGroupRef());
4078 aal = new ArrayList<>();
4079 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4084 if (annotation.getScore() != null)
4086 jaa.setScore(annotation.getScore().doubleValue());
4088 if (annotation.isVisible() != null)
4090 jaa.visible = annotation.isVisible().booleanValue();
4093 if (annotation.isCentreColLabels() != null)
4095 jaa.centreColLabels = annotation.isCentreColLabels()
4099 if (annotation.isScaleColLabels() != null)
4101 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4103 if (annotation.isAutoCalculated())
4105 // newer files have an 'autoCalculated' flag and store calculation
4106 // state in viewport properties
4107 jaa.autoCalculated = true; // means annotation will be marked for
4108 // update at end of load.
4110 if (annotation.getGraphHeight() != null)
4112 jaa.graphHeight = annotation.getGraphHeight().intValue();
4114 jaa.belowAlignment = annotation.isBelowAlignment();
4115 jaa.setCalcId(annotation.getCalcId());
4116 if (annotation.getProperty().size() > 0)
4118 for (jalview.xml.binding.jalview.Property prop : annotation
4121 jaa.setProperty(prop.getName(), prop.getValue());
4124 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4126 if (annotation.getContactmatrix() != null
4127 && annotation.getContactmatrix().size() > 0)
4129 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4131 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4136 if (jaa.autoCalculated)
4138 autoAlan.add(new JvAnnotRow(i, jaa));
4141 // if (!autoForView)
4143 // add autocalculated group annotation and any user created annotation
4145 al.addAnnotation(jaa);
4149 // ///////////////////////
4151 // Create alignment markup and styles for this view
4152 if (jalviewModel.getJGroup().size() > 0)
4154 List<JGroup> groups = jalviewModel.getJGroup();
4155 boolean addAnnotSchemeGroup = false;
4156 for (int i = 0; i < groups.size(); i++)
4158 JGroup jGroup = groups.get(i);
4159 ColourSchemeI cs = null;
4160 if (jGroup.getColour() != null)
4162 if (jGroup.getColour().startsWith("ucs"))
4164 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4166 else if (jGroup.getColour().equals("AnnotationColourGradient")
4167 && jGroup.getAnnotationColours() != null)
4169 addAnnotSchemeGroup = true;
4173 cs = ColourSchemeProperty.getColourScheme(null, al,
4174 jGroup.getColour());
4177 int pidThreshold = safeInt(jGroup.getPidThreshold());
4179 Vector<SequenceI> seqs = new Vector<>();
4181 for (int s = 0; s < jGroup.getSeq().size(); s++)
4183 String seqId = jGroup.getSeq().get(s);
4184 SequenceI ts = seqRefIds.get(seqId);
4188 seqs.addElement(ts);
4192 if (seqs.size() < 1)
4197 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4198 safeBoolean(jGroup.isDisplayBoxes()),
4199 safeBoolean(jGroup.isDisplayText()),
4200 safeBoolean(jGroup.isColourText()),
4201 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4202 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4203 sg.getGroupColourScheme()
4204 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4205 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4207 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4208 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4209 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4210 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4211 // attributes with a default in the schema are never null
4212 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4213 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4214 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4215 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4216 if (jGroup.getConsThreshold() != null
4217 && jGroup.getConsThreshold().intValue() != 0)
4219 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4222 c.verdict(false, 25);
4223 sg.cs.setConservation(c);
4226 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4228 // re-instate unique group/annotation row reference
4229 List<AlignmentAnnotation> jaal = groupAnnotRefs
4230 .get(jGroup.getId());
4233 for (AlignmentAnnotation jaa : jaal)
4236 if (jaa.autoCalculated)
4238 // match up and try to set group autocalc alignment row for this
4240 if (jaa.label.startsWith("Consensus for "))
4242 sg.setConsensus(jaa);
4244 // match up and try to set group autocalc alignment row for this
4246 if (jaa.label.startsWith("Conservation for "))
4248 sg.setConservationRow(jaa);
4255 if (addAnnotSchemeGroup)
4257 // reconstruct the annotation colourscheme
4259 constructAnnotationColour(jGroup.getAnnotationColours(),
4260 null, al, jalviewModel, false));
4266 // only dataset in this model, so just return.
4269 // ///////////////////////////////
4272 AlignFrame af = null;
4273 AlignViewport av = null;
4274 // now check to see if we really need to create a new viewport.
4275 if (multipleView && viewportsAdded.size() == 0)
4277 // We recovered an alignment for which a viewport already exists.
4278 // TODO: fix up any settings necessary for overlaying stored state onto
4279 // state recovered from another document. (may not be necessary).
4280 // we may need a binding from a viewport in memory to one recovered from
4282 // and then recover its containing af to allow the settings to be applied.
4283 // TODO: fix for vamsas demo
4285 "About to recover a viewport for existing alignment: Sequence set ID is "
4287 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4288 if (seqsetobj != null)
4290 if (seqsetobj instanceof String)
4292 uniqueSeqSetId = (String) seqsetobj;
4294 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4300 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4306 * indicate that annotation colours are applied across all groups (pre
4307 * Jalview 2.8.1 behaviour)
4309 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4310 jalviewModel.getVersion());
4312 AlignmentPanel ap = null;
4313 boolean isnewview = true;
4316 // Check to see if this alignment already has a view id == viewId
4317 jalview.gui.AlignmentPanel views[] = Desktop
4318 .getAlignmentPanels(uniqueSeqSetId);
4319 if (views != null && views.length > 0)
4321 for (int v = 0; v < views.length; v++)
4323 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4325 // recover the existing alignpanel, alignframe, viewport
4326 af = views[v].alignFrame;
4329 // TODO: could even skip resetting view settings if we don't want to
4330 // change the local settings from other jalview processes
4339 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4340 uniqueSeqSetId, viewId, autoAlan);
4341 av = af.getViewport();
4346 * Load any trees, PDB structures and viewers, Overview
4348 * Not done if flag is false (when this method is used for New View)
4350 if (loadTreesAndStructures)
4352 loadTrees(jalviewModel, view, af, av, ap);
4353 loadPCAViewers(jalviewModel, ap);
4354 loadPDBStructures(jprovider, jseqs, af, ap);
4355 loadRnaViewers(jprovider, jseqs, ap);
4356 loadOverview(view, jalviewModel.getVersion(), af);
4358 // and finally return.
4362 private void importMatrixData(List<MatrixType> xmlmatrices)
4364 for (MatrixType xmlmat:xmlmatrices)
4366 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4368 Console.error("Ignoring matrix '"+xmlmat.getId()+"' of type '"+xmlmat.getType());
4372 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4374 Console.error("Can't handle non square matrices");
4378 float[][] elements = ContactMatrix
4379 .fromFloatStringToContacts(xmlmat.getElements(),
4380 xmlmat.getCols().intValue(),
4381 xmlmat.getRows().intValue());
4383 List<BitSet> newgroups = new ArrayList<BitSet>();
4384 if (xmlmat.getGroups().size() > 0)
4386 for (String sgroup : xmlmat.getGroups())
4388 newgroups.add(deStringifyBitset(sgroup));
4391 String nwk = xmlmat.getNewick().size() > 0
4392 ? xmlmat.getNewick().get(0)
4394 if (xmlmat.getNewick().size() > 1)
4397 "Ignoring additional clusterings for contact matrix");
4399 String treeMethod = xmlmat.getTreeMethod();
4400 double thresh = xmlmat.getCutHeight() != null
4401 ? xmlmat.getCutHeight()
4403 GroupSet grpset = new GroupSet();
4404 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4406 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4407 contactMatrixRefs.put(xmlmat.getId(), newcm);
4408 Console.trace("Restored base contact matrix "+xmlmat.getId());
4412 private void restoreMatrixFor(SequenceI sequenceRef,
4413 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4415 // restore mapping data to matrix data
4416 jalview.util.MapList mapping = null;
4417 if (xmlmatmapping.getMapping() != null)
4419 MapListType m = xmlmatmapping.getMapping();
4420 // Mapping m = dr.getMapping();
4421 int fr[] = new int[m.getMapListFrom().size() * 2];
4422 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4423 for (int _i = 0; from.hasNext(); _i += 2)
4425 MapListFrom mf = from.next();
4426 fr[_i] = mf.getStart();
4427 fr[_i + 1] = mf.getEnd();
4429 int fto[] = new int[m.getMapListTo().size() * 2];
4430 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4431 for (int _i = 0; to.hasNext(); _i += 2)
4433 MapListTo mf = to.next();
4434 fto[_i] = mf.getStart();
4435 fto[_i + 1] = mf.getEnd();
4438 mapping = new jalview.util.MapList(fr, fto,
4439 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4442 // locate matrix data in project XML and import
4443 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4447 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4451 // create the PAEMatrix now
4452 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4455 jaa.sequenceRef.addContactListFor(jaa, newpae);
4462 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4463 * and geometry as saved
4468 protected void loadOverview(Viewport view, String version, AlignFrame af)
4470 if (!isVersionStringLaterThan("2.11.3", version)
4471 && view.getOverview() == null)
4476 * first close any Overview that was opened automatically
4477 * (if so configured in Preferences) so that the view is
4478 * restored in the same state as saved
4480 af.alignPanel.closeOverviewPanel();
4482 Overview overview = view.getOverview();
4483 if (overview != null)
4485 OverviewPanel overviewPanel = af
4486 .openOverviewPanel(overview.isShowHidden());
4487 overviewPanel.setTitle(overview.getTitle());
4488 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4489 overview.getWidth(), overview.getHeight());
4490 Color gap = new Color(overview.getGapColour());
4491 Color residue = new Color(overview.getResidueColour());
4492 Color hidden = new Color(overview.getHiddenColour());
4493 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4498 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4499 * panel is restored from separate jar entries, two (gapped and trimmed) per
4500 * sequence and secondary structure.
4502 * Currently each viewer shows just one sequence and structure (gapped and
4503 * trimmed), however this method is designed to support multiple sequences or
4504 * structures in viewers if wanted in future.
4510 private void loadRnaViewers(jarInputStreamProvider jprovider,
4511 List<JSeq> jseqs, AlignmentPanel ap)
4514 * scan the sequences for references to viewers; create each one the first
4515 * time it is referenced, add Rna models to existing viewers
4517 for (JSeq jseq : jseqs)
4519 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4521 RnaViewer viewer = jseq.getRnaViewer().get(i);
4522 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4525 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4527 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4528 SequenceI seq = seqRefIds.get(jseq.getId());
4529 AlignmentAnnotation ann = this.annotationIds
4530 .get(ss.getAnnotationId());
4533 * add the structure to the Varna display (with session state copied
4534 * from the jar to a temporary file)
4536 boolean gapped = safeBoolean(ss.isGapped());
4537 String rnaTitle = ss.getTitle();
4538 String sessionState = ss.getViewerState();
4539 String tempStateFile = copyJarEntry(jprovider, sessionState,
4541 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4542 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4544 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4550 * Locate and return an already instantiated matching AppVarna, or create one
4554 * @param viewIdSuffix
4558 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4559 String viewIdSuffix, AlignmentPanel ap)
4562 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4563 * if load is repeated
4565 String postLoadId = viewer.getViewId() + viewIdSuffix;
4566 for (JInternalFrame frame : getAllFrames())
4568 if (frame instanceof AppVarna)
4570 AppVarna varna = (AppVarna) frame;
4571 if (postLoadId.equals(varna.getViewId()))
4573 // this viewer is already instantiated
4574 // could in future here add ap as another 'parent' of the
4575 // AppVarna window; currently just 1-to-many
4582 * viewer not found - make it
4584 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4585 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4586 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4587 safeInt(viewer.getDividerLocation()));
4588 AppVarna varna = new AppVarna(model, ap);
4594 * Load any saved trees
4602 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4603 AlignViewport av, AlignmentPanel ap)
4605 // TODO result of automated refactoring - are all these parameters needed?
4608 for (int t = 0; t < jm.getTree().size(); t++)
4611 Tree tree = jm.getTree().get(t);
4613 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4616 if (tree.isColumnWise())
4618 AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds
4619 .get(tree.getColumnReference());
4623 "Null alignment annotation when restoring columnwise tree");
4625 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4626 tree.getTitle(), safeInt(tree.getWidth()),
4627 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4628 safeInt(tree.getYpos()));
4633 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4634 tree.getTitle(), safeInt(tree.getWidth()),
4635 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4636 safeInt(tree.getYpos()));
4638 if (tree.getId() != null)
4640 // perhaps bind the tree id to something ?
4645 // update local tree attributes ?
4646 // TODO: should check if tp has been manipulated by user - if so its
4647 // settings shouldn't be modified
4648 tp.setTitle(tree.getTitle());
4649 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4650 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4651 safeInt(tree.getHeight())));
4652 tp.setViewport(av); // af.viewport;
4653 // TODO: verify 'associate with all views' works still
4654 tp.getTreeCanvas().setViewport(av); // af.viewport;
4655 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4657 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4661 "There was a problem recovering stored Newick tree: \n"
4662 + tree.getNewick());
4666 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4667 tp.fitToWindow_actionPerformed(null);
4669 if (tree.getFontName() != null)
4672 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4673 safeInt(tree.getFontSize())));
4678 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4679 safeInt(view.getFontSize())));
4682 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4683 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4684 tp.showDistances(safeBoolean(tree.isShowDistances()));
4686 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4688 if (safeBoolean(tree.isCurrentTree()))
4690 af.getViewport().setCurrentTree(tp.getTree());
4694 } catch (Exception ex)
4696 ex.printStackTrace();
4701 * Load and link any saved structure viewers.
4708 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4709 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4712 * Run through all PDB ids on the alignment, and collect mappings between
4713 * distinct view ids and all sequences referring to that view.
4715 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4717 for (int i = 0; i < jseqs.size(); i++)
4719 JSeq jseq = jseqs.get(i);
4720 if (jseq.getPdbids().size() > 0)
4722 List<Pdbids> ids = jseq.getPdbids();
4723 for (int p = 0; p < ids.size(); p++)
4725 Pdbids pdbid = ids.get(p);
4726 final int structureStateCount = pdbid.getStructureState().size();
4727 for (int s = 0; s < structureStateCount; s++)
4729 // check to see if we haven't already created this structure view
4730 final StructureState structureState = pdbid.getStructureState()
4732 String sviewid = (structureState.getViewId() == null) ? null
4733 : structureState.getViewId() + uniqueSetSuffix;
4734 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4735 // Originally : pdbid.getFile()
4736 // : TODO: verify external PDB file recovery still works in normal
4737 // jalview project load
4739 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4740 jpdb.setId(pdbid.getId());
4742 int x = safeInt(structureState.getXpos());
4743 int y = safeInt(structureState.getYpos());
4744 int width = safeInt(structureState.getWidth());
4745 int height = safeInt(structureState.getHeight());
4747 // Probably don't need to do this anymore...
4748 // Desktop.desktop.getComponentAt(x, y);
4749 // TODO: NOW: check that this recovers the PDB file correctly.
4750 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4752 jalview.datamodel.SequenceI seq = seqRefIds
4753 .get(jseq.getId() + "");
4754 if (sviewid == null)
4756 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4759 if (!structureViewers.containsKey(sviewid))
4761 String viewerType = structureState.getType();
4762 if (viewerType == null) // pre Jalview 2.9
4764 viewerType = ViewerType.JMOL.toString();
4766 structureViewers.put(sviewid,
4767 new StructureViewerModel(x, y, width, height, false,
4768 false, true, structureState.getViewId(),
4770 // Legacy pre-2.7 conversion JAL-823 :
4771 // do not assume any view has to be linked for colour by
4775 // assemble String[] { pdb files }, String[] { id for each
4776 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4777 // seqs_file 2}, boolean[] {
4778 // linkAlignPanel,superposeWithAlignpanel}} from hash
4779 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4780 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4781 || structureState.isAlignwithAlignPanel());
4784 * Default colour by linked panel to false if not specified (e.g.
4785 * for pre-2.7 projects)
4787 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4788 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4789 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4792 * Default colour by viewer to true if not specified (e.g. for
4795 boolean colourByViewer = jmoldat.isColourByViewer();
4796 colourByViewer &= structureState.isColourByJmol();
4797 jmoldat.setColourByViewer(colourByViewer);
4799 if (jmoldat.getStateData().length() < structureState.getValue()
4800 /*Content()*/.length())
4802 jmoldat.setStateData(structureState.getValue());// Content());
4804 if (pdbid.getFile() != null)
4806 File mapkey = new File(pdbid.getFile());
4807 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4808 if (seqstrmaps == null)
4810 jmoldat.getFileData().put(mapkey,
4811 seqstrmaps = jmoldat.new StructureData(pdbFile,
4814 if (!seqstrmaps.getSeqList().contains(seq))
4816 seqstrmaps.getSeqList().add(seq);
4822 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");
4823 Console.warn(errorMessage);
4829 // Instantiate the associated structure views
4830 for (Entry<String, StructureViewerModel> entry : structureViewers
4835 createOrLinkStructureViewer(entry, af, ap, jprovider);
4836 } catch (Exception e)
4839 "Error loading structure viewer: " + e.getMessage());
4840 // failed - try the next one
4852 protected void createOrLinkStructureViewer(
4853 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4854 AlignmentPanel ap, jarInputStreamProvider jprovider)
4856 final StructureViewerModel stateData = viewerData.getValue();
4859 * Search for any viewer windows already open from other alignment views
4860 * that exactly match the stored structure state
4862 StructureViewerBase comp = findMatchingViewer(viewerData);
4866 linkStructureViewer(ap, comp, stateData);
4870 String type = stateData.getType();
4873 ViewerType viewerType = ViewerType.valueOf(type);
4874 createStructureViewer(viewerType, viewerData, af, jprovider);
4875 } catch (IllegalArgumentException | NullPointerException e)
4877 // TODO JAL-3619 show error dialog / offer an alternative viewer
4878 Console.error("Invalid structure viewer type: " + type);
4883 * Generates a name for the entry in the project jar file to hold state
4884 * information for a structure viewer
4889 protected String getViewerJarEntryName(String viewId)
4891 return VIEWER_PREFIX + viewId;
4895 * Returns any open frame that matches given structure viewer data. The match
4896 * is based on the unique viewId, or (for older project versions) the frame's
4902 protected StructureViewerBase findMatchingViewer(
4903 Entry<String, StructureViewerModel> viewerData)
4905 final String sviewid = viewerData.getKey();
4906 final StructureViewerModel svattrib = viewerData.getValue();
4907 StructureViewerBase comp = null;
4908 JInternalFrame[] frames = getAllFrames();
4909 for (JInternalFrame frame : frames)
4911 if (frame instanceof StructureViewerBase)
4914 * Post jalview 2.4 schema includes structure view id
4916 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4919 comp = (StructureViewerBase) frame;
4920 break; // break added in 2.9
4923 * Otherwise test for matching position and size of viewer frame
4925 else if (frame.getX() == svattrib.getX()
4926 && frame.getY() == svattrib.getY()
4927 && frame.getHeight() == svattrib.getHeight()
4928 && frame.getWidth() == svattrib.getWidth())
4930 comp = (StructureViewerBase) frame;
4931 // no break in faint hope of an exact match on viewId
4939 * Link an AlignmentPanel to an existing structure viewer.
4944 * @param useinViewerSuperpos
4945 * @param usetoColourbyseq
4946 * @param viewerColouring
4948 protected void linkStructureViewer(AlignmentPanel ap,
4949 StructureViewerBase viewer, StructureViewerModel stateData)
4951 // NOTE: if the jalview project is part of a shared session then
4952 // view synchronization should/could be done here.
4954 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4955 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4956 final boolean viewerColouring = stateData.isColourByViewer();
4957 Map<File, StructureData> oldFiles = stateData.getFileData();
4960 * Add mapping for sequences in this view to an already open viewer
4962 final AAStructureBindingModel binding = viewer.getBinding();
4963 for (File id : oldFiles.keySet())
4965 // add this and any other pdb files that should be present in the
4967 StructureData filedat = oldFiles.get(id);
4968 String pdbFile = filedat.getFilePath();
4969 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4970 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4972 binding.addSequenceForStructFile(pdbFile, seq);
4974 // and add the AlignmentPanel's reference to the view panel
4975 viewer.addAlignmentPanel(ap);
4976 if (useinViewerSuperpos)
4978 viewer.useAlignmentPanelForSuperposition(ap);
4982 viewer.excludeAlignmentPanelForSuperposition(ap);
4984 if (usetoColourbyseq)
4986 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4990 viewer.excludeAlignmentPanelForColourbyseq(ap);
4995 * Get all frames within the Desktop.
4999 protected JInternalFrame[] getAllFrames()
5001 JInternalFrame[] frames = null;
5002 // TODO is this necessary - is it safe - risk of hanging?
5007 frames = Desktop.desktop.getAllFrames();
5008 } catch (ArrayIndexOutOfBoundsException e)
5010 // occasional No such child exceptions are thrown here...
5014 } catch (InterruptedException f)
5018 } while (frames == null);
5023 * Answers true if 'version' is equal to or later than 'supported', where each
5024 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5025 * changes. Development and test values for 'version' are leniently treated
5029 * - minimum version we are comparing against
5031 * - version of data being processsed
5032 * @return true if version is equal to or later than supported
5034 public static boolean isVersionStringLaterThan(String supported,
5037 if (supported == null || version == null
5038 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5039 || version.equalsIgnoreCase("Test")
5040 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5042 System.err.println("Assuming project file with "
5043 + (version == null ? "null" : version)
5044 + " is compatible with Jalview version " + supported);
5049 return StringUtils.compareVersions(version, supported, "b") >= 0;
5053 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5055 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5057 if (newStructureViewers != null)
5059 sview.getBinding().setFinishedLoadingFromArchive(false);
5060 newStructureViewers.add(sview);
5064 protected void setLoadingFinishedForNewStructureViewers()
5066 if (newStructureViewers != null)
5068 for (JalviewStructureDisplayI sview : newStructureViewers)
5070 sview.getBinding().setFinishedLoadingFromArchive(true);
5072 newStructureViewers.clear();
5073 newStructureViewers = null;
5077 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5078 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5079 Viewport view, String uniqueSeqSetId, String viewId,
5080 List<JvAnnotRow> autoAlan)
5082 AlignFrame af = null;
5083 af = new AlignFrame(al, safeInt(view.getWidth()),
5084 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5088 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5089 // System.out.println("Jalview2XML AF " + e);
5090 // super.processKeyEvent(e);
5097 af.setFileName(file, FileFormat.Jalview);
5099 final AlignViewport viewport = af.getViewport();
5100 for (int i = 0; i < JSEQ.size(); i++)
5102 int colour = safeInt(JSEQ.get(i).getColour());
5103 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5109 viewport.setColourByReferenceSeq(true);
5110 viewport.setDisplayReferenceSeq(true);
5113 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5115 if (view.getSequenceSetId() != null)
5117 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5119 viewport.setSequenceSetId(uniqueSeqSetId);
5122 // propagate shared settings to this new view
5123 viewport.setHistoryList(av.getHistoryList());
5124 viewport.setRedoList(av.getRedoList());
5128 viewportsAdded.put(uniqueSeqSetId, viewport);
5130 // TODO: check if this method can be called repeatedly without
5131 // side-effects if alignpanel already registered.
5132 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5134 // apply Hidden regions to view.
5135 if (hiddenSeqs != null)
5137 for (int s = 0; s < JSEQ.size(); s++)
5139 SequenceGroup hidden = new SequenceGroup();
5140 boolean isRepresentative = false;
5141 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5143 isRepresentative = true;
5144 SequenceI sequenceToHide = al
5145 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5146 hidden.addSequence(sequenceToHide, false);
5147 // remove from hiddenSeqs list so we don't try to hide it twice
5148 hiddenSeqs.remove(sequenceToHide);
5150 if (isRepresentative)
5152 SequenceI representativeSequence = al.getSequenceAt(s);
5153 hidden.addSequence(representativeSequence, false);
5154 viewport.hideRepSequences(representativeSequence, hidden);
5158 SequenceI[] hseqs = hiddenSeqs
5159 .toArray(new SequenceI[hiddenSeqs.size()]);
5160 viewport.hideSequence(hseqs);
5163 // recover view properties and display parameters
5165 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5166 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5167 final int pidThreshold = safeInt(view.getPidThreshold());
5168 viewport.setThreshold(pidThreshold);
5170 viewport.setColourText(safeBoolean(view.isShowColourText()));
5172 viewport.setConservationSelected(
5173 safeBoolean(view.isConservationSelected()));
5174 viewport.setIncrement(safeInt(view.getConsThreshold()));
5175 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5176 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5178 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5179 safeInt(view.getFontSize())),
5180 (view.getCharWidth() != null) ? false : true);
5181 if (view.getCharWidth() != null)
5183 viewport.setCharWidth(view.getCharWidth());
5184 viewport.setCharHeight(view.getCharHeight());
5186 ViewStyleI vs = viewport.getViewStyle();
5187 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5188 viewport.setViewStyle(vs);
5189 // TODO: allow custom charWidth/Heights to be restored by updating them
5190 // after setting font - which means set above to false
5191 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5192 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5193 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5195 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5197 viewport.setShowText(safeBoolean(view.isShowText()));
5199 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5200 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5201 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5202 viewport.setShowUnconserved(view.isShowUnconserved());
5203 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5205 if (view.getViewName() != null)
5207 viewport.setViewName(view.getViewName());
5208 af.setInitialTabVisible();
5210 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5211 safeInt(view.getWidth()), safeInt(view.getHeight()));
5212 // startSeq set in af.alignPanel.updateLayout below
5213 af.alignPanel.updateLayout();
5214 ColourSchemeI cs = null;
5215 // apply colourschemes
5216 if (view.getBgColour() != null)
5218 if (view.getBgColour().startsWith("ucs"))
5220 cs = getUserColourScheme(jm, view.getBgColour());
5222 else if (view.getBgColour().startsWith("Annotation"))
5224 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5225 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5232 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5233 view.getBgColour());
5238 * turn off 'alignment colour applies to all groups'
5239 * while restoring global colour scheme
5241 viewport.setColourAppliesToAllGroups(false);
5242 viewport.setGlobalColourScheme(cs);
5243 viewport.getResidueShading().setThreshold(pidThreshold,
5244 view.isIgnoreGapsinConsensus());
5245 viewport.getResidueShading()
5246 .setConsensus(viewport.getSequenceConsensusHash());
5247 if (safeBoolean(view.isConservationSelected()) && cs != null)
5249 viewport.getResidueShading()
5250 .setConservationInc(safeInt(view.getConsThreshold()));
5252 af.changeColour(cs);
5253 viewport.setColourAppliesToAllGroups(true);
5255 viewport.setShowSequenceFeatures(
5256 safeBoolean(view.isShowSequenceFeatures()));
5258 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5259 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5260 viewport.setFollowHighlight(view.isFollowHighlight());
5261 viewport.followSelection = view.isFollowSelection();
5262 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5263 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5264 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5265 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5266 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5267 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5268 viewport.setShowGroupConservation(view.isShowGroupConservation());
5269 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5270 viewport.setShowComplementFeaturesOnTop(
5271 view.isShowComplementFeaturesOnTop());
5273 // recover feature settings
5274 if (jm.getFeatureSettings() != null)
5276 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5277 .getFeatureRenderer();
5278 FeaturesDisplayed fdi;
5279 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5280 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5282 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5283 Map<String, Float> featureOrder = new Hashtable<>();
5285 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5288 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5289 String featureType = setting.getType();
5292 * restore feature filters (if any)
5294 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5296 if (filters != null)
5298 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5300 if (!filter.isEmpty())
5302 fr.setFeatureFilter(featureType, filter);
5307 * restore feature colour scheme
5309 Color maxColour = new Color(setting.getColour());
5310 if (setting.getMincolour() != null)
5313 * minColour is always set unless a simple colour
5314 * (including for colour by label though it doesn't use it)
5316 Color minColour = new Color(setting.getMincolour().intValue());
5317 Color noValueColour = minColour;
5318 NoValueColour noColour = setting.getNoValueColour();
5319 if (noColour == NoValueColour.NONE)
5321 noValueColour = null;
5323 else if (noColour == NoValueColour.MAX)
5325 noValueColour = maxColour;
5327 float min = safeFloat(safeFloat(setting.getMin()));
5328 float max = setting.getMax() == null ? 1f
5329 : setting.getMax().floatValue();
5330 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5331 maxColour, noValueColour, min, max);
5332 if (setting.getAttributeName().size() > 0)
5334 gc.setAttributeName(setting.getAttributeName().toArray(
5335 new String[setting.getAttributeName().size()]));
5337 if (setting.getThreshold() != null)
5339 gc.setThreshold(setting.getThreshold().floatValue());
5340 int threshstate = safeInt(setting.getThreshstate());
5341 // -1 = None, 0 = Below, 1 = Above threshold
5342 if (threshstate == 0)
5344 gc.setBelowThreshold(true);
5346 else if (threshstate == 1)
5348 gc.setAboveThreshold(true);
5351 gc.setAutoScaled(true); // default
5352 if (setting.isAutoScale() != null)
5354 gc.setAutoScaled(setting.isAutoScale());
5356 if (setting.isColourByLabel() != null)
5358 gc.setColourByLabel(setting.isColourByLabel());
5360 // and put in the feature colour table.
5361 featureColours.put(featureType, gc);
5365 featureColours.put(featureType, new FeatureColour(maxColour));
5367 renderOrder[fs] = featureType;
5368 if (setting.getOrder() != null)
5370 featureOrder.put(featureType, setting.getOrder().floatValue());
5374 featureOrder.put(featureType, Float.valueOf(
5375 fs / jm.getFeatureSettings().getSetting().size()));
5377 if (safeBoolean(setting.isDisplay()))
5379 fdi.setVisible(featureType);
5382 Map<String, Boolean> fgtable = new Hashtable<>();
5383 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5385 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5386 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5388 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5389 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5390 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5391 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5392 fgtable, featureColours, 1.0f, featureOrder);
5393 fr.transferSettings(frs);
5396 if (view.getHiddenColumns().size() > 0)
5398 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5400 final HiddenColumns hc = view.getHiddenColumns().get(c);
5401 viewport.hideColumns(safeInt(hc.getStart()),
5402 safeInt(hc.getEnd()) /* +1 */);
5405 if (view.getCalcIdParam() != null)
5407 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5409 if (calcIdParam != null)
5411 if (recoverCalcIdParam(calcIdParam, viewport))
5416 Console.warn("Couldn't recover parameters for "
5417 + calcIdParam.getCalcId());
5422 af.setMenusFromViewport(viewport);
5423 af.setTitle(view.getTitle());
5424 // TODO: we don't need to do this if the viewport is aready visible.
5426 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5427 * has a 'cdna/protein complement' view, in which case save it in order to
5428 * populate a SplitFrame once all views have been read in.
5430 String complementaryViewId = view.getComplementId();
5431 if (complementaryViewId == null)
5433 Desktop.addInternalFrame(af, view.getTitle(),
5434 safeInt(view.getWidth()), safeInt(view.getHeight()));
5435 // recompute any autoannotation
5436 af.alignPanel.updateAnnotation(false, true);
5437 reorderAutoannotation(af, al, autoAlan);
5438 af.alignPanel.alignmentChanged();
5442 splitFrameCandidates.put(view, af);
5449 * Reads saved data to restore Colour by Annotation settings
5451 * @param viewAnnColour
5455 * @param checkGroupAnnColour
5458 private ColourSchemeI constructAnnotationColour(
5459 AnnotationColourScheme viewAnnColour, AlignFrame af,
5460 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5462 boolean propagateAnnColour = false;
5463 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5465 if (checkGroupAnnColour && al.getGroups() != null
5466 && al.getGroups().size() > 0)
5468 // pre 2.8.1 behaviour
5469 // check to see if we should transfer annotation colours
5470 propagateAnnColour = true;
5471 for (SequenceGroup sg : al.getGroups())
5473 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5475 propagateAnnColour = false;
5481 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5483 String annotationId = viewAnnColour.getAnnotation();
5484 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5487 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5489 if (matchedAnnotation == null
5490 && annAlignment.getAlignmentAnnotation() != null)
5492 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5495 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5497 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5502 if (matchedAnnotation == null)
5504 System.err.println("Failed to match annotation colour scheme for "
5508 // belt-and-braces create a threshold line if the
5509 // colourscheme needs one but the matchedAnnotation doesn't have one
5510 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5511 && matchedAnnotation.getThreshold() == null)
5513 matchedAnnotation.setThreshold(
5514 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5515 "Threshold", Color.black));
5518 AnnotationColourGradient cs = null;
5519 if (viewAnnColour.getColourScheme().equals("None"))
5521 cs = new AnnotationColourGradient(matchedAnnotation,
5522 new Color(safeInt(viewAnnColour.getMinColour())),
5523 new Color(safeInt(viewAnnColour.getMaxColour())),
5524 safeInt(viewAnnColour.getAboveThreshold()));
5526 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5528 cs = new AnnotationColourGradient(matchedAnnotation,
5529 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5530 safeInt(viewAnnColour.getAboveThreshold()));
5534 cs = new AnnotationColourGradient(matchedAnnotation,
5535 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5536 viewAnnColour.getColourScheme()),
5537 safeInt(viewAnnColour.getAboveThreshold()));
5540 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5541 boolean useOriginalColours = safeBoolean(
5542 viewAnnColour.isPredefinedColours());
5543 cs.setSeqAssociated(perSequenceOnly);
5544 cs.setPredefinedColours(useOriginalColours);
5546 if (propagateAnnColour && al.getGroups() != null)
5548 // Also use these settings for all the groups
5549 for (int g = 0; g < al.getGroups().size(); g++)
5551 SequenceGroup sg = al.getGroups().get(g);
5552 if (sg.getGroupColourScheme() == null)
5557 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5558 matchedAnnotation, sg.getColourScheme(),
5559 safeInt(viewAnnColour.getAboveThreshold()));
5560 sg.setColourScheme(groupScheme);
5561 groupScheme.setSeqAssociated(perSequenceOnly);
5562 groupScheme.setPredefinedColours(useOriginalColours);
5568 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5569 List<JvAnnotRow> autoAlan)
5571 // copy over visualization settings for autocalculated annotation in the
5573 if (al.getAlignmentAnnotation() != null)
5576 * Kludge for magic autoannotation names (see JAL-811)
5578 String[] magicNames = new String[] { "Consensus", "Quality",
5580 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5581 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5582 for (String nm : magicNames)
5584 visan.put(nm, nullAnnot);
5586 for (JvAnnotRow auan : autoAlan)
5588 visan.put(auan.template.label
5589 + (auan.template.getCalcId() == null ? ""
5590 : "\t" + auan.template.getCalcId()),
5593 int hSize = al.getAlignmentAnnotation().length;
5594 List<JvAnnotRow> reorder = new ArrayList<>();
5595 // work through any autoCalculated annotation already on the view
5596 // removing it if it should be placed in a different location on the
5597 // annotation panel.
5598 List<String> remains = new ArrayList<>(visan.keySet());
5599 for (int h = 0; h < hSize; h++)
5601 jalview.datamodel.AlignmentAnnotation jalan = al
5602 .getAlignmentAnnotation()[h];
5603 if (jalan.autoCalculated)
5606 JvAnnotRow valan = visan.get(k = jalan.label);
5607 if (jalan.getCalcId() != null)
5609 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5614 // delete the auto calculated row from the alignment
5615 al.deleteAnnotation(jalan, false);
5619 if (valan != nullAnnot)
5621 if (jalan != valan.template)
5623 // newly created autoannotation row instance
5624 // so keep a reference to the visible annotation row
5625 // and copy over all relevant attributes
5626 if (valan.template.graphHeight >= 0)
5629 jalan.graphHeight = valan.template.graphHeight;
5631 jalan.visible = valan.template.visible;
5633 reorder.add(new JvAnnotRow(valan.order, jalan));
5638 // Add any (possibly stale) autocalculated rows that were not appended to
5639 // the view during construction
5640 for (String other : remains)
5642 JvAnnotRow othera = visan.get(other);
5643 if (othera != nullAnnot && othera.template.getCalcId() != null
5644 && othera.template.getCalcId().length() > 0)
5646 reorder.add(othera);
5649 // now put the automatic annotation in its correct place
5650 int s = 0, srt[] = new int[reorder.size()];
5651 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5652 for (JvAnnotRow jvar : reorder)
5655 srt[s++] = jvar.order;
5658 jalview.util.QuickSort.sort(srt, rws);
5659 // and re-insert the annotation at its correct position
5660 for (JvAnnotRow jvar : rws)
5662 al.addAnnotation(jvar.template, jvar.order);
5664 af.alignPanel.adjustAnnotationHeight();
5668 Hashtable skipList = null;
5671 * TODO remove this method
5674 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5675 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5676 * throw new Error("Implementation Error. No skipList defined for this
5677 * Jalview2XML instance."); } return (AlignFrame)
5678 * skipList.get(view.getSequenceSetId()); }
5682 * Check if the Jalview view contained in object should be skipped or not.
5685 * @return true if view's sequenceSetId is a key in skipList
5687 private boolean skipViewport(JalviewModel object)
5689 if (skipList == null)
5693 String id = object.getViewport().get(0).getSequenceSetId();
5694 if (skipList.containsKey(id))
5696 Console.debug("Skipping seuqence set id " + id);
5702 public void addToSkipList(AlignFrame af)
5704 if (skipList == null)
5706 skipList = new Hashtable();
5708 skipList.put(af.getViewport().getSequenceSetId(), af);
5711 public void clearSkipList()
5713 if (skipList != null)
5720 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5721 boolean ignoreUnrefed, String uniqueSeqSetId)
5723 jalview.datamodel.AlignmentI ds = getDatasetFor(
5724 vamsasSet.getDatasetId());
5725 AlignmentI xtant_ds = ds;
5726 if (xtant_ds == null)
5728 // good chance we are about to create a new dataset, but check if we've
5729 // seen some of the dataset sequence IDs before.
5730 // TODO: skip this check if we are working with project generated by
5731 // version 2.11 or later
5732 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5733 if (xtant_ds != null)
5736 addDatasetRef(vamsasSet.getDatasetId(), ds);
5739 Vector<SequenceI> dseqs = null;
5742 // recovering an alignment View
5743 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5744 if (seqSetDS != null)
5746 if (ds != null && ds != seqSetDS)
5749 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5750 + " - CDS/Protein crossreference data may be lost");
5751 if (xtant_ds != null)
5753 // This can only happen if the unique sequence set ID was bound to a
5754 // dataset that did not contain any of the sequences in the view
5755 // currently being restored.
5757 "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.");
5761 addDatasetRef(vamsasSet.getDatasetId(), ds);
5766 // try even harder to restore dataset
5767 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5768 // create a list of new dataset sequences
5769 dseqs = new Vector<>();
5771 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5773 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5774 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5776 // create a new dataset
5779 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5780 dseqs.copyInto(dsseqs);
5781 ds = new jalview.datamodel.Alignment(dsseqs);
5782 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5783 + " for alignment " + System.identityHashCode(al));
5784 addDatasetRef(vamsasSet.getDatasetId(), ds);
5786 // set the dataset for the newly imported alignment.
5787 if (al.getDataset() == null && !ignoreUnrefed)
5790 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5791 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5793 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5797 * XML dataset sequence ID to materialised dataset reference
5799 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5802 * @return the first materialised dataset reference containing a dataset
5803 * sequence referenced in the given view
5805 * - sequences from the view
5807 AlignmentI checkIfHasDataset(List<Sequence> list)
5809 for (Sequence restoredSeq : list)
5811 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5812 if (datasetFor != null)
5821 * Register ds as the containing dataset for the dataset sequences referenced
5822 * by sequences in list
5825 * - sequences in a view
5828 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5830 for (Sequence restoredSeq : list)
5832 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5833 if (prevDS != null && prevDS != ds)
5835 Console.warn("Dataset sequence appears in many datasets: "
5836 + restoredSeq.getDsseqid());
5837 // TODO: try to merge!
5845 * sequence definition to create/merge dataset sequence for
5849 * vector to add new dataset sequence to
5850 * @param ignoreUnrefed
5851 * - when true, don't create new sequences from vamsasSeq if it's id
5852 * doesn't already have an asssociated Jalview sequence.
5854 * - used to reorder the sequence in the alignment according to the
5855 * vamsasSeq array ordering, to preserve ordering of dataset
5857 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5858 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5861 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5863 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5864 boolean reorder = false;
5865 SequenceI dsq = null;
5866 if (sq != null && sq.getDatasetSequence() != null)
5868 dsq = sq.getDatasetSequence();
5874 if (sq == null && ignoreUnrefed)
5878 String sqid = vamsasSeq.getDsseqid();
5881 // need to create or add a new dataset sequence reference to this sequence
5884 dsq = seqRefIds.get(sqid);
5889 // make a new dataset sequence
5890 dsq = sq.createDatasetSequence();
5893 // make up a new dataset reference for this sequence
5894 sqid = seqHash(dsq);
5896 dsq.setVamsasId(uniqueSetSuffix + sqid);
5897 seqRefIds.put(sqid, dsq);
5902 dseqs.addElement(dsq);
5907 ds.addSequence(dsq);
5913 { // make this dataset sequence sq's dataset sequence
5914 sq.setDatasetSequence(dsq);
5915 // and update the current dataset alignment
5920 if (!dseqs.contains(dsq))
5927 if (ds.findIndex(dsq) < 0)
5929 ds.addSequence(dsq);
5936 // TODO: refactor this as a merge dataset sequence function
5937 // now check that sq (the dataset sequence) sequence really is the union of
5938 // all references to it
5939 // boolean pre = sq.getStart() < dsq.getStart();
5940 // boolean post = sq.getEnd() > dsq.getEnd();
5944 // StringBuffer sb = new StringBuffer();
5945 String newres = jalview.analysis.AlignSeq.extractGaps(
5946 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5947 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5948 && newres.length() > dsq.getLength())
5950 // Update with the longer sequence.
5954 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5955 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5956 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5957 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5959 dsq.setSequence(newres);
5961 // TODO: merges will never happen if we 'know' we have the real dataset
5962 // sequence - this should be detected when id==dssid
5964 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5965 // + (pre ? "prepended" : "") + " "
5966 // + (post ? "appended" : ""));
5971 // sequence refs are identical. We may need to update the existing dataset
5972 // alignment with this one, though.
5973 if (ds != null && dseqs == null)
5975 int opos = ds.findIndex(dsq);
5976 SequenceI tseq = null;
5977 if (opos != -1 && vseqpos != opos)
5979 // remove from old position
5980 ds.deleteSequence(dsq);
5982 if (vseqpos < ds.getHeight())
5984 if (vseqpos != opos)
5986 // save sequence at destination position
5987 tseq = ds.getSequenceAt(vseqpos);
5988 ds.replaceSequenceAt(vseqpos, dsq);
5989 ds.addSequence(tseq);
5994 ds.addSequence(dsq);
6001 * TODO use AlignmentI here and in related methods - needs
6002 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6004 Hashtable<String, AlignmentI> datasetIds = null;
6006 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6008 private AlignmentI getDatasetFor(String datasetId)
6010 if (datasetIds == null)
6012 datasetIds = new Hashtable<>();
6015 if (datasetIds.containsKey(datasetId))
6017 return datasetIds.get(datasetId);
6022 private void addDatasetRef(String datasetId, AlignmentI dataset)
6024 if (datasetIds == null)
6026 datasetIds = new Hashtable<>();
6028 datasetIds.put(datasetId, dataset);
6032 * make a new dataset ID for this jalview dataset alignment
6037 private String getDatasetIdRef(AlignmentI dataset)
6039 if (dataset.getDataset() != null)
6042 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6044 String datasetId = makeHashCode(dataset, null);
6045 if (datasetId == null)
6047 // make a new datasetId and record it
6048 if (dataset2Ids == null)
6050 dataset2Ids = new IdentityHashMap<>();
6054 datasetId = dataset2Ids.get(dataset);
6056 if (datasetId == null)
6058 datasetId = "ds" + dataset2Ids.size() + 1;
6059 dataset2Ids.put(dataset, datasetId);
6066 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6067 * constructed as a special subclass GeneLocus.
6069 * @param datasetSequence
6072 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6074 for (int d = 0; d < sequence.getDBRef().size(); d++)
6076 DBRef dr = sequence.getDBRef().get(d);
6080 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6081 dr.getAccessionId());
6085 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6086 dr.getAccessionId());
6088 if (dr.getMapping() != null)
6090 entry.setMap(addMapping(dr.getMapping()));
6092 entry.setCanonical(dr.isCanonical());
6093 datasetSequence.addDBRef(entry);
6097 private jalview.datamodel.Mapping addMapping(Mapping m)
6099 SequenceI dsto = null;
6100 // Mapping m = dr.getMapping();
6101 int fr[] = new int[m.getMapListFrom().size() * 2];
6102 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6103 for (int _i = 0; from.hasNext(); _i += 2)
6105 MapListFrom mf = from.next();
6106 fr[_i] = mf.getStart();
6107 fr[_i + 1] = mf.getEnd();
6109 int fto[] = new int[m.getMapListTo().size() * 2];
6110 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6111 for (int _i = 0; to.hasNext(); _i += 2)
6113 MapListTo mf = to.next();
6114 fto[_i] = mf.getStart();
6115 fto[_i + 1] = mf.getEnd();
6117 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6118 fto, m.getMapFromUnit().intValue(),
6119 m.getMapToUnit().intValue());
6122 * (optional) choice of dseqFor or Sequence
6124 if (m.getDseqFor() != null)
6126 String dsfor = m.getDseqFor();
6127 if (seqRefIds.containsKey(dsfor))
6132 jmap.setTo(seqRefIds.get(dsfor));
6136 frefedSequence.add(newMappingRef(dsfor, jmap));
6139 else if (m.getSequence() != null)
6142 * local sequence definition
6144 Sequence ms = m.getSequence();
6145 SequenceI djs = null;
6146 String sqid = ms.getDsseqid();
6147 if (sqid != null && sqid.length() > 0)
6150 * recover dataset sequence
6152 djs = seqRefIds.get(sqid);
6157 "Warning - making up dataset sequence id for DbRef sequence map reference");
6158 sqid = ((Object) ms).toString(); // make up a new hascode for
6159 // undefined dataset sequence hash
6160 // (unlikely to happen)
6166 * make a new dataset sequence and add it to refIds hash
6168 djs = new jalview.datamodel.Sequence(ms.getName(),
6170 djs.setStart(jmap.getMap().getToLowest());
6171 djs.setEnd(jmap.getMap().getToHighest());
6172 djs.setVamsasId(uniqueSetSuffix + sqid);
6174 incompleteSeqs.put(sqid, djs);
6175 seqRefIds.put(sqid, djs);
6178 Console.debug("about to recurse on addDBRefs.");
6187 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6188 * view as XML (but not to file), and then reloading it
6193 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6196 JalviewModel jm = saveState(ap, null, null, null);
6199 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6200 ap.getAlignment().getDataset());
6202 uniqueSetSuffix = "";
6203 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6204 jm.getViewport().get(0).setId(null);
6205 // we don't overwrite the view we just copied
6207 if (this.frefedSequence == null)
6209 frefedSequence = new Vector<>();
6212 viewportsAdded.clear();
6214 AlignFrame af = loadFromObject(jm, null, false, null);
6215 af.getAlignPanels().clear();
6216 af.closeMenuItem_actionPerformed(true);
6219 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6220 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6221 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6222 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6223 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6226 return af.alignPanel;
6229 private Hashtable jvids2vobj;
6232 * set the object to ID mapping tables used to write/recover objects and XML
6233 * ID strings for the jalview project. If external tables are provided then
6234 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6235 * object goes out of scope. - also populates the datasetIds hashtable with
6236 * alignment objects containing dataset sequences
6239 * Map from ID strings to jalview datamodel
6241 * Map from jalview datamodel to ID strings
6245 public void setObjectMappingTables(Hashtable vobj2jv,
6246 IdentityHashMap jv2vobj)
6248 this.jv2vobj = jv2vobj;
6249 this.vobj2jv = vobj2jv;
6250 Iterator ds = jv2vobj.keySet().iterator();
6252 while (ds.hasNext())
6254 Object jvobj = ds.next();
6255 id = jv2vobj.get(jvobj).toString();
6256 if (jvobj instanceof jalview.datamodel.Alignment)
6258 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6260 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6263 else if (jvobj instanceof jalview.datamodel.Sequence)
6265 // register sequence object so the XML parser can recover it.
6266 if (seqRefIds == null)
6268 seqRefIds = new HashMap<>();
6270 if (seqsToIds == null)
6272 seqsToIds = new IdentityHashMap<>();
6274 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6275 seqsToIds.put((SequenceI) jvobj, id);
6277 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6280 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6281 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6282 if (jvann.annotationId == null)
6284 jvann.annotationId = anid;
6286 if (!jvann.annotationId.equals(anid))
6288 // TODO verify that this is the correct behaviour
6289 Console.warn("Overriding Annotation ID for " + anid
6290 + " from different id : " + jvann.annotationId);
6291 jvann.annotationId = anid;
6294 else if (jvobj instanceof String)
6296 if (jvids2vobj == null)
6298 jvids2vobj = new Hashtable();
6299 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6304 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6310 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6311 * objects created from the project archive. If string is null (default for
6312 * construction) then suffix will be set automatically.
6316 public void setUniqueSetSuffix(String string)
6318 uniqueSetSuffix = string;
6323 * uses skipList2 as the skipList for skipping views on sequence sets
6324 * associated with keys in the skipList
6328 public void setSkipList(Hashtable skipList2)
6330 skipList = skipList2;
6334 * Reads the jar entry of given name and returns its contents, or null if the
6335 * entry is not found.
6338 * @param jarEntryName
6341 protected String readJarEntry(jarInputStreamProvider jprovider,
6342 String jarEntryName)
6344 String result = null;
6345 BufferedReader in = null;
6350 * Reopen the jar input stream and traverse its entries to find a matching
6353 JarInputStream jin = jprovider.getJarInputStream();
6354 JarEntry entry = null;
6357 entry = jin.getNextJarEntry();
6358 } while (entry != null && !entry.getName().equals(jarEntryName));
6362 StringBuilder out = new StringBuilder(256);
6363 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6366 while ((data = in.readLine()) != null)
6370 result = out.toString();
6375 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6377 } catch (Exception ex)
6379 ex.printStackTrace();
6387 } catch (IOException e)
6398 * Returns an incrementing counter (0, 1, 2...)
6402 private synchronized int nextCounter()
6408 * Loads any saved PCA viewers
6413 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6417 List<PcaViewer> pcaviewers = model.getPcaViewer();
6418 for (PcaViewer viewer : pcaviewers)
6420 String modelName = viewer.getScoreModelName();
6421 SimilarityParamsI params = new SimilarityParams(
6422 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6423 viewer.isIncludeGaps(),
6424 viewer.isDenominateByShortestLength());
6427 * create the panel (without computing the PCA)
6429 PCAPanel panel = new PCAPanel(ap, modelName, params);
6431 panel.setTitle(viewer.getTitle());
6432 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6433 viewer.getWidth(), viewer.getHeight()));
6435 boolean showLabels = viewer.isShowLabels();
6436 panel.setShowLabels(showLabels);
6437 panel.getRotatableCanvas().setShowLabels(showLabels);
6438 panel.getRotatableCanvas()
6439 .setBgColour(new Color(viewer.getBgColour()));
6440 panel.getRotatableCanvas()
6441 .setApplyToAllViews(viewer.isLinkToAllViews());
6444 * load PCA output data
6446 ScoreModelI scoreModel = ScoreModels.getInstance()
6447 .getScoreModel(modelName, ap);
6448 PCA pca = new PCA(null, scoreModel, params);
6449 PcaDataType pcaData = viewer.getPcaData();
6451 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6452 pca.setPairwiseScores(pairwise);
6454 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6455 pca.setTridiagonal(triDiag);
6457 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6458 pca.setEigenmatrix(result);
6460 panel.getPcaModel().setPCA(pca);
6463 * we haven't saved the input data! (JAL-2647 to do)
6465 panel.setInputData(null);
6468 * add the sequence points for the PCA display
6470 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6471 for (SequencePoint sp : viewer.getSequencePoint())
6473 String seqId = sp.getSequenceRef();
6474 SequenceI seq = seqRefIds.get(seqId);
6477 throw new IllegalStateException(
6478 "Unmatched seqref for PCA: " + seqId);
6480 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6481 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6483 seqPoints.add(seqPoint);
6485 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6488 * set min-max ranges and scale after setPoints (which recomputes them)
6490 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6491 SeqPointMin spMin = viewer.getSeqPointMin();
6492 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6494 SeqPointMax spMax = viewer.getSeqPointMax();
6495 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6497 panel.getRotatableCanvas().setSeqMinMax(min, max);
6499 // todo: hold points list in PCAModel only
6500 panel.getPcaModel().setSequencePoints(seqPoints);
6502 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6503 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6504 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6506 // is this duplication needed?
6507 panel.setTop(seqPoints.size() - 1);
6508 panel.getPcaModel().setTop(seqPoints.size() - 1);
6511 * add the axes' end points for the display
6513 for (int i = 0; i < 3; i++)
6515 Axis axis = viewer.getAxis().get(i);
6516 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6517 axis.getXPos(), axis.getYPos(), axis.getZPos());
6520 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6521 "label.calc_title", "PCA", modelName), 475, 450);
6523 } catch (Exception ex)
6525 Console.error("Error loading PCA: " + ex.toString());
6530 * Creates a new structure viewer window
6537 protected void createStructureViewer(ViewerType viewerType,
6538 final Entry<String, StructureViewerModel> viewerData,
6539 AlignFrame af, jarInputStreamProvider jprovider)
6541 final StructureViewerModel viewerModel = viewerData.getValue();
6542 String sessionFilePath = null;
6544 if (viewerType == ViewerType.JMOL)
6546 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6550 String viewerJarEntryName = getViewerJarEntryName(
6551 viewerModel.getViewId());
6552 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6553 "viewerSession", ".tmp");
6555 final String sessionPath = sessionFilePath;
6556 final String sviewid = viewerData.getKey();
6559 SwingUtilities.invokeAndWait(new Runnable()
6564 JalviewStructureDisplayI sview = null;
6567 sview = StructureViewer.createView(viewerType, af.alignPanel,
6568 viewerModel, sessionPath, sviewid);
6569 addNewStructureViewer(sview);
6570 } catch (OutOfMemoryError ex)
6572 new OOMWarning("Restoring structure view for " + viewerType,
6573 (OutOfMemoryError) ex.getCause());
6574 if (sview != null && sview.isVisible())
6576 sview.closeViewer(false);
6577 sview.setVisible(false);
6583 } catch (InvocationTargetException | InterruptedException ex)
6585 Console.warn("Unexpected error when opening " + viewerType
6586 + " structure viewer", ex);
6591 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6592 * the path of the file. "load file" commands are rewritten to change the
6593 * original PDB file names to those created as the Jalview project is loaded.
6599 private String rewriteJmolSession(StructureViewerModel svattrib,
6600 jarInputStreamProvider jprovider)
6602 String state = svattrib.getStateData(); // Jalview < 2.9
6603 if (state == null || state.isEmpty()) // Jalview >= 2.9
6605 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6606 state = readJarEntry(jprovider, jarEntryName);
6608 // TODO or simpler? for each key in oldFiles,
6609 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6610 // (allowing for different path escapings)
6611 StringBuilder rewritten = new StringBuilder(state.length());
6612 int cp = 0, ncp, ecp;
6613 Map<File, StructureData> oldFiles = svattrib.getFileData();
6614 while ((ncp = state.indexOf("load ", cp)) > -1)
6618 // look for next filename in load statement
6619 rewritten.append(state.substring(cp,
6620 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6621 String oldfilenam = state.substring(ncp,
6622 ecp = state.indexOf("\"", ncp));
6623 // recover the new mapping data for this old filename
6624 // have to normalize filename - since Jmol and jalview do
6625 // filename translation differently.
6626 StructureData filedat = oldFiles.get(new File(oldfilenam));
6627 if (filedat == null)
6629 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6630 filedat = oldFiles.get(new File(reformatedOldFilename));
6632 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6633 rewritten.append("\"");
6634 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6635 // look for next file statement.
6636 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6640 // just append rest of state
6641 rewritten.append(state.substring(cp));
6645 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6646 rewritten = new StringBuilder(state);
6647 rewritten.append("; load append ");
6648 for (File id : oldFiles.keySet())
6650 // add pdb files that should be present in the viewer
6651 StructureData filedat = oldFiles.get(id);
6652 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6654 rewritten.append(";");
6657 if (rewritten.length() == 0)
6661 final String history = "history = ";
6662 int historyIndex = rewritten.indexOf(history);
6663 if (historyIndex > -1)
6666 * change "history = [true|false];" to "history = [1|0];"
6668 historyIndex += history.length();
6669 String val = rewritten.substring(historyIndex, historyIndex + 5);
6670 if (val.startsWith("true"))
6672 rewritten.replace(historyIndex, historyIndex + 4, "1");
6674 else if (val.startsWith("false"))
6676 rewritten.replace(historyIndex, historyIndex + 5, "0");
6682 File tmp = File.createTempFile("viewerSession", ".tmp");
6683 try (OutputStream os = new FileOutputStream(tmp))
6685 InputStream is = new ByteArrayInputStream(
6686 rewritten.toString().getBytes());
6688 return tmp.getAbsolutePath();
6690 } catch (IOException e)
6692 Console.error("Error restoring Jmol session: " + e.toString());
6698 * Populates an XML model of the feature colour scheme for one feature type
6700 * @param featureType
6704 public static Colour marshalColour(String featureType,
6705 FeatureColourI fcol)
6707 Colour col = new Colour();
6708 if (fcol.isSimpleColour())
6710 col.setRGB(Format.getHexString(fcol.getColour()));
6714 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6715 col.setMin(fcol.getMin());
6716 col.setMax(fcol.getMax());
6717 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6718 col.setAutoScale(fcol.isAutoScaled());
6719 col.setThreshold(fcol.getThreshold());
6720 col.setColourByLabel(fcol.isColourByLabel());
6721 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6722 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6723 : ThresholdType.NONE));
6724 if (fcol.isColourByAttribute())
6726 final String[] attName = fcol.getAttributeName();
6727 col.getAttributeName().add(attName[0]);
6728 if (attName.length > 1)
6730 col.getAttributeName().add(attName[1]);
6733 Color noColour = fcol.getNoColour();
6734 if (noColour == null)
6736 col.setNoValueColour(NoValueColour.NONE);
6738 else if (noColour == fcol.getMaxColour())
6740 col.setNoValueColour(NoValueColour.MAX);
6744 col.setNoValueColour(NoValueColour.MIN);
6747 col.setName(featureType);
6752 * Populates an XML model of the feature filter(s) for one feature type
6754 * @param firstMatcher
6755 * the first (or only) match condition)
6757 * remaining match conditions (if any)
6759 * if true, conditions are and-ed, else or-ed
6761 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6762 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6765 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6767 if (filters.hasNext())
6772 CompoundMatcher compound = new CompoundMatcher();
6773 compound.setAnd(and);
6774 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6775 firstMatcher, Collections.emptyIterator(), and);
6776 // compound.addMatcherSet(matcher1);
6777 compound.getMatcherSet().add(matcher1);
6778 FeatureMatcherI nextMatcher = filters.next();
6779 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6780 nextMatcher, filters, and);
6781 // compound.addMatcherSet(matcher2);
6782 compound.getMatcherSet().add(matcher2);
6783 result.setCompoundMatcher(compound);
6788 * single condition matcher
6790 // MatchCondition matcherModel = new MatchCondition();
6791 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6792 matcherModel.setCondition(
6793 firstMatcher.getMatcher().getCondition().getStableName());
6794 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6795 if (firstMatcher.isByAttribute())
6797 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6798 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6799 String[] attName = firstMatcher.getAttribute();
6800 matcherModel.getAttributeName().add(attName[0]); // attribute
6801 if (attName.length > 1)
6803 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6806 else if (firstMatcher.isByLabel())
6808 matcherModel.setBy(FilterBy.BY_LABEL);
6810 else if (firstMatcher.isByScore())
6812 matcherModel.setBy(FilterBy.BY_SCORE);
6814 result.setMatchCondition(matcherModel);
6821 * Loads one XML model of a feature filter to a Jalview object
6823 * @param featureType
6824 * @param matcherSetModel
6827 public static FeatureMatcherSetI parseFilter(String featureType,
6828 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6830 FeatureMatcherSetI result = new FeatureMatcherSet();
6833 parseFilterConditions(result, matcherSetModel, true);
6834 } catch (IllegalStateException e)
6836 // mixing AND and OR conditions perhaps
6838 String.format("Error reading filter conditions for '%s': %s",
6839 featureType, e.getMessage()));
6840 // return as much as was parsed up to the error
6847 * Adds feature match conditions to matcherSet as unmarshalled from XML
6848 * (possibly recursively for compound conditions)
6851 * @param matcherSetModel
6853 * if true, multiple conditions are AND-ed, else they are OR-ed
6854 * @throws IllegalStateException
6855 * if AND and OR conditions are mixed
6857 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6858 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6861 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6862 .getMatchCondition();
6868 FilterBy filterBy = mc.getBy();
6869 Condition cond = Condition.fromString(mc.getCondition());
6870 String pattern = mc.getValue();
6871 FeatureMatcherI matchCondition = null;
6872 if (filterBy == FilterBy.BY_LABEL)
6874 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6876 else if (filterBy == FilterBy.BY_SCORE)
6878 matchCondition = FeatureMatcher.byScore(cond, pattern);
6881 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6883 final List<String> attributeName = mc.getAttributeName();
6884 String[] attNames = attributeName
6885 .toArray(new String[attributeName.size()]);
6886 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6891 * note this throws IllegalStateException if AND-ing to a
6892 * previously OR-ed compound condition, or vice versa
6896 matcherSet.and(matchCondition);
6900 matcherSet.or(matchCondition);
6906 * compound condition
6908 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6909 .getCompoundMatcher().getMatcherSet();
6910 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6911 if (matchers.size() == 2)
6913 parseFilterConditions(matcherSet, matchers.get(0), anded);
6914 parseFilterConditions(matcherSet, matchers.get(1), anded);
6918 System.err.println("Malformed compound filter condition");
6924 * Loads one XML model of a feature colour to a Jalview object
6926 * @param colourModel
6929 public static FeatureColourI parseColour(Colour colourModel)
6931 FeatureColourI colour = null;
6933 if (colourModel.getMax() != null)
6935 Color mincol = null;
6936 Color maxcol = null;
6937 Color noValueColour = null;
6941 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6942 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6943 } catch (Exception e)
6945 Console.warn("Couldn't parse out graduated feature color.", e);
6948 NoValueColour noCol = colourModel.getNoValueColour();
6949 if (noCol == NoValueColour.MIN)
6951 noValueColour = mincol;
6953 else if (noCol == NoValueColour.MAX)
6955 noValueColour = maxcol;
6958 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6959 safeFloat(colourModel.getMin()),
6960 safeFloat(colourModel.getMax()));
6961 final List<String> attributeName = colourModel.getAttributeName();
6962 String[] attributes = attributeName
6963 .toArray(new String[attributeName.size()]);
6964 if (attributes != null && attributes.length > 0)
6966 colour.setAttributeName(attributes);
6968 if (colourModel.isAutoScale() != null)
6970 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6972 if (colourModel.isColourByLabel() != null)
6974 colour.setColourByLabel(
6975 colourModel.isColourByLabel().booleanValue());
6977 if (colourModel.getThreshold() != null)
6979 colour.setThreshold(colourModel.getThreshold().floatValue());
6981 ThresholdType ttyp = colourModel.getThreshType();
6982 if (ttyp == ThresholdType.ABOVE)
6984 colour.setAboveThreshold(true);
6986 else if (ttyp == ThresholdType.BELOW)
6988 colour.setBelowThreshold(true);
6993 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6994 colour = new FeatureColour(color);
7000 public static void setStateSavedUpToDate(boolean s)
7002 Console.debug("Setting overall stateSavedUpToDate to " + s);
7003 stateSavedUpToDate = s;
7006 public static boolean stateSavedUpToDate()
7008 Console.debug("Returning overall stateSavedUpToDate value: "
7009 + stateSavedUpToDate);
7010 return stateSavedUpToDate;
7013 public static boolean allSavedUpToDate()
7015 if (stateSavedUpToDate()) // nothing happened since last project save
7018 AlignFrame[] frames = Desktop.getAlignFrames();
7021 for (int i = 0; i < frames.length; i++)
7023 if (frames[i] == null)
7025 if (!frames[i].getViewport().savedUpToDate())
7026 return false; // at least one alignment is not individually saved
7032 // used for debugging and tests
7033 private static int debugDelaySave = 20;
7035 public static void setDebugDelaySave(int n)