2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.BitSet;
48 import java.util.Collections;
49 import java.util.Enumeration;
50 import java.util.GregorianCalendar;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Hashtable;
54 import java.util.IdentityHashMap;
55 import java.util.Iterator;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Locale;
60 import java.util.Map.Entry;
62 import java.util.Vector;
63 import java.util.jar.JarEntry;
64 import java.util.jar.JarInputStream;
65 import java.util.jar.JarOutputStream;
67 import javax.swing.JInternalFrame;
68 import javax.swing.SwingUtilities;
69 import javax.xml.bind.JAXBContext;
70 import javax.xml.bind.JAXBElement;
71 import javax.xml.bind.Marshaller;
72 import javax.xml.datatype.DatatypeConfigurationException;
73 import javax.xml.datatype.DatatypeFactory;
74 import javax.xml.datatype.XMLGregorianCalendar;
75 import javax.xml.stream.XMLInputFactory;
76 import javax.xml.stream.XMLStreamReader;
78 import jalview.analysis.Conservation;
79 import jalview.analysis.PCA;
80 import jalview.analysis.scoremodels.ScoreModels;
81 import jalview.analysis.scoremodels.SimilarityParams;
82 import jalview.api.FeatureColourI;
83 import jalview.api.ViewStyleI;
84 import jalview.api.analysis.ScoreModelI;
85 import jalview.api.analysis.SimilarityParamsI;
86 import jalview.api.structures.JalviewStructureDisplayI;
87 import jalview.bin.Cache;
88 import jalview.bin.Console;
89 import jalview.bin.Jalview;
90 import jalview.datamodel.AlignedCodonFrame;
91 import jalview.datamodel.Alignment;
92 import jalview.datamodel.AlignmentAnnotation;
93 import jalview.datamodel.AlignmentI;
94 import jalview.datamodel.ContactListI;
95 import jalview.datamodel.ContactMatrix;
96 import jalview.datamodel.ContactMatrixI;
97 import jalview.datamodel.DBRefEntry;
98 import jalview.datamodel.FloatContactMatrix;
99 import jalview.datamodel.GeneLocus;
100 import jalview.datamodel.GraphLine;
101 import jalview.datamodel.GroupSet;
102 import jalview.datamodel.GroupSetI;
103 import jalview.datamodel.PDBEntry;
104 import jalview.datamodel.Point;
105 import jalview.datamodel.RnaViewerModel;
106 import jalview.datamodel.SequenceFeature;
107 import jalview.datamodel.SequenceGroup;
108 import jalview.datamodel.SequenceI;
109 import jalview.datamodel.StructureViewerModel;
110 import jalview.datamodel.StructureViewerModel.StructureData;
111 import jalview.datamodel.features.FeatureMatcher;
112 import jalview.datamodel.features.FeatureMatcherI;
113 import jalview.datamodel.features.FeatureMatcherSet;
114 import jalview.datamodel.features.FeatureMatcherSetI;
115 import jalview.ext.varna.RnaModel;
116 import jalview.gui.AlignFrame;
117 import jalview.gui.AlignViewport;
118 import jalview.gui.AlignmentPanel;
119 import jalview.gui.AppVarna;
120 import jalview.gui.Desktop;
121 import jalview.gui.JvOptionPane;
122 import jalview.gui.OOMWarning;
123 import jalview.gui.OverviewPanel;
124 import jalview.gui.PCAPanel;
125 import jalview.gui.PaintRefresher;
126 import jalview.gui.SplitFrame;
127 import jalview.gui.StructureViewer;
128 import jalview.gui.StructureViewer.ViewerType;
129 import jalview.gui.StructureViewerBase;
130 import jalview.gui.TreePanel;
131 import jalview.io.BackupFiles;
132 import jalview.io.DataSourceType;
133 import jalview.io.FileFormat;
134 import jalview.io.NewickFile;
135 import jalview.math.Matrix;
136 import jalview.math.MatrixI;
137 import jalview.renderer.ResidueShaderI;
138 import jalview.schemes.AnnotationColourGradient;
139 import jalview.schemes.ColourSchemeI;
140 import jalview.schemes.ColourSchemeProperty;
141 import jalview.schemes.FeatureColour;
142 import jalview.schemes.ResidueProperties;
143 import jalview.schemes.UserColourScheme;
144 import jalview.structure.StructureSelectionManager;
145 import jalview.structures.models.AAStructureBindingModel;
146 import jalview.util.Format;
147 import jalview.util.HttpUtils;
148 import jalview.util.MessageManager;
149 import jalview.util.Platform;
150 import jalview.util.StringUtils;
151 import jalview.util.jarInputStreamProvider;
152 import jalview.util.matcher.Condition;
153 import jalview.viewmodel.AlignmentViewport;
154 import jalview.viewmodel.PCAModel;
155 import jalview.viewmodel.ViewportRanges;
156 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
157 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
158 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
159 import jalview.ws.datamodel.MappableContactMatrixI;
160 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
161 import jalview.ws.jws2.Jws2Discoverer;
162 import jalview.ws.jws2.dm.AAConSettings;
163 import jalview.ws.jws2.jabaws2.Jws2Instance;
164 import jalview.ws.params.ArgumentI;
165 import jalview.ws.params.AutoCalcSetting;
166 import jalview.ws.params.WsParamSetI;
167 import jalview.xml.binding.jalview.AlcodonFrame;
168 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
169 import jalview.xml.binding.jalview.Annotation;
170 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
171 import jalview.xml.binding.jalview.AnnotationColourScheme;
172 import jalview.xml.binding.jalview.AnnotationElement;
173 import jalview.xml.binding.jalview.DoubleMatrix;
174 import jalview.xml.binding.jalview.DoubleVector;
175 import jalview.xml.binding.jalview.Feature;
176 import jalview.xml.binding.jalview.Feature.OtherData;
177 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
178 import jalview.xml.binding.jalview.FilterBy;
179 import jalview.xml.binding.jalview.JalviewModel;
180 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
181 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
182 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
183 import jalview.xml.binding.jalview.JalviewModel.JGroup;
184 import jalview.xml.binding.jalview.JalviewModel.JSeq;
185 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
186 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
187 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
188 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
189 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
190 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
191 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
192 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
193 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
194 import jalview.xml.binding.jalview.JalviewModel.Tree;
195 import jalview.xml.binding.jalview.JalviewModel.UserColours;
196 import jalview.xml.binding.jalview.JalviewModel.Viewport;
197 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
198 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
199 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
200 import jalview.xml.binding.jalview.JalviewUserColours;
201 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
202 import jalview.xml.binding.jalview.MapListType;
203 import jalview.xml.binding.jalview.MapListType.MapListFrom;
204 import jalview.xml.binding.jalview.MapListType.MapListTo;
205 import jalview.xml.binding.jalview.MapOnAMatrixType;
206 import jalview.xml.binding.jalview.Mapping;
207 import jalview.xml.binding.jalview.MatrixType;
208 import jalview.xml.binding.jalview.NoValueColour;
209 import jalview.xml.binding.jalview.ObjectFactory;
210 import jalview.xml.binding.jalview.PcaDataType;
211 import jalview.xml.binding.jalview.Pdbentry.Property;
212 import jalview.xml.binding.jalview.Sequence;
213 import jalview.xml.binding.jalview.Sequence.DBRef;
214 import jalview.xml.binding.jalview.SequenceSet;
215 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
216 import jalview.xml.binding.jalview.ThresholdType;
217 import jalview.xml.binding.jalview.VAMSAS;
220 * Write out the current jalview desktop state as a Jalview XML stream.
222 * Note: the vamsas objects referred to here are primitive versions of the
223 * VAMSAS project schema elements - they are not the same and most likely never
227 * @version $Revision: 1.134 $
229 public class Jalview2XML
232 // BH 2018 we add the .jvp binary extension to J2S so that
233 // it will declare that binary when we do the file save from the browser
237 Platform.addJ2SBinaryType(".jvp?");
240 private static final String VIEWER_PREFIX = "viewer_";
242 private static final String RNA_PREFIX = "rna_";
244 private static final String UTF_8 = "UTF-8";
247 * used in decision if quit confirmation should be issued
249 private static boolean stateSavedUpToDate = false;
252 * prefix for recovering datasets for alignments with multiple views where
253 * non-existent dataset IDs were written for some views
255 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
257 // use this with nextCounter() to make unique names for entities
258 private int counter = 0;
261 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
262 * of sequence objects are created.
264 IdentityHashMap<SequenceI, String> seqsToIds = null;
267 * jalview XML Sequence ID to jalview sequence object reference (both dataset
268 * and alignment sequences. Populated as XML reps of sequence objects are
271 Map<String, SequenceI> seqRefIds = null;
273 Map<String, SequenceI> incompleteSeqs = null;
275 List<forwardRef> frefedSequence = null;
277 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
280 * Map of reconstructed AlignFrame objects that appear to have come from
281 * SplitFrame objects (have a dna/protein complement view).
283 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
286 * Map from displayed rna structure models to their saved session state jar
289 private Map<RnaModel, String> rnaSessions = new HashMap<>();
292 * map from contact matrices to their XML ids
294 private Map<ContactMatrixI,String> contactMatrices = new HashMap<>();
295 private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
296 private List<jalview.xml.binding.jalview.MatrixType> xmlMatrices= new ArrayList<>();
299 * A helper method for safely using the value of an optional attribute that
300 * may be null if not present in the XML. Answers the boolean value, or false
306 public static boolean safeBoolean(Boolean b)
308 return b == null ? false : b.booleanValue();
312 * A helper method for safely using the value of an optional attribute that
313 * may be null if not present in the XML. Answers the integer value, or zero
319 public static int safeInt(Integer i)
321 return i == null ? 0 : i.intValue();
325 * A helper method for safely using the value of an optional attribute that
326 * may be null if not present in the XML. Answers the float value, or zero if
332 public static float safeFloat(Float f)
334 return f == null ? 0f : f.floatValue();
338 * create/return unique hash string for sq
341 * @return new or existing unique string for sq
343 String seqHash(SequenceI sq)
345 if (seqsToIds == null)
349 if (seqsToIds.containsKey(sq))
351 return seqsToIds.get(sq);
355 // create sequential key
356 String key = "sq" + (seqsToIds.size() + 1);
357 key = makeHashCode(sq, key); // check we don't have an external reference
359 seqsToIds.put(sq, key);
366 if (seqsToIds == null)
368 seqsToIds = new IdentityHashMap<>();
370 if (seqRefIds == null)
372 seqRefIds = new HashMap<>();
374 if (incompleteSeqs == null)
376 incompleteSeqs = new HashMap<>();
378 if (frefedSequence == null)
380 frefedSequence = new ArrayList<>();
388 public Jalview2XML(boolean raiseGUI)
390 this.raiseGUI = raiseGUI;
394 * base class for resolving forward references to an as-yet unmarshalled object referenced by already unmarshalled objects
399 abstract class forwardRef {
404 public forwardRef(String _sref, String type)
410 public String getSref()
415 public abstract boolean isResolvable();
417 * @return true if the forward reference was fully resolved
419 abstract boolean resolve();
422 public String toString()
424 return type + " reference to " + sref;
428 * resolve forward references to sequences by their ID
431 abstract class SeqFref extends forwardRef
433 public SeqFref(String _sref, String type)
437 public SequenceI getSrefSeq()
439 return seqRefIds.get(sref);
442 public boolean isResolvable()
444 return seqRefIds.get(sref) != null;
447 public SequenceI getSrefDatasetSeq()
449 SequenceI sq = seqRefIds.get(sref);
452 while (sq.getDatasetSequence() != null)
454 sq = sq.getDatasetSequence();
462 * create forward reference for a mapping
468 public SeqFref newMappingRef(final String sref,
469 final jalview.datamodel.Mapping _jmap)
471 SeqFref fref = new SeqFref(sref, "Mapping")
473 public jalview.datamodel.Mapping jmap = _jmap;
478 SequenceI seq = getSrefDatasetSeq();
490 public SeqFref newAlcodMapRef(final String sref,
491 final AlignedCodonFrame _cf,
492 final jalview.datamodel.Mapping _jmap)
495 SeqFref fref = new SeqFref(sref, "Codon Frame")
497 AlignedCodonFrame cf = _cf;
499 public jalview.datamodel.Mapping mp = _jmap;
502 public boolean isResolvable()
504 return super.isResolvable() && mp.getTo() != null;
510 SequenceI seq = getSrefDatasetSeq();
515 cf.addMap(seq, mp.getTo(), mp.getMap());
522 public forwardRef newMatrixFref(final String matRef,
523 final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
525 forwardRef fref = new forwardRef(matRef,
526 "Matrix Reference for sequence and annotation")
532 ContactMatrixI cm = contactMatrixRefs.get(matRef);
533 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
536 jaa.sequenceRef.addContactListFor(jaa, newpae);
541 public boolean isResolvable()
543 return (contactMatrixRefs.get(matRef) != null);
549 public void resolveFrefedSequences()
551 Iterator<forwardRef> nextFref = frefedSequence.iterator();
552 int toresolve = frefedSequence.size();
553 int unresolved = 0, failedtoresolve = 0;
554 while (nextFref.hasNext())
556 forwardRef ref = nextFref.next();
557 if (ref.isResolvable())
569 } catch (Exception x)
571 jalview.bin.Console.errPrintln(
572 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
585 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
587 + " forward references left unresolved on the stack.");
589 if (failedtoresolve > 0)
591 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
592 + " resolvable forward references failed to resolve.");
594 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
596 jalview.bin.Console.errPrintln(
597 "Jalview Project Import: There are " + incompleteSeqs.size()
598 + " sequences which may have incomplete metadata.");
599 if (incompleteSeqs.size() < 10)
601 for (SequenceI s : incompleteSeqs.values())
603 jalview.bin.Console.errPrintln(s.toString());
608 jalview.bin.Console.errPrintln(
609 "Too many to report. Skipping output of incomplete sequences.");
615 * This maintains a map of viewports, the key being the seqSetId. Important to
616 * set historyItem and redoList for multiple views
618 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
620 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
622 String uniqueSetSuffix = "";
625 * List of pdbfiles added to Jar
627 List<String> pdbfiles = null;
629 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
630 public void saveState(File statefile)
632 FileOutputStream fos = null;
637 fos = new FileOutputStream(statefile);
639 JarOutputStream jout = new JarOutputStream(fos);
643 } catch (Exception e)
645 Console.error("Couln't write Jalview state to " + statefile, e);
646 // TODO: inform user of the problem - they need to know if their data was
648 if (errorMessage == null)
650 errorMessage = "Did't write Jalview Archive to output file '"
651 + statefile + "' - See console error log for details";
655 errorMessage += "(Didn't write Jalview Archive to output file '"
666 } catch (IOException e)
676 * Writes a jalview project archive to the given Jar output stream.
680 public void saveState(JarOutputStream jout)
682 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
684 setStateSavedUpToDate(true);
686 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
688 int n = debugDelaySave;
692 Console.debug("***** debugging save sleep " + i + "/" + n);
696 } catch (InterruptedException e)
698 // TODO Auto-generated catch block
709 saveAllFrames(Arrays.asList(frames), jout);
713 * core method for storing state for a set of AlignFrames.
716 * - frames involving all data to be exported (including containing
719 * - project output stream
721 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
723 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
726 * ensure cached data is clear before starting
728 // todo tidy up seqRefIds, seqsToIds initialisation / reset
730 splitFrameCandidates.clear();
735 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
736 // //////////////////////////////////////////////////
738 List<String> shortNames = new ArrayList<>();
739 List<String> viewIds = new ArrayList<>();
742 for (int i = frames.size() - 1; i > -1; i--)
744 AlignFrame af = frames.get(i);
746 if (skipList != null && skipList
747 .containsKey(af.getViewport().getSequenceSetId()))
752 String shortName = makeFilename(af, shortNames);
754 int apSize = af.getAlignPanels().size();
756 for (int ap = 0; ap < apSize; ap++)
758 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
760 String fileName = apSize == 1 ? shortName : ap + shortName;
761 if (!fileName.endsWith(".xml"))
763 fileName = fileName + ".xml";
766 saveState(apanel, fileName, jout, viewIds);
768 String dssid = getDatasetIdRef(
769 af.getViewport().getAlignment().getDataset());
770 if (!dsses.containsKey(dssid))
772 dsses.put(dssid, af);
777 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
783 } catch (Exception foo)
787 } catch (Exception ex)
789 // TODO: inform user of the problem - they need to know if their data was
791 if (errorMessage == null)
793 errorMessage = "Couldn't write Jalview Archive - see error output for details";
795 ex.printStackTrace();
800 * Generates a distinct file name, based on the title of the AlignFrame, by
801 * appending _n for increasing n until an unused name is generated. The new
802 * name (without its extension) is added to the list.
806 * @return the generated name, with .xml extension
808 protected String makeFilename(AlignFrame af, List<String> namesUsed)
810 String shortName = af.getTitle();
812 if (shortName.indexOf(File.separatorChar) > -1)
814 shortName = shortName
815 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
820 while (namesUsed.contains(shortName))
822 if (shortName.endsWith("_" + (count - 1)))
824 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
827 shortName = shortName.concat("_" + count);
831 namesUsed.add(shortName);
833 if (!shortName.endsWith(".xml"))
835 shortName = shortName + ".xml";
840 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
841 public boolean saveAlignment(AlignFrame af, String jarFile,
846 // create backupfiles object and get new temp filename destination
847 boolean doBackup = BackupFiles.getEnabled();
848 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
849 FileOutputStream fos = new FileOutputStream(
850 doBackup ? backupfiles.getTempFilePath() : jarFile);
852 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
854 int n = debugDelaySave;
858 Console.debug("***** debugging save sleep " + i + "/" + n);
862 } catch (InterruptedException e)
864 // TODO Auto-generated catch block
871 JarOutputStream jout = new JarOutputStream(fos);
872 List<AlignFrame> frames = new ArrayList<>();
874 // resolve splitframes
875 if (af.getViewport().getCodingComplement() != null)
877 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
883 saveAllFrames(frames, jout);
887 } catch (Exception foo)
891 boolean success = true;
895 backupfiles.setWriteSuccess(success);
896 success = backupfiles.rollBackupsAndRenameTempFile();
900 } catch (Exception ex)
902 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
903 ex.printStackTrace();
908 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
909 String fileName, JarOutputStream jout)
912 for (String dssids : dsses.keySet())
914 AlignFrame _af = dsses.get(dssids);
915 String jfileName = fileName + " Dataset for " + _af.getTitle();
916 if (!jfileName.endsWith(".xml"))
918 jfileName = jfileName + ".xml";
920 saveState(_af.alignPanel, jfileName, true, jout, null);
925 * create a JalviewModel from an alignment view and marshall it to a
929 * panel to create jalview model for
931 * name of alignment panel written to output stream
938 public JalviewModel saveState(AlignmentPanel ap, String fileName,
939 JarOutputStream jout, List<String> viewIds)
941 return saveState(ap, fileName, false, jout, viewIds);
945 * create a JalviewModel from an alignment view and marshall it to a
949 * panel to create jalview model for
951 * name of alignment panel written to output stream
953 * when true, only write the dataset for the alignment, not the data
954 * associated with the view.
960 public JalviewModel saveState(AlignmentPanel ap, String fileName,
961 boolean storeDS, JarOutputStream jout, List<String> viewIds)
965 viewIds = new ArrayList<>();
970 List<UserColourScheme> userColours = new ArrayList<>();
972 AlignViewport av = ap.av;
973 ViewportRanges vpRanges = av.getRanges();
975 final ObjectFactory objectFactory = new ObjectFactory();
976 JalviewModel object = objectFactory.createJalviewModel();
977 object.setVamsasModel(new VAMSAS());
979 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
982 GregorianCalendar c = new GregorianCalendar();
983 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
984 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
985 object.setCreationDate(now);
986 } catch (DatatypeConfigurationException e)
988 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
990 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
993 * rjal is full height alignment, jal is actual alignment with full metadata
994 * but excludes hidden sequences.
996 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
998 if (av.hasHiddenRows())
1000 rjal = jal.getHiddenSequences().getFullAlignment();
1003 SequenceSet vamsasSet = new SequenceSet();
1005 // JalviewModelSequence jms = new JalviewModelSequence();
1007 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1009 if (jal.getDataset() != null)
1011 // dataset id is the dataset's hashcode
1012 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1015 // switch jal and the dataset
1016 jal = jal.getDataset();
1020 if (jal.getProperties() != null)
1022 Enumeration en = jal.getProperties().keys();
1023 while (en.hasMoreElements())
1025 String key = en.nextElement().toString();
1026 SequenceSetProperties ssp = new SequenceSetProperties();
1028 ssp.setValue(jal.getProperties().get(key).toString());
1029 // vamsasSet.addSequenceSetProperties(ssp);
1030 vamsasSet.getSequenceSetProperties().add(ssp);
1035 Set<String> calcIdSet = new HashSet<>();
1036 // record the set of vamsas sequence XML POJO we create.
1037 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1039 for (final SequenceI jds : rjal.getSequences())
1041 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1042 : jds.getDatasetSequence();
1043 String id = seqHash(jds);
1044 if (vamsasSetIds.get(id) == null)
1046 if (seqRefIds.get(id) != null && !storeDS)
1048 // This happens for two reasons: 1. multiple views are being
1050 // 2. the hashCode has collided with another sequence's code. This
1052 // HAPPEN! (PF00072.15.stk does this)
1053 // JBPNote: Uncomment to debug writing out of files that do not read
1054 // back in due to ArrayOutOfBoundExceptions.
1055 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1056 // jalview.bin.Console.errPrintln(jds.getName()+"
1057 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1058 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1059 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1060 // jalview.bin.Console.errPrintln(rsq.getName()+"
1061 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1062 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1066 vamsasSeq = createVamsasSequence(id, jds);
1067 // vamsasSet.addSequence(vamsasSeq);
1068 vamsasSet.getSequence().add(vamsasSeq);
1069 vamsasSetIds.put(id, vamsasSeq);
1070 seqRefIds.put(id, jds);
1074 jseq.setStart(jds.getStart());
1075 jseq.setEnd(jds.getEnd());
1076 jseq.setColour(av.getSequenceColour(jds).getRGB());
1078 jseq.setId(id); // jseq id should be a string not a number
1081 // Store any sequences this sequence represents
1082 if (av.hasHiddenRows())
1084 // use rjal, contains the full height alignment
1086 av.getAlignment().getHiddenSequences().isHidden(jds));
1088 if (av.isHiddenRepSequence(jds))
1090 jalview.datamodel.SequenceI[] reps = av
1091 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1093 for (int h = 0; h < reps.length; h++)
1097 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1098 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1103 // mark sequence as reference - if it is the reference for this view
1104 if (jal.hasSeqrep())
1106 jseq.setViewreference(jds == jal.getSeqrep());
1110 // TODO: omit sequence features from each alignment view's XML dump if we
1111 // are storing dataset
1112 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1113 for (SequenceFeature sf : sfs)
1115 // Features features = new Features();
1116 Feature features = new Feature();
1118 features.setBegin(sf.getBegin());
1119 features.setEnd(sf.getEnd());
1120 features.setDescription(sf.getDescription());
1121 features.setType(sf.getType());
1122 features.setFeatureGroup(sf.getFeatureGroup());
1123 features.setScore(sf.getScore());
1124 if (sf.links != null)
1126 for (int l = 0; l < sf.links.size(); l++)
1128 OtherData keyValue = new OtherData();
1129 keyValue.setKey("LINK_" + l);
1130 keyValue.setValue(sf.links.elementAt(l).toString());
1131 // features.addOtherData(keyValue);
1132 features.getOtherData().add(keyValue);
1135 if (sf.otherDetails != null)
1138 * save feature attributes, which may be simple strings or
1139 * map valued (have sub-attributes)
1141 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1143 String key = entry.getKey();
1144 Object value = entry.getValue();
1145 if (value instanceof Map<?, ?>)
1147 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1150 OtherData otherData = new OtherData();
1151 otherData.setKey(key);
1152 otherData.setKey2(subAttribute.getKey());
1153 otherData.setValue(subAttribute.getValue().toString());
1154 // features.addOtherData(otherData);
1155 features.getOtherData().add(otherData);
1160 OtherData otherData = new OtherData();
1161 otherData.setKey(key);
1162 otherData.setValue(value.toString());
1163 // features.addOtherData(otherData);
1164 features.getOtherData().add(otherData);
1169 // jseq.addFeatures(features);
1170 jseq.getFeatures().add(features);
1173 if (jdatasq.getAllPDBEntries() != null)
1175 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1176 while (en.hasMoreElements())
1178 Pdbids pdb = new Pdbids();
1179 jalview.datamodel.PDBEntry entry = en.nextElement();
1181 String pdbId = entry.getId();
1183 pdb.setType(entry.getType());
1186 * Store any structure views associated with this sequence. This
1187 * section copes with duplicate entries in the project, so a dataset
1188 * only view *should* be coped with sensibly.
1190 // This must have been loaded, is it still visible?
1191 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1192 if (Desktop.desktop != null)
1194 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1197 for (JInternalFrame jif : jifs)
1199 if (jif instanceof JalviewStructureDisplayI)
1201 viewFrames.add((JalviewStructureDisplayI) jif);
1206 else if (Jalview.isHeadlessMode()
1207 && Jalview.getInstance().getCommands() != null)
1210 StructureViewerBase.getAllStructureViewerBases());
1213 String matchedFile = null;
1214 for (JalviewStructureDisplayI viewFrame : viewFrames)
1216 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1217 matchedFile, viewFrame);
1219 * Only store each structure viewer's state once in the project
1220 * jar. First time through only (storeDS==false)
1222 String viewId = viewFrame.getViewId();
1223 String viewerType = viewFrame.getViewerType().toString();
1224 if (!storeDS && !viewIds.contains(viewId))
1226 viewIds.add(viewId);
1227 File viewerState = viewFrame.saveSession();
1228 if (viewerState != null)
1230 copyFileToJar(jout, viewerState.getPath(),
1231 getViewerJarEntryName(viewId), viewerType);
1236 "Failed to save viewer state for " + viewerType);
1241 if (matchedFile != null || entry.getFile() != null)
1243 if (entry.getFile() != null)
1246 matchedFile = entry.getFile();
1248 pdb.setFile(matchedFile); // entry.getFile());
1249 if (pdbfiles == null)
1251 pdbfiles = new ArrayList<>();
1254 if (!pdbfiles.contains(pdbId))
1256 pdbfiles.add(pdbId);
1257 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1261 Enumeration<String> props = entry.getProperties();
1262 if (props.hasMoreElements())
1264 // PdbentryItem item = new PdbentryItem();
1265 while (props.hasMoreElements())
1267 Property prop = new Property();
1268 String key = props.nextElement();
1270 prop.setValue(entry.getProperty(key).toString());
1271 // item.addProperty(prop);
1272 pdb.getProperty().add(prop);
1274 // pdb.addPdbentryItem(item);
1277 // jseq.addPdbids(pdb);
1278 jseq.getPdbids().add(pdb);
1282 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1284 // jms.addJSeq(jseq);
1285 object.getJSeq().add(jseq);
1288 if (!storeDS && av.hasHiddenRows())
1290 jal = av.getAlignment();
1294 if (storeDS && jal.getCodonFrames() != null)
1296 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1297 for (AlignedCodonFrame acf : jac)
1299 AlcodonFrame alc = new AlcodonFrame();
1300 if (acf.getProtMappings() != null
1301 && acf.getProtMappings().length > 0)
1303 boolean hasMap = false;
1304 SequenceI[] dnas = acf.getdnaSeqs();
1305 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1306 for (int m = 0; m < pmaps.length; m++)
1308 AlcodMap alcmap = new AlcodMap();
1309 alcmap.setDnasq(seqHash(dnas[m]));
1311 createVamsasMapping(pmaps[m], dnas[m], null, false));
1312 // alc.addAlcodMap(alcmap);
1313 alc.getAlcodMap().add(alcmap);
1318 // vamsasSet.addAlcodonFrame(alc);
1319 vamsasSet.getAlcodonFrame().add(alc);
1322 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1324 // AlcodonFrame alc = new AlcodonFrame();
1325 // vamsasSet.addAlcodonFrame(alc);
1326 // for (int p = 0; p < acf.aaWidth; p++)
1328 // Alcodon cmap = new Alcodon();
1329 // if (acf.codons[p] != null)
1331 // // Null codons indicate a gapped column in the translated peptide
1333 // cmap.setPos1(acf.codons[p][0]);
1334 // cmap.setPos2(acf.codons[p][1]);
1335 // cmap.setPos3(acf.codons[p][2]);
1337 // alc.addAlcodon(cmap);
1339 // if (acf.getProtMappings() != null
1340 // && acf.getProtMappings().length > 0)
1342 // SequenceI[] dnas = acf.getdnaSeqs();
1343 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1344 // for (int m = 0; m < pmaps.length; m++)
1346 // AlcodMap alcmap = new AlcodMap();
1347 // alcmap.setDnasq(seqHash(dnas[m]));
1348 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1350 // alc.addAlcodMap(alcmap);
1357 // /////////////////////////////////
1358 if (!storeDS && av.getCurrentTree() != null)
1360 // FIND ANY ASSOCIATED TREES
1361 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1362 if (Desktop.desktop != null)
1364 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1366 for (int t = 0; t < frames.length; t++)
1368 if (frames[t] instanceof TreePanel)
1370 TreePanel tp = (TreePanel) frames[t];
1372 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1374 JalviewModel.Tree tree = new JalviewModel.Tree();
1375 tree.setTitle(tp.getTitle());
1376 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1377 tree.setNewick(tp.getTree().print());
1378 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1380 tree.setFitToWindow(tp.fitToWindow.getState());
1381 tree.setFontName(tp.getTreeFont().getName());
1382 tree.setFontSize(tp.getTreeFont().getSize());
1383 tree.setFontStyle(tp.getTreeFont().getStyle());
1384 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1386 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1387 tree.setShowDistances(tp.distanceMenu.getState());
1389 tree.setHeight(tp.getHeight());
1390 tree.setWidth(tp.getWidth());
1391 tree.setXpos(tp.getX());
1392 tree.setYpos(tp.getY());
1393 tree.setId(makeHashCode(tp, null));
1394 tree.setLinkToAllViews(
1395 tp.getTreeCanvas().isApplyToAllViews());
1398 if (tp.isColumnWise())
1400 tree.setColumnWise(true);
1401 String annId = tp.getAssocAnnotation().annotationId;
1402 tree.setColumnReference(annId);
1404 // jms.addTree(tree);
1405 object.getTree().add(tree);
1415 if (!storeDS && Desktop.desktop != null)
1417 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1419 if (frame instanceof PCAPanel)
1421 PCAPanel panel = (PCAPanel) frame;
1422 if (panel.getAlignViewport().getAlignment() == jal)
1424 savePCA(panel, object);
1432 * store forward refs from an annotationRow to any groups
1434 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1437 for (SequenceI sq : jal.getSequences())
1439 // Store annotation on dataset sequences only
1440 AlignmentAnnotation[] aa = sq.getAnnotation();
1441 if (aa != null && aa.length > 0)
1443 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1450 if (jal.getAlignmentAnnotation() != null)
1452 // Store the annotation shown on the alignment.
1453 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1454 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1459 if (jal.getGroups() != null)
1461 JGroup[] groups = new JGroup[jal.getGroups().size()];
1463 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1465 JGroup jGroup = new JGroup();
1466 groups[++i] = jGroup;
1468 jGroup.setStart(sg.getStartRes());
1469 jGroup.setEnd(sg.getEndRes());
1470 jGroup.setName(sg.getName());
1471 if (groupRefs.containsKey(sg))
1473 // group has references so set its ID field
1474 jGroup.setId(groupRefs.get(sg));
1476 ColourSchemeI colourScheme = sg.getColourScheme();
1477 if (colourScheme != null)
1479 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1480 if (groupColourScheme.conservationApplied())
1482 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1484 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1486 jGroup.setColour(setUserColourScheme(colourScheme,
1487 userColours, object));
1491 jGroup.setColour(colourScheme.getSchemeName());
1494 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1496 jGroup.setColour("AnnotationColourGradient");
1497 jGroup.setAnnotationColours(constructAnnotationColours(
1498 (jalview.schemes.AnnotationColourGradient) colourScheme,
1499 userColours, object));
1501 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1504 setUserColourScheme(colourScheme, userColours, object));
1508 jGroup.setColour(colourScheme.getSchemeName());
1511 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1514 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1515 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1516 jGroup.setDisplayText(sg.getDisplayText());
1517 jGroup.setColourText(sg.getColourText());
1518 jGroup.setTextCol1(sg.textColour.getRGB());
1519 jGroup.setTextCol2(sg.textColour2.getRGB());
1520 jGroup.setTextColThreshold(sg.thresholdTextColour);
1521 jGroup.setShowUnconserved(sg.getShowNonconserved());
1522 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1523 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1524 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1525 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1526 for (SequenceI seq : sg.getSequences())
1528 // jGroup.addSeq(seqHash(seq));
1529 jGroup.getSeq().add(seqHash(seq));
1533 // jms.setJGroup(groups);
1535 for (JGroup grp : groups)
1537 object.getJGroup().add(grp);
1542 // /////////SAVE VIEWPORT
1543 Viewport view = new Viewport();
1544 view.setTitle(ap.alignFrame.getTitle());
1545 view.setSequenceSetId(
1546 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1547 view.setId(av.getViewId());
1548 if (av.getCodingComplement() != null)
1550 view.setComplementId(av.getCodingComplement().getViewId());
1552 view.setViewName(av.getViewName());
1553 view.setGatheredViews(av.isGatherViewsHere());
1555 Rectangle size = ap.av.getExplodedGeometry();
1556 Rectangle position = size;
1559 size = ap.alignFrame.getBounds();
1560 if (av.getCodingComplement() != null)
1562 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1570 view.setXpos(position.x);
1571 view.setYpos(position.y);
1573 view.setWidth(size.width);
1574 view.setHeight(size.height);
1576 view.setStartRes(vpRanges.getStartRes());
1577 view.setStartSeq(vpRanges.getStartSeq());
1579 OverviewPanel ov = ap.getOverviewPanel();
1582 Overview overview = new Overview();
1583 overview.setTitle(ov.getTitle());
1584 Rectangle bounds = ov.getFrameBounds();
1585 overview.setXpos(bounds.x);
1586 overview.setYpos(bounds.y);
1587 overview.setWidth(bounds.width);
1588 overview.setHeight(bounds.height);
1589 overview.setShowHidden(ov.isShowHiddenRegions());
1590 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1591 overview.setResidueColour(
1592 ov.getCanvas().getResidueColour().getRGB());
1593 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1594 view.setOverview(overview);
1596 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1598 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1599 userColours, object));
1602 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1604 AnnotationColourScheme ac = constructAnnotationColours(
1605 (jalview.schemes.AnnotationColourGradient) av
1606 .getGlobalColourScheme(),
1607 userColours, object);
1609 view.setAnnotationColours(ac);
1610 view.setBgColour("AnnotationColourGradient");
1614 view.setBgColour(ColourSchemeProperty
1615 .getColourName(av.getGlobalColourScheme()));
1618 ResidueShaderI vcs = av.getResidueShading();
1619 ColourSchemeI cs = av.getGlobalColourScheme();
1623 if (vcs.conservationApplied())
1625 view.setConsThreshold(vcs.getConservationInc());
1626 if (cs instanceof jalview.schemes.UserColourScheme)
1628 view.setBgColour(setUserColourScheme(cs, userColours, object));
1631 view.setPidThreshold(vcs.getThreshold());
1634 view.setConservationSelected(av.getConservationSelected());
1635 view.setPidSelected(av.getAbovePIDThreshold());
1636 view.setCharHeight(av.getCharHeight());
1637 view.setCharWidth(av.getCharWidth());
1638 final Font font = av.getFont();
1639 view.setFontName(font.getName());
1640 view.setFontSize(font.getSize());
1641 view.setFontStyle(font.getStyle());
1642 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1643 view.setRenderGaps(av.isRenderGaps());
1644 view.setShowAnnotation(av.isShowAnnotation());
1645 view.setShowBoxes(av.getShowBoxes());
1646 view.setShowColourText(av.getColourText());
1647 view.setShowFullId(av.getShowJVSuffix());
1648 view.setRightAlignIds(av.isRightAlignIds());
1649 view.setIdWidth(av.getIdWidth());
1650 view.setIdWidthManuallyAdjusted(ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1652 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1653 view.setShowText(av.getShowText());
1654 view.setShowUnconserved(av.getShowUnconserved());
1655 view.setWrapAlignment(av.getWrapAlignment());
1656 view.setTextCol1(av.getTextColour().getRGB());
1657 view.setTextCol2(av.getTextColour2().getRGB());
1658 view.setTextColThreshold(av.getThresholdTextColour());
1659 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1660 view.setShowSequenceLogo(av.isShowSequenceLogo());
1661 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1662 view.setShowGroupConsensus(av.isShowGroupConsensus());
1663 view.setShowGroupConservation(av.isShowGroupConservation());
1664 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1665 view.setShowDbRefTooltip(av.isShowDBRefs());
1666 view.setFollowHighlight(av.isFollowHighlight());
1667 view.setFollowSelection(av.followSelection);
1668 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1669 view.setShowComplementFeatures(av.isShowComplementFeatures());
1670 view.setShowComplementFeaturesOnTop(
1671 av.isShowComplementFeaturesOnTop());
1672 if (av.getFeaturesDisplayed() != null)
1674 FeatureSettings fs = new FeatureSettings();
1676 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1677 .getFeatureRenderer();
1678 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1680 Vector<String> settingsAdded = new Vector<>();
1681 if (renderOrder != null)
1683 for (String featureType : renderOrder)
1685 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1686 setting.setType(featureType);
1689 * save any filter for the feature type
1691 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1694 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1696 FeatureMatcherI firstFilter = filters.next();
1697 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1698 filters, filter.isAnded()));
1702 * save colour scheme for the feature type
1704 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1705 if (!fcol.isSimpleColour())
1707 setting.setColour(fcol.getMaxColour().getRGB());
1708 setting.setMincolour(fcol.getMinColour().getRGB());
1709 setting.setMin(fcol.getMin());
1710 setting.setMax(fcol.getMax());
1711 setting.setColourByLabel(fcol.isColourByLabel());
1712 if (fcol.isColourByAttribute())
1714 String[] attName = fcol.getAttributeName();
1715 setting.getAttributeName().add(attName[0]);
1716 if (attName.length > 1)
1718 setting.getAttributeName().add(attName[1]);
1721 setting.setAutoScale(fcol.isAutoScaled());
1722 setting.setThreshold(fcol.getThreshold());
1723 Color noColour = fcol.getNoColour();
1724 if (noColour == null)
1726 setting.setNoValueColour(NoValueColour.NONE);
1728 else if (noColour.equals(fcol.getMaxColour()))
1730 setting.setNoValueColour(NoValueColour.MAX);
1734 setting.setNoValueColour(NoValueColour.MIN);
1736 // -1 = No threshold, 0 = Below, 1 = Above
1737 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1738 : (fcol.isBelowThreshold() ? 0 : -1));
1742 setting.setColour(fcol.getColour().getRGB());
1746 av.getFeaturesDisplayed().isVisible(featureType));
1747 float rorder = fr.getOrder(featureType);
1750 setting.setOrder(rorder);
1752 /// fs.addSetting(setting);
1753 fs.getSetting().add(setting);
1754 settingsAdded.addElement(featureType);
1758 // is groups actually supposed to be a map here ?
1759 Iterator<String> en = fr.getFeatureGroups().iterator();
1760 Vector<String> groupsAdded = new Vector<>();
1761 while (en.hasNext())
1763 String grp = en.next();
1764 if (groupsAdded.contains(grp))
1768 Group g = new Group();
1770 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1773 fs.getGroup().add(g);
1774 groupsAdded.addElement(grp);
1776 // jms.setFeatureSettings(fs);
1777 object.setFeatureSettings(fs);
1780 if (av.hasHiddenColumns())
1782 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1783 .getHiddenColumns();
1787 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1791 Iterator<int[]> hiddenRegions = hidden.iterator();
1792 while (hiddenRegions.hasNext())
1794 int[] region = hiddenRegions.next();
1795 HiddenColumns hc = new HiddenColumns();
1796 hc.setStart(region[0]);
1797 hc.setEnd(region[1]);
1798 // view.addHiddenColumns(hc);
1799 view.getHiddenColumns().add(hc);
1803 if (calcIdSet.size() > 0)
1805 for (String calcId : calcIdSet)
1807 if (calcId.trim().length() > 0)
1809 CalcIdParam cidp = createCalcIdParam(calcId, av);
1810 // Some calcIds have no parameters.
1813 // view.addCalcIdParam(cidp);
1814 view.getCalcIdParam().add(cidp);
1820 // jms.addViewport(view);
1821 object.getViewport().add(view);
1827 // store matrices referenced by any views or annotation in this dataset
1828 if (xmlMatrices!=null && xmlMatrices.size()>0)
1830 Console.debug("Adding "+xmlMatrices.size()+" matrices to dataset.");
1831 vamsasSet.getMatrix().addAll(xmlMatrices);
1832 xmlMatrices.clear();
1837 // object.setJalviewModelSequence(jms);
1838 // object.getVamsasModel().addSequenceSet(vamsasSet);
1839 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1841 if (jout != null && fileName != null)
1843 // We may not want to write the object to disk,
1844 // eg we can copy the alignViewport to a new view object
1845 // using save and then load
1848 fileName = fileName.replace('\\', '/');
1849 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1850 JarEntry entry = new JarEntry(fileName);
1851 jout.putNextEntry(entry);
1852 PrintWriter pout = new PrintWriter(
1853 new OutputStreamWriter(jout, UTF_8));
1854 JAXBContext jaxbContext = JAXBContext
1855 .newInstance(JalviewModel.class);
1856 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1858 // output pretty printed
1859 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1860 jaxbMarshaller.marshal(
1861 new ObjectFactory().createJalviewModel(object), pout);
1863 // jaxbMarshaller.marshal(object, pout);
1864 // marshaller.marshal(object);
1867 } catch (Exception ex)
1869 // TODO: raise error in GUI if marshalling failed.
1870 jalview.bin.Console.errPrintln("Error writing Jalview project");
1871 ex.printStackTrace();
1878 * Writes PCA viewer attributes and computed values to an XML model object and
1879 * adds it to the JalviewModel. Any exceptions are reported by logging.
1881 protected void savePCA(PCAPanel panel, JalviewModel object)
1885 PcaViewer viewer = new PcaViewer();
1886 viewer.setHeight(panel.getHeight());
1887 viewer.setWidth(panel.getWidth());
1888 viewer.setXpos(panel.getX());
1889 viewer.setYpos(panel.getY());
1890 viewer.setTitle(panel.getTitle());
1891 PCAModel pcaModel = panel.getPcaModel();
1892 viewer.setScoreModelName(pcaModel.getScoreModelName());
1893 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1894 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1895 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1897 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1898 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1899 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1900 SeqPointMin spmin = new SeqPointMin();
1901 spmin.setXPos(spMin[0]);
1902 spmin.setYPos(spMin[1]);
1903 spmin.setZPos(spMin[2]);
1904 viewer.setSeqPointMin(spmin);
1905 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1906 SeqPointMax spmax = new SeqPointMax();
1907 spmax.setXPos(spMax[0]);
1908 spmax.setYPos(spMax[1]);
1909 spmax.setZPos(spMax[2]);
1910 viewer.setSeqPointMax(spmax);
1911 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1912 viewer.setLinkToAllViews(
1913 panel.getRotatableCanvas().isApplyToAllViews());
1914 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1915 viewer.setIncludeGaps(sp.includeGaps());
1916 viewer.setMatchGaps(sp.matchGaps());
1917 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1918 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1921 * sequence points on display
1923 for (jalview.datamodel.SequencePoint spt : pcaModel
1924 .getSequencePoints())
1926 SequencePoint point = new SequencePoint();
1927 point.setSequenceRef(seqHash(spt.getSequence()));
1928 point.setXPos(spt.coord.x);
1929 point.setYPos(spt.coord.y);
1930 point.setZPos(spt.coord.z);
1931 viewer.getSequencePoint().add(point);
1935 * (end points of) axes on display
1937 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1940 Axis axis = new Axis();
1944 viewer.getAxis().add(axis);
1948 * raw PCA data (note we are not restoring PCA inputs here -
1949 * alignment view, score model, similarity parameters)
1951 PcaDataType data = new PcaDataType();
1952 viewer.setPcaData(data);
1953 PCA pca = pcaModel.getPcaData();
1955 DoubleMatrix pm = new DoubleMatrix();
1956 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1957 data.setPairwiseMatrix(pm);
1959 DoubleMatrix tm = new DoubleMatrix();
1960 saveDoubleMatrix(pca.getTridiagonal(), tm);
1961 data.setTridiagonalMatrix(tm);
1963 DoubleMatrix eigenMatrix = new DoubleMatrix();
1964 data.setEigenMatrix(eigenMatrix);
1965 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1967 object.getPcaViewer().add(viewer);
1968 } catch (Throwable t)
1970 Console.error("Error saving PCA: " + t.getMessage());
1975 * Stores values from a matrix into an XML element, including (if present) the
1980 * @see #loadDoubleMatrix(DoubleMatrix)
1982 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1984 xmlMatrix.setRows(m.height());
1985 xmlMatrix.setColumns(m.width());
1986 for (int i = 0; i < m.height(); i++)
1988 DoubleVector row = new DoubleVector();
1989 for (int j = 0; j < m.width(); j++)
1991 row.getV().add(m.getValue(i, j));
1993 xmlMatrix.getRow().add(row);
1995 if (m.getD() != null)
1997 DoubleVector dVector = new DoubleVector();
1998 for (double d : m.getD())
2000 dVector.getV().add(d);
2002 xmlMatrix.setD(dVector);
2004 if (m.getE() != null)
2006 DoubleVector eVector = new DoubleVector();
2007 for (double e : m.getE())
2009 eVector.getV().add(e);
2011 xmlMatrix.setE(eVector);
2016 * Loads XML matrix data into a new Matrix object, including the D and/or E
2017 * vectors (if present)
2021 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2023 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2025 int rows = mData.getRows();
2026 double[][] vals = new double[rows][];
2028 for (int i = 0; i < rows; i++)
2030 List<Double> dVector = mData.getRow().get(i).getV();
2031 vals[i] = new double[dVector.size()];
2033 for (Double d : dVector)
2039 MatrixI m = new Matrix(vals);
2041 if (mData.getD() != null)
2043 List<Double> dVector = mData.getD().getV();
2044 double[] vec = new double[dVector.size()];
2046 for (Double d : dVector)
2052 if (mData.getE() != null)
2054 List<Double> dVector = mData.getE().getV();
2055 double[] vec = new double[dVector.size()];
2057 for (Double d : dVector)
2068 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2069 * for each viewer, with
2071 * <li>viewer geometry (position, size, split pane divider location)</li>
2072 * <li>index of the selected structure in the viewer (currently shows gapped
2074 * <li>the id of the annotation holding RNA secondary structure</li>
2075 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2077 * Varna viewer state is also written out (in native Varna XML) to separate
2078 * project jar entries. A separate entry is written for each RNA structure
2079 * displayed, with the naming convention
2081 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2089 * @param storeDataset
2091 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2092 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2093 boolean storeDataset)
2095 if (Desktop.desktop == null)
2099 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2100 for (int f = frames.length - 1; f > -1; f--)
2102 if (frames[f] instanceof AppVarna)
2104 AppVarna varna = (AppVarna) frames[f];
2106 * link the sequence to every viewer that is showing it and is linked to
2107 * its alignment panel
2109 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2111 String viewId = varna.getViewId();
2112 RnaViewer rna = new RnaViewer();
2113 rna.setViewId(viewId);
2114 rna.setTitle(varna.getTitle());
2115 rna.setXpos(varna.getX());
2116 rna.setYpos(varna.getY());
2117 rna.setWidth(varna.getWidth());
2118 rna.setHeight(varna.getHeight());
2119 rna.setDividerLocation(varna.getDividerLocation());
2120 rna.setSelectedRna(varna.getSelectedIndex());
2121 // jseq.addRnaViewer(rna);
2122 jseq.getRnaViewer().add(rna);
2125 * Store each Varna panel's state once in the project per sequence.
2126 * First time through only (storeDataset==false)
2128 // boolean storeSessions = false;
2129 // String sequenceViewId = viewId + seqsToIds.get(jds);
2130 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2132 // viewIds.add(sequenceViewId);
2133 // storeSessions = true;
2135 for (RnaModel model : varna.getModels())
2137 if (model.seq == jds)
2140 * VARNA saves each view (sequence or alignment secondary
2141 * structure, gapped or trimmed) as a separate XML file
2143 String jarEntryName = rnaSessions.get(model);
2144 if (jarEntryName == null)
2147 String varnaStateFile = varna.getStateInfo(model.rna);
2148 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2149 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2150 rnaSessions.put(model, jarEntryName);
2152 SecondaryStructure ss = new SecondaryStructure();
2153 String annotationId = varna.getAnnotation(jds).annotationId;
2154 ss.setAnnotationId(annotationId);
2155 ss.setViewerState(jarEntryName);
2156 ss.setGapped(model.gapped);
2157 ss.setTitle(model.title);
2158 // rna.addSecondaryStructure(ss);
2159 rna.getSecondaryStructure().add(ss);
2168 * Copy the contents of a file to a new entry added to the output jar
2172 * @param jarEntryName
2174 * additional identifying info to log to the console
2176 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2177 String jarEntryName, String msg)
2179 try (InputStream is = new FileInputStream(infilePath))
2181 File file = new File(infilePath);
2182 if (file.exists() && jout != null)
2184 jalview.bin.Console.outPrintln(
2185 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2186 jout.putNextEntry(new JarEntry(jarEntryName));
2189 // dis = new DataInputStream(new FileInputStream(file));
2190 // byte[] data = new byte[(int) file.length()];
2191 // dis.readFully(data);
2192 // writeJarEntry(jout, jarEntryName, data);
2194 } catch (Exception ex)
2196 ex.printStackTrace();
2201 * Copies input to output, in 4K buffers; handles any data (text or binary)
2205 * @throws IOException
2207 protected void copyAll(InputStream in, OutputStream out)
2210 byte[] buffer = new byte[4096];
2212 while ((bytesRead = in.read(buffer)) != -1)
2214 out.write(buffer, 0, bytesRead);
2219 * Save the state of a structure viewer
2224 * the archive XML element under which to save the state
2227 * @param matchedFile
2231 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2232 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2233 String matchedFile, JalviewStructureDisplayI viewFrame)
2235 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2238 * Look for any bindings for this viewer to the PDB file of interest
2239 * (including part matches excluding chain id)
2241 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2243 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2244 final String pdbId = pdbentry.getId();
2245 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2246 && entry.getId().toLowerCase(Locale.ROOT)
2247 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2250 * not interested in a binding to a different PDB entry here
2254 if (matchedFile == null)
2256 matchedFile = pdbentry.getFile();
2258 else if (!matchedFile.equals(pdbentry.getFile()))
2261 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2262 + pdbentry.getFile());
2266 // can get at it if the ID
2267 // match is ambiguous (e.g.
2270 for (int smap = 0; smap < viewFrame.getBinding()
2271 .getSequence()[peid].length; smap++)
2273 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2274 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2276 StructureState state = new StructureState();
2277 state.setVisible(true);
2278 state.setXpos(viewFrame.getY());
2279 state.setYpos(viewFrame.getY());
2280 state.setWidth(viewFrame.getWidth());
2281 state.setHeight(viewFrame.getHeight());
2282 final String viewId = viewFrame.getViewId();
2283 state.setViewId(viewId);
2284 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2285 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2286 state.setColourByJmol(viewFrame.isColouredByViewer());
2287 state.setType(viewFrame.getViewerType().toString());
2288 // pdb.addStructureState(state);
2289 pdb.getStructureState().add(state);
2297 * Populates the AnnotationColourScheme xml for save. This captures the
2298 * settings of the options in the 'Colour by Annotation' dialog.
2301 * @param userColours
2305 private AnnotationColourScheme constructAnnotationColours(
2306 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2309 AnnotationColourScheme ac = new AnnotationColourScheme();
2310 ac.setAboveThreshold(acg.getAboveThreshold());
2311 ac.setThreshold(acg.getAnnotationThreshold());
2312 // 2.10.2 save annotationId (unique) not annotation label
2313 ac.setAnnotation(acg.getAnnotation().annotationId);
2314 if (acg.getBaseColour() instanceof UserColourScheme)
2317 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2322 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2325 ac.setMaxColour(acg.getMaxColour().getRGB());
2326 ac.setMinColour(acg.getMinColour().getRGB());
2327 ac.setPerSequence(acg.isSeqAssociated());
2328 ac.setPredefinedColours(acg.isPredefinedColours());
2332 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2333 IdentityHashMap<SequenceGroup, String> groupRefs,
2334 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2335 SequenceSet vamsasSet)
2338 for (int i = 0; i < aa.length; i++)
2340 Annotation an = new Annotation();
2342 AlignmentAnnotation annotation = aa[i];
2343 if (annotation.annotationId != null)
2345 annotationIds.put(annotation.annotationId, annotation);
2348 an.setId(annotation.annotationId);
2350 an.setVisible(annotation.visible);
2352 an.setDescription(annotation.description);
2354 if (annotation.sequenceRef != null)
2356 // 2.9 JAL-1781 xref on sequence id rather than name
2357 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2359 if (annotation.groupRef != null)
2361 String groupIdr = groupRefs.get(annotation.groupRef);
2362 if (groupIdr == null)
2364 // make a locally unique String
2365 groupRefs.put(annotation.groupRef,
2366 groupIdr = ("" + System.currentTimeMillis()
2367 + annotation.groupRef.getName()
2368 + groupRefs.size()));
2370 an.setGroupRef(groupIdr.toString());
2373 // store all visualization attributes for annotation
2374 an.setGraphHeight(annotation.graphHeight);
2375 an.setCentreColLabels(annotation.centreColLabels);
2376 an.setScaleColLabels(annotation.scaleColLabel);
2377 an.setShowAllColLabels(annotation.showAllColLabels);
2378 an.setBelowAlignment(annotation.belowAlignment);
2380 if (annotation.graph > 0)
2383 an.setGraphType(annotation.graph);
2384 an.setGraphGroup(annotation.graphGroup);
2385 if (annotation.getThreshold() != null)
2387 ThresholdLine line = new ThresholdLine();
2388 line.setLabel(annotation.getThreshold().label);
2389 line.setValue(annotation.getThreshold().value);
2390 line.setColour(annotation.getThreshold().colour.getRGB());
2391 an.setThresholdLine(line);
2393 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2395 if (annotation.sequenceRef.getContactMaps() != null)
2397 ContactMatrixI cm = annotation.sequenceRef
2398 .getContactMatrixFor(annotation);
2401 storeMatrixFor(vamsasSet, an,annotation, cm);
2411 an.setLabel(annotation.label);
2413 if (annotation == av.getAlignmentQualityAnnot()
2414 || annotation == av.getAlignmentConservationAnnotation()
2415 || annotation == av.getAlignmentConsensusAnnotation()
2416 || annotation.autoCalculated)
2418 // new way of indicating autocalculated annotation -
2419 an.setAutoCalculated(annotation.autoCalculated);
2421 if (annotation.hasScore())
2423 an.setScore(annotation.getScore());
2426 if (annotation.getCalcId() != null)
2428 calcIdSet.add(annotation.getCalcId());
2429 an.setCalcId(annotation.getCalcId());
2431 if (annotation.hasProperties())
2433 for (String pr : annotation.getProperties())
2435 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2437 prop.setValue(annotation.getProperty(pr));
2438 an.getProperty().add(prop);
2442 AnnotationElement ae;
2443 if (annotation.annotations != null)
2445 an.setScoreOnly(false);
2446 for (int a = 0; a < annotation.annotations.length; a++)
2448 if ((annotation == null) || (annotation.annotations[a] == null))
2453 ae = new AnnotationElement();
2454 if (annotation.annotations[a].description != null)
2456 ae.setDescription(annotation.annotations[a].description);
2458 if (annotation.annotations[a].displayCharacter != null)
2460 ae.setDisplayCharacter(
2461 annotation.annotations[a].displayCharacter);
2464 if (!Float.isNaN(annotation.annotations[a].value))
2466 ae.setValue(annotation.annotations[a].value);
2470 if (annotation.annotations[a].secondaryStructure > ' ')
2472 ae.setSecondaryStructure(
2473 annotation.annotations[a].secondaryStructure + "");
2476 if (annotation.annotations[a].colour != null
2477 && annotation.annotations[a].colour != java.awt.Color.black)
2479 ae.setColour(annotation.annotations[a].colour.getRGB());
2482 // an.addAnnotationElement(ae);
2483 an.getAnnotationElement().add(ae);
2484 if (annotation.autoCalculated)
2486 // only write one non-null entry into the annotation row -
2487 // sufficient to get the visualization attributes necessary to
2495 an.setScoreOnly(true);
2497 if (!storeDS || (storeDS && !annotation.autoCalculated))
2499 // skip autocalculated annotation - these are only provided for
2501 // vamsasSet.addAnnotation(an);
2502 vamsasSet.getAnnotation().add(an);
2508 private void storeMatrixFor(SequenceSet root, Annotation an, AlignmentAnnotation annotation, ContactMatrixI cm)
2510 String cmId = contactMatrices.get(cm);
2511 MatrixType xmlmat=null;
2513 // first create an xml ref for the matrix data, if none exist
2516 xmlmat = new MatrixType();
2517 xmlmat.setType(cm.getType());
2518 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2519 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2520 // consider using an opaque to/from -> allow instance to control
2521 // its representation ?
2522 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2525 for (BitSet gp : cm.getGroups())
2527 xmlmat.getGroups().add(stringifyBitset(gp));
2532 // provenance object for tree ?
2533 xmlmat.getNewick().add(cm.getNewick());
2534 xmlmat.setTreeMethod(cm.getTreeMethod());
2536 if (cm.hasCutHeight())
2538 xmlmat.setCutHeight(cm.getCutHeight());
2540 xmlmat.setId(cmId = "m"+contactMatrices.size()+System.currentTimeMillis());
2541 Console.trace("Matrix data stored :"+cmId);
2542 contactMatrices.put(cm, cmId);
2543 contactMatrixRefs.put(cmId, cm);
2544 xmlMatrices.add(xmlmat);
2546 Console.trace("Existing Matrix stored :"+cmId);
2549 // now store mapping
2551 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2552 xmlmatmapping.setMatrix(cmId);
2554 // Pretty much all matrices currently managed in this way are
2555 // mappableContactMatrixI implementations - but check anyway
2556 if (cm instanceof MappableContactMatrixI)
2558 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2559 .getMapFor(annotation.sequenceRef);
2562 MapListType mp = new MapListType();
2563 List<int[]> r = mlst.getFromRanges();
2564 for (int[] range : r)
2566 MapListFrom mfrom = new MapListFrom();
2567 mfrom.setStart(range[0]);
2568 mfrom.setEnd(range[1]);
2569 // mp.addMapListFrom(mfrom);
2570 mp.getMapListFrom().add(mfrom);
2572 r = mlst.getToRanges();
2573 for (int[] range : r)
2575 MapListTo mto = new MapListTo();
2576 mto.setStart(range[0]);
2577 mto.setEnd(range[1]);
2578 // mp.addMapListTo(mto);
2579 mp.getMapListTo().add(mto);
2581 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2582 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2583 xmlmatmapping.setMapping(mp);
2587 an.getContactmatrix().add(xmlmatmapping);
2590 private String stringifyBitset(BitSet gp)
2592 StringBuilder sb = new StringBuilder();
2593 for (long val : gp.toLongArray())
2595 if (sb.length() > 0)
2601 return sb.toString();
2604 private BitSet deStringifyBitset(String stringified)
2606 if ("".equals(stringified) || stringified == null)
2608 return new BitSet();
2610 String[] longvals = stringified.split(",");
2611 long[] newlongvals = new long[longvals.length];
2612 for (int lv = 0; lv < longvals.length; lv++)
2616 newlongvals[lv] = Long.valueOf(longvals[lv]);
2617 } catch (Exception x)
2619 errorMessage += "Couldn't destringify bitset from: '" + stringified
2621 newlongvals[lv] = 0;
2624 return BitSet.valueOf(newlongvals);
2628 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2630 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2631 if (settings != null)
2633 CalcIdParam vCalcIdParam = new CalcIdParam();
2634 vCalcIdParam.setCalcId(calcId);
2635 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2636 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2637 // generic URI allowing a third party to resolve another instance of the
2638 // service used for this calculation
2639 for (String url : settings.getServiceURLs())
2641 // vCalcIdParam.addServiceURL(urls);
2642 vCalcIdParam.getServiceURL().add(url);
2644 vCalcIdParam.setVersion("1.0");
2645 if (settings.getPreset() != null)
2647 WsParamSetI setting = settings.getPreset();
2648 vCalcIdParam.setName(setting.getName());
2649 vCalcIdParam.setDescription(setting.getDescription());
2653 vCalcIdParam.setName("");
2654 vCalcIdParam.setDescription("Last used parameters");
2656 // need to be able to recover 1) settings 2) user-defined presets or
2657 // recreate settings from preset 3) predefined settings provided by
2658 // service - or settings that can be transferred (or discarded)
2659 vCalcIdParam.setParameters(
2660 settings.getWsParamFile().replace("\n", "|\\n|"));
2661 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2662 // todo - decide if updateImmediately is needed for any projects.
2664 return vCalcIdParam;
2669 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2672 if (calcIdParam.getVersion().equals("1.0"))
2674 final String[] calcIds = calcIdParam.getServiceURL()
2675 .toArray(new String[0]);
2676 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2677 .getPreferredServiceFor(calcIds);
2678 if (service != null)
2680 WsParamSetI parmSet = null;
2683 parmSet = service.getParamStore().parseServiceParameterFile(
2684 calcIdParam.getName(), calcIdParam.getDescription(),
2686 calcIdParam.getParameters().replace("|\\n|", "\n"));
2687 } catch (IOException x)
2689 Console.warn("Couldn't parse parameter data for "
2690 + calcIdParam.getCalcId(), x);
2693 List<ArgumentI> argList = null;
2694 if (calcIdParam.getName().length() > 0)
2696 parmSet = service.getParamStore()
2697 .getPreset(calcIdParam.getName());
2698 if (parmSet != null)
2700 // TODO : check we have a good match with settings in AACon -
2701 // otherwise we'll need to create a new preset
2706 argList = parmSet.getArguments();
2709 AAConSettings settings = new AAConSettings(
2710 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2711 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2712 calcIdParam.isNeedsUpdate());
2718 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2722 throw new Error(MessageManager.formatMessage(
2723 "error.unsupported_version_calcIdparam", new Object[]
2724 { calcIdParam.toString() }));
2728 * External mapping between jalview objects and objects yielding a valid and
2729 * unique object ID string. This is null for normal Jalview project IO, but
2730 * non-null when a jalview project is being read or written as part of a
2733 IdentityHashMap jv2vobj = null;
2736 * Construct a unique ID for jvobj using either existing bindings or if none
2737 * exist, the result of the hashcode call for the object.
2740 * jalview data object
2741 * @return unique ID for referring to jvobj
2743 private String makeHashCode(Object jvobj, String altCode)
2745 if (jv2vobj != null)
2747 Object id = jv2vobj.get(jvobj);
2750 return id.toString();
2752 // check string ID mappings
2753 if (jvids2vobj != null && jvobj instanceof String)
2755 id = jvids2vobj.get(jvobj);
2759 return id.toString();
2761 // give up and warn that something has gone wrong
2763 "Cannot find ID for object in external mapping : " + jvobj);
2769 * return local jalview object mapped to ID, if it exists
2773 * @return null or object bound to idcode
2775 private Object retrieveExistingObj(String idcode)
2777 if (idcode != null && vobj2jv != null)
2779 return vobj2jv.get(idcode);
2785 * binding from ID strings from external mapping table to jalview data model
2788 private Hashtable vobj2jv;
2790 private Sequence createVamsasSequence(String id, SequenceI jds)
2792 return createVamsasSequence(true, id, jds, null);
2795 private Sequence createVamsasSequence(boolean recurse, String id,
2796 SequenceI jds, SequenceI parentseq)
2798 Sequence vamsasSeq = new Sequence();
2799 vamsasSeq.setId(id);
2800 vamsasSeq.setName(jds.getName());
2801 vamsasSeq.setSequence(jds.getSequenceAsString());
2802 vamsasSeq.setDescription(jds.getDescription());
2803 List<DBRefEntry> dbrefs = null;
2804 if (jds.getDatasetSequence() != null)
2806 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2810 // seqId==dsseqid so we can tell which sequences really are
2811 // dataset sequences only
2812 vamsasSeq.setDsseqid(id);
2813 dbrefs = jds.getDBRefs();
2814 if (parentseq == null)
2821 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2825 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2827 DBRef dbref = new DBRef();
2828 DBRefEntry ref = dbrefs.get(d);
2829 dbref.setSource(ref.getSource());
2830 dbref.setVersion(ref.getVersion());
2831 dbref.setAccessionId(ref.getAccessionId());
2832 dbref.setCanonical(ref.isCanonical());
2833 if (ref instanceof GeneLocus)
2835 dbref.setLocus(true);
2839 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2841 dbref.setMapping(mp);
2843 vamsasSeq.getDBRef().add(dbref);
2849 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2850 SequenceI parentseq, SequenceI jds, boolean recurse)
2853 if (jmp.getMap() != null)
2857 jalview.util.MapList mlst = jmp.getMap();
2858 List<int[]> r = mlst.getFromRanges();
2859 for (int[] range : r)
2861 MapListFrom mfrom = new MapListFrom();
2862 mfrom.setStart(range[0]);
2863 mfrom.setEnd(range[1]);
2864 // mp.addMapListFrom(mfrom);
2865 mp.getMapListFrom().add(mfrom);
2867 r = mlst.getToRanges();
2868 for (int[] range : r)
2870 MapListTo mto = new MapListTo();
2871 mto.setStart(range[0]);
2872 mto.setEnd(range[1]);
2873 // mp.addMapListTo(mto);
2874 mp.getMapListTo().add(mto);
2876 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2877 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2878 if (jmp.getTo() != null)
2880 // MappingChoice mpc = new MappingChoice();
2882 // check/create ID for the sequence referenced by getTo()
2885 SequenceI ps = null;
2886 if (parentseq != jmp.getTo()
2887 && parentseq.getDatasetSequence() != jmp.getTo())
2889 // chaining dbref rather than a handshaking one
2890 jmpid = seqHash(ps = jmp.getTo());
2894 jmpid = seqHash(ps = parentseq);
2896 // mpc.setDseqFor(jmpid);
2897 mp.setDseqFor(jmpid);
2898 if (!seqRefIds.containsKey(jmpid))
2900 Console.debug("creatign new DseqFor ID");
2901 seqRefIds.put(jmpid, ps);
2905 Console.debug("reusing DseqFor ID");
2908 // mp.setMappingChoice(mpc);
2914 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2915 List<UserColourScheme> userColours, JalviewModel jm)
2918 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2919 boolean newucs = false;
2920 if (!userColours.contains(ucs))
2922 userColours.add(ucs);
2925 id = "ucs" + userColours.indexOf(ucs);
2928 // actually create the scheme's entry in the XML model
2929 java.awt.Color[] colours = ucs.getColours();
2930 UserColours uc = new UserColours();
2931 // UserColourScheme jbucs = new UserColourScheme();
2932 JalviewUserColours jbucs = new JalviewUserColours();
2934 for (int i = 0; i < colours.length; i++)
2936 Colour col = new Colour();
2937 col.setName(ResidueProperties.aa[i]);
2938 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2939 // jbucs.addColour(col);
2940 jbucs.getColour().add(col);
2942 if (ucs.getLowerCaseColours() != null)
2944 colours = ucs.getLowerCaseColours();
2945 for (int i = 0; i < colours.length; i++)
2947 Colour col = new Colour();
2948 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2949 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2950 // jbucs.addColour(col);
2951 jbucs.getColour().add(col);
2956 uc.setUserColourScheme(jbucs);
2957 // jm.addUserColours(uc);
2958 jm.getUserColours().add(uc);
2964 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2967 List<UserColours> uc = jm.getUserColours();
2968 UserColours colours = null;
2970 for (int i = 0; i < uc.length; i++)
2972 if (uc[i].getId().equals(id))
2979 for (UserColours c : uc)
2981 if (c.getId().equals(id))
2988 java.awt.Color[] newColours = new java.awt.Color[24];
2990 for (int i = 0; i < 24; i++)
2992 newColours[i] = new java.awt.Color(Integer.parseInt(
2993 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2994 colours.getUserColourScheme().getColour().get(i).getRGB(),
2998 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
3001 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3003 newColours = new java.awt.Color[23];
3004 for (int i = 0; i < 23; i++)
3006 newColours[i] = new java.awt.Color(
3007 Integer.parseInt(colours.getUserColourScheme().getColour()
3008 .get(i + 24).getRGB(), 16));
3010 ucs.setLowerCaseColours(newColours);
3017 * contains last error message (if any) encountered by XML loader.
3019 String errorMessage = null;
3022 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3023 * exceptions are raised during project XML parsing
3025 public boolean attemptversion1parse = false;
3028 * Load a jalview project archive from a jar file
3031 * - HTTP URL or filename
3033 public AlignFrame loadJalviewAlign(final Object file)
3036 jalview.gui.AlignFrame af = null;
3040 // create list to store references for any new Jmol viewers created
3041 newStructureViewers = new Vector<>();
3042 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3043 // Workaround is to make sure caller implements the JarInputStreamProvider
3045 // so we can re-open the jar input stream for each entry.
3047 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3048 af = loadJalviewAlign(jprovider);
3051 af.setMenusForViewport();
3053 } catch (MalformedURLException e)
3055 errorMessage = "Invalid URL format for '" + file + "'";
3061 SwingUtilities.invokeAndWait(new Runnable()
3066 setLoadingFinishedForNewStructureViewers();
3069 } catch (Exception x)
3072 .errPrintln("Error loading alignment: " + x.getMessage());
3078 @SuppressWarnings("unused")
3079 private jarInputStreamProvider createjarInputStreamProvider(
3080 final Object ofile) throws MalformedURLException
3083 // BH 2018 allow for bytes already attached to File object
3086 String file = (ofile instanceof File
3087 ? ((File) ofile).getCanonicalPath()
3088 : ofile.toString());
3089 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3092 errorMessage = null;
3093 uniqueSetSuffix = null;
3095 viewportsAdded.clear();
3096 frefedSequence = null;
3098 if (HttpUtils.startsWithHttpOrHttps(file))
3100 url = new URL(file);
3102 final URL _url = url;
3103 return new jarInputStreamProvider()
3107 public JarInputStream getJarInputStream() throws IOException
3111 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3112 // jarInputStream for
3113 // bytes.length=" + bytes.length);
3114 return new JarInputStream(new ByteArrayInputStream(bytes));
3118 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3119 // jarInputStream for "
3121 return new JarInputStream(_url.openStream());
3125 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3126 // jarInputStream for
3128 return new JarInputStream(new FileInputStream(file));
3133 public String getFilename()
3138 } catch (IOException e)
3140 e.printStackTrace();
3146 * Recover jalview session from a jalview project archive. Caller may
3147 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3148 * themselves. Any null fields will be initialised with default values,
3149 * non-null fields are left alone.
3154 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3156 errorMessage = null;
3157 if (uniqueSetSuffix == null)
3159 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3161 if (seqRefIds == null)
3165 AlignFrame af = null, _af = null;
3166 List<AlignFrame> toRepaint=new ArrayList<AlignFrame>();
3167 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3168 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3169 final String file = jprovider.getFilename();
3172 JarInputStream jin = null;
3173 JarEntry jarentry = null;
3178 jin = jprovider.getJarInputStream();
3179 for (int i = 0; i < entryCount; i++)
3181 jarentry = jin.getNextJarEntry();
3184 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3186 JAXBContext jc = JAXBContext
3187 .newInstance("jalview.xml.binding.jalview");
3188 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3189 .createXMLStreamReader(jin);
3190 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3191 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3192 JalviewModel.class);
3193 JalviewModel object = jbe.getValue();
3195 if (true) // !skipViewport(object))
3197 _af = loadFromObject(object, file, true, jprovider);
3198 if (_af != null && object.getViewport().size() > 0)
3199 // getJalviewModelSequence().getViewportCount() > 0)
3204 // store a reference to the first view
3207 if (_af.getViewport().isGatherViewsHere())
3209 // if this is a gathered view, keep its reference since
3210 // after gathering views, only this frame will remain
3212 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3215 // Save dataset to register mappings once all resolved
3216 importedDatasets.put(
3217 af.getViewport().getAlignment().getDataset(),
3218 af.getViewport().getAlignment().getDataset());
3223 else if (jarentry != null)
3225 // Some other file here.
3228 } while (jarentry != null);
3230 resolveFrefedSequences();
3231 for (AlignFrame alignFrame:toRepaint)
3233 alignFrame.repaint();
3235 } catch (IOException ex)
3237 ex.printStackTrace();
3238 errorMessage = "Couldn't locate Jalview XML file : " + file;
3239 jalview.bin.Console.errPrintln(
3240 "Exception whilst loading jalview XML file : " + ex + "\n");
3241 } catch (Exception ex)
3244 .errPrintln("Parsing as Jalview Version 2 file failed.");
3245 ex.printStackTrace(System.err);
3246 if (attemptversion1parse)
3248 // used to attempt to parse as V1 castor-generated xml
3250 if (Desktop.instance != null)
3252 Desktop.instance.stopLoading();
3256 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3259 ex.printStackTrace();
3261 jalview.bin.Console.errPrintln(
3262 "Exception whilst loading jalview XML file : " + ex + "\n");
3263 } catch (OutOfMemoryError e)
3265 // Don't use the OOM Window here
3266 errorMessage = "Out of memory loading jalview XML file";
3268 .errPrintln("Out of memory whilst loading jalview XML file");
3269 e.printStackTrace();
3273 * Regather multiple views (with the same sequence set id) to the frame (if
3274 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3275 * views instead of separate frames. Note this doesn't restore a state where
3276 * some expanded views in turn have tabbed views - the last "first tab" read
3277 * in will play the role of gatherer for all.
3279 for (AlignFrame fr : gatherToThisFrame.values())
3281 Desktop.instance.gatherViews(fr);
3284 restoreSplitFrames();
3285 for (AlignmentI ds : importedDatasets.keySet())
3287 if (ds.getCodonFrames() != null)
3289 StructureSelectionManager
3290 .getStructureSelectionManager(Desktop.instance)
3291 .registerMappings(ds.getCodonFrames());
3294 if (errorMessage != null)
3299 if (Desktop.instance != null)
3301 Desktop.instance.stopLoading();
3308 * Try to reconstruct and display SplitFrame windows, where each contains
3309 * complementary dna and protein alignments. Done by pairing up AlignFrame
3310 * objects (created earlier) which have complementary viewport ids associated.
3312 protected void restoreSplitFrames()
3314 List<SplitFrame> gatherTo = new ArrayList<>();
3315 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3316 Map<String, AlignFrame> dna = new HashMap<>();
3319 * Identify the DNA alignments
3321 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3324 AlignFrame af = candidate.getValue();
3325 if (af.getViewport().getAlignment().isNucleotide())
3327 dna.put(candidate.getKey().getId(), af);
3332 * Try to match up the protein complements
3334 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3337 AlignFrame af = candidate.getValue();
3338 if (!af.getViewport().getAlignment().isNucleotide())
3340 String complementId = candidate.getKey().getComplementId();
3341 // only non-null complements should be in the Map
3342 if (complementId != null && dna.containsKey(complementId))
3344 final AlignFrame dnaFrame = dna.get(complementId);
3345 SplitFrame sf = createSplitFrame(dnaFrame, af);
3346 addedToSplitFrames.add(dnaFrame);
3347 addedToSplitFrames.add(af);
3348 dnaFrame.setMenusForViewport();
3349 af.setMenusForViewport();
3350 if (af.getViewport().isGatherViewsHere())
3359 * Open any that we failed to pair up (which shouldn't happen!) as
3360 * standalone AlignFrame's.
3362 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3365 AlignFrame af = candidate.getValue();
3366 if (!addedToSplitFrames.contains(af))
3368 Viewport view = candidate.getKey();
3369 Desktop.addInternalFrame(af, view.getTitle(),
3370 safeInt(view.getWidth()), safeInt(view.getHeight()));
3371 af.setMenusForViewport();
3372 jalview.bin.Console.errPrintln("Failed to restore view "
3373 + view.getTitle() + " to split frame");
3378 * Gather back into tabbed views as flagged.
3380 for (SplitFrame sf : gatherTo)
3382 Desktop.instance.gatherViews(sf);
3385 splitFrameCandidates.clear();
3389 * Construct and display one SplitFrame holding DNA and protein alignments.
3392 * @param proteinFrame
3395 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3396 AlignFrame proteinFrame)
3398 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3399 String title = MessageManager.getString("label.linked_view_title");
3400 int width = (int) dnaFrame.getBounds().getWidth();
3401 int height = (int) (dnaFrame.getBounds().getHeight()
3402 + proteinFrame.getBounds().getHeight() + 50);
3405 * SplitFrame location is saved to both enclosed frames
3407 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3408 Desktop.addInternalFrame(splitFrame, title, width, height);
3411 * And compute cDNA consensus (couldn't do earlier with consensus as
3412 * mappings were not yet present)
3414 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3420 * check errorMessage for a valid error message and raise an error box in the
3421 * GUI or write the current errorMessage to stderr and then clear the error
3424 protected void reportErrors()
3426 reportErrors(false);
3429 protected void reportErrors(final boolean saving)
3431 if (errorMessage != null)
3433 final String finalErrorMessage = errorMessage;
3436 javax.swing.SwingUtilities.invokeLater(new Runnable()
3441 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3443 "Error " + (saving ? "saving" : "loading")
3445 JvOptionPane.WARNING_MESSAGE);
3451 jalview.bin.Console.errPrintln(
3452 "Problem loading Jalview file: " + errorMessage);
3455 errorMessage = null;
3458 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3461 * when set, local views will be updated from view stored in JalviewXML
3462 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3463 * sync if this is set to true.
3465 private final boolean updateLocalViews = false;
3468 * Returns the path to a temporary file holding the PDB file for the given PDB
3469 * id. The first time of asking, searches for a file of that name in the
3470 * Jalview project jar, and copies it to a new temporary file. Any repeat
3471 * requests just return the path to the file previously created.
3477 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3480 if (alreadyLoadedPDB.containsKey(pdbId))
3482 return alreadyLoadedPDB.get(pdbId).toString();
3485 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3487 if (tempFile != null)
3489 alreadyLoadedPDB.put(pdbId, tempFile);
3495 * Copies the jar entry of given name to a new temporary file and returns the
3496 * path to the file, or null if the entry is not found.
3499 * @param jarEntryName
3501 * a prefix for the temporary file name, must be at least three
3503 * @param suffixModel
3504 * null or original file - so new file can be given the same suffix
3508 protected String copyJarEntry(jarInputStreamProvider jprovider,
3509 String jarEntryName, String prefix, String suffixModel)
3511 String suffix = ".tmp";
3512 if (suffixModel == null)
3514 suffixModel = jarEntryName;
3516 int sfpos = suffixModel.lastIndexOf(".");
3517 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3519 suffix = "." + suffixModel.substring(sfpos + 1);
3522 try (JarInputStream jin = jprovider.getJarInputStream())
3524 JarEntry entry = null;
3527 entry = jin.getNextJarEntry();
3528 } while (entry != null && !entry.getName().equals(jarEntryName));
3532 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3533 File outFile = File.createTempFile(prefix, suffix);
3534 outFile.deleteOnExit();
3535 try (OutputStream os = new FileOutputStream(outFile))
3539 String t = outFile.getAbsolutePath();
3545 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3547 } catch (Exception ex)
3549 ex.printStackTrace();
3555 private class JvAnnotRow
3557 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3564 * persisted version of annotation row from which to take vis properties
3566 public jalview.datamodel.AlignmentAnnotation template;
3569 * original position of the annotation row in the alignment
3575 * Load alignment frame from jalview XML DOM object
3577 * @param jalviewModel
3580 * filename source string
3581 * @param loadTreesAndStructures
3582 * when false only create Viewport
3584 * data source provider
3585 * @return alignment frame created from view stored in DOM
3587 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3588 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3590 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3592 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3594 // JalviewModelSequence jms = object.getJalviewModelSequence();
3596 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3598 Viewport view = (jalviewModel.getViewport().size() > 0)
3599 ? jalviewModel.getViewport().get(0)
3602 // ////////////////////////////////
3603 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3606 // If we just load in the same jar file again, the sequenceSetId
3607 // will be the same, and we end up with multiple references
3608 // to the same sequenceSet. We must modify this id on load
3609 // so that each load of the file gives a unique id
3612 * used to resolve correct alignment dataset for alignments with multiple
3615 String uniqueSeqSetId = null;
3616 String viewId = null;
3619 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3620 viewId = (view.getId() == null ? null
3621 : view.getId() + uniqueSetSuffix);
3624 // ////////////////////////////////
3625 // LOAD MATRICES (IF ANY)
3627 if (vamsasSet.getMatrix()!=null && vamsasSet.getMatrix().size()>0)
3629 importMatrixData(vamsasSet.getMatrix());
3632 // ////////////////////////////////
3635 List<SequenceI> hiddenSeqs = null;
3637 List<SequenceI> tmpseqs = new ArrayList<>();
3639 boolean multipleView = false;
3640 SequenceI referenceseqForView = null;
3641 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3642 List<JSeq> jseqs = jalviewModel.getJSeq();
3643 int vi = 0; // counter in vamsasSeq array
3644 for (int i = 0; i < jseqs.size(); i++)
3646 JSeq jseq = jseqs.get(i);
3647 String seqId = jseq.getId();
3649 SequenceI tmpSeq = seqRefIds.get(seqId);
3652 if (!incompleteSeqs.containsKey(seqId))
3654 // may not need this check, but keep it for at least 2.9,1 release
3655 if (tmpSeq.getStart() != jseq.getStart()
3656 || tmpSeq.getEnd() != jseq.getEnd())
3658 jalview.bin.Console.errPrintln(String.format(
3659 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3660 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3661 jseq.getStart(), jseq.getEnd()));
3666 incompleteSeqs.remove(seqId);
3668 if (vamsasSeqs.size() > vi
3669 && vamsasSeqs.get(vi).getId().equals(seqId))
3671 // most likely we are reading a dataset XML document so
3672 // update from vamsasSeq section of XML for this sequence
3673 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3674 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3675 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3680 // reading multiple views, so vamsasSeq set is a subset of JSeq
3681 multipleView = true;
3683 tmpSeq.setStart(jseq.getStart());
3684 tmpSeq.setEnd(jseq.getEnd());
3685 tmpseqs.add(tmpSeq);
3689 Sequence vamsasSeq = vamsasSeqs.get(vi);
3690 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3691 vamsasSeq.getSequence());
3692 tmpSeq.setDescription(vamsasSeq.getDescription());
3693 tmpSeq.setStart(jseq.getStart());
3694 tmpSeq.setEnd(jseq.getEnd());
3695 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3696 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3697 tmpseqs.add(tmpSeq);
3701 if (safeBoolean(jseq.isViewreference()))
3703 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3706 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3708 if (hiddenSeqs == null)
3710 hiddenSeqs = new ArrayList<>();
3713 hiddenSeqs.add(tmpSeq);
3718 // Create the alignment object from the sequence set
3719 // ///////////////////////////////
3720 SequenceI[] orderedSeqs = tmpseqs
3721 .toArray(new SequenceI[tmpseqs.size()]);
3723 AlignmentI al = null;
3724 // so we must create or recover the dataset alignment before going further
3725 // ///////////////////////////////
3726 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3728 // older jalview projects do not have a dataset - so creat alignment and
3730 al = new Alignment(orderedSeqs);
3731 al.setDataset(null);
3735 boolean isdsal = jalviewModel.getViewport().isEmpty();
3738 // we are importing a dataset record, so
3739 // recover reference to an alignment already materialsed as dataset
3740 al = getDatasetFor(vamsasSet.getDatasetId());
3744 // materialse the alignment
3745 al = new Alignment(orderedSeqs);
3749 addDatasetRef(vamsasSet.getDatasetId(), al);
3752 // finally, verify all data in vamsasSet is actually present in al
3753 // passing on flag indicating if it is actually a stored dataset
3754 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3757 if (referenceseqForView != null)
3759 al.setSeqrep(referenceseqForView);
3761 // / Add the alignment properties
3762 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3764 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3766 al.setProperty(ssp.getKey(), ssp.getValue());
3769 // ///////////////////////////////
3771 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3774 // load sequence features, database references and any associated PDB
3775 // structures for the alignment
3777 // prior to 2.10, this part would only be executed the first time a
3778 // sequence was encountered, but not afterwards.
3779 // now, for 2.10 projects, this is also done if the xml doc includes
3780 // dataset sequences not actually present in any particular view.
3782 for (int i = 0; i < vamsasSeqs.size(); i++)
3784 JSeq jseq = jseqs.get(i);
3785 if (jseq.getFeatures().size() > 0)
3787 List<Feature> features = jseq.getFeatures();
3788 for (int f = 0; f < features.size(); f++)
3790 Feature feat = features.get(f);
3791 SequenceFeature sf = new SequenceFeature(feat.getType(),
3792 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3793 safeFloat(feat.getScore()), feat.getFeatureGroup());
3794 sf.setStatus(feat.getStatus());
3797 * load any feature attributes - include map-valued attributes
3799 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3800 for (int od = 0; od < feat.getOtherData().size(); od++)
3802 OtherData keyValue = feat.getOtherData().get(od);
3803 String attributeName = keyValue.getKey();
3804 String attributeValue = keyValue.getValue();
3805 if (attributeName.startsWith("LINK"))
3807 sf.addLink(attributeValue);
3811 String subAttribute = keyValue.getKey2();
3812 if (subAttribute == null)
3814 // simple string-valued attribute
3815 sf.setValue(attributeName, attributeValue);
3819 // attribute 'key' has sub-attribute 'key2'
3820 if (!mapAttributes.containsKey(attributeName))
3822 mapAttributes.put(attributeName, new HashMap<>());
3824 mapAttributes.get(attributeName).put(subAttribute,
3829 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3832 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3835 // adds feature to datasequence's feature set (since Jalview 2.10)
3836 al.getSequenceAt(i).addSequenceFeature(sf);
3839 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3841 // adds dbrefs to datasequence's set (since Jalview 2.10)
3843 al.getSequenceAt(i).getDatasetSequence() == null
3844 ? al.getSequenceAt(i)
3845 : al.getSequenceAt(i).getDatasetSequence(),
3848 if (jseq.getPdbids().size() > 0)
3850 List<Pdbids> ids = jseq.getPdbids();
3851 for (int p = 0; p < ids.size(); p++)
3853 Pdbids pdbid = ids.get(p);
3854 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3855 entry.setId(pdbid.getId());
3856 if (pdbid.getType() != null)
3858 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3860 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3864 entry.setType(PDBEntry.Type.FILE);
3867 // jprovider is null when executing 'New View'
3868 if (pdbid.getFile() != null && jprovider != null)
3870 if (!pdbloaded.containsKey(pdbid.getFile()))
3872 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3877 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3881 if (pdbid.getPdbentryItem() != null)
3883 for (PdbentryItem item : pdbid.getPdbentryItem())
3885 for (Property pr : item.getProperty())
3887 entry.setProperty(pr.getName(), pr.getValue());
3892 for (Property prop : pdbid.getProperty())
3894 entry.setProperty(prop.getName(), prop.getValue());
3896 StructureSelectionManager
3897 .getStructureSelectionManager(Desktop.instance)
3898 .registerPDBEntry(entry);
3899 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3900 if (al.getSequenceAt(i).getDatasetSequence() != null)
3902 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3906 al.getSequenceAt(i).addPDBId(entry);
3911 } // end !multipleview
3913 // ///////////////////////////////
3914 // LOAD SEQUENCE MAPPINGS
3916 if (vamsasSet.getAlcodonFrame().size() > 0)
3918 // TODO Potentially this should only be done once for all views of an
3920 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3921 for (int i = 0; i < alc.size(); i++)
3923 AlignedCodonFrame cf = new AlignedCodonFrame();
3924 if (alc.get(i).getAlcodMap().size() > 0)
3926 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3927 for (int m = 0; m < maps.size(); m++)
3929 AlcodMap map = maps.get(m);
3930 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3932 jalview.datamodel.Mapping mapping = null;
3933 // attach to dna sequence reference.
3934 if (map.getMapping() != null)
3936 mapping = addMapping(map.getMapping());
3937 if (dnaseq != null && mapping.getTo() != null)
3939 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3945 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3949 al.addCodonFrame(cf);
3954 // ////////////////////////////////
3956 List<JvAnnotRow> autoAlan = new ArrayList<>();
3959 * store any annotations which forward reference a group's ID
3961 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3963 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3965 List<Annotation> an = vamsasSet.getAnnotation();
3967 for (int i = 0; i < an.size(); i++)
3969 Annotation annotation = an.get(i);
3972 * test if annotation is automatically calculated for this view only
3974 boolean autoForView = false;
3975 if (annotation.getLabel().equals("Quality")
3976 || annotation.getLabel().equals("Conservation")
3977 || annotation.getLabel().equals("Consensus"))
3979 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3981 // JAXB has no has() test; schema defaults value to false
3982 // if (!annotation.hasAutoCalculated())
3984 // annotation.setAutoCalculated(true);
3987 if (autoForView || annotation.isAutoCalculated())
3989 // remove ID - we don't recover annotation from other views for
3990 // view-specific annotation
3991 annotation.setId(null);
3994 // set visibility for other annotation in this view
3995 String annotationId = annotation.getId();
3996 if (annotationId != null && annotationIds.containsKey(annotationId))
3998 AlignmentAnnotation jda = annotationIds.get(annotationId);
3999 // in principle Visible should always be true for annotation displayed
4000 // in multiple views
4001 if (annotation.isVisible() != null)
4003 jda.visible = annotation.isVisible();
4006 al.addAnnotation(jda);
4010 // Construct new annotation from model.
4011 List<AnnotationElement> ae = annotation.getAnnotationElement();
4012 jalview.datamodel.Annotation[] anot = null;
4013 java.awt.Color firstColour = null;
4015 if (!annotation.isScoreOnly())
4017 anot = new jalview.datamodel.Annotation[al.getWidth()];
4018 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4020 AnnotationElement annElement = ae.get(aa);
4021 anpos = annElement.getPosition();
4023 if (anpos >= anot.length)
4028 float value = safeFloat(annElement.getValue());
4029 anot[anpos] = new jalview.datamodel.Annotation(
4030 annElement.getDisplayCharacter(),
4031 annElement.getDescription(),
4032 (annElement.getSecondaryStructure() == null
4033 || annElement.getSecondaryStructure()
4037 .getSecondaryStructure()
4040 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4041 if (firstColour == null)
4043 firstColour = anot[anpos].colour;
4047 jalview.datamodel.AlignmentAnnotation jaa = null;
4049 if (annotation.isGraph())
4051 float llim = 0, hlim = 0;
4052 // if (autoForView || an[i].isAutoCalculated()) {
4055 jaa = new jalview.datamodel.AlignmentAnnotation(
4056 annotation.getLabel(), annotation.getDescription(), anot,
4057 llim, hlim, safeInt(annotation.getGraphType()));
4059 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4060 jaa._linecolour = firstColour;
4061 if (annotation.getThresholdLine() != null)
4063 jaa.setThreshold(new jalview.datamodel.GraphLine(
4064 safeFloat(annotation.getThresholdLine().getValue()),
4065 annotation.getThresholdLine().getLabel(),
4066 new java.awt.Color(safeInt(
4067 annotation.getThresholdLine().getColour()))));
4069 if (autoForView || annotation.isAutoCalculated())
4071 // Hardwire the symbol display line to ensure that labels for
4072 // histograms are displayed
4078 jaa = new jalview.datamodel.AlignmentAnnotation(
4079 annotation.getLabel(), annotation.getDescription(), anot);
4080 jaa._linecolour = firstColour;
4082 // register new annotation
4083 if (annotation.getId() != null)
4085 annotationIds.put(annotation.getId(), jaa);
4086 jaa.annotationId = annotation.getId();
4088 // recover sequence association
4089 String sequenceRef = annotation.getSequenceRef();
4090 if (sequenceRef != null)
4092 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4093 SequenceI sequence = seqRefIds.get(sequenceRef);
4094 if (sequence == null)
4096 // in pre-2.9 projects sequence ref is to sequence name
4097 sequence = al.findName(sequenceRef);
4099 if (sequence != null)
4101 jaa.createSequenceMapping(sequence, 1, true);
4102 sequence.addAlignmentAnnotation(jaa);
4105 // and make a note of any group association
4106 if (annotation.getGroupRef() != null
4107 && annotation.getGroupRef().length() > 0)
4109 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4110 .get(annotation.getGroupRef());
4113 aal = new ArrayList<>();
4114 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4119 if (annotation.getScore() != null)
4121 jaa.setScore(annotation.getScore().doubleValue());
4123 if (annotation.isVisible() != null)
4125 jaa.visible = annotation.isVisible().booleanValue();
4128 if (annotation.isCentreColLabels() != null)
4130 jaa.centreColLabels = annotation.isCentreColLabels()
4134 if (annotation.isScaleColLabels() != null)
4136 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4138 if (annotation.isAutoCalculated())
4140 // newer files have an 'autoCalculated' flag and store calculation
4141 // state in viewport properties
4142 jaa.autoCalculated = true; // means annotation will be marked for
4143 // update at end of load.
4145 if (annotation.getGraphHeight() != null)
4147 jaa.graphHeight = annotation.getGraphHeight().intValue();
4149 jaa.belowAlignment = annotation.isBelowAlignment();
4150 jaa.setCalcId(annotation.getCalcId());
4151 if (annotation.getProperty().size() > 0)
4153 for (jalview.xml.binding.jalview.Property prop : annotation
4156 jaa.setProperty(prop.getName(), prop.getValue());
4159 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4161 if (annotation.getContactmatrix() != null
4162 && annotation.getContactmatrix().size() > 0)
4164 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4166 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4171 if (jaa.autoCalculated)
4173 autoAlan.add(new JvAnnotRow(i, jaa));
4176 // if (!autoForView)
4178 // add autocalculated group annotation and any user created annotation
4180 al.addAnnotation(jaa);
4184 // ///////////////////////
4186 // Create alignment markup and styles for this view
4187 if (jalviewModel.getJGroup().size() > 0)
4189 List<JGroup> groups = jalviewModel.getJGroup();
4190 boolean addAnnotSchemeGroup = false;
4191 for (int i = 0; i < groups.size(); i++)
4193 JGroup jGroup = groups.get(i);
4194 ColourSchemeI cs = null;
4195 if (jGroup.getColour() != null)
4197 if (jGroup.getColour().startsWith("ucs"))
4199 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4201 else if (jGroup.getColour().equals("AnnotationColourGradient")
4202 && jGroup.getAnnotationColours() != null)
4204 addAnnotSchemeGroup = true;
4208 cs = ColourSchemeProperty.getColourScheme(null, al,
4209 jGroup.getColour());
4212 int pidThreshold = safeInt(jGroup.getPidThreshold());
4214 Vector<SequenceI> seqs = new Vector<>();
4216 for (int s = 0; s < jGroup.getSeq().size(); s++)
4218 String seqId = jGroup.getSeq().get(s);
4219 SequenceI ts = seqRefIds.get(seqId);
4223 seqs.addElement(ts);
4227 if (seqs.size() < 1)
4232 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4233 safeBoolean(jGroup.isDisplayBoxes()),
4234 safeBoolean(jGroup.isDisplayText()),
4235 safeBoolean(jGroup.isColourText()),
4236 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4237 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4238 sg.getGroupColourScheme()
4239 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4240 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4242 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4243 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4244 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4245 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4246 // attributes with a default in the schema are never null
4247 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4248 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4249 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4250 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4251 if (jGroup.getConsThreshold() != null
4252 && jGroup.getConsThreshold().intValue() != 0)
4254 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4257 c.verdict(false, 25);
4258 sg.cs.setConservation(c);
4261 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4263 // re-instate unique group/annotation row reference
4264 List<AlignmentAnnotation> jaal = groupAnnotRefs
4265 .get(jGroup.getId());
4268 for (AlignmentAnnotation jaa : jaal)
4271 if (jaa.autoCalculated)
4273 // match up and try to set group autocalc alignment row for this
4275 if (jaa.label.startsWith("Consensus for "))
4277 sg.setConsensus(jaa);
4279 // match up and try to set group autocalc alignment row for this
4281 if (jaa.label.startsWith("Conservation for "))
4283 sg.setConservationRow(jaa);
4290 if (addAnnotSchemeGroup)
4292 // reconstruct the annotation colourscheme
4294 constructAnnotationColour(jGroup.getAnnotationColours(),
4295 null, al, jalviewModel, false));
4301 // only dataset in this model, so just return.
4304 // ///////////////////////////////
4307 AlignFrame af = null;
4308 AlignViewport av = null;
4309 // now check to see if we really need to create a new viewport.
4310 if (multipleView && viewportsAdded.size() == 0)
4312 // We recovered an alignment for which a viewport already exists.
4313 // TODO: fix up any settings necessary for overlaying stored state onto
4314 // state recovered from another document. (may not be necessary).
4315 // we may need a binding from a viewport in memory to one recovered from
4317 // and then recover its containing af to allow the settings to be applied.
4318 // TODO: fix for vamsas demo
4319 jalview.bin.Console.errPrintln(
4320 "About to recover a viewport for existing alignment: Sequence set ID is "
4322 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4323 if (seqsetobj != null)
4325 if (seqsetobj instanceof String)
4327 uniqueSeqSetId = (String) seqsetobj;
4328 jalview.bin.Console.errPrintln(
4329 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4334 jalview.bin.Console.errPrintln(
4335 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4341 * indicate that annotation colours are applied across all groups (pre
4342 * Jalview 2.8.1 behaviour)
4344 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4345 jalviewModel.getVersion());
4347 AlignmentPanel ap = null;
4348 boolean isnewview = true;
4351 // Check to see if this alignment already has a view id == viewId
4352 jalview.gui.AlignmentPanel views[] = Desktop
4353 .getAlignmentPanels(uniqueSeqSetId);
4354 if (views != null && views.length > 0)
4356 for (int v = 0; v < views.length; v++)
4358 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4360 // recover the existing alignpanel, alignframe, viewport
4361 af = views[v].alignFrame;
4364 // TODO: could even skip resetting view settings if we don't want to
4365 // change the local settings from other jalview processes
4374 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4375 uniqueSeqSetId, viewId, autoAlan);
4376 av = af.getViewport();
4381 * Load any trees, PDB structures and viewers, Overview
4383 * Not done if flag is false (when this method is used for New View)
4385 if (loadTreesAndStructures)
4387 loadTrees(jalviewModel, view, af, av, ap);
4388 loadPCAViewers(jalviewModel, ap);
4389 loadPDBStructures(jprovider, jseqs, af, ap);
4390 loadRnaViewers(jprovider, jseqs, ap);
4391 loadOverview(view, jalviewModel.getVersion(), af);
4393 // and finally return.
4397 private void importMatrixData(List<MatrixType> xmlmatrices)
4399 for (MatrixType xmlmat:xmlmatrices)
4401 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4403 Console.error("Ignoring matrix '"+xmlmat.getId()+"' of type '"+xmlmat.getType());
4407 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4409 Console.error("Can't handle non square matrices");
4413 float[][] elements = ContactMatrix
4414 .fromFloatStringToContacts(xmlmat.getElements(),
4415 xmlmat.getCols().intValue(),
4416 xmlmat.getRows().intValue());
4418 List<BitSet> newgroups = new ArrayList<BitSet>();
4419 if (xmlmat.getGroups().size() > 0)
4421 for (String sgroup : xmlmat.getGroups())
4423 newgroups.add(deStringifyBitset(sgroup));
4426 String nwk = xmlmat.getNewick().size() > 0
4427 ? xmlmat.getNewick().get(0)
4429 if (xmlmat.getNewick().size() > 1)
4432 "Ignoring additional clusterings for contact matrix");
4434 String treeMethod = xmlmat.getTreeMethod();
4435 double thresh = xmlmat.getCutHeight() != null
4436 ? xmlmat.getCutHeight()
4438 GroupSet grpset = new GroupSet();
4439 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4441 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4442 contactMatrixRefs.put(xmlmat.getId(), newcm);
4443 Console.trace("Restored base contact matrix "+xmlmat.getId());
4447 private void restoreMatrixFor(SequenceI sequenceRef,
4448 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4450 // restore mapping data to matrix data
4451 jalview.util.MapList mapping = null;
4452 if (xmlmatmapping.getMapping() != null)
4454 MapListType m = xmlmatmapping.getMapping();
4455 // Mapping m = dr.getMapping();
4456 int fr[] = new int[m.getMapListFrom().size() * 2];
4457 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4458 for (int _i = 0; from.hasNext(); _i += 2)
4460 MapListFrom mf = from.next();
4461 fr[_i] = mf.getStart();
4462 fr[_i + 1] = mf.getEnd();
4464 int fto[] = new int[m.getMapListTo().size() * 2];
4465 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4466 for (int _i = 0; to.hasNext(); _i += 2)
4468 MapListTo mf = to.next();
4469 fto[_i] = mf.getStart();
4470 fto[_i + 1] = mf.getEnd();
4473 mapping = new jalview.util.MapList(fr, fto,
4474 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4477 // locate matrix data in project XML and import
4478 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4482 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4486 // create the PAEMatrix now
4487 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4490 jaa.sequenceRef.addContactListFor(jaa, newpae);
4497 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4498 * and geometry as saved
4503 protected void loadOverview(Viewport view, String version, AlignFrame af)
4505 if (!isVersionStringLaterThan("2.11.3", version)
4506 && view.getOverview() == null)
4511 * first close any Overview that was opened automatically
4512 * (if so configured in Preferences) so that the view is
4513 * restored in the same state as saved
4515 af.alignPanel.closeOverviewPanel();
4517 Overview overview = view.getOverview();
4518 if (overview != null)
4520 OverviewPanel overviewPanel = af
4521 .openOverviewPanel(overview.isShowHidden());
4522 overviewPanel.setTitle(overview.getTitle());
4523 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4524 overview.getWidth(), overview.getHeight());
4525 Color gap = new Color(overview.getGapColour());
4526 Color residue = new Color(overview.getResidueColour());
4527 Color hidden = new Color(overview.getHiddenColour());
4528 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4533 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4534 * panel is restored from separate jar entries, two (gapped and trimmed) per
4535 * sequence and secondary structure.
4537 * Currently each viewer shows just one sequence and structure (gapped and
4538 * trimmed), however this method is designed to support multiple sequences or
4539 * structures in viewers if wanted in future.
4545 private void loadRnaViewers(jarInputStreamProvider jprovider,
4546 List<JSeq> jseqs, AlignmentPanel ap)
4549 * scan the sequences for references to viewers; create each one the first
4550 * time it is referenced, add Rna models to existing viewers
4552 for (JSeq jseq : jseqs)
4554 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4556 RnaViewer viewer = jseq.getRnaViewer().get(i);
4557 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4560 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4562 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4563 SequenceI seq = seqRefIds.get(jseq.getId());
4564 AlignmentAnnotation ann = this.annotationIds
4565 .get(ss.getAnnotationId());
4568 * add the structure to the Varna display (with session state copied
4569 * from the jar to a temporary file)
4571 boolean gapped = safeBoolean(ss.isGapped());
4572 String rnaTitle = ss.getTitle();
4573 String sessionState = ss.getViewerState();
4574 String tempStateFile = copyJarEntry(jprovider, sessionState,
4576 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4577 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4579 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4585 * Locate and return an already instantiated matching AppVarna, or create one
4589 * @param viewIdSuffix
4593 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4594 String viewIdSuffix, AlignmentPanel ap)
4597 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4598 * if load is repeated
4600 String postLoadId = viewer.getViewId() + viewIdSuffix;
4601 for (JInternalFrame frame : getAllFrames())
4603 if (frame instanceof AppVarna)
4605 AppVarna varna = (AppVarna) frame;
4606 if (postLoadId.equals(varna.getViewId()))
4608 // this viewer is already instantiated
4609 // could in future here add ap as another 'parent' of the
4610 // AppVarna window; currently just 1-to-many
4617 * viewer not found - make it
4619 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4620 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4621 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4622 safeInt(viewer.getDividerLocation()));
4623 AppVarna varna = new AppVarna(model, ap);
4629 * Load any saved trees
4637 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4638 AlignViewport av, AlignmentPanel ap)
4640 // TODO result of automated refactoring - are all these parameters needed?
4643 for (int t = 0; t < jm.getTree().size(); t++)
4646 Tree tree = jm.getTree().get(t);
4648 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4651 if (tree.isColumnWise())
4653 AlignmentAnnotation aa = annotationIds
4654 .get(tree.getColumnReference());
4658 "Null alignment annotation when restoring columnwise tree");
4660 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4661 tree.getTitle(), safeInt(tree.getWidth()),
4662 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4663 safeInt(tree.getYpos()));
4668 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4669 tree.getTitle(), safeInt(tree.getWidth()),
4670 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4671 safeInt(tree.getYpos()));
4673 if (tree.getId() != null)
4675 // perhaps bind the tree id to something ?
4680 // update local tree attributes ?
4681 // TODO: should check if tp has been manipulated by user - if so its
4682 // settings shouldn't be modified
4683 tp.setTitle(tree.getTitle());
4684 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4685 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4686 safeInt(tree.getHeight())));
4687 tp.setViewport(av); // af.viewport;
4688 // TODO: verify 'associate with all views' works still
4689 tp.getTreeCanvas().setViewport(av); // af.viewport;
4690 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4692 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4696 "There was a problem recovering stored Newick tree: \n"
4697 + tree.getNewick());
4701 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4702 tp.fitToWindow_actionPerformed(null);
4704 if (tree.getFontName() != null)
4707 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4708 safeInt(tree.getFontSize())));
4713 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4714 safeInt(view.getFontSize())));
4717 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4718 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4719 tp.showDistances(safeBoolean(tree.isShowDistances()));
4721 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4723 if (safeBoolean(tree.isCurrentTree()))
4725 af.getViewport().setCurrentTree(tp.getTree());
4729 } catch (Exception ex)
4731 ex.printStackTrace();
4736 * Load and link any saved structure viewers.
4743 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4744 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4747 * Run through all PDB ids on the alignment, and collect mappings between
4748 * distinct view ids and all sequences referring to that view.
4750 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4752 for (int i = 0; i < jseqs.size(); i++)
4754 JSeq jseq = jseqs.get(i);
4755 if (jseq.getPdbids().size() > 0)
4757 List<Pdbids> ids = jseq.getPdbids();
4758 for (int p = 0; p < ids.size(); p++)
4760 Pdbids pdbid = ids.get(p);
4761 final int structureStateCount = pdbid.getStructureState().size();
4762 for (int s = 0; s < structureStateCount; s++)
4764 // check to see if we haven't already created this structure view
4765 final StructureState structureState = pdbid.getStructureState()
4767 String sviewid = (structureState.getViewId() == null) ? null
4768 : structureState.getViewId() + uniqueSetSuffix;
4769 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4770 // Originally : pdbid.getFile()
4771 // : TODO: verify external PDB file recovery still works in normal
4772 // jalview project load
4774 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4775 jpdb.setId(pdbid.getId());
4777 int x = safeInt(structureState.getXpos());
4778 int y = safeInt(structureState.getYpos());
4779 int width = safeInt(structureState.getWidth());
4780 int height = safeInt(structureState.getHeight());
4782 // Probably don't need to do this anymore...
4783 // Desktop.desktop.getComponentAt(x, y);
4784 // TODO: NOW: check that this recovers the PDB file correctly.
4785 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4787 jalview.datamodel.SequenceI seq = seqRefIds
4788 .get(jseq.getId() + "");
4789 if (sviewid == null)
4791 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4794 if (!structureViewers.containsKey(sviewid))
4796 String viewerType = structureState.getType();
4797 if (viewerType == null) // pre Jalview 2.9
4799 viewerType = ViewerType.JMOL.toString();
4801 structureViewers.put(sviewid,
4802 new StructureViewerModel(x, y, width, height, false,
4803 false, true, structureState.getViewId(),
4805 // Legacy pre-2.7 conversion JAL-823 :
4806 // do not assume any view has to be linked for colour by
4810 // assemble String[] { pdb files }, String[] { id for each
4811 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4812 // seqs_file 2}, boolean[] {
4813 // linkAlignPanel,superposeWithAlignpanel}} from hash
4814 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4815 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4816 || structureState.isAlignwithAlignPanel());
4819 * Default colour by linked panel to false if not specified (e.g.
4820 * for pre-2.7 projects)
4822 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4823 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4824 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4827 * Default colour by viewer to true if not specified (e.g. for
4830 boolean colourByViewer = jmoldat.isColourByViewer();
4831 colourByViewer &= structureState.isColourByJmol();
4832 jmoldat.setColourByViewer(colourByViewer);
4834 if (jmoldat.getStateData().length() < structureState.getValue()
4835 /*Content()*/.length())
4837 jmoldat.setStateData(structureState.getValue());// Content());
4839 if (pdbid.getFile() != null)
4841 File mapkey = new File(pdbid.getFile());
4842 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4843 if (seqstrmaps == null)
4845 jmoldat.getFileData().put(mapkey,
4846 seqstrmaps = jmoldat.new StructureData(pdbFile,
4849 if (!seqstrmaps.getSeqList().contains(seq))
4851 seqstrmaps.getSeqList().add(seq);
4857 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");
4858 Console.warn(errorMessage);
4864 // Instantiate the associated structure views
4865 for (Entry<String, StructureViewerModel> entry : structureViewers
4870 createOrLinkStructureViewer(entry, af, ap, jprovider);
4871 } catch (Exception e)
4873 jalview.bin.Console.errPrintln(
4874 "Error loading structure viewer: " + e.getMessage());
4875 // failed - try the next one
4887 protected void createOrLinkStructureViewer(
4888 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4889 AlignmentPanel ap, jarInputStreamProvider jprovider)
4891 final StructureViewerModel stateData = viewerData.getValue();
4894 * Search for any viewer windows already open from other alignment views
4895 * that exactly match the stored structure state
4897 StructureViewerBase comp = findMatchingViewer(viewerData);
4901 linkStructureViewer(ap, comp, stateData);
4905 String type = stateData.getType();
4908 ViewerType viewerType = ViewerType.valueOf(type);
4909 createStructureViewer(viewerType, viewerData, af, jprovider);
4910 } catch (IllegalArgumentException | NullPointerException e)
4912 // TODO JAL-3619 show error dialog / offer an alternative viewer
4913 Console.error("Invalid structure viewer type: " + type);
4918 * Generates a name for the entry in the project jar file to hold state
4919 * information for a structure viewer
4924 protected String getViewerJarEntryName(String viewId)
4926 return VIEWER_PREFIX + viewId;
4930 * Returns any open frame that matches given structure viewer data. The match
4931 * is based on the unique viewId, or (for older project versions) the frame's
4937 protected StructureViewerBase findMatchingViewer(
4938 Entry<String, StructureViewerModel> viewerData)
4940 final String sviewid = viewerData.getKey();
4941 final StructureViewerModel svattrib = viewerData.getValue();
4942 StructureViewerBase comp = null;
4943 JInternalFrame[] frames = getAllFrames();
4944 for (JInternalFrame frame : frames)
4946 if (frame instanceof StructureViewerBase)
4949 * Post jalview 2.4 schema includes structure view id
4951 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4954 comp = (StructureViewerBase) frame;
4955 break; // break added in 2.9
4958 * Otherwise test for matching position and size of viewer frame
4960 else if (frame.getX() == svattrib.getX()
4961 && frame.getY() == svattrib.getY()
4962 && frame.getHeight() == svattrib.getHeight()
4963 && frame.getWidth() == svattrib.getWidth())
4965 comp = (StructureViewerBase) frame;
4966 // no break in faint hope of an exact match on viewId
4974 * Link an AlignmentPanel to an existing structure viewer.
4979 * @param useinViewerSuperpos
4980 * @param usetoColourbyseq
4981 * @param viewerColouring
4983 protected void linkStructureViewer(AlignmentPanel ap,
4984 StructureViewerBase viewer, StructureViewerModel stateData)
4986 // NOTE: if the jalview project is part of a shared session then
4987 // view synchronization should/could be done here.
4989 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4990 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4991 final boolean viewerColouring = stateData.isColourByViewer();
4992 Map<File, StructureData> oldFiles = stateData.getFileData();
4995 * Add mapping for sequences in this view to an already open viewer
4997 final AAStructureBindingModel binding = viewer.getBinding();
4998 for (File id : oldFiles.keySet())
5000 // add this and any other pdb files that should be present in the
5002 StructureData filedat = oldFiles.get(id);
5003 String pdbFile = filedat.getFilePath();
5004 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5005 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5007 binding.addSequenceForStructFile(pdbFile, seq);
5009 // and add the AlignmentPanel's reference to the view panel
5010 viewer.addAlignmentPanel(ap);
5011 if (useinViewerSuperpos)
5013 viewer.useAlignmentPanelForSuperposition(ap);
5017 viewer.excludeAlignmentPanelForSuperposition(ap);
5019 if (usetoColourbyseq)
5021 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5025 viewer.excludeAlignmentPanelForColourbyseq(ap);
5030 * Get all frames within the Desktop.
5034 protected JInternalFrame[] getAllFrames()
5036 JInternalFrame[] frames = null;
5037 // TODO is this necessary - is it safe - risk of hanging?
5042 frames = Desktop.desktop.getAllFrames();
5043 } catch (ArrayIndexOutOfBoundsException e)
5045 // occasional No such child exceptions are thrown here...
5049 } catch (InterruptedException f)
5053 } while (frames == null);
5058 * Answers true if 'version' is equal to or later than 'supported', where each
5059 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5060 * changes. Development and test values for 'version' are leniently treated
5064 * - minimum version we are comparing against
5066 * - version of data being processsed
5067 * @return true if version is equal to or later than supported
5069 public static boolean isVersionStringLaterThan(String supported,
5072 if (supported == null || version == null
5073 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5074 || version.equalsIgnoreCase("Test")
5075 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5077 jalview.bin.Console.errPrintln("Assuming project file with "
5078 + (version == null ? "null" : version)
5079 + " is compatible with Jalview version " + supported);
5084 return StringUtils.compareVersions(version, supported, "b") >= 0;
5088 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5090 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5092 if (newStructureViewers != null)
5094 sview.getBinding().setFinishedLoadingFromArchive(false);
5095 newStructureViewers.add(sview);
5099 protected void setLoadingFinishedForNewStructureViewers()
5101 if (newStructureViewers != null)
5103 for (JalviewStructureDisplayI sview : newStructureViewers)
5105 sview.getBinding().setFinishedLoadingFromArchive(true);
5107 newStructureViewers.clear();
5108 newStructureViewers = null;
5112 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5113 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5114 Viewport view, String uniqueSeqSetId, String viewId,
5115 List<JvAnnotRow> autoAlan)
5117 AlignFrame af = null;
5118 af = new AlignFrame(al, safeInt(view.getWidth()),
5119 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5123 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5124 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5125 // super.processKeyEvent(e);
5132 af.setFileName(file, FileFormat.Jalview);
5134 final AlignViewport viewport = af.getViewport();
5135 for (int i = 0; i < JSEQ.size(); i++)
5137 int colour = safeInt(JSEQ.get(i).getColour());
5138 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5144 viewport.setColourByReferenceSeq(true);
5145 viewport.setDisplayReferenceSeq(true);
5148 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5150 if (view.getSequenceSetId() != null)
5152 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5154 viewport.setSequenceSetId(uniqueSeqSetId);
5157 // propagate shared settings to this new view
5158 viewport.setHistoryList(av.getHistoryList());
5159 viewport.setRedoList(av.getRedoList());
5163 viewportsAdded.put(uniqueSeqSetId, viewport);
5165 // TODO: check if this method can be called repeatedly without
5166 // side-effects if alignpanel already registered.
5167 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5169 // apply Hidden regions to view.
5170 if (hiddenSeqs != null)
5172 for (int s = 0; s < JSEQ.size(); s++)
5174 SequenceGroup hidden = new SequenceGroup();
5175 boolean isRepresentative = false;
5176 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5178 isRepresentative = true;
5179 SequenceI sequenceToHide = al
5180 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5181 hidden.addSequence(sequenceToHide, false);
5182 // remove from hiddenSeqs list so we don't try to hide it twice
5183 hiddenSeqs.remove(sequenceToHide);
5185 if (isRepresentative)
5187 SequenceI representativeSequence = al.getSequenceAt(s);
5188 hidden.addSequence(representativeSequence, false);
5189 viewport.hideRepSequences(representativeSequence, hidden);
5193 SequenceI[] hseqs = hiddenSeqs
5194 .toArray(new SequenceI[hiddenSeqs.size()]);
5195 viewport.hideSequence(hseqs);
5198 // recover view properties and display parameters
5200 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5201 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5202 final int pidThreshold = safeInt(view.getPidThreshold());
5203 viewport.setThreshold(pidThreshold);
5205 viewport.setColourText(safeBoolean(view.isShowColourText()));
5207 viewport.setConservationSelected(
5208 safeBoolean(view.isConservationSelected()));
5209 viewport.setIncrement(safeInt(view.getConsThreshold()));
5210 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5211 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5213 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5214 safeInt(view.getFontSize())),
5215 (view.getCharWidth() != null) ? false : true);
5216 if (view.getCharWidth() != null)
5218 viewport.setCharWidth(view.getCharWidth());
5219 viewport.setCharHeight(view.getCharHeight());
5221 ViewStyleI vs = viewport.getViewStyle();
5222 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5223 viewport.setViewStyle(vs);
5224 // TODO: allow custom charWidth/Heights to be restored by updating them
5225 // after setting font - which means set above to false
5226 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5227 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5228 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5230 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5232 viewport.setShowText(safeBoolean(view.isShowText()));
5234 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5235 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5236 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5237 viewport.setShowUnconserved(view.isShowUnconserved());
5238 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5240 if (view.getViewName() != null)
5242 viewport.setViewName(view.getViewName());
5243 af.setInitialTabVisible();
5245 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5246 safeInt(view.getWidth()), safeInt(view.getHeight()));
5248 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID width
5249 if (view.getIdWidth()==null)
5251 if (!isVersionStringLaterThan("2.11.3", jm.getVersion())) {
5252 // Pre 2.11.3 jalview projects do not store the id width
5253 // idWidth was also calculated in a different way.
5254 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5255 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5258 viewport.setIdWidth(view.getIdWidth());
5259 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5262 // startSeq set in af.alignPanel.updateLayout below
5263 af.alignPanel.updateLayout();
5264 ColourSchemeI cs = null;
5265 // apply colourschemes
5266 if (view.getBgColour() != null)
5268 if (view.getBgColour().startsWith("ucs"))
5270 cs = getUserColourScheme(jm, view.getBgColour());
5272 else if (view.getBgColour().startsWith("Annotation"))
5274 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5275 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5282 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5283 view.getBgColour());
5288 * turn off 'alignment colour applies to all groups'
5289 * while restoring global colour scheme
5291 viewport.setColourAppliesToAllGroups(false);
5292 viewport.setGlobalColourScheme(cs);
5293 viewport.getResidueShading().setThreshold(pidThreshold,
5294 view.isIgnoreGapsinConsensus());
5295 viewport.getResidueShading()
5296 .setConsensus(viewport.getSequenceConsensusHash());
5297 if (safeBoolean(view.isConservationSelected()) && cs != null)
5299 viewport.getResidueShading()
5300 .setConservationInc(safeInt(view.getConsThreshold()));
5302 af.changeColour(cs);
5303 viewport.setColourAppliesToAllGroups(true);
5305 viewport.setShowSequenceFeatures(
5306 safeBoolean(view.isShowSequenceFeatures()));
5308 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5309 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5310 viewport.setFollowHighlight(view.isFollowHighlight());
5311 viewport.followSelection = view.isFollowSelection();
5312 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5313 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5314 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5315 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5316 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5317 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5318 viewport.setShowGroupConservation(view.isShowGroupConservation());
5319 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5320 viewport.setShowComplementFeaturesOnTop(
5321 view.isShowComplementFeaturesOnTop());
5323 // recover feature settings
5324 if (jm.getFeatureSettings() != null)
5326 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5327 .getFeatureRenderer();
5328 FeaturesDisplayed fdi;
5329 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5330 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5332 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5333 Map<String, Float> featureOrder = new Hashtable<>();
5335 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5338 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5339 String featureType = setting.getType();
5342 * restore feature filters (if any)
5344 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5346 if (filters != null)
5348 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5350 if (!filter.isEmpty())
5352 fr.setFeatureFilter(featureType, filter);
5357 * restore feature colour scheme
5359 Color maxColour = new Color(setting.getColour());
5360 if (setting.getMincolour() != null)
5363 * minColour is always set unless a simple colour
5364 * (including for colour by label though it doesn't use it)
5366 Color minColour = new Color(setting.getMincolour().intValue());
5367 Color noValueColour = minColour;
5368 NoValueColour noColour = setting.getNoValueColour();
5369 if (noColour == NoValueColour.NONE)
5371 noValueColour = null;
5373 else if (noColour == NoValueColour.MAX)
5375 noValueColour = maxColour;
5377 float min = safeFloat(safeFloat(setting.getMin()));
5378 float max = setting.getMax() == null ? 1f
5379 : setting.getMax().floatValue();
5380 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5381 maxColour, noValueColour, min, max);
5382 if (setting.getAttributeName().size() > 0)
5384 gc.setAttributeName(setting.getAttributeName().toArray(
5385 new String[setting.getAttributeName().size()]));
5387 if (setting.getThreshold() != null)
5389 gc.setThreshold(setting.getThreshold().floatValue());
5390 int threshstate = safeInt(setting.getThreshstate());
5391 // -1 = None, 0 = Below, 1 = Above threshold
5392 if (threshstate == 0)
5394 gc.setBelowThreshold(true);
5396 else if (threshstate == 1)
5398 gc.setAboveThreshold(true);
5401 gc.setAutoScaled(true); // default
5402 if (setting.isAutoScale() != null)
5404 gc.setAutoScaled(setting.isAutoScale());
5406 if (setting.isColourByLabel() != null)
5408 gc.setColourByLabel(setting.isColourByLabel());
5410 // and put in the feature colour table.
5411 featureColours.put(featureType, gc);
5415 featureColours.put(featureType, new FeatureColour(maxColour));
5417 renderOrder[fs] = featureType;
5418 if (setting.getOrder() != null)
5420 featureOrder.put(featureType, setting.getOrder().floatValue());
5424 featureOrder.put(featureType, Float.valueOf(
5425 fs / jm.getFeatureSettings().getSetting().size()));
5427 if (safeBoolean(setting.isDisplay()))
5429 fdi.setVisible(featureType);
5432 Map<String, Boolean> fgtable = new Hashtable<>();
5433 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5435 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5436 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5438 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5439 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5440 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5441 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5442 fgtable, featureColours, 1.0f, featureOrder);
5443 fr.transferSettings(frs);
5446 if (view.getHiddenColumns().size() > 0)
5448 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5450 final HiddenColumns hc = view.getHiddenColumns().get(c);
5451 viewport.hideColumns(safeInt(hc.getStart()),
5452 safeInt(hc.getEnd()) /* +1 */);
5455 if (view.getCalcIdParam() != null)
5457 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5459 if (calcIdParam != null)
5461 if (recoverCalcIdParam(calcIdParam, viewport))
5466 Console.warn("Couldn't recover parameters for "
5467 + calcIdParam.getCalcId());
5472 af.setMenusFromViewport(viewport);
5473 af.setTitle(view.getTitle());
5474 // TODO: we don't need to do this if the viewport is aready visible.
5476 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5477 * has a 'cdna/protein complement' view, in which case save it in order to
5478 * populate a SplitFrame once all views have been read in.
5480 String complementaryViewId = view.getComplementId();
5481 if (complementaryViewId == null)
5483 Desktop.addInternalFrame(af, view.getTitle(),
5484 safeInt(view.getWidth()), safeInt(view.getHeight()));
5485 // recompute any autoannotation
5486 af.alignPanel.updateAnnotation(false, true);
5487 reorderAutoannotation(af, al, autoAlan);
5488 af.alignPanel.alignmentChanged();
5492 splitFrameCandidates.put(view, af);
5499 * Reads saved data to restore Colour by Annotation settings
5501 * @param viewAnnColour
5505 * @param checkGroupAnnColour
5508 private ColourSchemeI constructAnnotationColour(
5509 AnnotationColourScheme viewAnnColour, AlignFrame af,
5510 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5512 boolean propagateAnnColour = false;
5513 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5515 if (checkGroupAnnColour && al.getGroups() != null
5516 && al.getGroups().size() > 0)
5518 // pre 2.8.1 behaviour
5519 // check to see if we should transfer annotation colours
5520 propagateAnnColour = true;
5521 for (SequenceGroup sg : al.getGroups())
5523 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5525 propagateAnnColour = false;
5531 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5533 String annotationId = viewAnnColour.getAnnotation();
5534 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5537 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5539 if (matchedAnnotation == null
5540 && annAlignment.getAlignmentAnnotation() != null)
5542 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5545 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5547 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5552 if (matchedAnnotation == null)
5555 .errPrintln("Failed to match annotation colour scheme for "
5559 // belt-and-braces create a threshold line if the
5560 // colourscheme needs one but the matchedAnnotation doesn't have one
5561 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5562 && matchedAnnotation.getThreshold() == null)
5564 matchedAnnotation.setThreshold(
5565 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5566 "Threshold", Color.black));
5569 AnnotationColourGradient cs = null;
5570 if (viewAnnColour.getColourScheme().equals("None"))
5572 cs = new AnnotationColourGradient(matchedAnnotation,
5573 new Color(safeInt(viewAnnColour.getMinColour())),
5574 new Color(safeInt(viewAnnColour.getMaxColour())),
5575 safeInt(viewAnnColour.getAboveThreshold()));
5577 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5579 cs = new AnnotationColourGradient(matchedAnnotation,
5580 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5581 safeInt(viewAnnColour.getAboveThreshold()));
5585 cs = new AnnotationColourGradient(matchedAnnotation,
5586 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5587 viewAnnColour.getColourScheme()),
5588 safeInt(viewAnnColour.getAboveThreshold()));
5591 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5592 boolean useOriginalColours = safeBoolean(
5593 viewAnnColour.isPredefinedColours());
5594 cs.setSeqAssociated(perSequenceOnly);
5595 cs.setPredefinedColours(useOriginalColours);
5597 if (propagateAnnColour && al.getGroups() != null)
5599 // Also use these settings for all the groups
5600 for (int g = 0; g < al.getGroups().size(); g++)
5602 SequenceGroup sg = al.getGroups().get(g);
5603 if (sg.getGroupColourScheme() == null)
5608 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5609 matchedAnnotation, sg.getColourScheme(),
5610 safeInt(viewAnnColour.getAboveThreshold()));
5611 sg.setColourScheme(groupScheme);
5612 groupScheme.setSeqAssociated(perSequenceOnly);
5613 groupScheme.setPredefinedColours(useOriginalColours);
5619 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5620 List<JvAnnotRow> autoAlan)
5622 // copy over visualization settings for autocalculated annotation in the
5624 if (al.getAlignmentAnnotation() != null)
5627 * Kludge for magic autoannotation names (see JAL-811)
5629 String[] magicNames = new String[] { "Consensus", "Quality",
5631 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5632 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5633 for (String nm : magicNames)
5635 visan.put(nm, nullAnnot);
5637 for (JvAnnotRow auan : autoAlan)
5639 visan.put(auan.template.label
5640 + (auan.template.getCalcId() == null ? ""
5641 : "\t" + auan.template.getCalcId()),
5644 int hSize = al.getAlignmentAnnotation().length;
5645 List<JvAnnotRow> reorder = new ArrayList<>();
5646 // work through any autoCalculated annotation already on the view
5647 // removing it if it should be placed in a different location on the
5648 // annotation panel.
5649 List<String> remains = new ArrayList<>(visan.keySet());
5650 for (int h = 0; h < hSize; h++)
5652 jalview.datamodel.AlignmentAnnotation jalan = al
5653 .getAlignmentAnnotation()[h];
5654 if (jalan.autoCalculated)
5657 JvAnnotRow valan = visan.get(k = jalan.label);
5658 if (jalan.getCalcId() != null)
5660 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5665 // delete the auto calculated row from the alignment
5666 al.deleteAnnotation(jalan, false);
5670 if (valan != nullAnnot)
5672 if (jalan != valan.template)
5674 // newly created autoannotation row instance
5675 // so keep a reference to the visible annotation row
5676 // and copy over all relevant attributes
5677 if (valan.template.graphHeight >= 0)
5680 jalan.graphHeight = valan.template.graphHeight;
5682 jalan.visible = valan.template.visible;
5684 reorder.add(new JvAnnotRow(valan.order, jalan));
5689 // Add any (possibly stale) autocalculated rows that were not appended to
5690 // the view during construction
5691 for (String other : remains)
5693 JvAnnotRow othera = visan.get(other);
5694 if (othera != nullAnnot && othera.template.getCalcId() != null
5695 && othera.template.getCalcId().length() > 0)
5697 reorder.add(othera);
5700 // now put the automatic annotation in its correct place
5701 int s = 0, srt[] = new int[reorder.size()];
5702 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5703 for (JvAnnotRow jvar : reorder)
5706 srt[s++] = jvar.order;
5709 jalview.util.QuickSort.sort(srt, rws);
5710 // and re-insert the annotation at its correct position
5711 for (JvAnnotRow jvar : rws)
5713 al.addAnnotation(jvar.template, jvar.order);
5715 af.alignPanel.adjustAnnotationHeight();
5719 Hashtable skipList = null;
5722 * TODO remove this method
5725 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5726 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5727 * throw new Error("Implementation Error. No skipList defined for this
5728 * Jalview2XML instance."); } return (AlignFrame)
5729 * skipList.get(view.getSequenceSetId()); }
5733 * Check if the Jalview view contained in object should be skipped or not.
5736 * @return true if view's sequenceSetId is a key in skipList
5738 private boolean skipViewport(JalviewModel object)
5740 if (skipList == null)
5744 String id = object.getViewport().get(0).getSequenceSetId();
5745 if (skipList.containsKey(id))
5747 Console.debug("Skipping seuqence set id " + id);
5753 public void addToSkipList(AlignFrame af)
5755 if (skipList == null)
5757 skipList = new Hashtable();
5759 skipList.put(af.getViewport().getSequenceSetId(), af);
5762 public void clearSkipList()
5764 if (skipList != null)
5771 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5772 boolean ignoreUnrefed, String uniqueSeqSetId)
5774 jalview.datamodel.AlignmentI ds = getDatasetFor(
5775 vamsasSet.getDatasetId());
5776 AlignmentI xtant_ds = ds;
5777 if (xtant_ds == null)
5779 // good chance we are about to create a new dataset, but check if we've
5780 // seen some of the dataset sequence IDs before.
5781 // TODO: skip this check if we are working with project generated by
5782 // version 2.11 or later
5783 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5784 if (xtant_ds != null)
5787 addDatasetRef(vamsasSet.getDatasetId(), ds);
5790 Vector<SequenceI> dseqs = null;
5793 // recovering an alignment View
5794 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5795 if (seqSetDS != null)
5797 if (ds != null && ds != seqSetDS)
5800 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5801 + " - CDS/Protein crossreference data may be lost");
5802 if (xtant_ds != null)
5804 // This can only happen if the unique sequence set ID was bound to a
5805 // dataset that did not contain any of the sequences in the view
5806 // currently being restored.
5808 "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.");
5812 addDatasetRef(vamsasSet.getDatasetId(), ds);
5817 // try even harder to restore dataset
5818 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5819 // create a list of new dataset sequences
5820 dseqs = new Vector<>();
5822 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5824 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5825 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5827 // create a new dataset
5830 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5831 dseqs.copyInto(dsseqs);
5832 ds = new jalview.datamodel.Alignment(dsseqs);
5833 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5834 + " for alignment " + System.identityHashCode(al));
5835 addDatasetRef(vamsasSet.getDatasetId(), ds);
5837 // set the dataset for the newly imported alignment.
5838 if (al.getDataset() == null && !ignoreUnrefed)
5841 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5842 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5844 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5848 * XML dataset sequence ID to materialised dataset reference
5850 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5853 * @return the first materialised dataset reference containing a dataset
5854 * sequence referenced in the given view
5856 * - sequences from the view
5858 AlignmentI checkIfHasDataset(List<Sequence> list)
5860 for (Sequence restoredSeq : list)
5862 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5863 if (datasetFor != null)
5872 * Register ds as the containing dataset for the dataset sequences referenced
5873 * by sequences in list
5876 * - sequences in a view
5879 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5881 for (Sequence restoredSeq : list)
5883 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5884 if (prevDS != null && prevDS != ds)
5886 Console.warn("Dataset sequence appears in many datasets: "
5887 + restoredSeq.getDsseqid());
5888 // TODO: try to merge!
5896 * sequence definition to create/merge dataset sequence for
5900 * vector to add new dataset sequence to
5901 * @param ignoreUnrefed
5902 * - when true, don't create new sequences from vamsasSeq if it's id
5903 * doesn't already have an asssociated Jalview sequence.
5905 * - used to reorder the sequence in the alignment according to the
5906 * vamsasSeq array ordering, to preserve ordering of dataset
5908 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5909 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5912 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5914 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5915 boolean reorder = false;
5916 SequenceI dsq = null;
5917 if (sq != null && sq.getDatasetSequence() != null)
5919 dsq = sq.getDatasetSequence();
5925 if (sq == null && ignoreUnrefed)
5929 String sqid = vamsasSeq.getDsseqid();
5932 // need to create or add a new dataset sequence reference to this sequence
5935 dsq = seqRefIds.get(sqid);
5940 // make a new dataset sequence
5941 dsq = sq.createDatasetSequence();
5944 // make up a new dataset reference for this sequence
5945 sqid = seqHash(dsq);
5947 dsq.setVamsasId(uniqueSetSuffix + sqid);
5948 seqRefIds.put(sqid, dsq);
5953 dseqs.addElement(dsq);
5958 ds.addSequence(dsq);
5964 { // make this dataset sequence sq's dataset sequence
5965 sq.setDatasetSequence(dsq);
5966 // and update the current dataset alignment
5971 if (!dseqs.contains(dsq))
5978 if (ds.findIndex(dsq) < 0)
5980 ds.addSequence(dsq);
5987 // TODO: refactor this as a merge dataset sequence function
5988 // now check that sq (the dataset sequence) sequence really is the union of
5989 // all references to it
5990 // boolean pre = sq.getStart() < dsq.getStart();
5991 // boolean post = sq.getEnd() > dsq.getEnd();
5995 // StringBuffer sb = new StringBuffer();
5996 String newres = jalview.analysis.AlignSeq.extractGaps(
5997 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5998 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5999 && newres.length() > dsq.getLength())
6001 // Update with the longer sequence.
6005 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
6006 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
6007 * sb.append(newres.substring(newres.length() - sq.getEnd() -
6008 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
6010 dsq.setSequence(newres);
6012 // TODO: merges will never happen if we 'know' we have the real dataset
6013 // sequence - this should be detected when id==dssid
6014 jalview.bin.Console.errPrintln(
6015 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
6016 // + (pre ? "prepended" : "") + " "
6017 // + (post ? "appended" : ""));
6022 // sequence refs are identical. We may need to update the existing dataset
6023 // alignment with this one, though.
6024 if (ds != null && dseqs == null)
6026 int opos = ds.findIndex(dsq);
6027 SequenceI tseq = null;
6028 if (opos != -1 && vseqpos != opos)
6030 // remove from old position
6031 ds.deleteSequence(dsq);
6033 if (vseqpos < ds.getHeight())
6035 if (vseqpos != opos)
6037 // save sequence at destination position
6038 tseq = ds.getSequenceAt(vseqpos);
6039 ds.replaceSequenceAt(vseqpos, dsq);
6040 ds.addSequence(tseq);
6045 ds.addSequence(dsq);
6052 * TODO use AlignmentI here and in related methods - needs
6053 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6055 Hashtable<String, AlignmentI> datasetIds = null;
6057 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6059 private AlignmentI getDatasetFor(String datasetId)
6061 if (datasetIds == null)
6063 datasetIds = new Hashtable<>();
6066 if (datasetIds.containsKey(datasetId))
6068 return datasetIds.get(datasetId);
6073 private void addDatasetRef(String datasetId, AlignmentI dataset)
6075 if (datasetIds == null)
6077 datasetIds = new Hashtable<>();
6079 datasetIds.put(datasetId, dataset);
6083 * make a new dataset ID for this jalview dataset alignment
6088 private String getDatasetIdRef(AlignmentI dataset)
6090 if (dataset.getDataset() != null)
6093 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6095 String datasetId = makeHashCode(dataset, null);
6096 if (datasetId == null)
6098 // make a new datasetId and record it
6099 if (dataset2Ids == null)
6101 dataset2Ids = new IdentityHashMap<>();
6105 datasetId = dataset2Ids.get(dataset);
6107 if (datasetId == null)
6109 datasetId = "ds" + dataset2Ids.size() + 1;
6110 dataset2Ids.put(dataset, datasetId);
6117 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6118 * constructed as a special subclass GeneLocus.
6120 * @param datasetSequence
6123 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6125 for (int d = 0; d < sequence.getDBRef().size(); d++)
6127 DBRef dr = sequence.getDBRef().get(d);
6131 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6132 dr.getAccessionId());
6136 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6137 dr.getAccessionId());
6139 if (dr.getMapping() != null)
6141 entry.setMap(addMapping(dr.getMapping()));
6143 entry.setCanonical(dr.isCanonical());
6144 datasetSequence.addDBRef(entry);
6148 private jalview.datamodel.Mapping addMapping(Mapping m)
6150 SequenceI dsto = null;
6151 // Mapping m = dr.getMapping();
6152 int fr[] = new int[m.getMapListFrom().size() * 2];
6153 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6154 for (int _i = 0; from.hasNext(); _i += 2)
6156 MapListFrom mf = from.next();
6157 fr[_i] = mf.getStart();
6158 fr[_i + 1] = mf.getEnd();
6160 int fto[] = new int[m.getMapListTo().size() * 2];
6161 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6162 for (int _i = 0; to.hasNext(); _i += 2)
6164 MapListTo mf = to.next();
6165 fto[_i] = mf.getStart();
6166 fto[_i + 1] = mf.getEnd();
6168 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6169 fto, m.getMapFromUnit().intValue(),
6170 m.getMapToUnit().intValue());
6173 * (optional) choice of dseqFor or Sequence
6175 if (m.getDseqFor() != null)
6177 String dsfor = m.getDseqFor();
6178 if (seqRefIds.containsKey(dsfor))
6183 jmap.setTo(seqRefIds.get(dsfor));
6187 frefedSequence.add(newMappingRef(dsfor, jmap));
6190 else if (m.getSequence() != null)
6193 * local sequence definition
6195 Sequence ms = m.getSequence();
6196 SequenceI djs = null;
6197 String sqid = ms.getDsseqid();
6198 if (sqid != null && sqid.length() > 0)
6201 * recover dataset sequence
6203 djs = seqRefIds.get(sqid);
6207 jalview.bin.Console.errPrintln(
6208 "Warning - making up dataset sequence id for DbRef sequence map reference");
6209 sqid = ((Object) ms).toString(); // make up a new hascode for
6210 // undefined dataset sequence hash
6211 // (unlikely to happen)
6217 * make a new dataset sequence and add it to refIds hash
6219 djs = new jalview.datamodel.Sequence(ms.getName(),
6221 djs.setStart(jmap.getMap().getToLowest());
6222 djs.setEnd(jmap.getMap().getToHighest());
6223 djs.setVamsasId(uniqueSetSuffix + sqid);
6225 incompleteSeqs.put(sqid, djs);
6226 seqRefIds.put(sqid, djs);
6229 Console.debug("about to recurse on addDBRefs.");
6238 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6239 * view as XML (but not to file), and then reloading it
6244 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6247 JalviewModel jm = saveState(ap, null, null, null);
6250 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6251 ap.getAlignment().getDataset());
6253 uniqueSetSuffix = "";
6254 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6255 jm.getViewport().get(0).setId(null);
6256 // we don't overwrite the view we just copied
6258 if (this.frefedSequence == null)
6260 frefedSequence = new Vector<>();
6263 viewportsAdded.clear();
6265 AlignFrame af = loadFromObject(jm, null, false, null);
6266 af.getAlignPanels().clear();
6267 af.closeMenuItem_actionPerformed(true);
6270 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6271 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6272 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6273 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6274 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6277 return af.alignPanel;
6280 private Hashtable jvids2vobj;
6283 * set the object to ID mapping tables used to write/recover objects and XML
6284 * ID strings for the jalview project. If external tables are provided then
6285 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6286 * object goes out of scope. - also populates the datasetIds hashtable with
6287 * alignment objects containing dataset sequences
6290 * Map from ID strings to jalview datamodel
6292 * Map from jalview datamodel to ID strings
6296 public void setObjectMappingTables(Hashtable vobj2jv,
6297 IdentityHashMap jv2vobj)
6299 this.jv2vobj = jv2vobj;
6300 this.vobj2jv = vobj2jv;
6301 Iterator ds = jv2vobj.keySet().iterator();
6303 while (ds.hasNext())
6305 Object jvobj = ds.next();
6306 id = jv2vobj.get(jvobj).toString();
6307 if (jvobj instanceof jalview.datamodel.Alignment)
6309 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6311 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6314 else if (jvobj instanceof jalview.datamodel.Sequence)
6316 // register sequence object so the XML parser can recover it.
6317 if (seqRefIds == null)
6319 seqRefIds = new HashMap<>();
6321 if (seqsToIds == null)
6323 seqsToIds = new IdentityHashMap<>();
6325 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6326 seqsToIds.put((SequenceI) jvobj, id);
6328 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6331 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6332 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6333 if (jvann.annotationId == null)
6335 jvann.annotationId = anid;
6337 if (!jvann.annotationId.equals(anid))
6339 // TODO verify that this is the correct behaviour
6340 Console.warn("Overriding Annotation ID for " + anid
6341 + " from different id : " + jvann.annotationId);
6342 jvann.annotationId = anid;
6345 else if (jvobj instanceof String)
6347 if (jvids2vobj == null)
6349 jvids2vobj = new Hashtable();
6350 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6355 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6361 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6362 * objects created from the project archive. If string is null (default for
6363 * construction) then suffix will be set automatically.
6367 public void setUniqueSetSuffix(String string)
6369 uniqueSetSuffix = string;
6374 * uses skipList2 as the skipList for skipping views on sequence sets
6375 * associated with keys in the skipList
6379 public void setSkipList(Hashtable skipList2)
6381 skipList = skipList2;
6385 * Reads the jar entry of given name and returns its contents, or null if the
6386 * entry is not found.
6389 * @param jarEntryName
6392 protected String readJarEntry(jarInputStreamProvider jprovider,
6393 String jarEntryName)
6395 String result = null;
6396 BufferedReader in = null;
6401 * Reopen the jar input stream and traverse its entries to find a matching
6404 JarInputStream jin = jprovider.getJarInputStream();
6405 JarEntry entry = null;
6408 entry = jin.getNextJarEntry();
6409 } while (entry != null && !entry.getName().equals(jarEntryName));
6413 StringBuilder out = new StringBuilder(256);
6414 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6417 while ((data = in.readLine()) != null)
6421 result = out.toString();
6426 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6428 } catch (Exception ex)
6430 ex.printStackTrace();
6438 } catch (IOException e)
6449 * Returns an incrementing counter (0, 1, 2...)
6453 private synchronized int nextCounter()
6459 * Loads any saved PCA viewers
6464 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6468 List<PcaViewer> pcaviewers = model.getPcaViewer();
6469 for (PcaViewer viewer : pcaviewers)
6471 String modelName = viewer.getScoreModelName();
6472 SimilarityParamsI params = new SimilarityParams(
6473 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6474 viewer.isIncludeGaps(),
6475 viewer.isDenominateByShortestLength());
6478 * create the panel (without computing the PCA)
6480 PCAPanel panel = new PCAPanel(ap, modelName, params);
6482 panel.setTitle(viewer.getTitle());
6483 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6484 viewer.getWidth(), viewer.getHeight()));
6486 boolean showLabels = viewer.isShowLabels();
6487 panel.setShowLabels(showLabels);
6488 panel.getRotatableCanvas().setShowLabels(showLabels);
6489 panel.getRotatableCanvas()
6490 .setBgColour(new Color(viewer.getBgColour()));
6491 panel.getRotatableCanvas()
6492 .setApplyToAllViews(viewer.isLinkToAllViews());
6495 * load PCA output data
6497 ScoreModelI scoreModel = ScoreModels.getInstance()
6498 .getScoreModel(modelName, ap);
6499 PCA pca = new PCA(null, scoreModel, params);
6500 PcaDataType pcaData = viewer.getPcaData();
6502 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6503 pca.setPairwiseScores(pairwise);
6505 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6506 pca.setTridiagonal(triDiag);
6508 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6509 pca.setEigenmatrix(result);
6511 panel.getPcaModel().setPCA(pca);
6514 * we haven't saved the input data! (JAL-2647 to do)
6516 panel.setInputData(null);
6519 * add the sequence points for the PCA display
6521 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6522 for (SequencePoint sp : viewer.getSequencePoint())
6524 String seqId = sp.getSequenceRef();
6525 SequenceI seq = seqRefIds.get(seqId);
6528 throw new IllegalStateException(
6529 "Unmatched seqref for PCA: " + seqId);
6531 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6532 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6534 seqPoints.add(seqPoint);
6536 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6539 * set min-max ranges and scale after setPoints (which recomputes them)
6541 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6542 SeqPointMin spMin = viewer.getSeqPointMin();
6543 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6545 SeqPointMax spMax = viewer.getSeqPointMax();
6546 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6548 panel.getRotatableCanvas().setSeqMinMax(min, max);
6550 // todo: hold points list in PCAModel only
6551 panel.getPcaModel().setSequencePoints(seqPoints);
6553 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6554 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6555 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6557 // is this duplication needed?
6558 panel.setTop(seqPoints.size() - 1);
6559 panel.getPcaModel().setTop(seqPoints.size() - 1);
6562 * add the axes' end points for the display
6564 for (int i = 0; i < 3; i++)
6566 Axis axis = viewer.getAxis().get(i);
6567 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6568 axis.getXPos(), axis.getYPos(), axis.getZPos());
6571 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6572 "label.calc_title", "PCA", modelName), 475, 450);
6574 } catch (Exception ex)
6576 Console.error("Error loading PCA: " + ex.toString());
6581 * Creates a new structure viewer window
6588 protected void createStructureViewer(ViewerType viewerType,
6589 final Entry<String, StructureViewerModel> viewerData,
6590 AlignFrame af, jarInputStreamProvider jprovider)
6592 final StructureViewerModel viewerModel = viewerData.getValue();
6593 String sessionFilePath = null;
6595 if (viewerType == ViewerType.JMOL)
6597 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6601 String viewerJarEntryName = getViewerJarEntryName(
6602 viewerModel.getViewId());
6603 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6604 "viewerSession", ".tmp");
6606 final String sessionPath = sessionFilePath;
6607 final String sviewid = viewerData.getKey();
6610 SwingUtilities.invokeAndWait(new Runnable()
6615 JalviewStructureDisplayI sview = null;
6618 sview = StructureViewer.createView(viewerType, af.alignPanel,
6619 viewerModel, sessionPath, sviewid);
6620 addNewStructureViewer(sview);
6621 } catch (OutOfMemoryError ex)
6623 new OOMWarning("Restoring structure view for " + viewerType,
6624 (OutOfMemoryError) ex.getCause());
6625 if (sview != null && sview.isVisible())
6627 sview.closeViewer(false);
6628 sview.setVisible(false);
6634 } catch (InvocationTargetException | InterruptedException ex)
6636 Console.warn("Unexpected error when opening " + viewerType
6637 + " structure viewer", ex);
6642 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6643 * the path of the file. "load file" commands are rewritten to change the
6644 * original PDB file names to those created as the Jalview project is loaded.
6650 private String rewriteJmolSession(StructureViewerModel svattrib,
6651 jarInputStreamProvider jprovider)
6653 String state = svattrib.getStateData(); // Jalview < 2.9
6654 if (state == null || state.isEmpty()) // Jalview >= 2.9
6656 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6657 state = readJarEntry(jprovider, jarEntryName);
6659 // TODO or simpler? for each key in oldFiles,
6660 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6661 // (allowing for different path escapings)
6662 StringBuilder rewritten = new StringBuilder(state.length());
6663 int cp = 0, ncp, ecp;
6664 Map<File, StructureData> oldFiles = svattrib.getFileData();
6665 while ((ncp = state.indexOf("load ", cp)) > -1)
6669 // look for next filename in load statement
6670 rewritten.append(state.substring(cp,
6671 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6672 String oldfilenam = state.substring(ncp,
6673 ecp = state.indexOf("\"", ncp));
6674 // recover the new mapping data for this old filename
6675 // have to normalize filename - since Jmol and jalview do
6676 // filename translation differently.
6677 StructureData filedat = oldFiles.get(new File(oldfilenam));
6678 if (filedat == null)
6680 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6681 filedat = oldFiles.get(new File(reformatedOldFilename));
6683 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6684 rewritten.append("\"");
6685 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6686 // look for next file statement.
6687 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6691 // just append rest of state
6692 rewritten.append(state.substring(cp));
6696 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6697 rewritten = new StringBuilder(state);
6698 rewritten.append("; load append ");
6699 for (File id : oldFiles.keySet())
6701 // add pdb files that should be present in the viewer
6702 StructureData filedat = oldFiles.get(id);
6703 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6705 rewritten.append(";");
6708 if (rewritten.length() == 0)
6712 final String history = "history = ";
6713 int historyIndex = rewritten.indexOf(history);
6714 if (historyIndex > -1)
6717 * change "history = [true|false];" to "history = [1|0];"
6719 historyIndex += history.length();
6720 String val = rewritten.substring(historyIndex, historyIndex + 5);
6721 if (val.startsWith("true"))
6723 rewritten.replace(historyIndex, historyIndex + 4, "1");
6725 else if (val.startsWith("false"))
6727 rewritten.replace(historyIndex, historyIndex + 5, "0");
6733 File tmp = File.createTempFile("viewerSession", ".tmp");
6734 try (OutputStream os = new FileOutputStream(tmp))
6736 InputStream is = new ByteArrayInputStream(
6737 rewritten.toString().getBytes());
6739 return tmp.getAbsolutePath();
6741 } catch (IOException e)
6743 Console.error("Error restoring Jmol session: " + e.toString());
6749 * Populates an XML model of the feature colour scheme for one feature type
6751 * @param featureType
6755 public static Colour marshalColour(String featureType,
6756 FeatureColourI fcol)
6758 Colour col = new Colour();
6759 if (fcol.isSimpleColour())
6761 col.setRGB(Format.getHexString(fcol.getColour()));
6765 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6766 col.setMin(fcol.getMin());
6767 col.setMax(fcol.getMax());
6768 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6769 col.setAutoScale(fcol.isAutoScaled());
6770 col.setThreshold(fcol.getThreshold());
6771 col.setColourByLabel(fcol.isColourByLabel());
6772 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6773 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6774 : ThresholdType.NONE));
6775 if (fcol.isColourByAttribute())
6777 final String[] attName = fcol.getAttributeName();
6778 col.getAttributeName().add(attName[0]);
6779 if (attName.length > 1)
6781 col.getAttributeName().add(attName[1]);
6784 Color noColour = fcol.getNoColour();
6785 if (noColour == null)
6787 col.setNoValueColour(NoValueColour.NONE);
6789 else if (noColour == fcol.getMaxColour())
6791 col.setNoValueColour(NoValueColour.MAX);
6795 col.setNoValueColour(NoValueColour.MIN);
6798 col.setName(featureType);
6803 * Populates an XML model of the feature filter(s) for one feature type
6805 * @param firstMatcher
6806 * the first (or only) match condition)
6808 * remaining match conditions (if any)
6810 * if true, conditions are and-ed, else or-ed
6812 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6813 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6816 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6818 if (filters.hasNext())
6823 CompoundMatcher compound = new CompoundMatcher();
6824 compound.setAnd(and);
6825 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6826 firstMatcher, Collections.emptyIterator(), and);
6827 // compound.addMatcherSet(matcher1);
6828 compound.getMatcherSet().add(matcher1);
6829 FeatureMatcherI nextMatcher = filters.next();
6830 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6831 nextMatcher, filters, and);
6832 // compound.addMatcherSet(matcher2);
6833 compound.getMatcherSet().add(matcher2);
6834 result.setCompoundMatcher(compound);
6839 * single condition matcher
6841 // MatchCondition matcherModel = new MatchCondition();
6842 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6843 matcherModel.setCondition(
6844 firstMatcher.getMatcher().getCondition().getStableName());
6845 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6846 if (firstMatcher.isByAttribute())
6848 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6849 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6850 String[] attName = firstMatcher.getAttribute();
6851 matcherModel.getAttributeName().add(attName[0]); // attribute
6852 if (attName.length > 1)
6854 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6857 else if (firstMatcher.isByLabel())
6859 matcherModel.setBy(FilterBy.BY_LABEL);
6861 else if (firstMatcher.isByScore())
6863 matcherModel.setBy(FilterBy.BY_SCORE);
6865 result.setMatchCondition(matcherModel);
6872 * Loads one XML model of a feature filter to a Jalview object
6874 * @param featureType
6875 * @param matcherSetModel
6878 public static FeatureMatcherSetI parseFilter(String featureType,
6879 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6881 FeatureMatcherSetI result = new FeatureMatcherSet();
6884 parseFilterConditions(result, matcherSetModel, true);
6885 } catch (IllegalStateException e)
6887 // mixing AND and OR conditions perhaps
6888 jalview.bin.Console.errPrintln(
6889 String.format("Error reading filter conditions for '%s': %s",
6890 featureType, e.getMessage()));
6891 // return as much as was parsed up to the error
6898 * Adds feature match conditions to matcherSet as unmarshalled from XML
6899 * (possibly recursively for compound conditions)
6902 * @param matcherSetModel
6904 * if true, multiple conditions are AND-ed, else they are OR-ed
6905 * @throws IllegalStateException
6906 * if AND and OR conditions are mixed
6908 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6909 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6912 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6913 .getMatchCondition();
6919 FilterBy filterBy = mc.getBy();
6920 Condition cond = Condition.fromString(mc.getCondition());
6921 String pattern = mc.getValue();
6922 FeatureMatcherI matchCondition = null;
6923 if (filterBy == FilterBy.BY_LABEL)
6925 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6927 else if (filterBy == FilterBy.BY_SCORE)
6929 matchCondition = FeatureMatcher.byScore(cond, pattern);
6932 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6934 final List<String> attributeName = mc.getAttributeName();
6935 String[] attNames = attributeName
6936 .toArray(new String[attributeName.size()]);
6937 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6942 * note this throws IllegalStateException if AND-ing to a
6943 * previously OR-ed compound condition, or vice versa
6947 matcherSet.and(matchCondition);
6951 matcherSet.or(matchCondition);
6957 * compound condition
6959 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6960 .getCompoundMatcher().getMatcherSet();
6961 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6962 if (matchers.size() == 2)
6964 parseFilterConditions(matcherSet, matchers.get(0), anded);
6965 parseFilterConditions(matcherSet, matchers.get(1), anded);
6970 .errPrintln("Malformed compound filter condition");
6976 * Loads one XML model of a feature colour to a Jalview object
6978 * @param colourModel
6981 public static FeatureColourI parseColour(Colour colourModel)
6983 FeatureColourI colour = null;
6985 if (colourModel.getMax() != null)
6987 Color mincol = null;
6988 Color maxcol = null;
6989 Color noValueColour = null;
6993 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6994 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6995 } catch (Exception e)
6997 Console.warn("Couldn't parse out graduated feature color.", e);
7000 NoValueColour noCol = colourModel.getNoValueColour();
7001 if (noCol == NoValueColour.MIN)
7003 noValueColour = mincol;
7005 else if (noCol == NoValueColour.MAX)
7007 noValueColour = maxcol;
7010 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
7011 safeFloat(colourModel.getMin()),
7012 safeFloat(colourModel.getMax()));
7013 final List<String> attributeName = colourModel.getAttributeName();
7014 String[] attributes = attributeName
7015 .toArray(new String[attributeName.size()]);
7016 if (attributes != null && attributes.length > 0)
7018 colour.setAttributeName(attributes);
7020 if (colourModel.isAutoScale() != null)
7022 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7024 if (colourModel.isColourByLabel() != null)
7026 colour.setColourByLabel(
7027 colourModel.isColourByLabel().booleanValue());
7029 if (colourModel.getThreshold() != null)
7031 colour.setThreshold(colourModel.getThreshold().floatValue());
7033 ThresholdType ttyp = colourModel.getThreshType();
7034 if (ttyp == ThresholdType.ABOVE)
7036 colour.setAboveThreshold(true);
7038 else if (ttyp == ThresholdType.BELOW)
7040 colour.setBelowThreshold(true);
7045 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7046 colour = new FeatureColour(color);
7052 public static void setStateSavedUpToDate(boolean s)
7054 Console.debug("Setting overall stateSavedUpToDate to " + s);
7055 stateSavedUpToDate = s;
7058 public static boolean stateSavedUpToDate()
7060 Console.debug("Returning overall stateSavedUpToDate value: "
7061 + stateSavedUpToDate);
7062 return stateSavedUpToDate;
7065 public static boolean allSavedUpToDate()
7067 if (stateSavedUpToDate()) // nothing happened since last project save
7070 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7073 for (int i = 0; i < frames.length; i++)
7075 if (frames[i] == null)
7077 if (!frames[i].getViewport().savedUpToDate())
7078 return false; // at least one alignment is not individually saved
7084 // used for debugging and tests
7085 private static int debugDelaySave = 20;
7087 public static void setDebugDelaySave(int n)