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 List<AlignFrame> toRepaint=new ArrayList<AlignFrame>();
3141 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3142 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3143 final String file = jprovider.getFilename();
3146 JarInputStream jin = null;
3147 JarEntry jarentry = null;
3152 jin = jprovider.getJarInputStream();
3153 for (int i = 0; i < entryCount; i++)
3155 jarentry = jin.getNextJarEntry();
3158 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3160 JAXBContext jc = JAXBContext
3161 .newInstance("jalview.xml.binding.jalview");
3162 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3163 .createXMLStreamReader(jin);
3164 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3165 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3166 JalviewModel.class);
3167 JalviewModel object = jbe.getValue();
3169 if (true) // !skipViewport(object))
3171 _af = loadFromObject(object, file, true, jprovider);
3172 if (_af != null && object.getViewport().size() > 0)
3173 // getJalviewModelSequence().getViewportCount() > 0)
3178 // store a reference to the first view
3181 if (_af.getViewport().isGatherViewsHere())
3183 // if this is a gathered view, keep its reference since
3184 // after gathering views, only this frame will remain
3186 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3189 // Save dataset to register mappings once all resolved
3190 importedDatasets.put(
3191 af.getViewport().getAlignment().getDataset(),
3192 af.getViewport().getAlignment().getDataset());
3197 else if (jarentry != null)
3199 // Some other file here.
3202 } while (jarentry != null);
3204 resolveFrefedSequences();
3205 for (AlignFrame alignFrame:toRepaint)
3207 alignFrame.repaint();
3209 } catch (IOException ex)
3211 ex.printStackTrace();
3212 errorMessage = "Couldn't locate Jalview XML file : " + file;
3214 "Exception whilst loading jalview XML file : " + ex + "\n");
3215 } catch (Exception ex)
3217 System.err.println("Parsing as Jalview Version 2 file failed.");
3218 ex.printStackTrace(System.err);
3219 if (attemptversion1parse)
3221 // used to attempt to parse as V1 castor-generated xml
3223 if (Desktop.instance != null)
3225 Desktop.instance.stopLoading();
3229 System.out.println("Successfully loaded archive file");
3232 ex.printStackTrace();
3235 "Exception whilst loading jalview XML file : " + ex + "\n");
3236 } catch (OutOfMemoryError e)
3238 // Don't use the OOM Window here
3239 errorMessage = "Out of memory loading jalview XML file";
3240 System.err.println("Out of memory whilst loading jalview XML file");
3241 e.printStackTrace();
3245 * Regather multiple views (with the same sequence set id) to the frame (if
3246 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3247 * views instead of separate frames. Note this doesn't restore a state where
3248 * some expanded views in turn have tabbed views - the last "first tab" read
3249 * in will play the role of gatherer for all.
3251 for (AlignFrame fr : gatherToThisFrame.values())
3253 Desktop.instance.gatherViews(fr);
3256 restoreSplitFrames();
3257 for (AlignmentI ds : importedDatasets.keySet())
3259 if (ds.getCodonFrames() != null)
3261 StructureSelectionManager
3262 .getStructureSelectionManager(Desktop.instance)
3263 .registerMappings(ds.getCodonFrames());
3266 if (errorMessage != null)
3271 if (Desktop.instance != null)
3273 Desktop.instance.stopLoading();
3280 * Try to reconstruct and display SplitFrame windows, where each contains
3281 * complementary dna and protein alignments. Done by pairing up AlignFrame
3282 * objects (created earlier) which have complementary viewport ids associated.
3284 protected void restoreSplitFrames()
3286 List<SplitFrame> gatherTo = new ArrayList<>();
3287 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3288 Map<String, AlignFrame> dna = new HashMap<>();
3291 * Identify the DNA alignments
3293 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3296 AlignFrame af = candidate.getValue();
3297 if (af.getViewport().getAlignment().isNucleotide())
3299 dna.put(candidate.getKey().getId(), af);
3304 * Try to match up the protein complements
3306 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3309 AlignFrame af = candidate.getValue();
3310 if (!af.getViewport().getAlignment().isNucleotide())
3312 String complementId = candidate.getKey().getComplementId();
3313 // only non-null complements should be in the Map
3314 if (complementId != null && dna.containsKey(complementId))
3316 final AlignFrame dnaFrame = dna.get(complementId);
3317 SplitFrame sf = createSplitFrame(dnaFrame, af);
3318 addedToSplitFrames.add(dnaFrame);
3319 addedToSplitFrames.add(af);
3320 dnaFrame.setMenusForViewport();
3321 af.setMenusForViewport();
3322 if (af.getViewport().isGatherViewsHere())
3331 * Open any that we failed to pair up (which shouldn't happen!) as
3332 * standalone AlignFrame's.
3334 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3337 AlignFrame af = candidate.getValue();
3338 if (!addedToSplitFrames.contains(af))
3340 Viewport view = candidate.getKey();
3341 Desktop.addInternalFrame(af, view.getTitle(),
3342 safeInt(view.getWidth()), safeInt(view.getHeight()));
3343 af.setMenusForViewport();
3344 System.err.println("Failed to restore view " + view.getTitle()
3345 + " to split frame");
3350 * Gather back into tabbed views as flagged.
3352 for (SplitFrame sf : gatherTo)
3354 Desktop.instance.gatherViews(sf);
3357 splitFrameCandidates.clear();
3361 * Construct and display one SplitFrame holding DNA and protein alignments.
3364 * @param proteinFrame
3367 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3368 AlignFrame proteinFrame)
3370 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3371 String title = MessageManager.getString("label.linked_view_title");
3372 int width = (int) dnaFrame.getBounds().getWidth();
3373 int height = (int) (dnaFrame.getBounds().getHeight()
3374 + proteinFrame.getBounds().getHeight() + 50);
3377 * SplitFrame location is saved to both enclosed frames
3379 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3380 Desktop.addInternalFrame(splitFrame, title, width, height);
3383 * And compute cDNA consensus (couldn't do earlier with consensus as
3384 * mappings were not yet present)
3386 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3392 * check errorMessage for a valid error message and raise an error box in the
3393 * GUI or write the current errorMessage to stderr and then clear the error
3396 protected void reportErrors()
3398 reportErrors(false);
3401 protected void reportErrors(final boolean saving)
3403 if (errorMessage != null)
3405 final String finalErrorMessage = errorMessage;
3408 javax.swing.SwingUtilities.invokeLater(new Runnable()
3413 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3415 "Error " + (saving ? "saving" : "loading")
3417 JvOptionPane.WARNING_MESSAGE);
3423 System.err.println("Problem loading Jalview file: " + errorMessage);
3426 errorMessage = null;
3429 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3432 * when set, local views will be updated from view stored in JalviewXML
3433 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3434 * sync if this is set to true.
3436 private final boolean updateLocalViews = false;
3439 * Returns the path to a temporary file holding the PDB file for the given PDB
3440 * id. The first time of asking, searches for a file of that name in the
3441 * Jalview project jar, and copies it to a new temporary file. Any repeat
3442 * requests just return the path to the file previously created.
3448 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3451 if (alreadyLoadedPDB.containsKey(pdbId))
3453 return alreadyLoadedPDB.get(pdbId).toString();
3456 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3458 if (tempFile != null)
3460 alreadyLoadedPDB.put(pdbId, tempFile);
3466 * Copies the jar entry of given name to a new temporary file and returns the
3467 * path to the file, or null if the entry is not found.
3470 * @param jarEntryName
3472 * a prefix for the temporary file name, must be at least three
3474 * @param suffixModel
3475 * null or original file - so new file can be given the same suffix
3479 protected String copyJarEntry(jarInputStreamProvider jprovider,
3480 String jarEntryName, String prefix, String suffixModel)
3482 String suffix = ".tmp";
3483 if (suffixModel == null)
3485 suffixModel = jarEntryName;
3487 int sfpos = suffixModel.lastIndexOf(".");
3488 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3490 suffix = "." + suffixModel.substring(sfpos + 1);
3493 try (JarInputStream jin = jprovider.getJarInputStream())
3495 JarEntry entry = null;
3498 entry = jin.getNextJarEntry();
3499 } while (entry != null && !entry.getName().equals(jarEntryName));
3503 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3504 File outFile = File.createTempFile(prefix, suffix);
3505 outFile.deleteOnExit();
3506 try (OutputStream os = new FileOutputStream(outFile))
3510 String t = outFile.getAbsolutePath();
3516 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3518 } catch (Exception ex)
3520 ex.printStackTrace();
3526 private class JvAnnotRow
3528 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3535 * persisted version of annotation row from which to take vis properties
3537 public jalview.datamodel.AlignmentAnnotation template;
3540 * original position of the annotation row in the alignment
3546 * Load alignment frame from jalview XML DOM object
3548 * @param jalviewModel
3551 * filename source string
3552 * @param loadTreesAndStructures
3553 * when false only create Viewport
3555 * data source provider
3556 * @return alignment frame created from view stored in DOM
3558 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3559 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3561 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3563 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3565 // JalviewModelSequence jms = object.getJalviewModelSequence();
3567 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3569 Viewport view = (jalviewModel.getViewport().size() > 0)
3570 ? jalviewModel.getViewport().get(0)
3573 // ////////////////////////////////
3574 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3577 // If we just load in the same jar file again, the sequenceSetId
3578 // will be the same, and we end up with multiple references
3579 // to the same sequenceSet. We must modify this id on load
3580 // so that each load of the file gives a unique id
3583 * used to resolve correct alignment dataset for alignments with multiple
3586 String uniqueSeqSetId = null;
3587 String viewId = null;
3590 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3591 viewId = (view.getId() == null ? null
3592 : view.getId() + uniqueSetSuffix);
3595 // ////////////////////////////////
3596 // LOAD MATRICES (IF ANY)
3598 if (vamsasSet.getMatrix()!=null && vamsasSet.getMatrix().size()>0)
3600 importMatrixData(vamsasSet.getMatrix());
3603 // ////////////////////////////////
3606 List<SequenceI> hiddenSeqs = null;
3608 List<SequenceI> tmpseqs = new ArrayList<>();
3610 boolean multipleView = false;
3611 SequenceI referenceseqForView = null;
3612 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3613 List<JSeq> jseqs = jalviewModel.getJSeq();
3614 int vi = 0; // counter in vamsasSeq array
3615 for (int i = 0; i < jseqs.size(); i++)
3617 JSeq jseq = jseqs.get(i);
3618 String seqId = jseq.getId();
3620 SequenceI tmpSeq = seqRefIds.get(seqId);
3623 if (!incompleteSeqs.containsKey(seqId))
3625 // may not need this check, but keep it for at least 2.9,1 release
3626 if (tmpSeq.getStart() != jseq.getStart()
3627 || tmpSeq.getEnd() != jseq.getEnd())
3629 System.err.println(String.format(
3630 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3631 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3632 jseq.getStart(), jseq.getEnd()));
3637 incompleteSeqs.remove(seqId);
3639 if (vamsasSeqs.size() > vi
3640 && vamsasSeqs.get(vi).getId().equals(seqId))
3642 // most likely we are reading a dataset XML document so
3643 // update from vamsasSeq section of XML for this sequence
3644 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3645 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3646 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3651 // reading multiple views, so vamsasSeq set is a subset of JSeq
3652 multipleView = true;
3654 tmpSeq.setStart(jseq.getStart());
3655 tmpSeq.setEnd(jseq.getEnd());
3656 tmpseqs.add(tmpSeq);
3660 Sequence vamsasSeq = vamsasSeqs.get(vi);
3661 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3662 vamsasSeq.getSequence());
3663 tmpSeq.setDescription(vamsasSeq.getDescription());
3664 tmpSeq.setStart(jseq.getStart());
3665 tmpSeq.setEnd(jseq.getEnd());
3666 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3667 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3668 tmpseqs.add(tmpSeq);
3672 if (safeBoolean(jseq.isViewreference()))
3674 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3677 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3679 if (hiddenSeqs == null)
3681 hiddenSeqs = new ArrayList<>();
3684 hiddenSeqs.add(tmpSeq);
3689 // Create the alignment object from the sequence set
3690 // ///////////////////////////////
3691 SequenceI[] orderedSeqs = tmpseqs
3692 .toArray(new SequenceI[tmpseqs.size()]);
3694 AlignmentI al = null;
3695 // so we must create or recover the dataset alignment before going further
3696 // ///////////////////////////////
3697 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3699 // older jalview projects do not have a dataset - so creat alignment and
3701 al = new Alignment(orderedSeqs);
3702 al.setDataset(null);
3706 boolean isdsal = jalviewModel.getViewport().isEmpty();
3709 // we are importing a dataset record, so
3710 // recover reference to an alignment already materialsed as dataset
3711 al = getDatasetFor(vamsasSet.getDatasetId());
3715 // materialse the alignment
3716 al = new Alignment(orderedSeqs);
3720 addDatasetRef(vamsasSet.getDatasetId(), al);
3723 // finally, verify all data in vamsasSet is actually present in al
3724 // passing on flag indicating if it is actually a stored dataset
3725 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3728 if (referenceseqForView != null)
3730 al.setSeqrep(referenceseqForView);
3732 // / Add the alignment properties
3733 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3735 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3737 al.setProperty(ssp.getKey(), ssp.getValue());
3740 // ///////////////////////////////
3742 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3745 // load sequence features, database references and any associated PDB
3746 // structures for the alignment
3748 // prior to 2.10, this part would only be executed the first time a
3749 // sequence was encountered, but not afterwards.
3750 // now, for 2.10 projects, this is also done if the xml doc includes
3751 // dataset sequences not actually present in any particular view.
3753 for (int i = 0; i < vamsasSeqs.size(); i++)
3755 JSeq jseq = jseqs.get(i);
3756 if (jseq.getFeatures().size() > 0)
3758 List<Feature> features = jseq.getFeatures();
3759 for (int f = 0; f < features.size(); f++)
3761 Feature feat = features.get(f);
3762 SequenceFeature sf = new SequenceFeature(feat.getType(),
3763 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3764 safeFloat(feat.getScore()), feat.getFeatureGroup());
3765 sf.setStatus(feat.getStatus());
3768 * load any feature attributes - include map-valued attributes
3770 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3771 for (int od = 0; od < feat.getOtherData().size(); od++)
3773 OtherData keyValue = feat.getOtherData().get(od);
3774 String attributeName = keyValue.getKey();
3775 String attributeValue = keyValue.getValue();
3776 if (attributeName.startsWith("LINK"))
3778 sf.addLink(attributeValue);
3782 String subAttribute = keyValue.getKey2();
3783 if (subAttribute == null)
3785 // simple string-valued attribute
3786 sf.setValue(attributeName, attributeValue);
3790 // attribute 'key' has sub-attribute 'key2'
3791 if (!mapAttributes.containsKey(attributeName))
3793 mapAttributes.put(attributeName, new HashMap<>());
3795 mapAttributes.get(attributeName).put(subAttribute,
3800 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3803 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3806 // adds feature to datasequence's feature set (since Jalview 2.10)
3807 al.getSequenceAt(i).addSequenceFeature(sf);
3810 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3812 // adds dbrefs to datasequence's set (since Jalview 2.10)
3814 al.getSequenceAt(i).getDatasetSequence() == null
3815 ? al.getSequenceAt(i)
3816 : al.getSequenceAt(i).getDatasetSequence(),
3819 if (jseq.getPdbids().size() > 0)
3821 List<Pdbids> ids = jseq.getPdbids();
3822 for (int p = 0; p < ids.size(); p++)
3824 Pdbids pdbid = ids.get(p);
3825 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3826 entry.setId(pdbid.getId());
3827 if (pdbid.getType() != null)
3829 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3831 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3835 entry.setType(PDBEntry.Type.FILE);
3838 // jprovider is null when executing 'New View'
3839 if (pdbid.getFile() != null && jprovider != null)
3841 if (!pdbloaded.containsKey(pdbid.getFile()))
3843 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3848 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3852 if (pdbid.getPdbentryItem() != null)
3854 for (PdbentryItem item : pdbid.getPdbentryItem())
3856 for (Property pr : item.getProperty())
3858 entry.setProperty(pr.getName(), pr.getValue());
3863 for (Property prop : pdbid.getProperty())
3865 entry.setProperty(prop.getName(), prop.getValue());
3867 StructureSelectionManager
3868 .getStructureSelectionManager(Desktop.instance)
3869 .registerPDBEntry(entry);
3870 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3871 if (al.getSequenceAt(i).getDatasetSequence() != null)
3873 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3877 al.getSequenceAt(i).addPDBId(entry);
3882 } // end !multipleview
3884 // ///////////////////////////////
3885 // LOAD SEQUENCE MAPPINGS
3887 if (vamsasSet.getAlcodonFrame().size() > 0)
3889 // TODO Potentially this should only be done once for all views of an
3891 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3892 for (int i = 0; i < alc.size(); i++)
3894 AlignedCodonFrame cf = new AlignedCodonFrame();
3895 if (alc.get(i).getAlcodMap().size() > 0)
3897 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3898 for (int m = 0; m < maps.size(); m++)
3900 AlcodMap map = maps.get(m);
3901 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3903 jalview.datamodel.Mapping mapping = null;
3904 // attach to dna sequence reference.
3905 if (map.getMapping() != null)
3907 mapping = addMapping(map.getMapping());
3908 if (dnaseq != null && mapping.getTo() != null)
3910 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3916 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3920 al.addCodonFrame(cf);
3925 // ////////////////////////////////
3927 List<JvAnnotRow> autoAlan = new ArrayList<>();
3930 * store any annotations which forward reference a group's ID
3932 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3934 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3936 List<Annotation> an = vamsasSet.getAnnotation();
3938 for (int i = 0; i < an.size(); i++)
3940 Annotation annotation = an.get(i);
3943 * test if annotation is automatically calculated for this view only
3945 boolean autoForView = false;
3946 if (annotation.getLabel().equals("Quality")
3947 || annotation.getLabel().equals("Conservation")
3948 || annotation.getLabel().equals("Consensus"))
3950 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3952 // JAXB has no has() test; schema defaults value to false
3953 // if (!annotation.hasAutoCalculated())
3955 // annotation.setAutoCalculated(true);
3958 if (autoForView || annotation.isAutoCalculated())
3960 // remove ID - we don't recover annotation from other views for
3961 // view-specific annotation
3962 annotation.setId(null);
3965 // set visibility for other annotation in this view
3966 String annotationId = annotation.getId();
3967 if (annotationId != null && annotationIds.containsKey(annotationId))
3969 AlignmentAnnotation jda = annotationIds.get(annotationId);
3970 // in principle Visible should always be true for annotation displayed
3971 // in multiple views
3972 if (annotation.isVisible() != null)
3974 jda.visible = annotation.isVisible();
3977 al.addAnnotation(jda);
3981 // Construct new annotation from model.
3982 List<AnnotationElement> ae = annotation.getAnnotationElement();
3983 jalview.datamodel.Annotation[] anot = null;
3984 java.awt.Color firstColour = null;
3986 if (!annotation.isScoreOnly())
3988 anot = new jalview.datamodel.Annotation[al.getWidth()];
3989 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3991 AnnotationElement annElement = ae.get(aa);
3992 anpos = annElement.getPosition();
3994 if (anpos >= anot.length)
3999 float value = safeFloat(annElement.getValue());
4000 anot[anpos] = new jalview.datamodel.Annotation(
4001 annElement.getDisplayCharacter(),
4002 annElement.getDescription(),
4003 (annElement.getSecondaryStructure() == null
4004 || annElement.getSecondaryStructure()
4008 .getSecondaryStructure()
4011 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4012 if (firstColour == null)
4014 firstColour = anot[anpos].colour;
4018 jalview.datamodel.AlignmentAnnotation jaa = null;
4020 if (annotation.isGraph())
4022 float llim = 0, hlim = 0;
4023 // if (autoForView || an[i].isAutoCalculated()) {
4026 jaa = new jalview.datamodel.AlignmentAnnotation(
4027 annotation.getLabel(), annotation.getDescription(), anot,
4028 llim, hlim, safeInt(annotation.getGraphType()));
4030 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4031 jaa._linecolour = firstColour;
4032 if (annotation.getThresholdLine() != null)
4034 jaa.setThreshold(new jalview.datamodel.GraphLine(
4035 safeFloat(annotation.getThresholdLine().getValue()),
4036 annotation.getThresholdLine().getLabel(),
4037 new java.awt.Color(safeInt(
4038 annotation.getThresholdLine().getColour()))));
4040 if (autoForView || annotation.isAutoCalculated())
4042 // Hardwire the symbol display line to ensure that labels for
4043 // histograms are displayed
4049 jaa = new jalview.datamodel.AlignmentAnnotation(
4050 annotation.getLabel(), annotation.getDescription(), anot);
4051 jaa._linecolour = firstColour;
4053 // register new annotation
4054 if (annotation.getId() != null)
4056 annotationIds.put(annotation.getId(), jaa);
4057 jaa.annotationId = annotation.getId();
4059 // recover sequence association
4060 String sequenceRef = annotation.getSequenceRef();
4061 if (sequenceRef != null)
4063 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4064 SequenceI sequence = seqRefIds.get(sequenceRef);
4065 if (sequence == null)
4067 // in pre-2.9 projects sequence ref is to sequence name
4068 sequence = al.findName(sequenceRef);
4070 if (sequence != null)
4072 jaa.createSequenceMapping(sequence, 1, true);
4073 sequence.addAlignmentAnnotation(jaa);
4076 // and make a note of any group association
4077 if (annotation.getGroupRef() != null
4078 && annotation.getGroupRef().length() > 0)
4080 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4081 .get(annotation.getGroupRef());
4084 aal = new ArrayList<>();
4085 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4090 if (annotation.getScore() != null)
4092 jaa.setScore(annotation.getScore().doubleValue());
4094 if (annotation.isVisible() != null)
4096 jaa.visible = annotation.isVisible().booleanValue();
4099 if (annotation.isCentreColLabels() != null)
4101 jaa.centreColLabels = annotation.isCentreColLabels()
4105 if (annotation.isScaleColLabels() != null)
4107 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4109 if (annotation.isAutoCalculated())
4111 // newer files have an 'autoCalculated' flag and store calculation
4112 // state in viewport properties
4113 jaa.autoCalculated = true; // means annotation will be marked for
4114 // update at end of load.
4116 if (annotation.getGraphHeight() != null)
4118 jaa.graphHeight = annotation.getGraphHeight().intValue();
4120 jaa.belowAlignment = annotation.isBelowAlignment();
4121 jaa.setCalcId(annotation.getCalcId());
4122 if (annotation.getProperty().size() > 0)
4124 for (jalview.xml.binding.jalview.Property prop : annotation
4127 jaa.setProperty(prop.getName(), prop.getValue());
4130 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4132 if (annotation.getContactmatrix() != null
4133 && annotation.getContactmatrix().size() > 0)
4135 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4137 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4142 if (jaa.autoCalculated)
4144 autoAlan.add(new JvAnnotRow(i, jaa));
4147 // if (!autoForView)
4149 // add autocalculated group annotation and any user created annotation
4151 al.addAnnotation(jaa);
4155 // ///////////////////////
4157 // Create alignment markup and styles for this view
4158 if (jalviewModel.getJGroup().size() > 0)
4160 List<JGroup> groups = jalviewModel.getJGroup();
4161 boolean addAnnotSchemeGroup = false;
4162 for (int i = 0; i < groups.size(); i++)
4164 JGroup jGroup = groups.get(i);
4165 ColourSchemeI cs = null;
4166 if (jGroup.getColour() != null)
4168 if (jGroup.getColour().startsWith("ucs"))
4170 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4172 else if (jGroup.getColour().equals("AnnotationColourGradient")
4173 && jGroup.getAnnotationColours() != null)
4175 addAnnotSchemeGroup = true;
4179 cs = ColourSchemeProperty.getColourScheme(null, al,
4180 jGroup.getColour());
4183 int pidThreshold = safeInt(jGroup.getPidThreshold());
4185 Vector<SequenceI> seqs = new Vector<>();
4187 for (int s = 0; s < jGroup.getSeq().size(); s++)
4189 String seqId = jGroup.getSeq().get(s);
4190 SequenceI ts = seqRefIds.get(seqId);
4194 seqs.addElement(ts);
4198 if (seqs.size() < 1)
4203 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4204 safeBoolean(jGroup.isDisplayBoxes()),
4205 safeBoolean(jGroup.isDisplayText()),
4206 safeBoolean(jGroup.isColourText()),
4207 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4208 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4209 sg.getGroupColourScheme()
4210 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4211 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4213 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4214 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4215 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4216 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4217 // attributes with a default in the schema are never null
4218 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4219 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4220 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4221 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4222 if (jGroup.getConsThreshold() != null
4223 && jGroup.getConsThreshold().intValue() != 0)
4225 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4228 c.verdict(false, 25);
4229 sg.cs.setConservation(c);
4232 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4234 // re-instate unique group/annotation row reference
4235 List<AlignmentAnnotation> jaal = groupAnnotRefs
4236 .get(jGroup.getId());
4239 for (AlignmentAnnotation jaa : jaal)
4242 if (jaa.autoCalculated)
4244 // match up and try to set group autocalc alignment row for this
4246 if (jaa.label.startsWith("Consensus for "))
4248 sg.setConsensus(jaa);
4250 // match up and try to set group autocalc alignment row for this
4252 if (jaa.label.startsWith("Conservation for "))
4254 sg.setConservationRow(jaa);
4261 if (addAnnotSchemeGroup)
4263 // reconstruct the annotation colourscheme
4265 constructAnnotationColour(jGroup.getAnnotationColours(),
4266 null, al, jalviewModel, false));
4272 // only dataset in this model, so just return.
4275 // ///////////////////////////////
4278 AlignFrame af = null;
4279 AlignViewport av = null;
4280 // now check to see if we really need to create a new viewport.
4281 if (multipleView && viewportsAdded.size() == 0)
4283 // We recovered an alignment for which a viewport already exists.
4284 // TODO: fix up any settings necessary for overlaying stored state onto
4285 // state recovered from another document. (may not be necessary).
4286 // we may need a binding from a viewport in memory to one recovered from
4288 // and then recover its containing af to allow the settings to be applied.
4289 // TODO: fix for vamsas demo
4291 "About to recover a viewport for existing alignment: Sequence set ID is "
4293 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4294 if (seqsetobj != null)
4296 if (seqsetobj instanceof String)
4298 uniqueSeqSetId = (String) seqsetobj;
4300 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4306 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4312 * indicate that annotation colours are applied across all groups (pre
4313 * Jalview 2.8.1 behaviour)
4315 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4316 jalviewModel.getVersion());
4318 AlignmentPanel ap = null;
4319 boolean isnewview = true;
4322 // Check to see if this alignment already has a view id == viewId
4323 jalview.gui.AlignmentPanel views[] = Desktop
4324 .getAlignmentPanels(uniqueSeqSetId);
4325 if (views != null && views.length > 0)
4327 for (int v = 0; v < views.length; v++)
4329 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4331 // recover the existing alignpanel, alignframe, viewport
4332 af = views[v].alignFrame;
4335 // TODO: could even skip resetting view settings if we don't want to
4336 // change the local settings from other jalview processes
4345 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4346 uniqueSeqSetId, viewId, autoAlan);
4347 av = af.getViewport();
4352 * Load any trees, PDB structures and viewers, Overview
4354 * Not done if flag is false (when this method is used for New View)
4356 if (loadTreesAndStructures)
4358 loadTrees(jalviewModel, view, af, av, ap);
4359 loadPCAViewers(jalviewModel, ap);
4360 loadPDBStructures(jprovider, jseqs, af, ap);
4361 loadRnaViewers(jprovider, jseqs, ap);
4362 loadOverview(view, jalviewModel.getVersion(), af);
4364 // and finally return.
4368 private void importMatrixData(List<MatrixType> xmlmatrices)
4370 for (MatrixType xmlmat:xmlmatrices)
4372 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4374 Console.error("Ignoring matrix '"+xmlmat.getId()+"' of type '"+xmlmat.getType());
4378 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4380 Console.error("Can't handle non square matrices");
4384 float[][] elements = ContactMatrix
4385 .fromFloatStringToContacts(xmlmat.getElements(),
4386 xmlmat.getCols().intValue(),
4387 xmlmat.getRows().intValue());
4389 List<BitSet> newgroups = new ArrayList<BitSet>();
4390 if (xmlmat.getGroups().size() > 0)
4392 for (String sgroup : xmlmat.getGroups())
4394 newgroups.add(deStringifyBitset(sgroup));
4397 String nwk = xmlmat.getNewick().size() > 0
4398 ? xmlmat.getNewick().get(0)
4400 if (xmlmat.getNewick().size() > 1)
4403 "Ignoring additional clusterings for contact matrix");
4405 String treeMethod = xmlmat.getTreeMethod();
4406 double thresh = xmlmat.getCutHeight() != null
4407 ? xmlmat.getCutHeight()
4409 GroupSet grpset = new GroupSet();
4410 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4412 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4413 contactMatrixRefs.put(xmlmat.getId(), newcm);
4414 Console.trace("Restored base contact matrix "+xmlmat.getId());
4418 private void restoreMatrixFor(SequenceI sequenceRef,
4419 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4421 // restore mapping data to matrix data
4422 jalview.util.MapList mapping = null;
4423 if (xmlmatmapping.getMapping() != null)
4425 MapListType m = xmlmatmapping.getMapping();
4426 // Mapping m = dr.getMapping();
4427 int fr[] = new int[m.getMapListFrom().size() * 2];
4428 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4429 for (int _i = 0; from.hasNext(); _i += 2)
4431 MapListFrom mf = from.next();
4432 fr[_i] = mf.getStart();
4433 fr[_i + 1] = mf.getEnd();
4435 int fto[] = new int[m.getMapListTo().size() * 2];
4436 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4437 for (int _i = 0; to.hasNext(); _i += 2)
4439 MapListTo mf = to.next();
4440 fto[_i] = mf.getStart();
4441 fto[_i + 1] = mf.getEnd();
4444 mapping = new jalview.util.MapList(fr, fto,
4445 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4448 // locate matrix data in project XML and import
4449 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4453 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4457 // create the PAEMatrix now
4458 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4461 jaa.sequenceRef.addContactListFor(jaa, newpae);
4468 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4469 * and geometry as saved
4474 protected void loadOverview(Viewport view, String version, AlignFrame af)
4476 if (!isVersionStringLaterThan("2.11.3", version)
4477 && view.getOverview() == null)
4482 * first close any Overview that was opened automatically
4483 * (if so configured in Preferences) so that the view is
4484 * restored in the same state as saved
4486 af.alignPanel.closeOverviewPanel();
4488 Overview overview = view.getOverview();
4489 if (overview != null)
4491 OverviewPanel overviewPanel = af
4492 .openOverviewPanel(overview.isShowHidden());
4493 overviewPanel.setTitle(overview.getTitle());
4494 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4495 overview.getWidth(), overview.getHeight());
4496 Color gap = new Color(overview.getGapColour());
4497 Color residue = new Color(overview.getResidueColour());
4498 Color hidden = new Color(overview.getHiddenColour());
4499 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4504 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4505 * panel is restored from separate jar entries, two (gapped and trimmed) per
4506 * sequence and secondary structure.
4508 * Currently each viewer shows just one sequence and structure (gapped and
4509 * trimmed), however this method is designed to support multiple sequences or
4510 * structures in viewers if wanted in future.
4516 private void loadRnaViewers(jarInputStreamProvider jprovider,
4517 List<JSeq> jseqs, AlignmentPanel ap)
4520 * scan the sequences for references to viewers; create each one the first
4521 * time it is referenced, add Rna models to existing viewers
4523 for (JSeq jseq : jseqs)
4525 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4527 RnaViewer viewer = jseq.getRnaViewer().get(i);
4528 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4531 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4533 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4534 SequenceI seq = seqRefIds.get(jseq.getId());
4535 AlignmentAnnotation ann = this.annotationIds
4536 .get(ss.getAnnotationId());
4539 * add the structure to the Varna display (with session state copied
4540 * from the jar to a temporary file)
4542 boolean gapped = safeBoolean(ss.isGapped());
4543 String rnaTitle = ss.getTitle();
4544 String sessionState = ss.getViewerState();
4545 String tempStateFile = copyJarEntry(jprovider, sessionState,
4547 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4548 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4550 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4556 * Locate and return an already instantiated matching AppVarna, or create one
4560 * @param viewIdSuffix
4564 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4565 String viewIdSuffix, AlignmentPanel ap)
4568 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4569 * if load is repeated
4571 String postLoadId = viewer.getViewId() + viewIdSuffix;
4572 for (JInternalFrame frame : getAllFrames())
4574 if (frame instanceof AppVarna)
4576 AppVarna varna = (AppVarna) frame;
4577 if (postLoadId.equals(varna.getViewId()))
4579 // this viewer is already instantiated
4580 // could in future here add ap as another 'parent' of the
4581 // AppVarna window; currently just 1-to-many
4588 * viewer not found - make it
4590 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4591 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4592 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4593 safeInt(viewer.getDividerLocation()));
4594 AppVarna varna = new AppVarna(model, ap);
4600 * Load any saved trees
4608 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4609 AlignViewport av, AlignmentPanel ap)
4611 // TODO result of automated refactoring - are all these parameters needed?
4614 for (int t = 0; t < jm.getTree().size(); t++)
4617 Tree tree = jm.getTree().get(t);
4619 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4622 if (tree.isColumnWise())
4624 AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds
4625 .get(tree.getColumnReference());
4629 "Null alignment annotation when restoring columnwise tree");
4631 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4632 tree.getTitle(), safeInt(tree.getWidth()),
4633 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4634 safeInt(tree.getYpos()));
4639 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4640 tree.getTitle(), safeInt(tree.getWidth()),
4641 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4642 safeInt(tree.getYpos()));
4644 if (tree.getId() != null)
4646 // perhaps bind the tree id to something ?
4651 // update local tree attributes ?
4652 // TODO: should check if tp has been manipulated by user - if so its
4653 // settings shouldn't be modified
4654 tp.setTitle(tree.getTitle());
4655 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4656 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4657 safeInt(tree.getHeight())));
4658 tp.setViewport(av); // af.viewport;
4659 // TODO: verify 'associate with all views' works still
4660 tp.getTreeCanvas().setViewport(av); // af.viewport;
4661 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4663 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4667 "There was a problem recovering stored Newick tree: \n"
4668 + tree.getNewick());
4672 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4673 tp.fitToWindow_actionPerformed(null);
4675 if (tree.getFontName() != null)
4678 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4679 safeInt(tree.getFontSize())));
4684 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4685 safeInt(view.getFontSize())));
4688 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4689 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4690 tp.showDistances(safeBoolean(tree.isShowDistances()));
4692 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4694 if (safeBoolean(tree.isCurrentTree()))
4696 af.getViewport().setCurrentTree(tp.getTree());
4700 } catch (Exception ex)
4702 ex.printStackTrace();
4707 * Load and link any saved structure viewers.
4714 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4715 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4718 * Run through all PDB ids on the alignment, and collect mappings between
4719 * distinct view ids and all sequences referring to that view.
4721 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4723 for (int i = 0; i < jseqs.size(); i++)
4725 JSeq jseq = jseqs.get(i);
4726 if (jseq.getPdbids().size() > 0)
4728 List<Pdbids> ids = jseq.getPdbids();
4729 for (int p = 0; p < ids.size(); p++)
4731 Pdbids pdbid = ids.get(p);
4732 final int structureStateCount = pdbid.getStructureState().size();
4733 for (int s = 0; s < structureStateCount; s++)
4735 // check to see if we haven't already created this structure view
4736 final StructureState structureState = pdbid.getStructureState()
4738 String sviewid = (structureState.getViewId() == null) ? null
4739 : structureState.getViewId() + uniqueSetSuffix;
4740 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4741 // Originally : pdbid.getFile()
4742 // : TODO: verify external PDB file recovery still works in normal
4743 // jalview project load
4745 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4746 jpdb.setId(pdbid.getId());
4748 int x = safeInt(structureState.getXpos());
4749 int y = safeInt(structureState.getYpos());
4750 int width = safeInt(structureState.getWidth());
4751 int height = safeInt(structureState.getHeight());
4753 // Probably don't need to do this anymore...
4754 // Desktop.desktop.getComponentAt(x, y);
4755 // TODO: NOW: check that this recovers the PDB file correctly.
4756 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4758 jalview.datamodel.SequenceI seq = seqRefIds
4759 .get(jseq.getId() + "");
4760 if (sviewid == null)
4762 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4765 if (!structureViewers.containsKey(sviewid))
4767 String viewerType = structureState.getType();
4768 if (viewerType == null) // pre Jalview 2.9
4770 viewerType = ViewerType.JMOL.toString();
4772 structureViewers.put(sviewid,
4773 new StructureViewerModel(x, y, width, height, false,
4774 false, true, structureState.getViewId(),
4776 // Legacy pre-2.7 conversion JAL-823 :
4777 // do not assume any view has to be linked for colour by
4781 // assemble String[] { pdb files }, String[] { id for each
4782 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4783 // seqs_file 2}, boolean[] {
4784 // linkAlignPanel,superposeWithAlignpanel}} from hash
4785 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4786 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4787 || structureState.isAlignwithAlignPanel());
4790 * Default colour by linked panel to false if not specified (e.g.
4791 * for pre-2.7 projects)
4793 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4794 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4795 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4798 * Default colour by viewer to true if not specified (e.g. for
4801 boolean colourByViewer = jmoldat.isColourByViewer();
4802 colourByViewer &= structureState.isColourByJmol();
4803 jmoldat.setColourByViewer(colourByViewer);
4805 if (jmoldat.getStateData().length() < structureState.getValue()
4806 /*Content()*/.length())
4808 jmoldat.setStateData(structureState.getValue());// Content());
4810 if (pdbid.getFile() != null)
4812 File mapkey = new File(pdbid.getFile());
4813 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4814 if (seqstrmaps == null)
4816 jmoldat.getFileData().put(mapkey,
4817 seqstrmaps = jmoldat.new StructureData(pdbFile,
4820 if (!seqstrmaps.getSeqList().contains(seq))
4822 seqstrmaps.getSeqList().add(seq);
4828 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");
4829 Console.warn(errorMessage);
4835 // Instantiate the associated structure views
4836 for (Entry<String, StructureViewerModel> entry : structureViewers
4841 createOrLinkStructureViewer(entry, af, ap, jprovider);
4842 } catch (Exception e)
4845 "Error loading structure viewer: " + e.getMessage());
4846 // failed - try the next one
4858 protected void createOrLinkStructureViewer(
4859 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4860 AlignmentPanel ap, jarInputStreamProvider jprovider)
4862 final StructureViewerModel stateData = viewerData.getValue();
4865 * Search for any viewer windows already open from other alignment views
4866 * that exactly match the stored structure state
4868 StructureViewerBase comp = findMatchingViewer(viewerData);
4872 linkStructureViewer(ap, comp, stateData);
4876 String type = stateData.getType();
4879 ViewerType viewerType = ViewerType.valueOf(type);
4880 createStructureViewer(viewerType, viewerData, af, jprovider);
4881 } catch (IllegalArgumentException | NullPointerException e)
4883 // TODO JAL-3619 show error dialog / offer an alternative viewer
4884 Console.error("Invalid structure viewer type: " + type);
4889 * Generates a name for the entry in the project jar file to hold state
4890 * information for a structure viewer
4895 protected String getViewerJarEntryName(String viewId)
4897 return VIEWER_PREFIX + viewId;
4901 * Returns any open frame that matches given structure viewer data. The match
4902 * is based on the unique viewId, or (for older project versions) the frame's
4908 protected StructureViewerBase findMatchingViewer(
4909 Entry<String, StructureViewerModel> viewerData)
4911 final String sviewid = viewerData.getKey();
4912 final StructureViewerModel svattrib = viewerData.getValue();
4913 StructureViewerBase comp = null;
4914 JInternalFrame[] frames = getAllFrames();
4915 for (JInternalFrame frame : frames)
4917 if (frame instanceof StructureViewerBase)
4920 * Post jalview 2.4 schema includes structure view id
4922 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4925 comp = (StructureViewerBase) frame;
4926 break; // break added in 2.9
4929 * Otherwise test for matching position and size of viewer frame
4931 else if (frame.getX() == svattrib.getX()
4932 && frame.getY() == svattrib.getY()
4933 && frame.getHeight() == svattrib.getHeight()
4934 && frame.getWidth() == svattrib.getWidth())
4936 comp = (StructureViewerBase) frame;
4937 // no break in faint hope of an exact match on viewId
4945 * Link an AlignmentPanel to an existing structure viewer.
4950 * @param useinViewerSuperpos
4951 * @param usetoColourbyseq
4952 * @param viewerColouring
4954 protected void linkStructureViewer(AlignmentPanel ap,
4955 StructureViewerBase viewer, StructureViewerModel stateData)
4957 // NOTE: if the jalview project is part of a shared session then
4958 // view synchronization should/could be done here.
4960 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4961 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4962 final boolean viewerColouring = stateData.isColourByViewer();
4963 Map<File, StructureData> oldFiles = stateData.getFileData();
4966 * Add mapping for sequences in this view to an already open viewer
4968 final AAStructureBindingModel binding = viewer.getBinding();
4969 for (File id : oldFiles.keySet())
4971 // add this and any other pdb files that should be present in the
4973 StructureData filedat = oldFiles.get(id);
4974 String pdbFile = filedat.getFilePath();
4975 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4976 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4978 binding.addSequenceForStructFile(pdbFile, seq);
4980 // and add the AlignmentPanel's reference to the view panel
4981 viewer.addAlignmentPanel(ap);
4982 if (useinViewerSuperpos)
4984 viewer.useAlignmentPanelForSuperposition(ap);
4988 viewer.excludeAlignmentPanelForSuperposition(ap);
4990 if (usetoColourbyseq)
4992 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4996 viewer.excludeAlignmentPanelForColourbyseq(ap);
5001 * Get all frames within the Desktop.
5005 protected JInternalFrame[] getAllFrames()
5007 JInternalFrame[] frames = null;
5008 // TODO is this necessary - is it safe - risk of hanging?
5013 frames = Desktop.desktop.getAllFrames();
5014 } catch (ArrayIndexOutOfBoundsException e)
5016 // occasional No such child exceptions are thrown here...
5020 } catch (InterruptedException f)
5024 } while (frames == null);
5029 * Answers true if 'version' is equal to or later than 'supported', where each
5030 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5031 * changes. Development and test values for 'version' are leniently treated
5035 * - minimum version we are comparing against
5037 * - version of data being processsed
5038 * @return true if version is equal to or later than supported
5040 public static boolean isVersionStringLaterThan(String supported,
5043 if (supported == null || version == null
5044 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5045 || version.equalsIgnoreCase("Test")
5046 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5048 System.err.println("Assuming project file with "
5049 + (version == null ? "null" : version)
5050 + " is compatible with Jalview version " + supported);
5055 return StringUtils.compareVersions(version, supported, "b") >= 0;
5059 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5061 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5063 if (newStructureViewers != null)
5065 sview.getBinding().setFinishedLoadingFromArchive(false);
5066 newStructureViewers.add(sview);
5070 protected void setLoadingFinishedForNewStructureViewers()
5072 if (newStructureViewers != null)
5074 for (JalviewStructureDisplayI sview : newStructureViewers)
5076 sview.getBinding().setFinishedLoadingFromArchive(true);
5078 newStructureViewers.clear();
5079 newStructureViewers = null;
5083 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5084 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5085 Viewport view, String uniqueSeqSetId, String viewId,
5086 List<JvAnnotRow> autoAlan)
5088 AlignFrame af = null;
5089 af = new AlignFrame(al, safeInt(view.getWidth()),
5090 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5094 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5095 // System.out.println("Jalview2XML AF " + e);
5096 // super.processKeyEvent(e);
5103 af.setFileName(file, FileFormat.Jalview);
5105 final AlignViewport viewport = af.getViewport();
5106 for (int i = 0; i < JSEQ.size(); i++)
5108 int colour = safeInt(JSEQ.get(i).getColour());
5109 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5115 viewport.setColourByReferenceSeq(true);
5116 viewport.setDisplayReferenceSeq(true);
5119 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5121 if (view.getSequenceSetId() != null)
5123 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5125 viewport.setSequenceSetId(uniqueSeqSetId);
5128 // propagate shared settings to this new view
5129 viewport.setHistoryList(av.getHistoryList());
5130 viewport.setRedoList(av.getRedoList());
5134 viewportsAdded.put(uniqueSeqSetId, viewport);
5136 // TODO: check if this method can be called repeatedly without
5137 // side-effects if alignpanel already registered.
5138 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5140 // apply Hidden regions to view.
5141 if (hiddenSeqs != null)
5143 for (int s = 0; s < JSEQ.size(); s++)
5145 SequenceGroup hidden = new SequenceGroup();
5146 boolean isRepresentative = false;
5147 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5149 isRepresentative = true;
5150 SequenceI sequenceToHide = al
5151 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5152 hidden.addSequence(sequenceToHide, false);
5153 // remove from hiddenSeqs list so we don't try to hide it twice
5154 hiddenSeqs.remove(sequenceToHide);
5156 if (isRepresentative)
5158 SequenceI representativeSequence = al.getSequenceAt(s);
5159 hidden.addSequence(representativeSequence, false);
5160 viewport.hideRepSequences(representativeSequence, hidden);
5164 SequenceI[] hseqs = hiddenSeqs
5165 .toArray(new SequenceI[hiddenSeqs.size()]);
5166 viewport.hideSequence(hseqs);
5169 // recover view properties and display parameters
5171 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5172 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5173 final int pidThreshold = safeInt(view.getPidThreshold());
5174 viewport.setThreshold(pidThreshold);
5176 viewport.setColourText(safeBoolean(view.isShowColourText()));
5178 viewport.setConservationSelected(
5179 safeBoolean(view.isConservationSelected()));
5180 viewport.setIncrement(safeInt(view.getConsThreshold()));
5181 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5182 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5184 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5185 safeInt(view.getFontSize())),
5186 (view.getCharWidth() != null) ? false : true);
5187 if (view.getCharWidth() != null)
5189 viewport.setCharWidth(view.getCharWidth());
5190 viewport.setCharHeight(view.getCharHeight());
5192 ViewStyleI vs = viewport.getViewStyle();
5193 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5194 viewport.setViewStyle(vs);
5195 // TODO: allow custom charWidth/Heights to be restored by updating them
5196 // after setting font - which means set above to false
5197 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5198 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5199 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5201 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5203 viewport.setShowText(safeBoolean(view.isShowText()));
5205 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5206 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5207 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5208 viewport.setShowUnconserved(view.isShowUnconserved());
5209 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5211 if (view.getViewName() != null)
5213 viewport.setViewName(view.getViewName());
5214 af.setInitialTabVisible();
5216 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5217 safeInt(view.getWidth()), safeInt(view.getHeight()));
5218 // startSeq set in af.alignPanel.updateLayout below
5219 af.alignPanel.updateLayout();
5220 ColourSchemeI cs = null;
5221 // apply colourschemes
5222 if (view.getBgColour() != null)
5224 if (view.getBgColour().startsWith("ucs"))
5226 cs = getUserColourScheme(jm, view.getBgColour());
5228 else if (view.getBgColour().startsWith("Annotation"))
5230 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5231 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5238 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5239 view.getBgColour());
5244 * turn off 'alignment colour applies to all groups'
5245 * while restoring global colour scheme
5247 viewport.setColourAppliesToAllGroups(false);
5248 viewport.setGlobalColourScheme(cs);
5249 viewport.getResidueShading().setThreshold(pidThreshold,
5250 view.isIgnoreGapsinConsensus());
5251 viewport.getResidueShading()
5252 .setConsensus(viewport.getSequenceConsensusHash());
5253 if (safeBoolean(view.isConservationSelected()) && cs != null)
5255 viewport.getResidueShading()
5256 .setConservationInc(safeInt(view.getConsThreshold()));
5258 af.changeColour(cs);
5259 viewport.setColourAppliesToAllGroups(true);
5261 viewport.setShowSequenceFeatures(
5262 safeBoolean(view.isShowSequenceFeatures()));
5264 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5265 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5266 viewport.setFollowHighlight(view.isFollowHighlight());
5267 viewport.followSelection = view.isFollowSelection();
5268 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5269 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5270 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5271 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5272 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5273 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5274 viewport.setShowGroupConservation(view.isShowGroupConservation());
5275 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5276 viewport.setShowComplementFeaturesOnTop(
5277 view.isShowComplementFeaturesOnTop());
5279 // recover feature settings
5280 if (jm.getFeatureSettings() != null)
5282 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5283 .getFeatureRenderer();
5284 FeaturesDisplayed fdi;
5285 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5286 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5288 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5289 Map<String, Float> featureOrder = new Hashtable<>();
5291 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5294 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5295 String featureType = setting.getType();
5298 * restore feature filters (if any)
5300 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5302 if (filters != null)
5304 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5306 if (!filter.isEmpty())
5308 fr.setFeatureFilter(featureType, filter);
5313 * restore feature colour scheme
5315 Color maxColour = new Color(setting.getColour());
5316 if (setting.getMincolour() != null)
5319 * minColour is always set unless a simple colour
5320 * (including for colour by label though it doesn't use it)
5322 Color minColour = new Color(setting.getMincolour().intValue());
5323 Color noValueColour = minColour;
5324 NoValueColour noColour = setting.getNoValueColour();
5325 if (noColour == NoValueColour.NONE)
5327 noValueColour = null;
5329 else if (noColour == NoValueColour.MAX)
5331 noValueColour = maxColour;
5333 float min = safeFloat(safeFloat(setting.getMin()));
5334 float max = setting.getMax() == null ? 1f
5335 : setting.getMax().floatValue();
5336 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5337 maxColour, noValueColour, min, max);
5338 if (setting.getAttributeName().size() > 0)
5340 gc.setAttributeName(setting.getAttributeName().toArray(
5341 new String[setting.getAttributeName().size()]));
5343 if (setting.getThreshold() != null)
5345 gc.setThreshold(setting.getThreshold().floatValue());
5346 int threshstate = safeInt(setting.getThreshstate());
5347 // -1 = None, 0 = Below, 1 = Above threshold
5348 if (threshstate == 0)
5350 gc.setBelowThreshold(true);
5352 else if (threshstate == 1)
5354 gc.setAboveThreshold(true);
5357 gc.setAutoScaled(true); // default
5358 if (setting.isAutoScale() != null)
5360 gc.setAutoScaled(setting.isAutoScale());
5362 if (setting.isColourByLabel() != null)
5364 gc.setColourByLabel(setting.isColourByLabel());
5366 // and put in the feature colour table.
5367 featureColours.put(featureType, gc);
5371 featureColours.put(featureType, new FeatureColour(maxColour));
5373 renderOrder[fs] = featureType;
5374 if (setting.getOrder() != null)
5376 featureOrder.put(featureType, setting.getOrder().floatValue());
5380 featureOrder.put(featureType, Float.valueOf(
5381 fs / jm.getFeatureSettings().getSetting().size()));
5383 if (safeBoolean(setting.isDisplay()))
5385 fdi.setVisible(featureType);
5388 Map<String, Boolean> fgtable = new Hashtable<>();
5389 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5391 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5392 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5394 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5395 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5396 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5397 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5398 fgtable, featureColours, 1.0f, featureOrder);
5399 fr.transferSettings(frs);
5402 if (view.getHiddenColumns().size() > 0)
5404 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5406 final HiddenColumns hc = view.getHiddenColumns().get(c);
5407 viewport.hideColumns(safeInt(hc.getStart()),
5408 safeInt(hc.getEnd()) /* +1 */);
5411 if (view.getCalcIdParam() != null)
5413 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5415 if (calcIdParam != null)
5417 if (recoverCalcIdParam(calcIdParam, viewport))
5422 Console.warn("Couldn't recover parameters for "
5423 + calcIdParam.getCalcId());
5428 af.setMenusFromViewport(viewport);
5429 af.setTitle(view.getTitle());
5430 // TODO: we don't need to do this if the viewport is aready visible.
5432 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5433 * has a 'cdna/protein complement' view, in which case save it in order to
5434 * populate a SplitFrame once all views have been read in.
5436 String complementaryViewId = view.getComplementId();
5437 if (complementaryViewId == null)
5439 Desktop.addInternalFrame(af, view.getTitle(),
5440 safeInt(view.getWidth()), safeInt(view.getHeight()));
5441 // recompute any autoannotation
5442 af.alignPanel.updateAnnotation(false, true);
5443 reorderAutoannotation(af, al, autoAlan);
5444 af.alignPanel.alignmentChanged();
5448 splitFrameCandidates.put(view, af);
5455 * Reads saved data to restore Colour by Annotation settings
5457 * @param viewAnnColour
5461 * @param checkGroupAnnColour
5464 private ColourSchemeI constructAnnotationColour(
5465 AnnotationColourScheme viewAnnColour, AlignFrame af,
5466 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5468 boolean propagateAnnColour = false;
5469 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5471 if (checkGroupAnnColour && al.getGroups() != null
5472 && al.getGroups().size() > 0)
5474 // pre 2.8.1 behaviour
5475 // check to see if we should transfer annotation colours
5476 propagateAnnColour = true;
5477 for (SequenceGroup sg : al.getGroups())
5479 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5481 propagateAnnColour = false;
5487 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5489 String annotationId = viewAnnColour.getAnnotation();
5490 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5493 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5495 if (matchedAnnotation == null
5496 && annAlignment.getAlignmentAnnotation() != null)
5498 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5501 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5503 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5508 if (matchedAnnotation == null)
5510 System.err.println("Failed to match annotation colour scheme for "
5514 // belt-and-braces create a threshold line if the
5515 // colourscheme needs one but the matchedAnnotation doesn't have one
5516 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5517 && matchedAnnotation.getThreshold() == null)
5519 matchedAnnotation.setThreshold(
5520 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5521 "Threshold", Color.black));
5524 AnnotationColourGradient cs = null;
5525 if (viewAnnColour.getColourScheme().equals("None"))
5527 cs = new AnnotationColourGradient(matchedAnnotation,
5528 new Color(safeInt(viewAnnColour.getMinColour())),
5529 new Color(safeInt(viewAnnColour.getMaxColour())),
5530 safeInt(viewAnnColour.getAboveThreshold()));
5532 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5534 cs = new AnnotationColourGradient(matchedAnnotation,
5535 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5536 safeInt(viewAnnColour.getAboveThreshold()));
5540 cs = new AnnotationColourGradient(matchedAnnotation,
5541 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5542 viewAnnColour.getColourScheme()),
5543 safeInt(viewAnnColour.getAboveThreshold()));
5546 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5547 boolean useOriginalColours = safeBoolean(
5548 viewAnnColour.isPredefinedColours());
5549 cs.setSeqAssociated(perSequenceOnly);
5550 cs.setPredefinedColours(useOriginalColours);
5552 if (propagateAnnColour && al.getGroups() != null)
5554 // Also use these settings for all the groups
5555 for (int g = 0; g < al.getGroups().size(); g++)
5557 SequenceGroup sg = al.getGroups().get(g);
5558 if (sg.getGroupColourScheme() == null)
5563 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5564 matchedAnnotation, sg.getColourScheme(),
5565 safeInt(viewAnnColour.getAboveThreshold()));
5566 sg.setColourScheme(groupScheme);
5567 groupScheme.setSeqAssociated(perSequenceOnly);
5568 groupScheme.setPredefinedColours(useOriginalColours);
5574 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5575 List<JvAnnotRow> autoAlan)
5577 // copy over visualization settings for autocalculated annotation in the
5579 if (al.getAlignmentAnnotation() != null)
5582 * Kludge for magic autoannotation names (see JAL-811)
5584 String[] magicNames = new String[] { "Consensus", "Quality",
5586 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5587 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5588 for (String nm : magicNames)
5590 visan.put(nm, nullAnnot);
5592 for (JvAnnotRow auan : autoAlan)
5594 visan.put(auan.template.label
5595 + (auan.template.getCalcId() == null ? ""
5596 : "\t" + auan.template.getCalcId()),
5599 int hSize = al.getAlignmentAnnotation().length;
5600 List<JvAnnotRow> reorder = new ArrayList<>();
5601 // work through any autoCalculated annotation already on the view
5602 // removing it if it should be placed in a different location on the
5603 // annotation panel.
5604 List<String> remains = new ArrayList<>(visan.keySet());
5605 for (int h = 0; h < hSize; h++)
5607 jalview.datamodel.AlignmentAnnotation jalan = al
5608 .getAlignmentAnnotation()[h];
5609 if (jalan.autoCalculated)
5612 JvAnnotRow valan = visan.get(k = jalan.label);
5613 if (jalan.getCalcId() != null)
5615 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5620 // delete the auto calculated row from the alignment
5621 al.deleteAnnotation(jalan, false);
5625 if (valan != nullAnnot)
5627 if (jalan != valan.template)
5629 // newly created autoannotation row instance
5630 // so keep a reference to the visible annotation row
5631 // and copy over all relevant attributes
5632 if (valan.template.graphHeight >= 0)
5635 jalan.graphHeight = valan.template.graphHeight;
5637 jalan.visible = valan.template.visible;
5639 reorder.add(new JvAnnotRow(valan.order, jalan));
5644 // Add any (possibly stale) autocalculated rows that were not appended to
5645 // the view during construction
5646 for (String other : remains)
5648 JvAnnotRow othera = visan.get(other);
5649 if (othera != nullAnnot && othera.template.getCalcId() != null
5650 && othera.template.getCalcId().length() > 0)
5652 reorder.add(othera);
5655 // now put the automatic annotation in its correct place
5656 int s = 0, srt[] = new int[reorder.size()];
5657 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5658 for (JvAnnotRow jvar : reorder)
5661 srt[s++] = jvar.order;
5664 jalview.util.QuickSort.sort(srt, rws);
5665 // and re-insert the annotation at its correct position
5666 for (JvAnnotRow jvar : rws)
5668 al.addAnnotation(jvar.template, jvar.order);
5670 af.alignPanel.adjustAnnotationHeight();
5674 Hashtable skipList = null;
5677 * TODO remove this method
5680 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5681 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5682 * throw new Error("Implementation Error. No skipList defined for this
5683 * Jalview2XML instance."); } return (AlignFrame)
5684 * skipList.get(view.getSequenceSetId()); }
5688 * Check if the Jalview view contained in object should be skipped or not.
5691 * @return true if view's sequenceSetId is a key in skipList
5693 private boolean skipViewport(JalviewModel object)
5695 if (skipList == null)
5699 String id = object.getViewport().get(0).getSequenceSetId();
5700 if (skipList.containsKey(id))
5702 Console.debug("Skipping seuqence set id " + id);
5708 public void addToSkipList(AlignFrame af)
5710 if (skipList == null)
5712 skipList = new Hashtable();
5714 skipList.put(af.getViewport().getSequenceSetId(), af);
5717 public void clearSkipList()
5719 if (skipList != null)
5726 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5727 boolean ignoreUnrefed, String uniqueSeqSetId)
5729 jalview.datamodel.AlignmentI ds = getDatasetFor(
5730 vamsasSet.getDatasetId());
5731 AlignmentI xtant_ds = ds;
5732 if (xtant_ds == null)
5734 // good chance we are about to create a new dataset, but check if we've
5735 // seen some of the dataset sequence IDs before.
5736 // TODO: skip this check if we are working with project generated by
5737 // version 2.11 or later
5738 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5739 if (xtant_ds != null)
5742 addDatasetRef(vamsasSet.getDatasetId(), ds);
5745 Vector<SequenceI> dseqs = null;
5748 // recovering an alignment View
5749 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5750 if (seqSetDS != null)
5752 if (ds != null && ds != seqSetDS)
5755 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5756 + " - CDS/Protein crossreference data may be lost");
5757 if (xtant_ds != null)
5759 // This can only happen if the unique sequence set ID was bound to a
5760 // dataset that did not contain any of the sequences in the view
5761 // currently being restored.
5763 "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.");
5767 addDatasetRef(vamsasSet.getDatasetId(), ds);
5772 // try even harder to restore dataset
5773 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5774 // create a list of new dataset sequences
5775 dseqs = new Vector<>();
5777 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5779 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5780 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5782 // create a new dataset
5785 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5786 dseqs.copyInto(dsseqs);
5787 ds = new jalview.datamodel.Alignment(dsseqs);
5788 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5789 + " for alignment " + System.identityHashCode(al));
5790 addDatasetRef(vamsasSet.getDatasetId(), ds);
5792 // set the dataset for the newly imported alignment.
5793 if (al.getDataset() == null && !ignoreUnrefed)
5796 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5797 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5799 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5803 * XML dataset sequence ID to materialised dataset reference
5805 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5808 * @return the first materialised dataset reference containing a dataset
5809 * sequence referenced in the given view
5811 * - sequences from the view
5813 AlignmentI checkIfHasDataset(List<Sequence> list)
5815 for (Sequence restoredSeq : list)
5817 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5818 if (datasetFor != null)
5827 * Register ds as the containing dataset for the dataset sequences referenced
5828 * by sequences in list
5831 * - sequences in a view
5834 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5836 for (Sequence restoredSeq : list)
5838 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5839 if (prevDS != null && prevDS != ds)
5841 Console.warn("Dataset sequence appears in many datasets: "
5842 + restoredSeq.getDsseqid());
5843 // TODO: try to merge!
5851 * sequence definition to create/merge dataset sequence for
5855 * vector to add new dataset sequence to
5856 * @param ignoreUnrefed
5857 * - when true, don't create new sequences from vamsasSeq if it's id
5858 * doesn't already have an asssociated Jalview sequence.
5860 * - used to reorder the sequence in the alignment according to the
5861 * vamsasSeq array ordering, to preserve ordering of dataset
5863 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5864 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5867 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5869 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5870 boolean reorder = false;
5871 SequenceI dsq = null;
5872 if (sq != null && sq.getDatasetSequence() != null)
5874 dsq = sq.getDatasetSequence();
5880 if (sq == null && ignoreUnrefed)
5884 String sqid = vamsasSeq.getDsseqid();
5887 // need to create or add a new dataset sequence reference to this sequence
5890 dsq = seqRefIds.get(sqid);
5895 // make a new dataset sequence
5896 dsq = sq.createDatasetSequence();
5899 // make up a new dataset reference for this sequence
5900 sqid = seqHash(dsq);
5902 dsq.setVamsasId(uniqueSetSuffix + sqid);
5903 seqRefIds.put(sqid, dsq);
5908 dseqs.addElement(dsq);
5913 ds.addSequence(dsq);
5919 { // make this dataset sequence sq's dataset sequence
5920 sq.setDatasetSequence(dsq);
5921 // and update the current dataset alignment
5926 if (!dseqs.contains(dsq))
5933 if (ds.findIndex(dsq) < 0)
5935 ds.addSequence(dsq);
5942 // TODO: refactor this as a merge dataset sequence function
5943 // now check that sq (the dataset sequence) sequence really is the union of
5944 // all references to it
5945 // boolean pre = sq.getStart() < dsq.getStart();
5946 // boolean post = sq.getEnd() > dsq.getEnd();
5950 // StringBuffer sb = new StringBuffer();
5951 String newres = jalview.analysis.AlignSeq.extractGaps(
5952 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5953 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5954 && newres.length() > dsq.getLength())
5956 // Update with the longer sequence.
5960 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5961 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5962 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5963 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5965 dsq.setSequence(newres);
5967 // TODO: merges will never happen if we 'know' we have the real dataset
5968 // sequence - this should be detected when id==dssid
5970 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5971 // + (pre ? "prepended" : "") + " "
5972 // + (post ? "appended" : ""));
5977 // sequence refs are identical. We may need to update the existing dataset
5978 // alignment with this one, though.
5979 if (ds != null && dseqs == null)
5981 int opos = ds.findIndex(dsq);
5982 SequenceI tseq = null;
5983 if (opos != -1 && vseqpos != opos)
5985 // remove from old position
5986 ds.deleteSequence(dsq);
5988 if (vseqpos < ds.getHeight())
5990 if (vseqpos != opos)
5992 // save sequence at destination position
5993 tseq = ds.getSequenceAt(vseqpos);
5994 ds.replaceSequenceAt(vseqpos, dsq);
5995 ds.addSequence(tseq);
6000 ds.addSequence(dsq);
6007 * TODO use AlignmentI here and in related methods - needs
6008 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6010 Hashtable<String, AlignmentI> datasetIds = null;
6012 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6014 private AlignmentI getDatasetFor(String datasetId)
6016 if (datasetIds == null)
6018 datasetIds = new Hashtable<>();
6021 if (datasetIds.containsKey(datasetId))
6023 return datasetIds.get(datasetId);
6028 private void addDatasetRef(String datasetId, AlignmentI dataset)
6030 if (datasetIds == null)
6032 datasetIds = new Hashtable<>();
6034 datasetIds.put(datasetId, dataset);
6038 * make a new dataset ID for this jalview dataset alignment
6043 private String getDatasetIdRef(AlignmentI dataset)
6045 if (dataset.getDataset() != null)
6048 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6050 String datasetId = makeHashCode(dataset, null);
6051 if (datasetId == null)
6053 // make a new datasetId and record it
6054 if (dataset2Ids == null)
6056 dataset2Ids = new IdentityHashMap<>();
6060 datasetId = dataset2Ids.get(dataset);
6062 if (datasetId == null)
6064 datasetId = "ds" + dataset2Ids.size() + 1;
6065 dataset2Ids.put(dataset, datasetId);
6072 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6073 * constructed as a special subclass GeneLocus.
6075 * @param datasetSequence
6078 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6080 for (int d = 0; d < sequence.getDBRef().size(); d++)
6082 DBRef dr = sequence.getDBRef().get(d);
6086 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6087 dr.getAccessionId());
6091 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6092 dr.getAccessionId());
6094 if (dr.getMapping() != null)
6096 entry.setMap(addMapping(dr.getMapping()));
6098 entry.setCanonical(dr.isCanonical());
6099 datasetSequence.addDBRef(entry);
6103 private jalview.datamodel.Mapping addMapping(Mapping m)
6105 SequenceI dsto = null;
6106 // Mapping m = dr.getMapping();
6107 int fr[] = new int[m.getMapListFrom().size() * 2];
6108 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6109 for (int _i = 0; from.hasNext(); _i += 2)
6111 MapListFrom mf = from.next();
6112 fr[_i] = mf.getStart();
6113 fr[_i + 1] = mf.getEnd();
6115 int fto[] = new int[m.getMapListTo().size() * 2];
6116 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6117 for (int _i = 0; to.hasNext(); _i += 2)
6119 MapListTo mf = to.next();
6120 fto[_i] = mf.getStart();
6121 fto[_i + 1] = mf.getEnd();
6123 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6124 fto, m.getMapFromUnit().intValue(),
6125 m.getMapToUnit().intValue());
6128 * (optional) choice of dseqFor or Sequence
6130 if (m.getDseqFor() != null)
6132 String dsfor = m.getDseqFor();
6133 if (seqRefIds.containsKey(dsfor))
6138 jmap.setTo(seqRefIds.get(dsfor));
6142 frefedSequence.add(newMappingRef(dsfor, jmap));
6145 else if (m.getSequence() != null)
6148 * local sequence definition
6150 Sequence ms = m.getSequence();
6151 SequenceI djs = null;
6152 String sqid = ms.getDsseqid();
6153 if (sqid != null && sqid.length() > 0)
6156 * recover dataset sequence
6158 djs = seqRefIds.get(sqid);
6163 "Warning - making up dataset sequence id for DbRef sequence map reference");
6164 sqid = ((Object) ms).toString(); // make up a new hascode for
6165 // undefined dataset sequence hash
6166 // (unlikely to happen)
6172 * make a new dataset sequence and add it to refIds hash
6174 djs = new jalview.datamodel.Sequence(ms.getName(),
6176 djs.setStart(jmap.getMap().getToLowest());
6177 djs.setEnd(jmap.getMap().getToHighest());
6178 djs.setVamsasId(uniqueSetSuffix + sqid);
6180 incompleteSeqs.put(sqid, djs);
6181 seqRefIds.put(sqid, djs);
6184 Console.debug("about to recurse on addDBRefs.");
6193 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6194 * view as XML (but not to file), and then reloading it
6199 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6202 JalviewModel jm = saveState(ap, null, null, null);
6205 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6206 ap.getAlignment().getDataset());
6208 uniqueSetSuffix = "";
6209 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6210 jm.getViewport().get(0).setId(null);
6211 // we don't overwrite the view we just copied
6213 if (this.frefedSequence == null)
6215 frefedSequence = new Vector<>();
6218 viewportsAdded.clear();
6220 AlignFrame af = loadFromObject(jm, null, false, null);
6221 af.getAlignPanels().clear();
6222 af.closeMenuItem_actionPerformed(true);
6225 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6226 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6227 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6228 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6229 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6232 return af.alignPanel;
6235 private Hashtable jvids2vobj;
6238 * set the object to ID mapping tables used to write/recover objects and XML
6239 * ID strings for the jalview project. If external tables are provided then
6240 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6241 * object goes out of scope. - also populates the datasetIds hashtable with
6242 * alignment objects containing dataset sequences
6245 * Map from ID strings to jalview datamodel
6247 * Map from jalview datamodel to ID strings
6251 public void setObjectMappingTables(Hashtable vobj2jv,
6252 IdentityHashMap jv2vobj)
6254 this.jv2vobj = jv2vobj;
6255 this.vobj2jv = vobj2jv;
6256 Iterator ds = jv2vobj.keySet().iterator();
6258 while (ds.hasNext())
6260 Object jvobj = ds.next();
6261 id = jv2vobj.get(jvobj).toString();
6262 if (jvobj instanceof jalview.datamodel.Alignment)
6264 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6266 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6269 else if (jvobj instanceof jalview.datamodel.Sequence)
6271 // register sequence object so the XML parser can recover it.
6272 if (seqRefIds == null)
6274 seqRefIds = new HashMap<>();
6276 if (seqsToIds == null)
6278 seqsToIds = new IdentityHashMap<>();
6280 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6281 seqsToIds.put((SequenceI) jvobj, id);
6283 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6286 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6287 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6288 if (jvann.annotationId == null)
6290 jvann.annotationId = anid;
6292 if (!jvann.annotationId.equals(anid))
6294 // TODO verify that this is the correct behaviour
6295 Console.warn("Overriding Annotation ID for " + anid
6296 + " from different id : " + jvann.annotationId);
6297 jvann.annotationId = anid;
6300 else if (jvobj instanceof String)
6302 if (jvids2vobj == null)
6304 jvids2vobj = new Hashtable();
6305 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6310 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6316 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6317 * objects created from the project archive. If string is null (default for
6318 * construction) then suffix will be set automatically.
6322 public void setUniqueSetSuffix(String string)
6324 uniqueSetSuffix = string;
6329 * uses skipList2 as the skipList for skipping views on sequence sets
6330 * associated with keys in the skipList
6334 public void setSkipList(Hashtable skipList2)
6336 skipList = skipList2;
6340 * Reads the jar entry of given name and returns its contents, or null if the
6341 * entry is not found.
6344 * @param jarEntryName
6347 protected String readJarEntry(jarInputStreamProvider jprovider,
6348 String jarEntryName)
6350 String result = null;
6351 BufferedReader in = null;
6356 * Reopen the jar input stream and traverse its entries to find a matching
6359 JarInputStream jin = jprovider.getJarInputStream();
6360 JarEntry entry = null;
6363 entry = jin.getNextJarEntry();
6364 } while (entry != null && !entry.getName().equals(jarEntryName));
6368 StringBuilder out = new StringBuilder(256);
6369 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6372 while ((data = in.readLine()) != null)
6376 result = out.toString();
6381 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6383 } catch (Exception ex)
6385 ex.printStackTrace();
6393 } catch (IOException e)
6404 * Returns an incrementing counter (0, 1, 2...)
6408 private synchronized int nextCounter()
6414 * Loads any saved PCA viewers
6419 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6423 List<PcaViewer> pcaviewers = model.getPcaViewer();
6424 for (PcaViewer viewer : pcaviewers)
6426 String modelName = viewer.getScoreModelName();
6427 SimilarityParamsI params = new SimilarityParams(
6428 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6429 viewer.isIncludeGaps(),
6430 viewer.isDenominateByShortestLength());
6433 * create the panel (without computing the PCA)
6435 PCAPanel panel = new PCAPanel(ap, modelName, params);
6437 panel.setTitle(viewer.getTitle());
6438 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6439 viewer.getWidth(), viewer.getHeight()));
6441 boolean showLabels = viewer.isShowLabels();
6442 panel.setShowLabels(showLabels);
6443 panel.getRotatableCanvas().setShowLabels(showLabels);
6444 panel.getRotatableCanvas()
6445 .setBgColour(new Color(viewer.getBgColour()));
6446 panel.getRotatableCanvas()
6447 .setApplyToAllViews(viewer.isLinkToAllViews());
6450 * load PCA output data
6452 ScoreModelI scoreModel = ScoreModels.getInstance()
6453 .getScoreModel(modelName, ap);
6454 PCA pca = new PCA(null, scoreModel, params);
6455 PcaDataType pcaData = viewer.getPcaData();
6457 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6458 pca.setPairwiseScores(pairwise);
6460 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6461 pca.setTridiagonal(triDiag);
6463 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6464 pca.setEigenmatrix(result);
6466 panel.getPcaModel().setPCA(pca);
6469 * we haven't saved the input data! (JAL-2647 to do)
6471 panel.setInputData(null);
6474 * add the sequence points for the PCA display
6476 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6477 for (SequencePoint sp : viewer.getSequencePoint())
6479 String seqId = sp.getSequenceRef();
6480 SequenceI seq = seqRefIds.get(seqId);
6483 throw new IllegalStateException(
6484 "Unmatched seqref for PCA: " + seqId);
6486 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6487 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6489 seqPoints.add(seqPoint);
6491 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6494 * set min-max ranges and scale after setPoints (which recomputes them)
6496 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6497 SeqPointMin spMin = viewer.getSeqPointMin();
6498 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6500 SeqPointMax spMax = viewer.getSeqPointMax();
6501 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6503 panel.getRotatableCanvas().setSeqMinMax(min, max);
6505 // todo: hold points list in PCAModel only
6506 panel.getPcaModel().setSequencePoints(seqPoints);
6508 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6509 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6510 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6512 // is this duplication needed?
6513 panel.setTop(seqPoints.size() - 1);
6514 panel.getPcaModel().setTop(seqPoints.size() - 1);
6517 * add the axes' end points for the display
6519 for (int i = 0; i < 3; i++)
6521 Axis axis = viewer.getAxis().get(i);
6522 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6523 axis.getXPos(), axis.getYPos(), axis.getZPos());
6526 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6527 "label.calc_title", "PCA", modelName), 475, 450);
6529 } catch (Exception ex)
6531 Console.error("Error loading PCA: " + ex.toString());
6536 * Creates a new structure viewer window
6543 protected void createStructureViewer(ViewerType viewerType,
6544 final Entry<String, StructureViewerModel> viewerData,
6545 AlignFrame af, jarInputStreamProvider jprovider)
6547 final StructureViewerModel viewerModel = viewerData.getValue();
6548 String sessionFilePath = null;
6550 if (viewerType == ViewerType.JMOL)
6552 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6556 String viewerJarEntryName = getViewerJarEntryName(
6557 viewerModel.getViewId());
6558 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6559 "viewerSession", ".tmp");
6561 final String sessionPath = sessionFilePath;
6562 final String sviewid = viewerData.getKey();
6565 SwingUtilities.invokeAndWait(new Runnable()
6570 JalviewStructureDisplayI sview = null;
6573 sview = StructureViewer.createView(viewerType, af.alignPanel,
6574 viewerModel, sessionPath, sviewid);
6575 addNewStructureViewer(sview);
6576 } catch (OutOfMemoryError ex)
6578 new OOMWarning("Restoring structure view for " + viewerType,
6579 (OutOfMemoryError) ex.getCause());
6580 if (sview != null && sview.isVisible())
6582 sview.closeViewer(false);
6583 sview.setVisible(false);
6589 } catch (InvocationTargetException | InterruptedException ex)
6591 Console.warn("Unexpected error when opening " + viewerType
6592 + " structure viewer", ex);
6597 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6598 * the path of the file. "load file" commands are rewritten to change the
6599 * original PDB file names to those created as the Jalview project is loaded.
6605 private String rewriteJmolSession(StructureViewerModel svattrib,
6606 jarInputStreamProvider jprovider)
6608 String state = svattrib.getStateData(); // Jalview < 2.9
6609 if (state == null || state.isEmpty()) // Jalview >= 2.9
6611 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6612 state = readJarEntry(jprovider, jarEntryName);
6614 // TODO or simpler? for each key in oldFiles,
6615 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6616 // (allowing for different path escapings)
6617 StringBuilder rewritten = new StringBuilder(state.length());
6618 int cp = 0, ncp, ecp;
6619 Map<File, StructureData> oldFiles = svattrib.getFileData();
6620 while ((ncp = state.indexOf("load ", cp)) > -1)
6624 // look for next filename in load statement
6625 rewritten.append(state.substring(cp,
6626 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6627 String oldfilenam = state.substring(ncp,
6628 ecp = state.indexOf("\"", ncp));
6629 // recover the new mapping data for this old filename
6630 // have to normalize filename - since Jmol and jalview do
6631 // filename translation differently.
6632 StructureData filedat = oldFiles.get(new File(oldfilenam));
6633 if (filedat == null)
6635 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6636 filedat = oldFiles.get(new File(reformatedOldFilename));
6638 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6639 rewritten.append("\"");
6640 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6641 // look for next file statement.
6642 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6646 // just append rest of state
6647 rewritten.append(state.substring(cp));
6651 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6652 rewritten = new StringBuilder(state);
6653 rewritten.append("; load append ");
6654 for (File id : oldFiles.keySet())
6656 // add pdb files that should be present in the viewer
6657 StructureData filedat = oldFiles.get(id);
6658 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6660 rewritten.append(";");
6663 if (rewritten.length() == 0)
6667 final String history = "history = ";
6668 int historyIndex = rewritten.indexOf(history);
6669 if (historyIndex > -1)
6672 * change "history = [true|false];" to "history = [1|0];"
6674 historyIndex += history.length();
6675 String val = rewritten.substring(historyIndex, historyIndex + 5);
6676 if (val.startsWith("true"))
6678 rewritten.replace(historyIndex, historyIndex + 4, "1");
6680 else if (val.startsWith("false"))
6682 rewritten.replace(historyIndex, historyIndex + 5, "0");
6688 File tmp = File.createTempFile("viewerSession", ".tmp");
6689 try (OutputStream os = new FileOutputStream(tmp))
6691 InputStream is = new ByteArrayInputStream(
6692 rewritten.toString().getBytes());
6694 return tmp.getAbsolutePath();
6696 } catch (IOException e)
6698 Console.error("Error restoring Jmol session: " + e.toString());
6704 * Populates an XML model of the feature colour scheme for one feature type
6706 * @param featureType
6710 public static Colour marshalColour(String featureType,
6711 FeatureColourI fcol)
6713 Colour col = new Colour();
6714 if (fcol.isSimpleColour())
6716 col.setRGB(Format.getHexString(fcol.getColour()));
6720 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6721 col.setMin(fcol.getMin());
6722 col.setMax(fcol.getMax());
6723 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6724 col.setAutoScale(fcol.isAutoScaled());
6725 col.setThreshold(fcol.getThreshold());
6726 col.setColourByLabel(fcol.isColourByLabel());
6727 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6728 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6729 : ThresholdType.NONE));
6730 if (fcol.isColourByAttribute())
6732 final String[] attName = fcol.getAttributeName();
6733 col.getAttributeName().add(attName[0]);
6734 if (attName.length > 1)
6736 col.getAttributeName().add(attName[1]);
6739 Color noColour = fcol.getNoColour();
6740 if (noColour == null)
6742 col.setNoValueColour(NoValueColour.NONE);
6744 else if (noColour == fcol.getMaxColour())
6746 col.setNoValueColour(NoValueColour.MAX);
6750 col.setNoValueColour(NoValueColour.MIN);
6753 col.setName(featureType);
6758 * Populates an XML model of the feature filter(s) for one feature type
6760 * @param firstMatcher
6761 * the first (or only) match condition)
6763 * remaining match conditions (if any)
6765 * if true, conditions are and-ed, else or-ed
6767 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6768 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6771 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6773 if (filters.hasNext())
6778 CompoundMatcher compound = new CompoundMatcher();
6779 compound.setAnd(and);
6780 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6781 firstMatcher, Collections.emptyIterator(), and);
6782 // compound.addMatcherSet(matcher1);
6783 compound.getMatcherSet().add(matcher1);
6784 FeatureMatcherI nextMatcher = filters.next();
6785 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6786 nextMatcher, filters, and);
6787 // compound.addMatcherSet(matcher2);
6788 compound.getMatcherSet().add(matcher2);
6789 result.setCompoundMatcher(compound);
6794 * single condition matcher
6796 // MatchCondition matcherModel = new MatchCondition();
6797 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6798 matcherModel.setCondition(
6799 firstMatcher.getMatcher().getCondition().getStableName());
6800 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6801 if (firstMatcher.isByAttribute())
6803 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6804 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6805 String[] attName = firstMatcher.getAttribute();
6806 matcherModel.getAttributeName().add(attName[0]); // attribute
6807 if (attName.length > 1)
6809 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6812 else if (firstMatcher.isByLabel())
6814 matcherModel.setBy(FilterBy.BY_LABEL);
6816 else if (firstMatcher.isByScore())
6818 matcherModel.setBy(FilterBy.BY_SCORE);
6820 result.setMatchCondition(matcherModel);
6827 * Loads one XML model of a feature filter to a Jalview object
6829 * @param featureType
6830 * @param matcherSetModel
6833 public static FeatureMatcherSetI parseFilter(String featureType,
6834 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6836 FeatureMatcherSetI result = new FeatureMatcherSet();
6839 parseFilterConditions(result, matcherSetModel, true);
6840 } catch (IllegalStateException e)
6842 // mixing AND and OR conditions perhaps
6844 String.format("Error reading filter conditions for '%s': %s",
6845 featureType, e.getMessage()));
6846 // return as much as was parsed up to the error
6853 * Adds feature match conditions to matcherSet as unmarshalled from XML
6854 * (possibly recursively for compound conditions)
6857 * @param matcherSetModel
6859 * if true, multiple conditions are AND-ed, else they are OR-ed
6860 * @throws IllegalStateException
6861 * if AND and OR conditions are mixed
6863 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6864 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6867 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6868 .getMatchCondition();
6874 FilterBy filterBy = mc.getBy();
6875 Condition cond = Condition.fromString(mc.getCondition());
6876 String pattern = mc.getValue();
6877 FeatureMatcherI matchCondition = null;
6878 if (filterBy == FilterBy.BY_LABEL)
6880 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6882 else if (filterBy == FilterBy.BY_SCORE)
6884 matchCondition = FeatureMatcher.byScore(cond, pattern);
6887 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6889 final List<String> attributeName = mc.getAttributeName();
6890 String[] attNames = attributeName
6891 .toArray(new String[attributeName.size()]);
6892 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6897 * note this throws IllegalStateException if AND-ing to a
6898 * previously OR-ed compound condition, or vice versa
6902 matcherSet.and(matchCondition);
6906 matcherSet.or(matchCondition);
6912 * compound condition
6914 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6915 .getCompoundMatcher().getMatcherSet();
6916 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6917 if (matchers.size() == 2)
6919 parseFilterConditions(matcherSet, matchers.get(0), anded);
6920 parseFilterConditions(matcherSet, matchers.get(1), anded);
6924 System.err.println("Malformed compound filter condition");
6930 * Loads one XML model of a feature colour to a Jalview object
6932 * @param colourModel
6935 public static FeatureColourI parseColour(Colour colourModel)
6937 FeatureColourI colour = null;
6939 if (colourModel.getMax() != null)
6941 Color mincol = null;
6942 Color maxcol = null;
6943 Color noValueColour = null;
6947 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6948 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6949 } catch (Exception e)
6951 Console.warn("Couldn't parse out graduated feature color.", e);
6954 NoValueColour noCol = colourModel.getNoValueColour();
6955 if (noCol == NoValueColour.MIN)
6957 noValueColour = mincol;
6959 else if (noCol == NoValueColour.MAX)
6961 noValueColour = maxcol;
6964 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6965 safeFloat(colourModel.getMin()),
6966 safeFloat(colourModel.getMax()));
6967 final List<String> attributeName = colourModel.getAttributeName();
6968 String[] attributes = attributeName
6969 .toArray(new String[attributeName.size()]);
6970 if (attributes != null && attributes.length > 0)
6972 colour.setAttributeName(attributes);
6974 if (colourModel.isAutoScale() != null)
6976 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6978 if (colourModel.isColourByLabel() != null)
6980 colour.setColourByLabel(
6981 colourModel.isColourByLabel().booleanValue());
6983 if (colourModel.getThreshold() != null)
6985 colour.setThreshold(colourModel.getThreshold().floatValue());
6987 ThresholdType ttyp = colourModel.getThreshType();
6988 if (ttyp == ThresholdType.ABOVE)
6990 colour.setAboveThreshold(true);
6992 else if (ttyp == ThresholdType.BELOW)
6994 colour.setBelowThreshold(true);
6999 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7000 colour = new FeatureColour(color);
7006 public static void setStateSavedUpToDate(boolean s)
7008 Console.debug("Setting overall stateSavedUpToDate to " + s);
7009 stateSavedUpToDate = s;
7012 public static boolean stateSavedUpToDate()
7014 Console.debug("Returning overall stateSavedUpToDate value: "
7015 + stateSavedUpToDate);
7016 return stateSavedUpToDate;
7019 public static boolean allSavedUpToDate()
7021 if (stateSavedUpToDate()) // nothing happened since last project save
7024 AlignFrame[] frames = Desktop.getAlignFrames();
7027 for (int i = 0; i < frames.length; i++)
7029 if (frames[i] == null)
7031 if (!frames[i].getViewport().savedUpToDate())
7032 return false; // at least one alignment is not individually saved
7038 // used for debugging and tests
7039 private static int debugDelaySave = 20;
7041 public static void setDebugDelaySave(int n)