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.ContactMatrix;
95 import jalview.datamodel.ContactMatrixI;
96 import jalview.datamodel.DBRefEntry;
97 import jalview.datamodel.FloatContactMatrix;
98 import jalview.datamodel.GeneLocus;
99 import jalview.datamodel.GraphLine;
100 import jalview.datamodel.GroupSet;
101 import jalview.datamodel.PDBEntry;
102 import jalview.datamodel.Point;
103 import jalview.datamodel.RnaViewerModel;
104 import jalview.datamodel.SequenceFeature;
105 import jalview.datamodel.SequenceGroup;
106 import jalview.datamodel.SequenceI;
107 import jalview.datamodel.StructureViewerModel;
108 import jalview.datamodel.StructureViewerModel.StructureData;
109 import jalview.datamodel.features.FeatureMatcher;
110 import jalview.datamodel.features.FeatureMatcherI;
111 import jalview.datamodel.features.FeatureMatcherSet;
112 import jalview.datamodel.features.FeatureMatcherSetI;
113 import jalview.ext.varna.RnaModel;
114 import jalview.gui.AlignFrame;
115 import jalview.gui.AlignViewport;
116 import jalview.gui.AlignmentPanel;
117 import jalview.gui.AppVarna;
118 import jalview.gui.Desktop;
119 import jalview.gui.JvOptionPane;
120 import jalview.gui.OOMWarning;
121 import jalview.gui.OverviewPanel;
122 import jalview.gui.PCAPanel;
123 import jalview.gui.PaintRefresher;
124 import jalview.gui.SplitFrame;
125 import jalview.gui.StructureViewer;
126 import jalview.gui.StructureViewer.ViewerType;
127 import jalview.gui.StructureViewerBase;
128 import jalview.gui.TreePanel;
129 import jalview.io.BackupFiles;
130 import jalview.io.DataSourceType;
131 import jalview.io.FileFormat;
132 import jalview.io.NewickFile;
133 import jalview.math.Matrix;
134 import jalview.math.MatrixI;
135 import jalview.renderer.ResidueShaderI;
136 import jalview.schemes.AnnotationColourGradient;
137 import jalview.schemes.ColourSchemeI;
138 import jalview.schemes.ColourSchemeProperty;
139 import jalview.schemes.FeatureColour;
140 import jalview.schemes.ResidueProperties;
141 import jalview.schemes.UserColourScheme;
142 import jalview.structure.StructureSelectionManager;
143 import jalview.structures.models.AAStructureBindingModel;
144 import jalview.util.Format;
145 import jalview.util.HttpUtils;
146 import jalview.util.MessageManager;
147 import jalview.util.Platform;
148 import jalview.util.StringUtils;
149 import jalview.util.jarInputStreamProvider;
150 import jalview.util.matcher.Condition;
151 import jalview.viewmodel.AlignmentViewport;
152 import jalview.viewmodel.PCAModel;
153 import jalview.viewmodel.ViewportRanges;
154 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
155 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
156 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
157 import jalview.ws.datamodel.MappableContactMatrixI;
158 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
159 import jalview.ws.jws2.Jws2Discoverer;
160 import jalview.ws.jws2.dm.AAConSettings;
161 import jalview.ws.jws2.jabaws2.Jws2Instance;
162 import jalview.ws.params.ArgumentI;
163 import jalview.ws.params.AutoCalcSetting;
164 import jalview.ws.params.WsParamSetI;
165 import jalview.xml.binding.jalview.AlcodonFrame;
166 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
167 import jalview.xml.binding.jalview.Annotation;
168 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
169 import jalview.xml.binding.jalview.AnnotationColourScheme;
170 import jalview.xml.binding.jalview.AnnotationElement;
171 import jalview.xml.binding.jalview.DoubleMatrix;
172 import jalview.xml.binding.jalview.DoubleVector;
173 import jalview.xml.binding.jalview.Feature;
174 import jalview.xml.binding.jalview.Feature.OtherData;
175 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
176 import jalview.xml.binding.jalview.FilterBy;
177 import jalview.xml.binding.jalview.JalviewModel;
178 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
179 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
180 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
181 import jalview.xml.binding.jalview.JalviewModel.JGroup;
182 import jalview.xml.binding.jalview.JalviewModel.JSeq;
183 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
184 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
185 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
186 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
187 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
188 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
189 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
190 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
191 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
192 import jalview.xml.binding.jalview.JalviewModel.Tree;
193 import jalview.xml.binding.jalview.JalviewModel.UserColours;
194 import jalview.xml.binding.jalview.JalviewModel.Viewport;
195 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
196 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
197 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
198 import jalview.xml.binding.jalview.JalviewUserColours;
199 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
200 import jalview.xml.binding.jalview.MapListType;
201 import jalview.xml.binding.jalview.MapListType.MapListFrom;
202 import jalview.xml.binding.jalview.MapListType.MapListTo;
203 import jalview.xml.binding.jalview.MapOnAMatrixType;
204 import jalview.xml.binding.jalview.Mapping;
205 import jalview.xml.binding.jalview.MatrixType;
206 import jalview.xml.binding.jalview.NoValueColour;
207 import jalview.xml.binding.jalview.ObjectFactory;
208 import jalview.xml.binding.jalview.PcaDataType;
209 import jalview.xml.binding.jalview.Pdbentry.Property;
210 import jalview.xml.binding.jalview.Sequence;
211 import jalview.xml.binding.jalview.Sequence.DBRef;
212 import jalview.xml.binding.jalview.SequenceSet;
213 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
214 import jalview.xml.binding.jalview.ThresholdType;
215 import jalview.xml.binding.jalview.VAMSAS;
218 * Write out the current jalview desktop state as a Jalview XML stream.
220 * Note: the vamsas objects referred to here are primitive versions of the
221 * VAMSAS project schema elements - they are not the same and most likely never
225 * @version $Revision: 1.134 $
227 public class Jalview2XML
230 // BH 2018 we add the .jvp binary extension to J2S so that
231 // it will declare that binary when we do the file save from the browser
235 Platform.addJ2SBinaryType(".jvp?");
238 private static final String VIEWER_PREFIX = "viewer_";
240 private static final String RNA_PREFIX = "rna_";
242 private static final String UTF_8 = "UTF-8";
245 * used in decision if quit confirmation should be issued
247 private static boolean stateSavedUpToDate = false;
250 * prefix for recovering datasets for alignments with multiple views where
251 * non-existent dataset IDs were written for some views
253 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
255 // use this with nextCounter() to make unique names for entities
256 private int counter = 0;
259 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
260 * of sequence objects are created.
262 IdentityHashMap<SequenceI, String> seqsToIds = null;
265 * jalview XML Sequence ID to jalview sequence object reference (both dataset
266 * and alignment sequences. Populated as XML reps of sequence objects are
269 Map<String, SequenceI> seqRefIds = null;
271 Map<String, SequenceI> incompleteSeqs = null;
273 List<forwardRef> frefedSequence = null;
275 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
278 * Map of reconstructed AlignFrame objects that appear to have come from
279 * SplitFrame objects (have a dna/protein complement view).
281 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
284 * Map from displayed rna structure models to their saved session state jar
287 private Map<RnaModel, String> rnaSessions = new HashMap<>();
290 * map from contact matrices to their XML ids
292 private Map<ContactMatrixI, String> contactMatrices = new HashMap<>();
294 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
395 * object referenced by already unmarshalled objects
400 abstract class forwardRef
406 public forwardRef(String _sref, String type)
412 public String getSref()
417 public abstract boolean isResolvable();
420 * @return true if the forward reference was fully resolved
422 abstract boolean resolve();
425 public String toString()
427 return type + " reference to " + sref;
432 * resolve forward references to sequences by their ID
436 abstract class SeqFref extends forwardRef
438 public SeqFref(String _sref, String type)
443 public SequenceI getSrefSeq()
445 return seqRefIds.get(sref);
448 public boolean isResolvable()
450 return seqRefIds.get(sref) != null;
453 public SequenceI getSrefDatasetSeq()
455 SequenceI sq = seqRefIds.get(sref);
458 while (sq.getDatasetSequence() != null)
460 sq = sq.getDatasetSequence();
468 * create forward reference for a mapping
474 public SeqFref newMappingRef(final String sref,
475 final jalview.datamodel.Mapping _jmap)
477 SeqFref fref = new SeqFref(sref, "Mapping")
479 public jalview.datamodel.Mapping jmap = _jmap;
484 SequenceI seq = getSrefDatasetSeq();
496 public SeqFref newAlcodMapRef(final String sref,
497 final AlignedCodonFrame _cf,
498 final jalview.datamodel.Mapping _jmap)
501 SeqFref fref = new SeqFref(sref, "Codon Frame")
503 AlignedCodonFrame cf = _cf;
505 public jalview.datamodel.Mapping mp = _jmap;
508 public boolean isResolvable()
510 return super.isResolvable() && mp.getTo() != null;
516 SequenceI seq = getSrefDatasetSeq();
521 cf.addMap(seq, mp.getTo(), mp.getMap());
528 public forwardRef newMatrixFref(final String matRef,
529 final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
531 forwardRef fref = new forwardRef(matRef,
532 "Matrix Reference for sequence and annotation")
538 ContactMatrixI cm = contactMatrixRefs.get(matRef);
539 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
542 jaa.sequenceRef.addContactListFor(jaa, newpae);
547 public boolean isResolvable()
549 return (contactMatrixRefs.get(matRef) != null);
555 public void resolveFrefedSequences()
557 Iterator<forwardRef> nextFref = frefedSequence.iterator();
558 int toresolve = frefedSequence.size();
559 int unresolved = 0, failedtoresolve = 0;
560 while (nextFref.hasNext())
562 forwardRef ref = nextFref.next();
563 if (ref.isResolvable())
575 } catch (Exception x)
577 jalview.bin.Console.errPrintln(
578 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
591 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
593 + " forward references left unresolved on the stack.");
595 if (failedtoresolve > 0)
597 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
598 + " resolvable forward references failed to resolve.");
600 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
602 jalview.bin.Console.errPrintln(
603 "Jalview Project Import: There are " + incompleteSeqs.size()
604 + " sequences which may have incomplete metadata.");
605 if (incompleteSeqs.size() < 10)
607 for (SequenceI s : incompleteSeqs.values())
609 jalview.bin.Console.errPrintln(s.toString());
614 jalview.bin.Console.errPrintln(
615 "Too many to report. Skipping output of incomplete sequences.");
621 * This maintains a map of viewports, the key being the seqSetId. Important to
622 * set historyItem and redoList for multiple views
624 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
626 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
628 String uniqueSetSuffix = "";
631 * List of pdbfiles added to Jar
633 List<String> pdbfiles = null;
635 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
636 public void saveState(File statefile)
638 FileOutputStream fos = null;
643 fos = new FileOutputStream(statefile);
645 JarOutputStream jout = new JarOutputStream(fos);
649 } catch (Exception e)
651 Console.error("Couln't write Jalview state to " + statefile, e);
652 // TODO: inform user of the problem - they need to know if their data was
654 if (errorMessage == null)
656 errorMessage = "Did't write Jalview Archive to output file '"
657 + statefile + "' - See console error log for details";
661 errorMessage += "(Didn't write Jalview Archive to output file '"
672 } catch (IOException e)
682 * Writes a jalview project archive to the given Jar output stream.
686 public void saveState(JarOutputStream jout)
688 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
690 setStateSavedUpToDate(true);
692 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
694 int n = debugDelaySave;
698 Console.debug("***** debugging save sleep " + i + "/" + n);
702 } catch (InterruptedException e)
704 // TODO Auto-generated catch block
715 saveAllFrames(Arrays.asList(frames), jout);
719 * core method for storing state for a set of AlignFrames.
722 * - frames involving all data to be exported (including containing
725 * - project output stream
727 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
729 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
732 * ensure cached data is clear before starting
734 // todo tidy up seqRefIds, seqsToIds initialisation / reset
736 splitFrameCandidates.clear();
741 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
742 // //////////////////////////////////////////////////
744 List<String> shortNames = new ArrayList<>();
745 List<String> viewIds = new ArrayList<>();
748 for (int i = frames.size() - 1; i > -1; i--)
750 AlignFrame af = frames.get(i);
752 if (skipList != null && skipList
753 .containsKey(af.getViewport().getSequenceSetId()))
758 String shortName = makeFilename(af, shortNames);
760 int apSize = af.getAlignPanels().size();
762 for (int ap = 0; ap < apSize; ap++)
764 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
766 String fileName = apSize == 1 ? shortName : ap + shortName;
767 if (!fileName.endsWith(".xml"))
769 fileName = fileName + ".xml";
772 saveState(apanel, fileName, jout, viewIds);
774 String dssid = getDatasetIdRef(
775 af.getViewport().getAlignment().getDataset());
776 if (!dsses.containsKey(dssid))
778 dsses.put(dssid, af);
783 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
789 } catch (Exception foo)
793 } catch (Exception ex)
795 // TODO: inform user of the problem - they need to know if their data was
797 if (errorMessage == null)
799 errorMessage = "Couldn't write Jalview Archive - see error output for details";
801 ex.printStackTrace();
806 * Generates a distinct file name, based on the title of the AlignFrame, by
807 * appending _n for increasing n until an unused name is generated. The new
808 * name (without its extension) is added to the list.
812 * @return the generated name, with .xml extension
814 protected String makeFilename(AlignFrame af, List<String> namesUsed)
816 String shortName = af.getTitle();
818 if (shortName.indexOf(File.separatorChar) > -1)
820 shortName = shortName
821 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
826 while (namesUsed.contains(shortName))
828 if (shortName.endsWith("_" + (count - 1)))
830 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
833 shortName = shortName.concat("_" + count);
837 namesUsed.add(shortName);
839 if (!shortName.endsWith(".xml"))
841 shortName = shortName + ".xml";
846 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
847 public boolean saveAlignment(AlignFrame af, String jarFile,
852 // create backupfiles object and get new temp filename destination
853 boolean doBackup = BackupFiles.getEnabled();
854 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
855 FileOutputStream fos = new FileOutputStream(
856 doBackup ? backupfiles.getTempFilePath() : jarFile);
858 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
860 int n = debugDelaySave;
864 Console.debug("***** debugging save sleep " + i + "/" + n);
868 } catch (InterruptedException e)
870 // TODO Auto-generated catch block
877 JarOutputStream jout = new JarOutputStream(fos);
878 List<AlignFrame> frames = new ArrayList<>();
880 // resolve splitframes
881 if (af.getViewport().getCodingComplement() != null)
883 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
889 saveAllFrames(frames, jout);
893 } catch (Exception foo)
897 boolean success = true;
901 backupfiles.setWriteSuccess(success);
902 success = backupfiles.rollBackupsAndRenameTempFile();
906 } catch (Exception ex)
908 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
909 ex.printStackTrace();
914 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
915 String fileName, JarOutputStream jout)
918 for (String dssids : dsses.keySet())
920 AlignFrame _af = dsses.get(dssids);
921 String jfileName = fileName + " Dataset for " + _af.getTitle();
922 if (!jfileName.endsWith(".xml"))
924 jfileName = jfileName + ".xml";
926 saveState(_af.alignPanel, jfileName, true, jout, null);
931 * create a JalviewModel from an alignment view and marshall it to a
935 * panel to create jalview model for
937 * name of alignment panel written to output stream
944 public JalviewModel saveState(AlignmentPanel ap, String fileName,
945 JarOutputStream jout, List<String> viewIds)
947 return saveState(ap, fileName, false, jout, viewIds);
951 * create a JalviewModel from an alignment view and marshall it to a
955 * panel to create jalview model for
957 * name of alignment panel written to output stream
959 * when true, only write the dataset for the alignment, not the data
960 * associated with the view.
966 public JalviewModel saveState(AlignmentPanel ap, String fileName,
967 boolean storeDS, JarOutputStream jout, List<String> viewIds)
971 viewIds = new ArrayList<>();
976 List<UserColourScheme> userColours = new ArrayList<>();
978 AlignViewport av = ap.av;
979 ViewportRanges vpRanges = av.getRanges();
981 final ObjectFactory objectFactory = new ObjectFactory();
982 JalviewModel object = objectFactory.createJalviewModel();
983 object.setVamsasModel(new VAMSAS());
985 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
988 GregorianCalendar c = new GregorianCalendar();
989 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
990 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
991 object.setCreationDate(now);
992 } catch (DatatypeConfigurationException e)
994 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
996 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
999 * rjal is full height alignment, jal is actual alignment with full metadata
1000 * but excludes hidden sequences.
1002 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
1004 if (av.hasHiddenRows())
1006 rjal = jal.getHiddenSequences().getFullAlignment();
1009 SequenceSet vamsasSet = new SequenceSet();
1011 // JalviewModelSequence jms = new JalviewModelSequence();
1013 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1015 if (jal.getDataset() != null)
1017 // dataset id is the dataset's hashcode
1018 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1021 // switch jal and the dataset
1022 jal = jal.getDataset();
1026 if (jal.getProperties() != null)
1028 Enumeration en = jal.getProperties().keys();
1029 while (en.hasMoreElements())
1031 String key = en.nextElement().toString();
1032 SequenceSetProperties ssp = new SequenceSetProperties();
1034 ssp.setValue(jal.getProperties().get(key).toString());
1035 // vamsasSet.addSequenceSetProperties(ssp);
1036 vamsasSet.getSequenceSetProperties().add(ssp);
1041 Set<String> calcIdSet = new HashSet<>();
1042 // record the set of vamsas sequence XML POJO we create.
1043 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1045 for (final SequenceI jds : rjal.getSequences())
1047 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1048 : jds.getDatasetSequence();
1049 String id = seqHash(jds);
1050 if (vamsasSetIds.get(id) == null)
1052 if (seqRefIds.get(id) != null && !storeDS)
1054 // This happens for two reasons: 1. multiple views are being
1056 // 2. the hashCode has collided with another sequence's code. This
1058 // HAPPEN! (PF00072.15.stk does this)
1059 // JBPNote: Uncomment to debug writing out of files that do not read
1060 // back in due to ArrayOutOfBoundExceptions.
1061 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1062 // jalview.bin.Console.errPrintln(jds.getName()+"
1063 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1064 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1065 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1066 // jalview.bin.Console.errPrintln(rsq.getName()+"
1067 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1068 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1072 vamsasSeq = createVamsasSequence(id, jds);
1073 // vamsasSet.addSequence(vamsasSeq);
1074 vamsasSet.getSequence().add(vamsasSeq);
1075 vamsasSetIds.put(id, vamsasSeq);
1076 seqRefIds.put(id, jds);
1080 jseq.setStart(jds.getStart());
1081 jseq.setEnd(jds.getEnd());
1082 jseq.setColour(av.getSequenceColour(jds).getRGB());
1084 jseq.setId(id); // jseq id should be a string not a number
1087 // Store any sequences this sequence represents
1088 if (av.hasHiddenRows())
1090 // use rjal, contains the full height alignment
1092 av.getAlignment().getHiddenSequences().isHidden(jds));
1094 if (av.isHiddenRepSequence(jds))
1096 jalview.datamodel.SequenceI[] reps = av
1097 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1099 for (int h = 0; h < reps.length; h++)
1103 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1104 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1109 // mark sequence as reference - if it is the reference for this view
1110 if (jal.hasSeqrep())
1112 jseq.setViewreference(jds == jal.getSeqrep());
1116 // TODO: omit sequence features from each alignment view's XML dump if we
1117 // are storing dataset
1118 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1119 for (SequenceFeature sf : sfs)
1121 // Features features = new Features();
1122 Feature features = new Feature();
1124 features.setBegin(sf.getBegin());
1125 features.setEnd(sf.getEnd());
1126 features.setDescription(sf.getDescription());
1127 features.setType(sf.getType());
1128 features.setFeatureGroup(sf.getFeatureGroup());
1129 features.setScore(sf.getScore());
1130 if (sf.links != null)
1132 for (int l = 0; l < sf.links.size(); l++)
1134 OtherData keyValue = new OtherData();
1135 keyValue.setKey("LINK_" + l);
1136 keyValue.setValue(sf.links.elementAt(l).toString());
1137 // features.addOtherData(keyValue);
1138 features.getOtherData().add(keyValue);
1141 if (sf.otherDetails != null)
1144 * save feature attributes, which may be simple strings or
1145 * map valued (have sub-attributes)
1147 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1149 String key = entry.getKey();
1150 Object value = entry.getValue();
1151 if (value instanceof Map<?, ?>)
1153 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1156 OtherData otherData = new OtherData();
1157 otherData.setKey(key);
1158 otherData.setKey2(subAttribute.getKey());
1159 otherData.setValue(subAttribute.getValue().toString());
1160 // features.addOtherData(otherData);
1161 features.getOtherData().add(otherData);
1166 OtherData otherData = new OtherData();
1167 otherData.setKey(key);
1168 otherData.setValue(value.toString());
1169 // features.addOtherData(otherData);
1170 features.getOtherData().add(otherData);
1175 // jseq.addFeatures(features);
1176 jseq.getFeatures().add(features);
1179 if (jdatasq.getAllPDBEntries() != null)
1181 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1182 while (en.hasMoreElements())
1184 Pdbids pdb = new Pdbids();
1185 jalview.datamodel.PDBEntry entry = en.nextElement();
1187 String pdbId = entry.getId();
1189 pdb.setType(entry.getType());
1192 * Store any structure views associated with this sequence. This
1193 * section copes with duplicate entries in the project, so a dataset
1194 * only view *should* be coped with sensibly.
1196 // This must have been loaded, is it still visible?
1197 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1198 if (Desktop.desktop != null)
1200 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1203 for (JInternalFrame jif : jifs)
1205 if (jif instanceof JalviewStructureDisplayI)
1207 viewFrames.add((JalviewStructureDisplayI) jif);
1212 else if (Jalview.isHeadlessMode()
1213 && Jalview.getInstance().getCommands() != null)
1216 StructureViewerBase.getAllStructureViewerBases());
1219 String matchedFile = null;
1220 for (JalviewStructureDisplayI viewFrame : viewFrames)
1222 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1223 matchedFile, viewFrame);
1225 * Only store each structure viewer's state once in the project
1226 * jar. First time through only (storeDS==false)
1228 String viewId = viewFrame.getViewId();
1229 String viewerType = viewFrame.getViewerType().toString();
1230 if (!storeDS && !viewIds.contains(viewId))
1232 viewIds.add(viewId);
1233 File viewerState = viewFrame.saveSession();
1234 if (viewerState != null)
1236 copyFileToJar(jout, viewerState.getPath(),
1237 getViewerJarEntryName(viewId), viewerType);
1242 "Failed to save viewer state for " + viewerType);
1247 if (matchedFile != null || entry.getFile() != null)
1249 if (entry.getFile() != null)
1252 matchedFile = entry.getFile();
1254 pdb.setFile(matchedFile); // entry.getFile());
1255 if (pdbfiles == null)
1257 pdbfiles = new ArrayList<>();
1260 if (!pdbfiles.contains(pdbId))
1262 pdbfiles.add(pdbId);
1263 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1267 Enumeration<String> props = entry.getProperties();
1268 if (props.hasMoreElements())
1270 // PdbentryItem item = new PdbentryItem();
1271 while (props.hasMoreElements())
1273 Property prop = new Property();
1274 String key = props.nextElement();
1276 prop.setValue(entry.getProperty(key).toString());
1277 // item.addProperty(prop);
1278 pdb.getProperty().add(prop);
1280 // pdb.addPdbentryItem(item);
1283 // jseq.addPdbids(pdb);
1284 jseq.getPdbids().add(pdb);
1288 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1290 // jms.addJSeq(jseq);
1291 object.getJSeq().add(jseq);
1294 if (!storeDS && av.hasHiddenRows())
1296 jal = av.getAlignment();
1300 if (storeDS && jal.getCodonFrames() != null)
1302 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1303 for (AlignedCodonFrame acf : jac)
1305 AlcodonFrame alc = new AlcodonFrame();
1306 if (acf.getProtMappings() != null
1307 && acf.getProtMappings().length > 0)
1309 boolean hasMap = false;
1310 SequenceI[] dnas = acf.getdnaSeqs();
1311 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1312 for (int m = 0; m < pmaps.length; m++)
1314 AlcodMap alcmap = new AlcodMap();
1315 alcmap.setDnasq(seqHash(dnas[m]));
1317 createVamsasMapping(pmaps[m], dnas[m], null, false));
1318 // alc.addAlcodMap(alcmap);
1319 alc.getAlcodMap().add(alcmap);
1324 // vamsasSet.addAlcodonFrame(alc);
1325 vamsasSet.getAlcodonFrame().add(alc);
1328 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1330 // AlcodonFrame alc = new AlcodonFrame();
1331 // vamsasSet.addAlcodonFrame(alc);
1332 // for (int p = 0; p < acf.aaWidth; p++)
1334 // Alcodon cmap = new Alcodon();
1335 // if (acf.codons[p] != null)
1337 // // Null codons indicate a gapped column in the translated peptide
1339 // cmap.setPos1(acf.codons[p][0]);
1340 // cmap.setPos2(acf.codons[p][1]);
1341 // cmap.setPos3(acf.codons[p][2]);
1343 // alc.addAlcodon(cmap);
1345 // if (acf.getProtMappings() != null
1346 // && acf.getProtMappings().length > 0)
1348 // SequenceI[] dnas = acf.getdnaSeqs();
1349 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1350 // for (int m = 0; m < pmaps.length; m++)
1352 // AlcodMap alcmap = new AlcodMap();
1353 // alcmap.setDnasq(seqHash(dnas[m]));
1354 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1356 // alc.addAlcodMap(alcmap);
1363 // /////////////////////////////////
1364 if (!storeDS && av.getCurrentTree() != null)
1366 // FIND ANY ASSOCIATED TREES
1367 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1368 if (Desktop.desktop != null)
1370 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1372 for (int t = 0; t < frames.length; t++)
1374 if (frames[t] instanceof TreePanel)
1376 TreePanel tp = (TreePanel) frames[t];
1378 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1380 JalviewModel.Tree tree = new JalviewModel.Tree();
1381 tree.setTitle(tp.getTitle());
1382 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1383 tree.setNewick(tp.getTree().print());
1384 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1386 tree.setFitToWindow(tp.fitToWindow.getState());
1387 tree.setFontName(tp.getTreeFont().getName());
1388 tree.setFontSize(tp.getTreeFont().getSize());
1389 tree.setFontStyle(tp.getTreeFont().getStyle());
1390 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1392 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1393 tree.setShowDistances(tp.distanceMenu.getState());
1395 tree.setHeight(tp.getHeight());
1396 tree.setWidth(tp.getWidth());
1397 tree.setXpos(tp.getX());
1398 tree.setYpos(tp.getY());
1399 tree.setId(makeHashCode(tp, null));
1400 tree.setLinkToAllViews(
1401 tp.getTreeCanvas().isApplyToAllViews());
1404 if (tp.isColumnWise())
1406 tree.setColumnWise(true);
1407 String annId = tp.getAssocAnnotation().annotationId;
1408 tree.setColumnReference(annId);
1410 // jms.addTree(tree);
1411 object.getTree().add(tree);
1421 if (!storeDS && Desktop.desktop != null)
1423 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1425 if (frame instanceof PCAPanel)
1427 PCAPanel panel = (PCAPanel) frame;
1428 if (panel.getAlignViewport().getAlignment() == jal)
1430 savePCA(panel, object);
1438 * store forward refs from an annotationRow to any groups
1440 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1443 for (SequenceI sq : jal.getSequences())
1445 // Store annotation on dataset sequences only
1446 AlignmentAnnotation[] aa = sq.getAnnotation();
1447 if (aa != null && aa.length > 0)
1449 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1456 if (jal.getAlignmentAnnotation() != null)
1458 // Store the annotation shown on the alignment.
1459 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1460 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1465 if (jal.getGroups() != null)
1467 JGroup[] groups = new JGroup[jal.getGroups().size()];
1469 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1471 JGroup jGroup = new JGroup();
1472 groups[++i] = jGroup;
1474 jGroup.setStart(sg.getStartRes());
1475 jGroup.setEnd(sg.getEndRes());
1476 jGroup.setName(sg.getName());
1477 if (groupRefs.containsKey(sg))
1479 // group has references so set its ID field
1480 jGroup.setId(groupRefs.get(sg));
1482 ColourSchemeI colourScheme = sg.getColourScheme();
1483 if (colourScheme != null)
1485 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1486 if (groupColourScheme.conservationApplied())
1488 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1490 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1492 jGroup.setColour(setUserColourScheme(colourScheme,
1493 userColours, object));
1497 jGroup.setColour(colourScheme.getSchemeName());
1500 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1502 jGroup.setColour("AnnotationColourGradient");
1503 jGroup.setAnnotationColours(constructAnnotationColours(
1504 (jalview.schemes.AnnotationColourGradient) colourScheme,
1505 userColours, object));
1507 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1510 setUserColourScheme(colourScheme, userColours, object));
1514 jGroup.setColour(colourScheme.getSchemeName());
1517 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1520 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1521 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1522 jGroup.setDisplayText(sg.getDisplayText());
1523 jGroup.setColourText(sg.getColourText());
1524 jGroup.setTextCol1(sg.textColour.getRGB());
1525 jGroup.setTextCol2(sg.textColour2.getRGB());
1526 jGroup.setTextColThreshold(sg.thresholdTextColour);
1527 jGroup.setShowUnconserved(sg.getShowNonconserved());
1528 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1529 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1530 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1531 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1532 for (SequenceI seq : sg.getSequences())
1534 // jGroup.addSeq(seqHash(seq));
1535 jGroup.getSeq().add(seqHash(seq));
1539 // jms.setJGroup(groups);
1541 for (JGroup grp : groups)
1543 object.getJGroup().add(grp);
1548 // /////////SAVE VIEWPORT
1549 Viewport view = new Viewport();
1550 view.setTitle(ap.alignFrame.getTitle());
1551 view.setSequenceSetId(
1552 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1553 view.setId(av.getViewId());
1554 if (av.getCodingComplement() != null)
1556 view.setComplementId(av.getCodingComplement().getViewId());
1558 view.setViewName(av.getViewName());
1559 view.setGatheredViews(av.isGatherViewsHere());
1561 Rectangle size = ap.av.getExplodedGeometry();
1562 Rectangle position = size;
1565 size = ap.alignFrame.getBounds();
1566 if (av.getCodingComplement() != null)
1568 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1576 view.setXpos(position.x);
1577 view.setYpos(position.y);
1579 view.setWidth(size.width);
1580 view.setHeight(size.height);
1582 view.setStartRes(vpRanges.getStartRes());
1583 view.setStartSeq(vpRanges.getStartSeq());
1585 OverviewPanel ov = ap.getOverviewPanel();
1588 Overview overview = new Overview();
1589 overview.setTitle(ov.getTitle());
1590 Rectangle bounds = ov.getFrameBounds();
1591 overview.setXpos(bounds.x);
1592 overview.setYpos(bounds.y);
1593 overview.setWidth(bounds.width);
1594 overview.setHeight(bounds.height);
1595 overview.setShowHidden(ov.isShowHiddenRegions());
1596 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1597 overview.setResidueColour(
1598 ov.getCanvas().getResidueColour().getRGB());
1599 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1600 view.setOverview(overview);
1602 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1604 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1605 userColours, object));
1608 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1610 AnnotationColourScheme ac = constructAnnotationColours(
1611 (jalview.schemes.AnnotationColourGradient) av
1612 .getGlobalColourScheme(),
1613 userColours, object);
1615 view.setAnnotationColours(ac);
1616 view.setBgColour("AnnotationColourGradient");
1620 view.setBgColour(ColourSchemeProperty
1621 .getColourName(av.getGlobalColourScheme()));
1624 ResidueShaderI vcs = av.getResidueShading();
1625 ColourSchemeI cs = av.getGlobalColourScheme();
1629 if (vcs.conservationApplied())
1631 view.setConsThreshold(vcs.getConservationInc());
1632 if (cs instanceof jalview.schemes.UserColourScheme)
1634 view.setBgColour(setUserColourScheme(cs, userColours, object));
1637 view.setPidThreshold(vcs.getThreshold());
1640 view.setConservationSelected(av.getConservationSelected());
1641 view.setPidSelected(av.getAbovePIDThreshold());
1642 view.setCharHeight(av.getCharHeight());
1643 view.setCharWidth(av.getCharWidth());
1644 final Font font = av.getFont();
1645 view.setFontName(font.getName());
1646 view.setFontSize(font.getSize());
1647 view.setFontStyle(font.getStyle());
1648 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1649 view.setRenderGaps(av.isRenderGaps());
1650 view.setShowAnnotation(av.isShowAnnotation());
1651 view.setShowBoxes(av.getShowBoxes());
1652 view.setShowColourText(av.getColourText());
1653 view.setShowFullId(av.getShowJVSuffix());
1654 view.setRightAlignIds(av.isRightAlignIds());
1655 view.setIdWidth(av.getIdWidth());
1656 view.setIdWidthManuallyAdjusted(
1657 ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1659 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1660 view.setShowText(av.getShowText());
1661 view.setShowUnconserved(av.getShowUnconserved());
1662 view.setWrapAlignment(av.getWrapAlignment());
1663 view.setTextCol1(av.getTextColour().getRGB());
1664 view.setTextCol2(av.getTextColour2().getRGB());
1665 view.setTextColThreshold(av.getThresholdTextColour());
1666 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1667 view.setShowSequenceLogo(av.isShowSequenceLogo());
1668 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1669 view.setShowGroupConsensus(av.isShowGroupConsensus());
1670 view.setShowGroupConservation(av.isShowGroupConservation());
1671 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1672 view.setShowDbRefTooltip(av.isShowDBRefs());
1673 view.setFollowHighlight(av.isFollowHighlight());
1674 view.setFollowSelection(av.followSelection);
1675 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1676 view.setShowComplementFeatures(av.isShowComplementFeatures());
1677 view.setShowComplementFeaturesOnTop(
1678 av.isShowComplementFeaturesOnTop());
1679 if (av.getFeaturesDisplayed() != null)
1681 FeatureSettings fs = new FeatureSettings();
1683 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1684 .getFeatureRenderer();
1685 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1687 Vector<String> settingsAdded = new Vector<>();
1688 if (renderOrder != null)
1690 for (String featureType : renderOrder)
1692 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1693 setting.setType(featureType);
1696 * save any filter for the feature type
1698 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1701 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1703 FeatureMatcherI firstFilter = filters.next();
1704 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1705 filters, filter.isAnded()));
1709 * save colour scheme for the feature type
1711 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1712 if (!fcol.isSimpleColour())
1714 setting.setColour(fcol.getMaxColour().getRGB());
1715 setting.setMincolour(fcol.getMinColour().getRGB());
1716 setting.setMin(fcol.getMin());
1717 setting.setMax(fcol.getMax());
1718 setting.setColourByLabel(fcol.isColourByLabel());
1719 if (fcol.isColourByAttribute())
1721 String[] attName = fcol.getAttributeName();
1722 setting.getAttributeName().add(attName[0]);
1723 if (attName.length > 1)
1725 setting.getAttributeName().add(attName[1]);
1728 setting.setAutoScale(fcol.isAutoScaled());
1729 setting.setThreshold(fcol.getThreshold());
1730 Color noColour = fcol.getNoColour();
1731 if (noColour == null)
1733 setting.setNoValueColour(NoValueColour.NONE);
1735 else if (noColour.equals(fcol.getMaxColour()))
1737 setting.setNoValueColour(NoValueColour.MAX);
1741 setting.setNoValueColour(NoValueColour.MIN);
1743 // -1 = No threshold, 0 = Below, 1 = Above
1744 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1745 : (fcol.isBelowThreshold() ? 0 : -1));
1749 setting.setColour(fcol.getColour().getRGB());
1753 av.getFeaturesDisplayed().isVisible(featureType));
1754 float rorder = fr.getOrder(featureType);
1757 setting.setOrder(rorder);
1759 /// fs.addSetting(setting);
1760 fs.getSetting().add(setting);
1761 settingsAdded.addElement(featureType);
1765 // is groups actually supposed to be a map here ?
1766 Iterator<String> en = fr.getFeatureGroups().iterator();
1767 Vector<String> groupsAdded = new Vector<>();
1768 while (en.hasNext())
1770 String grp = en.next();
1771 if (groupsAdded.contains(grp))
1775 Group g = new Group();
1777 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1780 fs.getGroup().add(g);
1781 groupsAdded.addElement(grp);
1783 // jms.setFeatureSettings(fs);
1784 object.setFeatureSettings(fs);
1787 if (av.hasHiddenColumns())
1789 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1790 .getHiddenColumns();
1794 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1798 Iterator<int[]> hiddenRegions = hidden.iterator();
1799 while (hiddenRegions.hasNext())
1801 int[] region = hiddenRegions.next();
1802 HiddenColumns hc = new HiddenColumns();
1803 hc.setStart(region[0]);
1804 hc.setEnd(region[1]);
1805 // view.addHiddenColumns(hc);
1806 view.getHiddenColumns().add(hc);
1810 if (calcIdSet.size() > 0)
1812 for (String calcId : calcIdSet)
1814 if (calcId.trim().length() > 0)
1816 CalcIdParam cidp = createCalcIdParam(calcId, av);
1817 // Some calcIds have no parameters.
1820 // view.addCalcIdParam(cidp);
1821 view.getCalcIdParam().add(cidp);
1827 // jms.addViewport(view);
1828 object.getViewport().add(view);
1833 // store matrices referenced by any views or annotation in this dataset
1834 if (xmlMatrices != null && xmlMatrices.size() > 0)
1837 "Adding " + xmlMatrices.size() + " matrices to dataset.");
1838 vamsasSet.getMatrix().addAll(xmlMatrices);
1839 xmlMatrices.clear();
1843 // object.setJalviewModelSequence(jms);
1844 // object.getVamsasModel().addSequenceSet(vamsasSet);
1845 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1847 if (jout != null && fileName != null)
1849 // We may not want to write the object to disk,
1850 // eg we can copy the alignViewport to a new view object
1851 // using save and then load
1854 fileName = fileName.replace('\\', '/');
1855 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1856 JarEntry entry = new JarEntry(fileName);
1857 jout.putNextEntry(entry);
1858 PrintWriter pout = new PrintWriter(
1859 new OutputStreamWriter(jout, UTF_8));
1860 JAXBContext jaxbContext = JAXBContext
1861 .newInstance(JalviewModel.class);
1862 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1864 // output pretty printed
1865 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1866 jaxbMarshaller.marshal(
1867 new ObjectFactory().createJalviewModel(object), pout);
1869 // jaxbMarshaller.marshal(object, pout);
1870 // marshaller.marshal(object);
1873 } catch (Exception ex)
1875 // TODO: raise error in GUI if marshalling failed.
1876 jalview.bin.Console.errPrintln("Error writing Jalview project");
1877 ex.printStackTrace();
1884 * Writes PCA viewer attributes and computed values to an XML model object and
1885 * adds it to the JalviewModel. Any exceptions are reported by logging.
1887 protected void savePCA(PCAPanel panel, JalviewModel object)
1891 PcaViewer viewer = new PcaViewer();
1892 viewer.setHeight(panel.getHeight());
1893 viewer.setWidth(panel.getWidth());
1894 viewer.setXpos(panel.getX());
1895 viewer.setYpos(panel.getY());
1896 viewer.setTitle(panel.getTitle());
1897 PCAModel pcaModel = panel.getPcaModel();
1898 viewer.setScoreModelName(pcaModel.getScoreModelName());
1899 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1900 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1901 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1903 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1904 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1905 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1906 SeqPointMin spmin = new SeqPointMin();
1907 spmin.setXPos(spMin[0]);
1908 spmin.setYPos(spMin[1]);
1909 spmin.setZPos(spMin[2]);
1910 viewer.setSeqPointMin(spmin);
1911 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1912 SeqPointMax spmax = new SeqPointMax();
1913 spmax.setXPos(spMax[0]);
1914 spmax.setYPos(spMax[1]);
1915 spmax.setZPos(spMax[2]);
1916 viewer.setSeqPointMax(spmax);
1917 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1918 viewer.setLinkToAllViews(
1919 panel.getRotatableCanvas().isApplyToAllViews());
1920 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1921 viewer.setIncludeGaps(sp.includeGaps());
1922 viewer.setMatchGaps(sp.matchGaps());
1923 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1924 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1927 * sequence points on display
1929 for (jalview.datamodel.SequencePoint spt : pcaModel
1930 .getSequencePoints())
1932 SequencePoint point = new SequencePoint();
1933 point.setSequenceRef(seqHash(spt.getSequence()));
1934 point.setXPos(spt.coord.x);
1935 point.setYPos(spt.coord.y);
1936 point.setZPos(spt.coord.z);
1937 viewer.getSequencePoint().add(point);
1941 * (end points of) axes on display
1943 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1946 Axis axis = new Axis();
1950 viewer.getAxis().add(axis);
1954 * raw PCA data (note we are not restoring PCA inputs here -
1955 * alignment view, score model, similarity parameters)
1957 PcaDataType data = new PcaDataType();
1958 viewer.setPcaData(data);
1959 PCA pca = pcaModel.getPcaData();
1961 DoubleMatrix pm = new DoubleMatrix();
1962 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1963 data.setPairwiseMatrix(pm);
1965 DoubleMatrix tm = new DoubleMatrix();
1966 saveDoubleMatrix(pca.getTridiagonal(), tm);
1967 data.setTridiagonalMatrix(tm);
1969 DoubleMatrix eigenMatrix = new DoubleMatrix();
1970 data.setEigenMatrix(eigenMatrix);
1971 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1973 object.getPcaViewer().add(viewer);
1974 } catch (Throwable t)
1976 Console.error("Error saving PCA: " + t.getMessage());
1981 * Stores values from a matrix into an XML element, including (if present) the
1986 * @see #loadDoubleMatrix(DoubleMatrix)
1988 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1990 xmlMatrix.setRows(m.height());
1991 xmlMatrix.setColumns(m.width());
1992 for (int i = 0; i < m.height(); i++)
1994 DoubleVector row = new DoubleVector();
1995 for (int j = 0; j < m.width(); j++)
1997 row.getV().add(m.getValue(i, j));
1999 xmlMatrix.getRow().add(row);
2001 if (m.getD() != null)
2003 DoubleVector dVector = new DoubleVector();
2004 for (double d : m.getD())
2006 dVector.getV().add(d);
2008 xmlMatrix.setD(dVector);
2010 if (m.getE() != null)
2012 DoubleVector eVector = new DoubleVector();
2013 for (double e : m.getE())
2015 eVector.getV().add(e);
2017 xmlMatrix.setE(eVector);
2022 * Loads XML matrix data into a new Matrix object, including the D and/or E
2023 * vectors (if present)
2027 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2029 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2031 int rows = mData.getRows();
2032 double[][] vals = new double[rows][];
2034 for (int i = 0; i < rows; i++)
2036 List<Double> dVector = mData.getRow().get(i).getV();
2037 vals[i] = new double[dVector.size()];
2039 for (Double d : dVector)
2045 MatrixI m = new Matrix(vals);
2047 if (mData.getD() != null)
2049 List<Double> dVector = mData.getD().getV();
2050 double[] vec = new double[dVector.size()];
2052 for (Double d : dVector)
2058 if (mData.getE() != null)
2060 List<Double> dVector = mData.getE().getV();
2061 double[] vec = new double[dVector.size()];
2063 for (Double d : dVector)
2074 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2075 * for each viewer, with
2077 * <li>viewer geometry (position, size, split pane divider location)</li>
2078 * <li>index of the selected structure in the viewer (currently shows gapped
2080 * <li>the id of the annotation holding RNA secondary structure</li>
2081 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2083 * Varna viewer state is also written out (in native Varna XML) to separate
2084 * project jar entries. A separate entry is written for each RNA structure
2085 * displayed, with the naming convention
2087 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2095 * @param storeDataset
2097 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2098 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2099 boolean storeDataset)
2101 if (Desktop.desktop == null)
2105 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2106 for (int f = frames.length - 1; f > -1; f--)
2108 if (frames[f] instanceof AppVarna)
2110 AppVarna varna = (AppVarna) frames[f];
2112 * link the sequence to every viewer that is showing it and is linked to
2113 * its alignment panel
2115 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2117 String viewId = varna.getViewId();
2118 RnaViewer rna = new RnaViewer();
2119 rna.setViewId(viewId);
2120 rna.setTitle(varna.getTitle());
2121 rna.setXpos(varna.getX());
2122 rna.setYpos(varna.getY());
2123 rna.setWidth(varna.getWidth());
2124 rna.setHeight(varna.getHeight());
2125 rna.setDividerLocation(varna.getDividerLocation());
2126 rna.setSelectedRna(varna.getSelectedIndex());
2127 // jseq.addRnaViewer(rna);
2128 jseq.getRnaViewer().add(rna);
2131 * Store each Varna panel's state once in the project per sequence.
2132 * First time through only (storeDataset==false)
2134 // boolean storeSessions = false;
2135 // String sequenceViewId = viewId + seqsToIds.get(jds);
2136 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2138 // viewIds.add(sequenceViewId);
2139 // storeSessions = true;
2141 for (RnaModel model : varna.getModels())
2143 if (model.seq == jds)
2146 * VARNA saves each view (sequence or alignment secondary
2147 * structure, gapped or trimmed) as a separate XML file
2149 String jarEntryName = rnaSessions.get(model);
2150 if (jarEntryName == null)
2153 String varnaStateFile = varna.getStateInfo(model.rna);
2154 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2155 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2156 rnaSessions.put(model, jarEntryName);
2158 SecondaryStructure ss = new SecondaryStructure();
2159 String annotationId = varna.getAnnotation(jds).annotationId;
2160 ss.setAnnotationId(annotationId);
2161 ss.setViewerState(jarEntryName);
2162 ss.setGapped(model.gapped);
2163 ss.setTitle(model.title);
2164 // rna.addSecondaryStructure(ss);
2165 rna.getSecondaryStructure().add(ss);
2174 * Copy the contents of a file to a new entry added to the output jar
2178 * @param jarEntryName
2180 * additional identifying info to log to the console
2182 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2183 String jarEntryName, String msg)
2185 try (InputStream is = new FileInputStream(infilePath))
2187 File file = new File(infilePath);
2188 if (file.exists() && jout != null)
2190 jalview.bin.Console.outPrintln(
2191 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2192 jout.putNextEntry(new JarEntry(jarEntryName));
2195 // dis = new DataInputStream(new FileInputStream(file));
2196 // byte[] data = new byte[(int) file.length()];
2197 // dis.readFully(data);
2198 // writeJarEntry(jout, jarEntryName, data);
2200 } catch (Exception ex)
2202 ex.printStackTrace();
2207 * Copies input to output, in 4K buffers; handles any data (text or binary)
2211 * @throws IOException
2213 protected void copyAll(InputStream in, OutputStream out)
2216 byte[] buffer = new byte[4096];
2218 while ((bytesRead = in.read(buffer)) != -1)
2220 out.write(buffer, 0, bytesRead);
2225 * Save the state of a structure viewer
2230 * the archive XML element under which to save the state
2233 * @param matchedFile
2237 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2238 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2239 String matchedFile, JalviewStructureDisplayI viewFrame)
2241 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2244 * Look for any bindings for this viewer to the PDB file of interest
2245 * (including part matches excluding chain id)
2247 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2249 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2250 final String pdbId = pdbentry.getId();
2251 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2252 && entry.getId().toLowerCase(Locale.ROOT)
2253 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2256 * not interested in a binding to a different PDB entry here
2260 if (matchedFile == null)
2262 matchedFile = pdbentry.getFile();
2264 else if (!matchedFile.equals(pdbentry.getFile()))
2267 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2268 + pdbentry.getFile());
2272 // can get at it if the ID
2273 // match is ambiguous (e.g.
2276 for (int smap = 0; smap < viewFrame.getBinding()
2277 .getSequence()[peid].length; smap++)
2279 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2280 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2282 StructureState state = new StructureState();
2283 state.setVisible(true);
2284 state.setXpos(viewFrame.getY());
2285 state.setYpos(viewFrame.getY());
2286 state.setWidth(viewFrame.getWidth());
2287 state.setHeight(viewFrame.getHeight());
2288 final String viewId = viewFrame.getViewId();
2289 state.setViewId(viewId);
2290 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2291 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2292 state.setColourByJmol(viewFrame.isColouredByViewer());
2293 state.setType(viewFrame.getViewerType().toString());
2294 // pdb.addStructureState(state);
2295 pdb.getStructureState().add(state);
2303 * Populates the AnnotationColourScheme xml for save. This captures the
2304 * settings of the options in the 'Colour by Annotation' dialog.
2307 * @param userColours
2311 private AnnotationColourScheme constructAnnotationColours(
2312 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2315 AnnotationColourScheme ac = new AnnotationColourScheme();
2316 ac.setAboveThreshold(acg.getAboveThreshold());
2317 ac.setThreshold(acg.getAnnotationThreshold());
2318 // 2.10.2 save annotationId (unique) not annotation label
2319 ac.setAnnotation(acg.getAnnotation().annotationId);
2320 if (acg.getBaseColour() instanceof UserColourScheme)
2323 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2328 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2331 ac.setMaxColour(acg.getMaxColour().getRGB());
2332 ac.setMinColour(acg.getMinColour().getRGB());
2333 ac.setPerSequence(acg.isSeqAssociated());
2334 ac.setPredefinedColours(acg.isPredefinedColours());
2338 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2339 IdentityHashMap<SequenceGroup, String> groupRefs,
2340 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2341 SequenceSet vamsasSet)
2344 for (int i = 0; i < aa.length; i++)
2346 Annotation an = new Annotation();
2348 AlignmentAnnotation annotation = aa[i];
2349 if (annotation.annotationId != null)
2351 annotationIds.put(annotation.annotationId, annotation);
2354 an.setId(annotation.annotationId);
2356 an.setVisible(annotation.visible);
2358 an.setDescription(annotation.description);
2360 if (annotation.sequenceRef != null)
2362 // 2.9 JAL-1781 xref on sequence id rather than name
2363 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2365 if (annotation.groupRef != null)
2367 String groupIdr = groupRefs.get(annotation.groupRef);
2368 if (groupIdr == null)
2370 // make a locally unique String
2371 groupRefs.put(annotation.groupRef,
2372 groupIdr = ("" + System.currentTimeMillis()
2373 + annotation.groupRef.getName()
2374 + groupRefs.size()));
2376 an.setGroupRef(groupIdr.toString());
2379 // store all visualization attributes for annotation
2380 an.setGraphHeight(annotation.graphHeight);
2381 an.setCentreColLabels(annotation.centreColLabels);
2382 an.setScaleColLabels(annotation.scaleColLabel);
2383 an.setShowAllColLabels(annotation.showAllColLabels);
2384 an.setBelowAlignment(annotation.belowAlignment);
2386 if (annotation.graph > 0)
2389 an.setGraphType(annotation.graph);
2390 an.setGraphGroup(annotation.graphGroup);
2391 if (annotation.getThreshold() != null)
2393 ThresholdLine line = new ThresholdLine();
2394 line.setLabel(annotation.getThreshold().label);
2395 line.setValue(annotation.getThreshold().value);
2396 line.setColour(annotation.getThreshold().colour.getRGB());
2397 an.setThresholdLine(line);
2399 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2401 if (annotation.sequenceRef.getContactMaps() != null)
2403 ContactMatrixI cm = annotation.sequenceRef
2404 .getContactMatrixFor(annotation);
2407 storeMatrixFor(vamsasSet, an, annotation, cm);
2417 an.setLabel(annotation.label);
2419 if (annotation == av.getAlignmentQualityAnnot()
2420 || annotation == av.getAlignmentConservationAnnotation()
2421 || annotation == av.getAlignmentConsensusAnnotation()
2422 || annotation.autoCalculated)
2424 // new way of indicating autocalculated annotation -
2425 an.setAutoCalculated(annotation.autoCalculated);
2427 if (annotation.hasScore())
2429 an.setScore(annotation.getScore());
2432 if (annotation.getCalcId() != null)
2434 calcIdSet.add(annotation.getCalcId());
2435 an.setCalcId(annotation.getCalcId());
2437 if (annotation.hasProperties())
2439 for (String pr : annotation.getProperties())
2441 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2443 prop.setValue(annotation.getProperty(pr));
2444 an.getProperty().add(prop);
2448 AnnotationElement ae;
2449 if (annotation.annotations != null)
2451 an.setScoreOnly(false);
2452 for (int a = 0; a < annotation.annotations.length; a++)
2454 if ((annotation == null) || (annotation.annotations[a] == null))
2459 ae = new AnnotationElement();
2460 if (annotation.annotations[a].description != null)
2462 ae.setDescription(annotation.annotations[a].description);
2464 if (annotation.annotations[a].displayCharacter != null)
2466 ae.setDisplayCharacter(
2467 annotation.annotations[a].displayCharacter);
2470 if (!Float.isNaN(annotation.annotations[a].value))
2472 ae.setValue(annotation.annotations[a].value);
2476 if (annotation.annotations[a].secondaryStructure > ' ')
2478 ae.setSecondaryStructure(
2479 annotation.annotations[a].secondaryStructure + "");
2482 if (annotation.annotations[a].colour != null
2483 && annotation.annotations[a].colour != java.awt.Color.black)
2485 ae.setColour(annotation.annotations[a].colour.getRGB());
2488 // an.addAnnotationElement(ae);
2489 an.getAnnotationElement().add(ae);
2490 if (annotation.autoCalculated)
2492 // only write one non-null entry into the annotation row -
2493 // sufficient to get the visualization attributes necessary to
2501 an.setScoreOnly(true);
2503 if (!storeDS || (storeDS && !annotation.autoCalculated))
2505 // skip autocalculated annotation - these are only provided for
2507 // vamsasSet.addAnnotation(an);
2508 vamsasSet.getAnnotation().add(an);
2514 private void storeMatrixFor(SequenceSet root, Annotation an,
2515 AlignmentAnnotation annotation, ContactMatrixI cm)
2517 String cmId = contactMatrices.get(cm);
2518 MatrixType xmlmat = null;
2520 // first create an xml ref for the matrix data, if none exist
2523 xmlmat = new MatrixType();
2524 xmlmat.setType(cm.getType());
2525 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2526 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2527 // consider using an opaque to/from -> allow instance to control
2528 // its representation ?
2529 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2532 for (BitSet gp : cm.getGroups())
2534 xmlmat.getGroups().add(stringifyBitset(gp));
2539 // provenance object for tree ?
2540 xmlmat.getNewick().add(cm.getNewick());
2541 xmlmat.setTreeMethod(cm.getTreeMethod());
2543 if (cm.hasCutHeight())
2545 xmlmat.setCutHeight(cm.getCutHeight());
2547 xmlmat.setId(cmId = "m" + contactMatrices.size()
2548 + System.currentTimeMillis());
2549 Console.trace("Matrix data stored :" + cmId);
2550 contactMatrices.put(cm, cmId);
2551 contactMatrixRefs.put(cmId, cm);
2552 xmlMatrices.add(xmlmat);
2556 Console.trace("Existing Matrix stored :" + cmId);
2559 // now store mapping
2561 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2562 xmlmatmapping.setMatrix(cmId);
2564 // Pretty much all matrices currently managed in this way are
2565 // mappableContactMatrixI implementations - but check anyway
2566 if (cm instanceof MappableContactMatrixI)
2568 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2569 .getMapFor(annotation.sequenceRef);
2572 MapListType mp = new MapListType();
2573 List<int[]> r = mlst.getFromRanges();
2574 for (int[] range : r)
2576 MapListFrom mfrom = new MapListFrom();
2577 mfrom.setStart(range[0]);
2578 mfrom.setEnd(range[1]);
2579 // mp.addMapListFrom(mfrom);
2580 mp.getMapListFrom().add(mfrom);
2582 r = mlst.getToRanges();
2583 for (int[] range : r)
2585 MapListTo mto = new MapListTo();
2586 mto.setStart(range[0]);
2587 mto.setEnd(range[1]);
2588 // mp.addMapListTo(mto);
2589 mp.getMapListTo().add(mto);
2591 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2592 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2593 xmlmatmapping.setMapping(mp);
2597 an.getContactmatrix().add(xmlmatmapping);
2600 private String stringifyBitset(BitSet gp)
2602 StringBuilder sb = new StringBuilder();
2603 for (long val : gp.toLongArray())
2605 if (sb.length() > 0)
2611 return sb.toString();
2614 private BitSet deStringifyBitset(String stringified)
2616 if ("".equals(stringified) || stringified == null)
2618 return new BitSet();
2620 String[] longvals = stringified.split(",");
2621 long[] newlongvals = new long[longvals.length];
2622 for (int lv = 0; lv < longvals.length; lv++)
2626 newlongvals[lv] = Long.valueOf(longvals[lv]);
2627 } catch (Exception x)
2629 errorMessage += "Couldn't destringify bitset from: '" + stringified
2631 newlongvals[lv] = 0;
2634 return BitSet.valueOf(newlongvals);
2638 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2640 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2641 if (settings != null)
2643 CalcIdParam vCalcIdParam = new CalcIdParam();
2644 vCalcIdParam.setCalcId(calcId);
2645 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2646 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2647 // generic URI allowing a third party to resolve another instance of the
2648 // service used for this calculation
2649 for (String url : settings.getServiceURLs())
2651 // vCalcIdParam.addServiceURL(urls);
2652 vCalcIdParam.getServiceURL().add(url);
2654 vCalcIdParam.setVersion("1.0");
2655 if (settings.getPreset() != null)
2657 WsParamSetI setting = settings.getPreset();
2658 vCalcIdParam.setName(setting.getName());
2659 vCalcIdParam.setDescription(setting.getDescription());
2663 vCalcIdParam.setName("");
2664 vCalcIdParam.setDescription("Last used parameters");
2666 // need to be able to recover 1) settings 2) user-defined presets or
2667 // recreate settings from preset 3) predefined settings provided by
2668 // service - or settings that can be transferred (or discarded)
2669 vCalcIdParam.setParameters(
2670 settings.getWsParamFile().replace("\n", "|\\n|"));
2671 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2672 // todo - decide if updateImmediately is needed for any projects.
2674 return vCalcIdParam;
2679 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2682 if (calcIdParam.getVersion().equals("1.0"))
2684 final String[] calcIds = calcIdParam.getServiceURL()
2685 .toArray(new String[0]);
2686 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2687 .getPreferredServiceFor(calcIds);
2688 if (service != null)
2690 WsParamSetI parmSet = null;
2693 parmSet = service.getParamStore().parseServiceParameterFile(
2694 calcIdParam.getName(), calcIdParam.getDescription(),
2696 calcIdParam.getParameters().replace("|\\n|", "\n"));
2697 } catch (IOException x)
2699 Console.warn("Couldn't parse parameter data for "
2700 + calcIdParam.getCalcId(), x);
2703 List<ArgumentI> argList = null;
2704 if (calcIdParam.getName().length() > 0)
2706 parmSet = service.getParamStore()
2707 .getPreset(calcIdParam.getName());
2708 if (parmSet != null)
2710 // TODO : check we have a good match with settings in AACon -
2711 // otherwise we'll need to create a new preset
2716 argList = parmSet.getArguments();
2719 AAConSettings settings = new AAConSettings(
2720 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2721 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2722 calcIdParam.isNeedsUpdate());
2728 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2732 throw new Error(MessageManager.formatMessage(
2733 "error.unsupported_version_calcIdparam", new Object[]
2734 { calcIdParam.toString() }));
2738 * External mapping between jalview objects and objects yielding a valid and
2739 * unique object ID string. This is null for normal Jalview project IO, but
2740 * non-null when a jalview project is being read or written as part of a
2743 IdentityHashMap jv2vobj = null;
2746 * Construct a unique ID for jvobj using either existing bindings or if none
2747 * exist, the result of the hashcode call for the object.
2750 * jalview data object
2751 * @return unique ID for referring to jvobj
2753 private String makeHashCode(Object jvobj, String altCode)
2755 if (jv2vobj != null)
2757 Object id = jv2vobj.get(jvobj);
2760 return id.toString();
2762 // check string ID mappings
2763 if (jvids2vobj != null && jvobj instanceof String)
2765 id = jvids2vobj.get(jvobj);
2769 return id.toString();
2771 // give up and warn that something has gone wrong
2773 "Cannot find ID for object in external mapping : " + jvobj);
2779 * return local jalview object mapped to ID, if it exists
2783 * @return null or object bound to idcode
2785 private Object retrieveExistingObj(String idcode)
2787 if (idcode != null && vobj2jv != null)
2789 return vobj2jv.get(idcode);
2795 * binding from ID strings from external mapping table to jalview data model
2798 private Hashtable vobj2jv;
2800 private Sequence createVamsasSequence(String id, SequenceI jds)
2802 return createVamsasSequence(true, id, jds, null);
2805 private Sequence createVamsasSequence(boolean recurse, String id,
2806 SequenceI jds, SequenceI parentseq)
2808 Sequence vamsasSeq = new Sequence();
2809 vamsasSeq.setId(id);
2810 vamsasSeq.setName(jds.getName());
2811 vamsasSeq.setSequence(jds.getSequenceAsString());
2812 vamsasSeq.setDescription(jds.getDescription());
2813 List<DBRefEntry> dbrefs = null;
2814 if (jds.getDatasetSequence() != null)
2816 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2820 // seqId==dsseqid so we can tell which sequences really are
2821 // dataset sequences only
2822 vamsasSeq.setDsseqid(id);
2823 dbrefs = jds.getDBRefs();
2824 if (parentseq == null)
2831 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2835 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2837 DBRef dbref = new DBRef();
2838 DBRefEntry ref = dbrefs.get(d);
2839 dbref.setSource(ref.getSource());
2840 dbref.setVersion(ref.getVersion());
2841 dbref.setAccessionId(ref.getAccessionId());
2842 dbref.setCanonical(ref.isCanonical());
2843 if (ref instanceof GeneLocus)
2845 dbref.setLocus(true);
2849 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2851 dbref.setMapping(mp);
2853 vamsasSeq.getDBRef().add(dbref);
2859 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2860 SequenceI parentseq, SequenceI jds, boolean recurse)
2863 if (jmp.getMap() != null)
2867 jalview.util.MapList mlst = jmp.getMap();
2868 List<int[]> r = mlst.getFromRanges();
2869 for (int[] range : r)
2871 MapListFrom mfrom = new MapListFrom();
2872 mfrom.setStart(range[0]);
2873 mfrom.setEnd(range[1]);
2874 // mp.addMapListFrom(mfrom);
2875 mp.getMapListFrom().add(mfrom);
2877 r = mlst.getToRanges();
2878 for (int[] range : r)
2880 MapListTo mto = new MapListTo();
2881 mto.setStart(range[0]);
2882 mto.setEnd(range[1]);
2883 // mp.addMapListTo(mto);
2884 mp.getMapListTo().add(mto);
2886 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2887 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2888 if (jmp.getTo() != null)
2890 // MappingChoice mpc = new MappingChoice();
2892 // check/create ID for the sequence referenced by getTo()
2895 SequenceI ps = null;
2896 if (parentseq != jmp.getTo()
2897 && parentseq.getDatasetSequence() != jmp.getTo())
2899 // chaining dbref rather than a handshaking one
2900 jmpid = seqHash(ps = jmp.getTo());
2904 jmpid = seqHash(ps = parentseq);
2906 // mpc.setDseqFor(jmpid);
2907 mp.setDseqFor(jmpid);
2908 if (!seqRefIds.containsKey(jmpid))
2910 Console.debug("creatign new DseqFor ID");
2911 seqRefIds.put(jmpid, ps);
2915 Console.debug("reusing DseqFor ID");
2918 // mp.setMappingChoice(mpc);
2924 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2925 List<UserColourScheme> userColours, JalviewModel jm)
2928 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2929 boolean newucs = false;
2930 if (!userColours.contains(ucs))
2932 userColours.add(ucs);
2935 id = "ucs" + userColours.indexOf(ucs);
2938 // actually create the scheme's entry in the XML model
2939 java.awt.Color[] colours = ucs.getColours();
2940 UserColours uc = new UserColours();
2941 // UserColourScheme jbucs = new UserColourScheme();
2942 JalviewUserColours jbucs = new JalviewUserColours();
2944 for (int i = 0; i < colours.length; i++)
2946 Colour col = new Colour();
2947 col.setName(ResidueProperties.aa[i]);
2948 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2949 // jbucs.addColour(col);
2950 jbucs.getColour().add(col);
2952 if (ucs.getLowerCaseColours() != null)
2954 colours = ucs.getLowerCaseColours();
2955 for (int i = 0; i < colours.length; i++)
2957 Colour col = new Colour();
2958 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2959 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2960 // jbucs.addColour(col);
2961 jbucs.getColour().add(col);
2966 uc.setUserColourScheme(jbucs);
2967 // jm.addUserColours(uc);
2968 jm.getUserColours().add(uc);
2974 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2977 List<UserColours> uc = jm.getUserColours();
2978 UserColours colours = null;
2980 for (int i = 0; i < uc.length; i++)
2982 if (uc[i].getId().equals(id))
2989 for (UserColours c : uc)
2991 if (c.getId().equals(id))
2998 java.awt.Color[] newColours = new java.awt.Color[24];
3000 for (int i = 0; i < 24; i++)
3002 newColours[i] = new java.awt.Color(Integer.parseInt(
3003 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
3004 colours.getUserColourScheme().getColour().get(i).getRGB(),
3008 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
3011 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3013 newColours = new java.awt.Color[23];
3014 for (int i = 0; i < 23; i++)
3016 newColours[i] = new java.awt.Color(
3017 Integer.parseInt(colours.getUserColourScheme().getColour()
3018 .get(i + 24).getRGB(), 16));
3020 ucs.setLowerCaseColours(newColours);
3027 * contains last error message (if any) encountered by XML loader.
3029 String errorMessage = null;
3032 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3033 * exceptions are raised during project XML parsing
3035 public boolean attemptversion1parse = false;
3038 * Load a jalview project archive from a jar file
3041 * - HTTP URL or filename
3043 public AlignFrame loadJalviewAlign(final Object file)
3046 jalview.gui.AlignFrame af = null;
3050 // create list to store references for any new Jmol viewers created
3051 newStructureViewers = new Vector<>();
3052 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3053 // Workaround is to make sure caller implements the JarInputStreamProvider
3055 // so we can re-open the jar input stream for each entry.
3057 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3058 af = loadJalviewAlign(jprovider);
3061 af.setMenusForViewport();
3063 } catch (MalformedURLException e)
3065 errorMessage = "Invalid URL format for '" + file + "'";
3071 SwingUtilities.invokeAndWait(new Runnable()
3076 setLoadingFinishedForNewStructureViewers();
3079 } catch (Exception x)
3082 .errPrintln("Error loading alignment: " + x.getMessage());
3088 @SuppressWarnings("unused")
3089 private jarInputStreamProvider createjarInputStreamProvider(
3090 final Object ofile) throws MalformedURLException
3093 // BH 2018 allow for bytes already attached to File object
3096 String file = (ofile instanceof File
3097 ? ((File) ofile).getCanonicalPath()
3098 : ofile.toString());
3099 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3102 errorMessage = null;
3103 uniqueSetSuffix = null;
3105 viewportsAdded.clear();
3106 frefedSequence = null;
3108 if (HttpUtils.startsWithHttpOrHttps(file))
3110 url = new URL(file);
3112 final URL _url = url;
3113 return new jarInputStreamProvider()
3117 public JarInputStream getJarInputStream() throws IOException
3121 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3122 // jarInputStream for
3123 // bytes.length=" + bytes.length);
3124 return new JarInputStream(new ByteArrayInputStream(bytes));
3128 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3129 // jarInputStream for "
3131 return new JarInputStream(HttpUtils.openStream(_url));
3135 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3136 // jarInputStream for
3138 return new JarInputStream(new FileInputStream(file));
3143 public String getFilename()
3148 } catch (IOException e)
3150 e.printStackTrace();
3156 * Recover jalview session from a jalview project archive. Caller may
3157 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3158 * themselves. Any null fields will be initialised with default values,
3159 * non-null fields are left alone.
3164 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3166 errorMessage = null;
3167 if (uniqueSetSuffix == null)
3169 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3171 if (seqRefIds == null)
3175 AlignFrame af = null, _af = null;
3176 List<AlignFrame> toRepaint = new ArrayList<AlignFrame>();
3177 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3178 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3179 final String file = jprovider.getFilename();
3182 JarInputStream jin = null;
3183 JarEntry jarentry = null;
3188 jin = jprovider.getJarInputStream();
3189 for (int i = 0; i < entryCount; i++)
3191 jarentry = jin.getNextJarEntry();
3194 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3196 JAXBContext jc = JAXBContext
3197 .newInstance("jalview.xml.binding.jalview");
3198 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3199 .createXMLStreamReader(jin);
3200 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3201 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3202 JalviewModel.class);
3203 JalviewModel object = jbe.getValue();
3205 if (true) // !skipViewport(object))
3207 _af = loadFromObject(object, file, true, jprovider);
3208 if (_af != null && object.getViewport().size() > 0)
3209 // getJalviewModelSequence().getViewportCount() > 0)
3214 // store a reference to the first view
3217 if (_af.getViewport().isGatherViewsHere())
3219 // if this is a gathered view, keep its reference since
3220 // after gathering views, only this frame will remain
3222 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3225 // Save dataset to register mappings once all resolved
3226 importedDatasets.put(
3227 af.getViewport().getAlignment().getDataset(),
3228 af.getViewport().getAlignment().getDataset());
3233 else if (jarentry != null)
3235 // Some other file here.
3238 } while (jarentry != null);
3240 resolveFrefedSequences();
3241 for (AlignFrame alignFrame : toRepaint)
3243 alignFrame.repaint();
3245 } catch (IOException ex)
3247 ex.printStackTrace();
3248 errorMessage = "Couldn't locate Jalview XML file : " + file;
3249 jalview.bin.Console.errPrintln(
3250 "Exception whilst loading jalview XML file : " + ex + "\n");
3251 } catch (Exception ex)
3254 .errPrintln("Parsing as Jalview Version 2 file failed.");
3255 ex.printStackTrace(System.err);
3256 if (attemptversion1parse)
3258 // used to attempt to parse as V1 castor-generated xml
3260 if (Desktop.instance != null)
3262 Desktop.instance.stopLoading();
3266 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3269 ex.printStackTrace();
3271 jalview.bin.Console.errPrintln(
3272 "Exception whilst loading jalview XML file : " + ex + "\n");
3273 } catch (OutOfMemoryError e)
3275 // Don't use the OOM Window here
3276 errorMessage = "Out of memory loading jalview XML file";
3278 .errPrintln("Out of memory whilst loading jalview XML file");
3279 e.printStackTrace();
3283 * Regather multiple views (with the same sequence set id) to the frame (if
3284 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3285 * views instead of separate frames. Note this doesn't restore a state where
3286 * some expanded views in turn have tabbed views - the last "first tab" read
3287 * in will play the role of gatherer for all.
3289 for (AlignFrame fr : gatherToThisFrame.values())
3291 Desktop.instance.gatherViews(fr);
3294 restoreSplitFrames();
3295 for (AlignmentI ds : importedDatasets.keySet())
3297 if (ds.getCodonFrames() != null)
3299 StructureSelectionManager
3300 .getStructureSelectionManager(Desktop.instance)
3301 .registerMappings(ds.getCodonFrames());
3304 if (errorMessage != null)
3309 if (Desktop.instance != null)
3311 Desktop.instance.stopLoading();
3318 * Try to reconstruct and display SplitFrame windows, where each contains
3319 * complementary dna and protein alignments. Done by pairing up AlignFrame
3320 * objects (created earlier) which have complementary viewport ids associated.
3322 protected void restoreSplitFrames()
3324 List<SplitFrame> gatherTo = new ArrayList<>();
3325 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3326 Map<String, AlignFrame> dna = new HashMap<>();
3329 * Identify the DNA alignments
3331 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3334 AlignFrame af = candidate.getValue();
3335 if (af.getViewport().getAlignment().isNucleotide())
3337 dna.put(candidate.getKey().getId(), af);
3342 * Try to match up the protein complements
3344 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3347 AlignFrame af = candidate.getValue();
3348 if (!af.getViewport().getAlignment().isNucleotide())
3350 String complementId = candidate.getKey().getComplementId();
3351 // only non-null complements should be in the Map
3352 if (complementId != null && dna.containsKey(complementId))
3354 final AlignFrame dnaFrame = dna.get(complementId);
3355 SplitFrame sf = createSplitFrame(dnaFrame, af);
3356 addedToSplitFrames.add(dnaFrame);
3357 addedToSplitFrames.add(af);
3358 dnaFrame.setMenusForViewport();
3359 af.setMenusForViewport();
3360 if (af.getViewport().isGatherViewsHere())
3369 * Open any that we failed to pair up (which shouldn't happen!) as
3370 * standalone AlignFrame's.
3372 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3375 AlignFrame af = candidate.getValue();
3376 if (!addedToSplitFrames.contains(af))
3378 Viewport view = candidate.getKey();
3379 Desktop.addInternalFrame(af, view.getTitle(),
3380 safeInt(view.getWidth()), safeInt(view.getHeight()));
3381 af.setMenusForViewport();
3382 jalview.bin.Console.errPrintln("Failed to restore view "
3383 + view.getTitle() + " to split frame");
3388 * Gather back into tabbed views as flagged.
3390 for (SplitFrame sf : gatherTo)
3392 Desktop.instance.gatherViews(sf);
3395 splitFrameCandidates.clear();
3399 * Construct and display one SplitFrame holding DNA and protein alignments.
3402 * @param proteinFrame
3405 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3406 AlignFrame proteinFrame)
3408 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3409 String title = MessageManager.getString("label.linked_view_title");
3410 int width = (int) dnaFrame.getBounds().getWidth();
3411 int height = (int) (dnaFrame.getBounds().getHeight()
3412 + proteinFrame.getBounds().getHeight() + 50);
3415 * SplitFrame location is saved to both enclosed frames
3417 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3418 Desktop.addInternalFrame(splitFrame, title, width, height);
3421 * And compute cDNA consensus (couldn't do earlier with consensus as
3422 * mappings were not yet present)
3424 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3430 * check errorMessage for a valid error message and raise an error box in the
3431 * GUI or write the current errorMessage to stderr and then clear the error
3434 protected void reportErrors()
3436 reportErrors(false);
3439 protected void reportErrors(final boolean saving)
3441 if (errorMessage != null)
3443 final String finalErrorMessage = errorMessage;
3446 javax.swing.SwingUtilities.invokeLater(new Runnable()
3451 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3453 "Error " + (saving ? "saving" : "loading")
3455 JvOptionPane.WARNING_MESSAGE);
3461 jalview.bin.Console.errPrintln(
3462 "Problem loading Jalview file: " + errorMessage);
3465 errorMessage = null;
3468 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3471 * when set, local views will be updated from view stored in JalviewXML
3472 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3473 * sync if this is set to true.
3475 private final boolean updateLocalViews = false;
3478 * Returns the path to a temporary file holding the PDB file for the given PDB
3479 * id. The first time of asking, searches for a file of that name in the
3480 * Jalview project jar, and copies it to a new temporary file. Any repeat
3481 * requests just return the path to the file previously created.
3487 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3490 if (alreadyLoadedPDB.containsKey(pdbId))
3492 return alreadyLoadedPDB.get(pdbId).toString();
3495 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3497 if (tempFile != null)
3499 alreadyLoadedPDB.put(pdbId, tempFile);
3505 * Copies the jar entry of given name to a new temporary file and returns the
3506 * path to the file, or null if the entry is not found.
3509 * @param jarEntryName
3511 * a prefix for the temporary file name, must be at least three
3513 * @param suffixModel
3514 * null or original file - so new file can be given the same suffix
3518 protected String copyJarEntry(jarInputStreamProvider jprovider,
3519 String jarEntryName, String prefix, String suffixModel)
3521 String suffix = ".tmp";
3522 if (suffixModel == null)
3524 suffixModel = jarEntryName;
3526 int sfpos = suffixModel.lastIndexOf(".");
3527 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3529 suffix = "." + suffixModel.substring(sfpos + 1);
3532 try (JarInputStream jin = jprovider.getJarInputStream())
3534 JarEntry entry = null;
3537 entry = jin.getNextJarEntry();
3538 } while (entry != null && !entry.getName().equals(jarEntryName));
3542 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3543 File outFile = File.createTempFile(prefix, suffix);
3544 outFile.deleteOnExit();
3545 try (OutputStream os = new FileOutputStream(outFile))
3549 String t = outFile.getAbsolutePath();
3555 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3557 } catch (Exception ex)
3559 ex.printStackTrace();
3565 private class JvAnnotRow
3567 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3574 * persisted version of annotation row from which to take vis properties
3576 public jalview.datamodel.AlignmentAnnotation template;
3579 * original position of the annotation row in the alignment
3585 * Load alignment frame from jalview XML DOM object
3587 * @param jalviewModel
3590 * filename source string
3591 * @param loadTreesAndStructures
3592 * when false only create Viewport
3594 * data source provider
3595 * @return alignment frame created from view stored in DOM
3597 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3598 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3600 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3602 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3604 // JalviewModelSequence jms = object.getJalviewModelSequence();
3606 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3608 Viewport view = (jalviewModel.getViewport().size() > 0)
3609 ? jalviewModel.getViewport().get(0)
3612 // ////////////////////////////////
3613 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3616 // If we just load in the same jar file again, the sequenceSetId
3617 // will be the same, and we end up with multiple references
3618 // to the same sequenceSet. We must modify this id on load
3619 // so that each load of the file gives a unique id
3622 * used to resolve correct alignment dataset for alignments with multiple
3625 String uniqueSeqSetId = null;
3626 String viewId = null;
3629 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3630 viewId = (view.getId() == null ? null
3631 : view.getId() + uniqueSetSuffix);
3634 // ////////////////////////////////
3635 // LOAD MATRICES (IF ANY)
3637 if (vamsasSet.getMatrix() != null && vamsasSet.getMatrix().size() > 0)
3639 importMatrixData(vamsasSet.getMatrix());
3642 // ////////////////////////////////
3645 List<SequenceI> hiddenSeqs = null;
3647 List<SequenceI> tmpseqs = new ArrayList<>();
3649 boolean multipleView = false;
3650 SequenceI referenceseqForView = null;
3651 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3652 List<JSeq> jseqs = jalviewModel.getJSeq();
3653 int vi = 0; // counter in vamsasSeq array
3654 for (int i = 0; i < jseqs.size(); i++)
3656 JSeq jseq = jseqs.get(i);
3657 String seqId = jseq.getId();
3659 SequenceI tmpSeq = seqRefIds.get(seqId);
3662 if (!incompleteSeqs.containsKey(seqId))
3664 // may not need this check, but keep it for at least 2.9,1 release
3665 if (tmpSeq.getStart() != jseq.getStart()
3666 || tmpSeq.getEnd() != jseq.getEnd())
3668 jalview.bin.Console.errPrintln(String.format(
3669 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3670 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3671 jseq.getStart(), jseq.getEnd()));
3676 incompleteSeqs.remove(seqId);
3678 if (vamsasSeqs.size() > vi
3679 && vamsasSeqs.get(vi).getId().equals(seqId))
3681 // most likely we are reading a dataset XML document so
3682 // update from vamsasSeq section of XML for this sequence
3683 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3684 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3685 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3690 // reading multiple views, so vamsasSeq set is a subset of JSeq
3691 multipleView = true;
3693 tmpSeq.setStart(jseq.getStart());
3694 tmpSeq.setEnd(jseq.getEnd());
3695 tmpseqs.add(tmpSeq);
3699 Sequence vamsasSeq = vamsasSeqs.get(vi);
3700 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3701 vamsasSeq.getSequence());
3702 tmpSeq.setDescription(vamsasSeq.getDescription());
3703 tmpSeq.setStart(jseq.getStart());
3704 tmpSeq.setEnd(jseq.getEnd());
3705 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3706 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3707 tmpseqs.add(tmpSeq);
3711 if (safeBoolean(jseq.isViewreference()))
3713 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3716 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3718 if (hiddenSeqs == null)
3720 hiddenSeqs = new ArrayList<>();
3723 hiddenSeqs.add(tmpSeq);
3728 // Create the alignment object from the sequence set
3729 // ///////////////////////////////
3730 SequenceI[] orderedSeqs = tmpseqs
3731 .toArray(new SequenceI[tmpseqs.size()]);
3733 AlignmentI al = null;
3734 // so we must create or recover the dataset alignment before going further
3735 // ///////////////////////////////
3736 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3738 // older jalview projects do not have a dataset - so creat alignment and
3740 al = new Alignment(orderedSeqs);
3741 al.setDataset(null);
3745 boolean isdsal = jalviewModel.getViewport().isEmpty();
3748 // we are importing a dataset record, so
3749 // recover reference to an alignment already materialsed as dataset
3750 al = getDatasetFor(vamsasSet.getDatasetId());
3754 // materialse the alignment
3755 al = new Alignment(orderedSeqs);
3759 addDatasetRef(vamsasSet.getDatasetId(), al);
3762 // finally, verify all data in vamsasSet is actually present in al
3763 // passing on flag indicating if it is actually a stored dataset
3764 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3767 if (referenceseqForView != null)
3769 al.setSeqrep(referenceseqForView);
3771 // / Add the alignment properties
3772 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3774 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3776 al.setProperty(ssp.getKey(), ssp.getValue());
3779 // ///////////////////////////////
3781 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3784 // load sequence features, database references and any associated PDB
3785 // structures for the alignment
3787 // prior to 2.10, this part would only be executed the first time a
3788 // sequence was encountered, but not afterwards.
3789 // now, for 2.10 projects, this is also done if the xml doc includes
3790 // dataset sequences not actually present in any particular view.
3792 for (int i = 0; i < vamsasSeqs.size(); i++)
3794 JSeq jseq = jseqs.get(i);
3795 if (jseq.getFeatures().size() > 0)
3797 List<Feature> features = jseq.getFeatures();
3798 for (int f = 0; f < features.size(); f++)
3800 Feature feat = features.get(f);
3801 SequenceFeature sf = new SequenceFeature(feat.getType(),
3802 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3803 safeFloat(feat.getScore()), feat.getFeatureGroup());
3804 sf.setStatus(feat.getStatus());
3807 * load any feature attributes - include map-valued attributes
3809 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3810 for (int od = 0; od < feat.getOtherData().size(); od++)
3812 OtherData keyValue = feat.getOtherData().get(od);
3813 String attributeName = keyValue.getKey();
3814 String attributeValue = keyValue.getValue();
3815 if (attributeName.startsWith("LINK"))
3817 sf.addLink(attributeValue);
3821 String subAttribute = keyValue.getKey2();
3822 if (subAttribute == null)
3824 // simple string-valued attribute
3825 sf.setValue(attributeName, attributeValue);
3829 // attribute 'key' has sub-attribute 'key2'
3830 if (!mapAttributes.containsKey(attributeName))
3832 mapAttributes.put(attributeName, new HashMap<>());
3834 mapAttributes.get(attributeName).put(subAttribute,
3839 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3842 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3845 // adds feature to datasequence's feature set (since Jalview 2.10)
3846 al.getSequenceAt(i).addSequenceFeature(sf);
3849 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3851 // adds dbrefs to datasequence's set (since Jalview 2.10)
3853 al.getSequenceAt(i).getDatasetSequence() == null
3854 ? al.getSequenceAt(i)
3855 : al.getSequenceAt(i).getDatasetSequence(),
3858 if (jseq.getPdbids().size() > 0)
3860 List<Pdbids> ids = jseq.getPdbids();
3861 for (int p = 0; p < ids.size(); p++)
3863 Pdbids pdbid = ids.get(p);
3864 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3865 entry.setId(pdbid.getId());
3866 if (pdbid.getType() != null)
3868 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3870 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3874 entry.setType(PDBEntry.Type.FILE);
3877 // jprovider is null when executing 'New View'
3878 if (pdbid.getFile() != null && jprovider != null)
3880 if (!pdbloaded.containsKey(pdbid.getFile()))
3882 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3887 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3891 if (pdbid.getPdbentryItem() != null)
3893 for (PdbentryItem item : pdbid.getPdbentryItem())
3895 for (Property pr : item.getProperty())
3897 entry.setProperty(pr.getName(), pr.getValue());
3902 for (Property prop : pdbid.getProperty())
3904 entry.setProperty(prop.getName(), prop.getValue());
3906 StructureSelectionManager
3907 .getStructureSelectionManager(Desktop.instance)
3908 .registerPDBEntry(entry);
3909 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3910 if (al.getSequenceAt(i).getDatasetSequence() != null)
3912 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3916 al.getSequenceAt(i).addPDBId(entry);
3921 } // end !multipleview
3923 // ///////////////////////////////
3924 // LOAD SEQUENCE MAPPINGS
3926 if (vamsasSet.getAlcodonFrame().size() > 0)
3928 // TODO Potentially this should only be done once for all views of an
3930 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3931 for (int i = 0; i < alc.size(); i++)
3933 AlignedCodonFrame cf = new AlignedCodonFrame();
3934 if (alc.get(i).getAlcodMap().size() > 0)
3936 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3937 for (int m = 0; m < maps.size(); m++)
3939 AlcodMap map = maps.get(m);
3940 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3942 jalview.datamodel.Mapping mapping = null;
3943 // attach to dna sequence reference.
3944 if (map.getMapping() != null)
3946 mapping = addMapping(map.getMapping());
3947 if (dnaseq != null && mapping.getTo() != null)
3949 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3955 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3959 al.addCodonFrame(cf);
3964 // ////////////////////////////////
3966 List<JvAnnotRow> autoAlan = new ArrayList<>();
3969 * store any annotations which forward reference a group's ID
3971 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3973 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3975 List<Annotation> an = vamsasSet.getAnnotation();
3977 for (int i = 0; i < an.size(); i++)
3979 Annotation annotation = an.get(i);
3982 * test if annotation is automatically calculated for this view only
3984 boolean autoForView = false;
3985 if (annotation.getLabel().equals("Quality")
3986 || annotation.getLabel().equals("Conservation")
3987 || annotation.getLabel().equals("Consensus"))
3989 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3991 // JAXB has no has() test; schema defaults value to false
3992 // if (!annotation.hasAutoCalculated())
3994 // annotation.setAutoCalculated(true);
3997 if (autoForView || annotation.isAutoCalculated())
3999 // remove ID - we don't recover annotation from other views for
4000 // view-specific annotation
4001 annotation.setId(null);
4004 // set visibility for other annotation in this view
4005 String annotationId = annotation.getId();
4006 if (annotationId != null && annotationIds.containsKey(annotationId))
4008 AlignmentAnnotation jda = annotationIds.get(annotationId);
4009 // in principle Visible should always be true for annotation displayed
4010 // in multiple views
4011 if (annotation.isVisible() != null)
4013 jda.visible = annotation.isVisible();
4016 al.addAnnotation(jda);
4020 // Construct new annotation from model.
4021 List<AnnotationElement> ae = annotation.getAnnotationElement();
4022 jalview.datamodel.Annotation[] anot = null;
4023 java.awt.Color firstColour = null;
4025 if (!annotation.isScoreOnly())
4027 anot = new jalview.datamodel.Annotation[al.getWidth()];
4028 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4030 AnnotationElement annElement = ae.get(aa);
4031 anpos = annElement.getPosition();
4033 if (anpos >= anot.length)
4038 float value = safeFloat(annElement.getValue());
4039 anot[anpos] = new jalview.datamodel.Annotation(
4040 annElement.getDisplayCharacter(),
4041 annElement.getDescription(),
4042 (annElement.getSecondaryStructure() == null
4043 || annElement.getSecondaryStructure()
4047 .getSecondaryStructure()
4050 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4051 if (firstColour == null)
4053 firstColour = anot[anpos].colour;
4057 jalview.datamodel.AlignmentAnnotation jaa = null;
4059 if (annotation.isGraph())
4061 float llim = 0, hlim = 0;
4062 // if (autoForView || an[i].isAutoCalculated()) {
4065 jaa = new jalview.datamodel.AlignmentAnnotation(
4066 annotation.getLabel(), annotation.getDescription(), anot,
4067 llim, hlim, safeInt(annotation.getGraphType()));
4069 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4070 jaa._linecolour = firstColour;
4071 if (annotation.getThresholdLine() != null)
4073 jaa.setThreshold(new jalview.datamodel.GraphLine(
4074 safeFloat(annotation.getThresholdLine().getValue()),
4075 annotation.getThresholdLine().getLabel(),
4076 new java.awt.Color(safeInt(
4077 annotation.getThresholdLine().getColour()))));
4079 if (autoForView || annotation.isAutoCalculated())
4081 // Hardwire the symbol display line to ensure that labels for
4082 // histograms are displayed
4088 jaa = new jalview.datamodel.AlignmentAnnotation(
4089 annotation.getLabel(), annotation.getDescription(), anot);
4090 jaa._linecolour = firstColour;
4092 // register new annotation
4093 if (annotation.getId() != null)
4095 annotationIds.put(annotation.getId(), jaa);
4096 jaa.annotationId = annotation.getId();
4098 // recover sequence association
4099 String sequenceRef = annotation.getSequenceRef();
4100 if (sequenceRef != null)
4102 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4103 SequenceI sequence = seqRefIds.get(sequenceRef);
4104 if (sequence == null)
4106 // in pre-2.9 projects sequence ref is to sequence name
4107 sequence = al.findName(sequenceRef);
4109 if (sequence != null)
4111 jaa.createSequenceMapping(sequence, 1, true);
4112 sequence.addAlignmentAnnotation(jaa);
4115 // and make a note of any group association
4116 if (annotation.getGroupRef() != null
4117 && annotation.getGroupRef().length() > 0)
4119 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4120 .get(annotation.getGroupRef());
4123 aal = new ArrayList<>();
4124 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4129 if (annotation.getScore() != null)
4131 jaa.setScore(annotation.getScore().doubleValue());
4133 if (annotation.isVisible() != null)
4135 jaa.visible = annotation.isVisible().booleanValue();
4138 if (annotation.isCentreColLabels() != null)
4140 jaa.centreColLabels = annotation.isCentreColLabels()
4144 if (annotation.isScaleColLabels() != null)
4146 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4148 if (annotation.isAutoCalculated())
4150 // newer files have an 'autoCalculated' flag and store calculation
4151 // state in viewport properties
4152 jaa.autoCalculated = true; // means annotation will be marked for
4153 // update at end of load.
4155 if (annotation.getGraphHeight() != null)
4157 jaa.graphHeight = annotation.getGraphHeight().intValue();
4159 jaa.belowAlignment = annotation.isBelowAlignment();
4160 jaa.setCalcId(annotation.getCalcId());
4161 if (annotation.getProperty().size() > 0)
4163 for (jalview.xml.binding.jalview.Property prop : annotation
4166 jaa.setProperty(prop.getName(), prop.getValue());
4169 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4171 if (annotation.getContactmatrix() != null
4172 && annotation.getContactmatrix().size() > 0)
4174 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4176 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4181 if (jaa.autoCalculated)
4183 autoAlan.add(new JvAnnotRow(i, jaa));
4186 // if (!autoForView)
4188 // add autocalculated group annotation and any user created annotation
4190 al.addAnnotation(jaa);
4194 // ///////////////////////
4196 // Create alignment markup and styles for this view
4197 if (jalviewModel.getJGroup().size() > 0)
4199 List<JGroup> groups = jalviewModel.getJGroup();
4200 boolean addAnnotSchemeGroup = false;
4201 for (int i = 0; i < groups.size(); i++)
4203 JGroup jGroup = groups.get(i);
4204 ColourSchemeI cs = null;
4205 if (jGroup.getColour() != null)
4207 if (jGroup.getColour().startsWith("ucs"))
4209 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4211 else if (jGroup.getColour().equals("AnnotationColourGradient")
4212 && jGroup.getAnnotationColours() != null)
4214 addAnnotSchemeGroup = true;
4218 cs = ColourSchemeProperty.getColourScheme(null, al,
4219 jGroup.getColour());
4222 int pidThreshold = safeInt(jGroup.getPidThreshold());
4224 Vector<SequenceI> seqs = new Vector<>();
4226 for (int s = 0; s < jGroup.getSeq().size(); s++)
4228 String seqId = jGroup.getSeq().get(s);
4229 SequenceI ts = seqRefIds.get(seqId);
4233 seqs.addElement(ts);
4237 if (seqs.size() < 1)
4242 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4243 safeBoolean(jGroup.isDisplayBoxes()),
4244 safeBoolean(jGroup.isDisplayText()),
4245 safeBoolean(jGroup.isColourText()),
4246 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4247 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4248 sg.getGroupColourScheme()
4249 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4250 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4252 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4253 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4254 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4255 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4256 // attributes with a default in the schema are never null
4257 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4258 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4259 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4260 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4261 if (jGroup.getConsThreshold() != null
4262 && jGroup.getConsThreshold().intValue() != 0)
4264 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4267 c.verdict(false, 25);
4268 sg.cs.setConservation(c);
4271 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4273 // re-instate unique group/annotation row reference
4274 List<AlignmentAnnotation> jaal = groupAnnotRefs
4275 .get(jGroup.getId());
4278 for (AlignmentAnnotation jaa : jaal)
4281 if (jaa.autoCalculated)
4283 // match up and try to set group autocalc alignment row for this
4285 if (jaa.label.startsWith("Consensus for "))
4287 sg.setConsensus(jaa);
4289 // match up and try to set group autocalc alignment row for this
4291 if (jaa.label.startsWith("Conservation for "))
4293 sg.setConservationRow(jaa);
4300 if (addAnnotSchemeGroup)
4302 // reconstruct the annotation colourscheme
4304 constructAnnotationColour(jGroup.getAnnotationColours(),
4305 null, al, jalviewModel, false));
4311 // only dataset in this model, so just return.
4314 // ///////////////////////////////
4317 AlignFrame af = null;
4318 AlignViewport av = null;
4319 // now check to see if we really need to create a new viewport.
4320 if (multipleView && viewportsAdded.size() == 0)
4322 // We recovered an alignment for which a viewport already exists.
4323 // TODO: fix up any settings necessary for overlaying stored state onto
4324 // state recovered from another document. (may not be necessary).
4325 // we may need a binding from a viewport in memory to one recovered from
4327 // and then recover its containing af to allow the settings to be applied.
4328 // TODO: fix for vamsas demo
4329 jalview.bin.Console.errPrintln(
4330 "About to recover a viewport for existing alignment: Sequence set ID is "
4332 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4333 if (seqsetobj != null)
4335 if (seqsetobj instanceof String)
4337 uniqueSeqSetId = (String) seqsetobj;
4338 jalview.bin.Console.errPrintln(
4339 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4344 jalview.bin.Console.errPrintln(
4345 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4351 * indicate that annotation colours are applied across all groups (pre
4352 * Jalview 2.8.1 behaviour)
4354 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4355 jalviewModel.getVersion());
4357 AlignmentPanel ap = null;
4358 boolean isnewview = true;
4361 // Check to see if this alignment already has a view id == viewId
4362 jalview.gui.AlignmentPanel views[] = Desktop
4363 .getAlignmentPanels(uniqueSeqSetId);
4364 if (views != null && views.length > 0)
4366 for (int v = 0; v < views.length; v++)
4368 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4370 // recover the existing alignpanel, alignframe, viewport
4371 af = views[v].alignFrame;
4374 // TODO: could even skip resetting view settings if we don't want to
4375 // change the local settings from other jalview processes
4384 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4385 uniqueSeqSetId, viewId, autoAlan);
4386 av = af.getViewport();
4391 * Load any trees, PDB structures and viewers, Overview
4393 * Not done if flag is false (when this method is used for New View)
4395 if (loadTreesAndStructures)
4397 loadTrees(jalviewModel, view, af, av, ap);
4398 loadPCAViewers(jalviewModel, ap);
4399 loadPDBStructures(jprovider, jseqs, af, ap);
4400 loadRnaViewers(jprovider, jseqs, ap);
4401 loadOverview(view, jalviewModel.getVersion(), af);
4403 // and finally return.
4407 private void importMatrixData(List<MatrixType> xmlmatrices)
4409 for (MatrixType xmlmat : xmlmatrices)
4411 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4413 Console.error("Ignoring matrix '" + xmlmat.getId() + "' of type '"
4414 + xmlmat.getType());
4418 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4420 Console.error("Can't handle non square matrices");
4424 float[][] elements = ContactMatrix.fromFloatStringToContacts(
4425 xmlmat.getElements(), xmlmat.getCols().intValue(),
4426 xmlmat.getRows().intValue());
4428 List<BitSet> newgroups = new ArrayList<BitSet>();
4429 if (xmlmat.getGroups().size() > 0)
4431 for (String sgroup : xmlmat.getGroups())
4433 newgroups.add(deStringifyBitset(sgroup));
4436 String nwk = xmlmat.getNewick().size() > 0 ? xmlmat.getNewick().get(0)
4438 if (xmlmat.getNewick().size() > 1)
4441 .info("Ignoring additional clusterings for contact matrix");
4443 String treeMethod = xmlmat.getTreeMethod();
4444 double thresh = xmlmat.getCutHeight() != null ? xmlmat.getCutHeight()
4446 GroupSet grpset = new GroupSet();
4447 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4449 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4450 contactMatrixRefs.put(xmlmat.getId(), newcm);
4451 Console.trace("Restored base contact matrix " + xmlmat.getId());
4455 private void restoreMatrixFor(SequenceI sequenceRef,
4456 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4458 // restore mapping data to matrix data
4459 jalview.util.MapList mapping = null;
4460 if (xmlmatmapping.getMapping() != null)
4462 MapListType m = xmlmatmapping.getMapping();
4463 // Mapping m = dr.getMapping();
4464 int fr[] = new int[m.getMapListFrom().size() * 2];
4465 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4466 for (int _i = 0; from.hasNext(); _i += 2)
4468 MapListFrom mf = from.next();
4469 fr[_i] = mf.getStart();
4470 fr[_i + 1] = mf.getEnd();
4472 int fto[] = new int[m.getMapListTo().size() * 2];
4473 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4474 for (int _i = 0; to.hasNext(); _i += 2)
4476 MapListTo mf = to.next();
4477 fto[_i] = mf.getStart();
4478 fto[_i + 1] = mf.getEnd();
4481 mapping = new jalview.util.MapList(fr, fto,
4482 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4485 // locate matrix data in project XML and import
4486 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4490 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4494 // create the PAEMatrix now
4495 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4498 jaa.sequenceRef.addContactListFor(jaa, newpae);
4505 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4506 * and geometry as saved
4511 protected void loadOverview(Viewport view, String version, AlignFrame af)
4513 if (!isVersionStringLaterThan("2.11.3", version)
4514 && view.getOverview() == null)
4519 * first close any Overview that was opened automatically
4520 * (if so configured in Preferences) so that the view is
4521 * restored in the same state as saved
4523 af.alignPanel.closeOverviewPanel();
4525 Overview overview = view.getOverview();
4526 if (overview != null)
4528 OverviewPanel overviewPanel = af
4529 .openOverviewPanel(overview.isShowHidden());
4530 overviewPanel.setTitle(overview.getTitle());
4531 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4532 overview.getWidth(), overview.getHeight());
4533 Color gap = new Color(overview.getGapColour());
4534 Color residue = new Color(overview.getResidueColour());
4535 Color hidden = new Color(overview.getHiddenColour());
4536 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4541 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4542 * panel is restored from separate jar entries, two (gapped and trimmed) per
4543 * sequence and secondary structure.
4545 * Currently each viewer shows just one sequence and structure (gapped and
4546 * trimmed), however this method is designed to support multiple sequences or
4547 * structures in viewers if wanted in future.
4553 private void loadRnaViewers(jarInputStreamProvider jprovider,
4554 List<JSeq> jseqs, AlignmentPanel ap)
4557 * scan the sequences for references to viewers; create each one the first
4558 * time it is referenced, add Rna models to existing viewers
4560 for (JSeq jseq : jseqs)
4562 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4564 RnaViewer viewer = jseq.getRnaViewer().get(i);
4565 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4568 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4570 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4571 SequenceI seq = seqRefIds.get(jseq.getId());
4572 AlignmentAnnotation ann = this.annotationIds
4573 .get(ss.getAnnotationId());
4576 * add the structure to the Varna display (with session state copied
4577 * from the jar to a temporary file)
4579 boolean gapped = safeBoolean(ss.isGapped());
4580 String rnaTitle = ss.getTitle();
4581 String sessionState = ss.getViewerState();
4582 String tempStateFile = copyJarEntry(jprovider, sessionState,
4584 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4585 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4587 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4593 * Locate and return an already instantiated matching AppVarna, or create one
4597 * @param viewIdSuffix
4601 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4602 String viewIdSuffix, AlignmentPanel ap)
4605 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4606 * if load is repeated
4608 String postLoadId = viewer.getViewId() + viewIdSuffix;
4609 for (JInternalFrame frame : getAllFrames())
4611 if (frame instanceof AppVarna)
4613 AppVarna varna = (AppVarna) frame;
4614 if (postLoadId.equals(varna.getViewId()))
4616 // this viewer is already instantiated
4617 // could in future here add ap as another 'parent' of the
4618 // AppVarna window; currently just 1-to-many
4625 * viewer not found - make it
4627 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4628 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4629 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4630 safeInt(viewer.getDividerLocation()));
4631 AppVarna varna = new AppVarna(model, ap);
4637 * Load any saved trees
4645 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4646 AlignViewport av, AlignmentPanel ap)
4648 // TODO result of automated refactoring - are all these parameters needed?
4651 for (int t = 0; t < jm.getTree().size(); t++)
4654 Tree tree = jm.getTree().get(t);
4656 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4659 if (tree.isColumnWise())
4661 AlignmentAnnotation aa = annotationIds
4662 .get(tree.getColumnReference());
4666 "Null alignment annotation when restoring columnwise tree");
4668 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4669 tree.getTitle(), safeInt(tree.getWidth()),
4670 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4671 safeInt(tree.getYpos()));
4676 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4677 tree.getTitle(), safeInt(tree.getWidth()),
4678 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4679 safeInt(tree.getYpos()));
4681 if (tree.getId() != null)
4683 // perhaps bind the tree id to something ?
4688 // update local tree attributes ?
4689 // TODO: should check if tp has been manipulated by user - if so its
4690 // settings shouldn't be modified
4691 tp.setTitle(tree.getTitle());
4692 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4693 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4694 safeInt(tree.getHeight())));
4695 tp.setViewport(av); // af.viewport;
4696 // TODO: verify 'associate with all views' works still
4697 tp.getTreeCanvas().setViewport(av); // af.viewport;
4698 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4700 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4704 "There was a problem recovering stored Newick tree: \n"
4705 + tree.getNewick());
4709 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4710 tp.fitToWindow_actionPerformed(null);
4712 if (tree.getFontName() != null)
4715 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4716 safeInt(tree.getFontSize())));
4721 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4722 safeInt(view.getFontSize())));
4725 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4726 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4727 tp.showDistances(safeBoolean(tree.isShowDistances()));
4729 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4731 if (safeBoolean(tree.isCurrentTree()))
4733 af.getViewport().setCurrentTree(tp.getTree());
4737 } catch (Exception ex)
4739 ex.printStackTrace();
4744 * Load and link any saved structure viewers.
4751 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4752 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4755 * Run through all PDB ids on the alignment, and collect mappings between
4756 * distinct view ids and all sequences referring to that view.
4758 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4760 for (int i = 0; i < jseqs.size(); i++)
4762 JSeq jseq = jseqs.get(i);
4763 if (jseq.getPdbids().size() > 0)
4765 List<Pdbids> ids = jseq.getPdbids();
4766 for (int p = 0; p < ids.size(); p++)
4768 Pdbids pdbid = ids.get(p);
4769 final int structureStateCount = pdbid.getStructureState().size();
4770 for (int s = 0; s < structureStateCount; s++)
4772 // check to see if we haven't already created this structure view
4773 final StructureState structureState = pdbid.getStructureState()
4775 String sviewid = (structureState.getViewId() == null) ? null
4776 : structureState.getViewId() + uniqueSetSuffix;
4777 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4778 // Originally : pdbid.getFile()
4779 // : TODO: verify external PDB file recovery still works in normal
4780 // jalview project load
4782 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4783 jpdb.setId(pdbid.getId());
4785 int x = safeInt(structureState.getXpos());
4786 int y = safeInt(structureState.getYpos());
4787 int width = safeInt(structureState.getWidth());
4788 int height = safeInt(structureState.getHeight());
4790 // Probably don't need to do this anymore...
4791 // Desktop.desktop.getComponentAt(x, y);
4792 // TODO: NOW: check that this recovers the PDB file correctly.
4793 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4795 jalview.datamodel.SequenceI seq = seqRefIds
4796 .get(jseq.getId() + "");
4797 if (sviewid == null)
4799 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4802 if (!structureViewers.containsKey(sviewid))
4804 String viewerType = structureState.getType();
4805 if (viewerType == null) // pre Jalview 2.9
4807 viewerType = ViewerType.JMOL.toString();
4809 structureViewers.put(sviewid,
4810 new StructureViewerModel(x, y, width, height, false,
4811 false, true, structureState.getViewId(),
4813 // Legacy pre-2.7 conversion JAL-823 :
4814 // do not assume any view has to be linked for colour by
4818 // assemble String[] { pdb files }, String[] { id for each
4819 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4820 // seqs_file 2}, boolean[] {
4821 // linkAlignPanel,superposeWithAlignpanel}} from hash
4822 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4823 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4824 || structureState.isAlignwithAlignPanel());
4827 * Default colour by linked panel to false if not specified (e.g.
4828 * for pre-2.7 projects)
4830 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4831 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4832 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4835 * Default colour by viewer to true if not specified (e.g. for
4838 boolean colourByViewer = jmoldat.isColourByViewer();
4839 colourByViewer &= structureState.isColourByJmol();
4840 jmoldat.setColourByViewer(colourByViewer);
4842 if (jmoldat.getStateData().length() < structureState.getValue()
4843 /*Content()*/.length())
4845 jmoldat.setStateData(structureState.getValue());// Content());
4847 if (pdbid.getFile() != null)
4849 File mapkey = new File(pdbid.getFile());
4850 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4851 if (seqstrmaps == null)
4853 jmoldat.getFileData().put(mapkey,
4854 seqstrmaps = jmoldat.new StructureData(pdbFile,
4857 if (!seqstrmaps.getSeqList().contains(seq))
4859 seqstrmaps.getSeqList().add(seq);
4865 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");
4866 Console.warn(errorMessage);
4872 // Instantiate the associated structure views
4873 for (Entry<String, StructureViewerModel> entry : structureViewers
4878 createOrLinkStructureViewer(entry, af, ap, jprovider);
4879 } catch (Exception e)
4881 jalview.bin.Console.errPrintln(
4882 "Error loading structure viewer: " + e.getMessage());
4883 // failed - try the next one
4895 protected void createOrLinkStructureViewer(
4896 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4897 AlignmentPanel ap, jarInputStreamProvider jprovider)
4899 final StructureViewerModel stateData = viewerData.getValue();
4902 * Search for any viewer windows already open from other alignment views
4903 * that exactly match the stored structure state
4905 StructureViewerBase comp = findMatchingViewer(viewerData);
4909 linkStructureViewer(ap, comp, stateData);
4913 String type = stateData.getType();
4916 ViewerType viewerType = ViewerType.valueOf(type);
4917 createStructureViewer(viewerType, viewerData, af, jprovider);
4918 } catch (IllegalArgumentException | NullPointerException e)
4920 // TODO JAL-3619 show error dialog / offer an alternative viewer
4921 Console.error("Invalid structure viewer type: " + type);
4926 * Generates a name for the entry in the project jar file to hold state
4927 * information for a structure viewer
4932 protected String getViewerJarEntryName(String viewId)
4934 return VIEWER_PREFIX + viewId;
4938 * Returns any open frame that matches given structure viewer data. The match
4939 * is based on the unique viewId, or (for older project versions) the frame's
4945 protected StructureViewerBase findMatchingViewer(
4946 Entry<String, StructureViewerModel> viewerData)
4948 final String sviewid = viewerData.getKey();
4949 final StructureViewerModel svattrib = viewerData.getValue();
4950 StructureViewerBase comp = null;
4951 JInternalFrame[] frames = getAllFrames();
4952 for (JInternalFrame frame : frames)
4954 if (frame instanceof StructureViewerBase)
4957 * Post jalview 2.4 schema includes structure view id
4959 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4962 comp = (StructureViewerBase) frame;
4963 break; // break added in 2.9
4966 * Otherwise test for matching position and size of viewer frame
4968 else if (frame.getX() == svattrib.getX()
4969 && frame.getY() == svattrib.getY()
4970 && frame.getHeight() == svattrib.getHeight()
4971 && frame.getWidth() == svattrib.getWidth())
4973 comp = (StructureViewerBase) frame;
4974 // no break in faint hope of an exact match on viewId
4982 * Link an AlignmentPanel to an existing structure viewer.
4987 * @param useinViewerSuperpos
4988 * @param usetoColourbyseq
4989 * @param viewerColouring
4991 protected void linkStructureViewer(AlignmentPanel ap,
4992 StructureViewerBase viewer, StructureViewerModel stateData)
4994 // NOTE: if the jalview project is part of a shared session then
4995 // view synchronization should/could be done here.
4997 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4998 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4999 final boolean viewerColouring = stateData.isColourByViewer();
5000 Map<File, StructureData> oldFiles = stateData.getFileData();
5003 * Add mapping for sequences in this view to an already open viewer
5005 final AAStructureBindingModel binding = viewer.getBinding();
5006 for (File id : oldFiles.keySet())
5008 // add this and any other pdb files that should be present in the
5010 StructureData filedat = oldFiles.get(id);
5011 String pdbFile = filedat.getFilePath();
5012 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5013 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5015 binding.addSequenceForStructFile(pdbFile, seq);
5017 // and add the AlignmentPanel's reference to the view panel
5018 viewer.addAlignmentPanel(ap);
5019 if (useinViewerSuperpos)
5021 viewer.useAlignmentPanelForSuperposition(ap);
5025 viewer.excludeAlignmentPanelForSuperposition(ap);
5027 if (usetoColourbyseq)
5029 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5033 viewer.excludeAlignmentPanelForColourbyseq(ap);
5038 * Get all frames within the Desktop.
5042 protected JInternalFrame[] getAllFrames()
5044 JInternalFrame[] frames = null;
5045 // TODO is this necessary - is it safe - risk of hanging?
5050 frames = Desktop.desktop.getAllFrames();
5051 } catch (ArrayIndexOutOfBoundsException e)
5053 // occasional No such child exceptions are thrown here...
5057 } catch (InterruptedException f)
5061 } while (frames == null);
5066 * Answers true if 'version' is equal to or later than 'supported', where each
5067 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5068 * changes. Development and test values for 'version' are leniently treated
5072 * - minimum version we are comparing against
5074 * - version of data being processsed
5075 * @return true if version is equal to or later than supported
5077 public static boolean isVersionStringLaterThan(String supported,
5080 if (supported == null || version == null
5081 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5082 || version.equalsIgnoreCase("Test")
5083 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5085 jalview.bin.Console.errPrintln("Assuming project file with "
5086 + (version == null ? "null" : version)
5087 + " is compatible with Jalview version " + supported);
5092 return StringUtils.compareVersions(version, supported, "b") >= 0;
5096 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5098 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5100 if (newStructureViewers != null)
5102 sview.getBinding().setFinishedLoadingFromArchive(false);
5103 newStructureViewers.add(sview);
5107 protected void setLoadingFinishedForNewStructureViewers()
5109 if (newStructureViewers != null)
5111 for (JalviewStructureDisplayI sview : newStructureViewers)
5113 sview.getBinding().setFinishedLoadingFromArchive(true);
5115 newStructureViewers.clear();
5116 newStructureViewers = null;
5120 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5121 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5122 Viewport view, String uniqueSeqSetId, String viewId,
5123 List<JvAnnotRow> autoAlan)
5125 AlignFrame af = null;
5126 af = new AlignFrame(al, safeInt(view.getWidth()),
5127 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5131 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5132 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5133 // super.processKeyEvent(e);
5140 af.setFileName(file, FileFormat.Jalview);
5142 final AlignViewport viewport = af.getViewport();
5143 for (int i = 0; i < JSEQ.size(); i++)
5145 int colour = safeInt(JSEQ.get(i).getColour());
5146 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5152 viewport.setColourByReferenceSeq(true);
5153 viewport.setDisplayReferenceSeq(true);
5156 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5158 if (view.getSequenceSetId() != null)
5160 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5162 viewport.setSequenceSetId(uniqueSeqSetId);
5165 // propagate shared settings to this new view
5166 viewport.setHistoryList(av.getHistoryList());
5167 viewport.setRedoList(av.getRedoList());
5171 viewportsAdded.put(uniqueSeqSetId, viewport);
5173 // TODO: check if this method can be called repeatedly without
5174 // side-effects if alignpanel already registered.
5175 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5177 // apply Hidden regions to view.
5178 if (hiddenSeqs != null)
5180 for (int s = 0; s < JSEQ.size(); s++)
5182 SequenceGroup hidden = new SequenceGroup();
5183 boolean isRepresentative = false;
5184 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5186 isRepresentative = true;
5187 SequenceI sequenceToHide = al
5188 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5189 hidden.addSequence(sequenceToHide, false);
5190 // remove from hiddenSeqs list so we don't try to hide it twice
5191 hiddenSeqs.remove(sequenceToHide);
5193 if (isRepresentative)
5195 SequenceI representativeSequence = al.getSequenceAt(s);
5196 hidden.addSequence(representativeSequence, false);
5197 viewport.hideRepSequences(representativeSequence, hidden);
5201 SequenceI[] hseqs = hiddenSeqs
5202 .toArray(new SequenceI[hiddenSeqs.size()]);
5203 viewport.hideSequence(hseqs);
5206 // recover view properties and display parameters
5208 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5209 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5210 final int pidThreshold = safeInt(view.getPidThreshold());
5211 viewport.setThreshold(pidThreshold);
5213 viewport.setColourText(safeBoolean(view.isShowColourText()));
5215 viewport.setConservationSelected(
5216 safeBoolean(view.isConservationSelected()));
5217 viewport.setIncrement(safeInt(view.getConsThreshold()));
5218 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5219 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5221 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5222 safeInt(view.getFontSize())),
5223 (view.getCharWidth() != null) ? false : true);
5224 if (view.getCharWidth() != null)
5226 viewport.setCharWidth(view.getCharWidth());
5227 viewport.setCharHeight(view.getCharHeight());
5229 ViewStyleI vs = viewport.getViewStyle();
5230 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5231 viewport.setViewStyle(vs);
5232 // TODO: allow custom charWidth/Heights to be restored by updating them
5233 // after setting font - which means set above to false
5234 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5235 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5236 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5238 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5240 viewport.setShowText(safeBoolean(view.isShowText()));
5242 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5243 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5244 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5245 viewport.setShowUnconserved(view.isShowUnconserved());
5246 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5248 if (view.getViewName() != null)
5250 viewport.setViewName(view.getViewName());
5251 af.setInitialTabVisible();
5253 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5254 safeInt(view.getWidth()), safeInt(view.getHeight()));
5256 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID
5258 if (view.getIdWidth() == null)
5260 if (!isVersionStringLaterThan("2.11.3", jm.getVersion()))
5262 // Pre 2.11.3 jalview projects do not store the id width
5263 // idWidth was also calculated in a different way.
5264 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5265 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5270 viewport.setIdWidth(view.getIdWidth());
5271 af.alignPanel.getIdPanel().getIdCanvas()
5272 .setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5275 // startSeq set in af.alignPanel.updateLayout below
5276 af.alignPanel.updateLayout();
5277 ColourSchemeI cs = null;
5278 // apply colourschemes
5279 if (view.getBgColour() != null)
5281 if (view.getBgColour().startsWith("ucs"))
5283 cs = getUserColourScheme(jm, view.getBgColour());
5285 else if (view.getBgColour().startsWith("Annotation"))
5287 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5288 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5295 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5296 view.getBgColour());
5301 * turn off 'alignment colour applies to all groups'
5302 * while restoring global colour scheme
5304 viewport.setColourAppliesToAllGroups(false);
5305 viewport.setGlobalColourScheme(cs);
5306 viewport.getResidueShading().setThreshold(pidThreshold,
5307 view.isIgnoreGapsinConsensus());
5308 viewport.getResidueShading()
5309 .setConsensus(viewport.getSequenceConsensusHash());
5310 if (safeBoolean(view.isConservationSelected()) && cs != null)
5312 viewport.getResidueShading()
5313 .setConservationInc(safeInt(view.getConsThreshold()));
5315 af.changeColour(cs);
5316 viewport.setColourAppliesToAllGroups(true);
5318 viewport.setShowSequenceFeatures(
5319 safeBoolean(view.isShowSequenceFeatures()));
5321 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5322 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5323 viewport.setFollowHighlight(view.isFollowHighlight());
5324 viewport.followSelection = view.isFollowSelection();
5325 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5326 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5327 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5328 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5329 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5330 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5331 viewport.setShowGroupConservation(view.isShowGroupConservation());
5332 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5333 viewport.setShowComplementFeaturesOnTop(
5334 view.isShowComplementFeaturesOnTop());
5336 // recover feature settings
5337 if (jm.getFeatureSettings() != null)
5339 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5340 .getFeatureRenderer();
5341 FeaturesDisplayed fdi;
5342 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5343 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5345 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5346 Map<String, Float> featureOrder = new Hashtable<>();
5348 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5351 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5352 String featureType = setting.getType();
5355 * restore feature filters (if any)
5357 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5359 if (filters != null)
5361 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5363 if (!filter.isEmpty())
5365 fr.setFeatureFilter(featureType, filter);
5370 * restore feature colour scheme
5372 Color maxColour = new Color(setting.getColour());
5373 if (setting.getMincolour() != null)
5376 * minColour is always set unless a simple colour
5377 * (including for colour by label though it doesn't use it)
5379 Color minColour = new Color(setting.getMincolour().intValue());
5380 Color noValueColour = minColour;
5381 NoValueColour noColour = setting.getNoValueColour();
5382 if (noColour == NoValueColour.NONE)
5384 noValueColour = null;
5386 else if (noColour == NoValueColour.MAX)
5388 noValueColour = maxColour;
5390 float min = safeFloat(safeFloat(setting.getMin()));
5391 float max = setting.getMax() == null ? 1f
5392 : setting.getMax().floatValue();
5393 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5394 maxColour, noValueColour, min, max);
5395 if (setting.getAttributeName().size() > 0)
5397 gc.setAttributeName(setting.getAttributeName().toArray(
5398 new String[setting.getAttributeName().size()]));
5400 if (setting.getThreshold() != null)
5402 gc.setThreshold(setting.getThreshold().floatValue());
5403 int threshstate = safeInt(setting.getThreshstate());
5404 // -1 = None, 0 = Below, 1 = Above threshold
5405 if (threshstate == 0)
5407 gc.setBelowThreshold(true);
5409 else if (threshstate == 1)
5411 gc.setAboveThreshold(true);
5414 gc.setAutoScaled(true); // default
5415 if (setting.isAutoScale() != null)
5417 gc.setAutoScaled(setting.isAutoScale());
5419 if (setting.isColourByLabel() != null)
5421 gc.setColourByLabel(setting.isColourByLabel());
5423 // and put in the feature colour table.
5424 featureColours.put(featureType, gc);
5428 featureColours.put(featureType, new FeatureColour(maxColour));
5430 renderOrder[fs] = featureType;
5431 if (setting.getOrder() != null)
5433 featureOrder.put(featureType, setting.getOrder().floatValue());
5437 featureOrder.put(featureType, Float.valueOf(
5438 fs / jm.getFeatureSettings().getSetting().size()));
5440 if (safeBoolean(setting.isDisplay()))
5442 fdi.setVisible(featureType);
5445 Map<String, Boolean> fgtable = new Hashtable<>();
5446 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5448 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5449 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5451 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5452 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5453 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5454 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5455 fgtable, featureColours, 1.0f, featureOrder);
5456 fr.transferSettings(frs);
5459 if (view.getHiddenColumns().size() > 0)
5461 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5463 final HiddenColumns hc = view.getHiddenColumns().get(c);
5464 viewport.hideColumns(safeInt(hc.getStart()),
5465 safeInt(hc.getEnd()) /* +1 */);
5468 if (view.getCalcIdParam() != null)
5470 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5472 if (calcIdParam != null)
5474 if (recoverCalcIdParam(calcIdParam, viewport))
5479 Console.warn("Couldn't recover parameters for "
5480 + calcIdParam.getCalcId());
5485 af.setMenusFromViewport(viewport);
5486 af.setTitle(view.getTitle());
5487 // TODO: we don't need to do this if the viewport is aready visible.
5489 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5490 * has a 'cdna/protein complement' view, in which case save it in order to
5491 * populate a SplitFrame once all views have been read in.
5493 String complementaryViewId = view.getComplementId();
5494 if (complementaryViewId == null)
5496 Desktop.addInternalFrame(af, view.getTitle(),
5497 safeInt(view.getWidth()), safeInt(view.getHeight()));
5498 // recompute any autoannotation
5499 af.alignPanel.updateAnnotation(false, true);
5500 reorderAutoannotation(af, al, autoAlan);
5501 af.alignPanel.alignmentChanged();
5505 splitFrameCandidates.put(view, af);
5512 * Reads saved data to restore Colour by Annotation settings
5514 * @param viewAnnColour
5518 * @param checkGroupAnnColour
5521 private ColourSchemeI constructAnnotationColour(
5522 AnnotationColourScheme viewAnnColour, AlignFrame af,
5523 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5525 boolean propagateAnnColour = false;
5526 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5528 if (checkGroupAnnColour && al.getGroups() != null
5529 && al.getGroups().size() > 0)
5531 // pre 2.8.1 behaviour
5532 // check to see if we should transfer annotation colours
5533 propagateAnnColour = true;
5534 for (SequenceGroup sg : al.getGroups())
5536 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5538 propagateAnnColour = false;
5544 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5546 String annotationId = viewAnnColour.getAnnotation();
5547 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5550 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5552 if (matchedAnnotation == null
5553 && annAlignment.getAlignmentAnnotation() != null)
5555 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5558 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5560 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5565 if (matchedAnnotation == null)
5568 .errPrintln("Failed to match annotation colour scheme for "
5572 // belt-and-braces create a threshold line if the
5573 // colourscheme needs one but the matchedAnnotation doesn't have one
5574 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5575 && matchedAnnotation.getThreshold() == null)
5577 matchedAnnotation.setThreshold(
5578 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5579 "Threshold", Color.black));
5582 AnnotationColourGradient cs = null;
5583 if (viewAnnColour.getColourScheme().equals("None"))
5585 cs = new AnnotationColourGradient(matchedAnnotation,
5586 new Color(safeInt(viewAnnColour.getMinColour())),
5587 new Color(safeInt(viewAnnColour.getMaxColour())),
5588 safeInt(viewAnnColour.getAboveThreshold()));
5590 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5592 cs = new AnnotationColourGradient(matchedAnnotation,
5593 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5594 safeInt(viewAnnColour.getAboveThreshold()));
5598 cs = new AnnotationColourGradient(matchedAnnotation,
5599 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5600 viewAnnColour.getColourScheme()),
5601 safeInt(viewAnnColour.getAboveThreshold()));
5604 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5605 boolean useOriginalColours = safeBoolean(
5606 viewAnnColour.isPredefinedColours());
5607 cs.setSeqAssociated(perSequenceOnly);
5608 cs.setPredefinedColours(useOriginalColours);
5610 if (propagateAnnColour && al.getGroups() != null)
5612 // Also use these settings for all the groups
5613 for (int g = 0; g < al.getGroups().size(); g++)
5615 SequenceGroup sg = al.getGroups().get(g);
5616 if (sg.getGroupColourScheme() == null)
5621 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5622 matchedAnnotation, sg.getColourScheme(),
5623 safeInt(viewAnnColour.getAboveThreshold()));
5624 sg.setColourScheme(groupScheme);
5625 groupScheme.setSeqAssociated(perSequenceOnly);
5626 groupScheme.setPredefinedColours(useOriginalColours);
5632 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5633 List<JvAnnotRow> autoAlan)
5635 // copy over visualization settings for autocalculated annotation in the
5637 if (al.getAlignmentAnnotation() != null)
5640 * Kludge for magic autoannotation names (see JAL-811)
5642 String[] magicNames = new String[] { "Consensus", "Quality",
5644 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5645 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5646 for (String nm : magicNames)
5648 visan.put(nm, nullAnnot);
5650 for (JvAnnotRow auan : autoAlan)
5652 visan.put(auan.template.label
5653 + (auan.template.getCalcId() == null ? ""
5654 : "\t" + auan.template.getCalcId()),
5657 int hSize = al.getAlignmentAnnotation().length;
5658 List<JvAnnotRow> reorder = new ArrayList<>();
5659 // work through any autoCalculated annotation already on the view
5660 // removing it if it should be placed in a different location on the
5661 // annotation panel.
5662 List<String> remains = new ArrayList<>(visan.keySet());
5663 for (int h = 0; h < hSize; h++)
5665 jalview.datamodel.AlignmentAnnotation jalan = al
5666 .getAlignmentAnnotation()[h];
5667 if (jalan.autoCalculated)
5670 JvAnnotRow valan = visan.get(k = jalan.label);
5671 if (jalan.getCalcId() != null)
5673 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5678 // delete the auto calculated row from the alignment
5679 al.deleteAnnotation(jalan, false);
5683 if (valan != nullAnnot)
5685 if (jalan != valan.template)
5687 // newly created autoannotation row instance
5688 // so keep a reference to the visible annotation row
5689 // and copy over all relevant attributes
5690 if (valan.template.graphHeight >= 0)
5693 jalan.graphHeight = valan.template.graphHeight;
5695 jalan.visible = valan.template.visible;
5697 reorder.add(new JvAnnotRow(valan.order, jalan));
5702 // Add any (possibly stale) autocalculated rows that were not appended to
5703 // the view during construction
5704 for (String other : remains)
5706 JvAnnotRow othera = visan.get(other);
5707 if (othera != nullAnnot && othera.template.getCalcId() != null
5708 && othera.template.getCalcId().length() > 0)
5710 reorder.add(othera);
5713 // now put the automatic annotation in its correct place
5714 int s = 0, srt[] = new int[reorder.size()];
5715 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5716 for (JvAnnotRow jvar : reorder)
5719 srt[s++] = jvar.order;
5722 jalview.util.QuickSort.sort(srt, rws);
5723 // and re-insert the annotation at its correct position
5724 for (JvAnnotRow jvar : rws)
5726 al.addAnnotation(jvar.template, jvar.order);
5728 af.alignPanel.adjustAnnotationHeight();
5732 Hashtable skipList = null;
5735 * TODO remove this method
5738 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5739 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5740 * throw new Error("Implementation Error. No skipList defined for this
5741 * Jalview2XML instance."); } return (AlignFrame)
5742 * skipList.get(view.getSequenceSetId()); }
5746 * Check if the Jalview view contained in object should be skipped or not.
5749 * @return true if view's sequenceSetId is a key in skipList
5751 private boolean skipViewport(JalviewModel object)
5753 if (skipList == null)
5757 String id = object.getViewport().get(0).getSequenceSetId();
5758 if (skipList.containsKey(id))
5760 Console.debug("Skipping seuqence set id " + id);
5766 public void addToSkipList(AlignFrame af)
5768 if (skipList == null)
5770 skipList = new Hashtable();
5772 skipList.put(af.getViewport().getSequenceSetId(), af);
5775 public void clearSkipList()
5777 if (skipList != null)
5784 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5785 boolean ignoreUnrefed, String uniqueSeqSetId)
5787 jalview.datamodel.AlignmentI ds = getDatasetFor(
5788 vamsasSet.getDatasetId());
5789 AlignmentI xtant_ds = ds;
5790 if (xtant_ds == null)
5792 // good chance we are about to create a new dataset, but check if we've
5793 // seen some of the dataset sequence IDs before.
5794 // TODO: skip this check if we are working with project generated by
5795 // version 2.11 or later
5796 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5797 if (xtant_ds != null)
5800 addDatasetRef(vamsasSet.getDatasetId(), ds);
5803 Vector<SequenceI> dseqs = null;
5806 // recovering an alignment View
5807 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5808 if (seqSetDS != null)
5810 if (ds != null && ds != seqSetDS)
5813 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5814 + " - CDS/Protein crossreference data may be lost");
5815 if (xtant_ds != null)
5817 // This can only happen if the unique sequence set ID was bound to a
5818 // dataset that did not contain any of the sequences in the view
5819 // currently being restored.
5821 "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.");
5825 addDatasetRef(vamsasSet.getDatasetId(), ds);
5830 // try even harder to restore dataset
5831 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5832 // create a list of new dataset sequences
5833 dseqs = new Vector<>();
5835 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5837 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5838 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5840 // create a new dataset
5843 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5844 dseqs.copyInto(dsseqs);
5845 ds = new jalview.datamodel.Alignment(dsseqs);
5846 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5847 + " for alignment " + System.identityHashCode(al));
5848 addDatasetRef(vamsasSet.getDatasetId(), ds);
5850 // set the dataset for the newly imported alignment.
5851 if (al.getDataset() == null && !ignoreUnrefed)
5854 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5855 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5857 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5861 * XML dataset sequence ID to materialised dataset reference
5863 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5866 * @return the first materialised dataset reference containing a dataset
5867 * sequence referenced in the given view
5869 * - sequences from the view
5871 AlignmentI checkIfHasDataset(List<Sequence> list)
5873 for (Sequence restoredSeq : list)
5875 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5876 if (datasetFor != null)
5885 * Register ds as the containing dataset for the dataset sequences referenced
5886 * by sequences in list
5889 * - sequences in a view
5892 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5894 for (Sequence restoredSeq : list)
5896 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5897 if (prevDS != null && prevDS != ds)
5899 Console.warn("Dataset sequence appears in many datasets: "
5900 + restoredSeq.getDsseqid());
5901 // TODO: try to merge!
5909 * sequence definition to create/merge dataset sequence for
5913 * vector to add new dataset sequence to
5914 * @param ignoreUnrefed
5915 * - when true, don't create new sequences from vamsasSeq if it's id
5916 * doesn't already have an asssociated Jalview sequence.
5918 * - used to reorder the sequence in the alignment according to the
5919 * vamsasSeq array ordering, to preserve ordering of dataset
5921 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5922 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5925 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5927 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5928 boolean reorder = false;
5929 SequenceI dsq = null;
5930 if (sq != null && sq.getDatasetSequence() != null)
5932 dsq = sq.getDatasetSequence();
5938 if (sq == null && ignoreUnrefed)
5942 String sqid = vamsasSeq.getDsseqid();
5945 // need to create or add a new dataset sequence reference to this sequence
5948 dsq = seqRefIds.get(sqid);
5953 // make a new dataset sequence
5954 dsq = sq.createDatasetSequence();
5957 // make up a new dataset reference for this sequence
5958 sqid = seqHash(dsq);
5960 dsq.setVamsasId(uniqueSetSuffix + sqid);
5961 seqRefIds.put(sqid, dsq);
5966 dseqs.addElement(dsq);
5971 ds.addSequence(dsq);
5977 { // make this dataset sequence sq's dataset sequence
5978 sq.setDatasetSequence(dsq);
5979 // and update the current dataset alignment
5984 if (!dseqs.contains(dsq))
5991 if (ds.findIndex(dsq) < 0)
5993 ds.addSequence(dsq);
6000 // TODO: refactor this as a merge dataset sequence function
6001 // now check that sq (the dataset sequence) sequence really is the union of
6002 // all references to it
6003 // boolean pre = sq.getStart() < dsq.getStart();
6004 // boolean post = sq.getEnd() > dsq.getEnd();
6008 // StringBuffer sb = new StringBuffer();
6009 String newres = jalview.analysis.AlignSeq.extractGaps(
6010 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
6011 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
6012 && newres.length() > dsq.getLength())
6014 // Update with the longer sequence.
6018 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
6019 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
6020 * sb.append(newres.substring(newres.length() - sq.getEnd() -
6021 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
6023 dsq.setSequence(newres);
6025 // TODO: merges will never happen if we 'know' we have the real dataset
6026 // sequence - this should be detected when id==dssid
6027 jalview.bin.Console.errPrintln(
6028 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
6029 // + (pre ? "prepended" : "") + " "
6030 // + (post ? "appended" : ""));
6035 // sequence refs are identical. We may need to update the existing dataset
6036 // alignment with this one, though.
6037 if (ds != null && dseqs == null)
6039 int opos = ds.findIndex(dsq);
6040 SequenceI tseq = null;
6041 if (opos != -1 && vseqpos != opos)
6043 // remove from old position
6044 ds.deleteSequence(dsq);
6046 if (vseqpos < ds.getHeight())
6048 if (vseqpos != opos)
6050 // save sequence at destination position
6051 tseq = ds.getSequenceAt(vseqpos);
6052 ds.replaceSequenceAt(vseqpos, dsq);
6053 ds.addSequence(tseq);
6058 ds.addSequence(dsq);
6065 * TODO use AlignmentI here and in related methods - needs
6066 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6068 Hashtable<String, AlignmentI> datasetIds = null;
6070 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6072 private AlignmentI getDatasetFor(String datasetId)
6074 if (datasetIds == null)
6076 datasetIds = new Hashtable<>();
6079 if (datasetIds.containsKey(datasetId))
6081 return datasetIds.get(datasetId);
6086 private void addDatasetRef(String datasetId, AlignmentI dataset)
6088 if (datasetIds == null)
6090 datasetIds = new Hashtable<>();
6092 datasetIds.put(datasetId, dataset);
6096 * make a new dataset ID for this jalview dataset alignment
6101 private String getDatasetIdRef(AlignmentI dataset)
6103 if (dataset.getDataset() != null)
6106 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6108 String datasetId = makeHashCode(dataset, null);
6109 if (datasetId == null)
6111 // make a new datasetId and record it
6112 if (dataset2Ids == null)
6114 dataset2Ids = new IdentityHashMap<>();
6118 datasetId = dataset2Ids.get(dataset);
6120 if (datasetId == null)
6122 datasetId = "ds" + dataset2Ids.size() + 1;
6123 dataset2Ids.put(dataset, datasetId);
6130 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6131 * constructed as a special subclass GeneLocus.
6133 * @param datasetSequence
6136 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6138 for (int d = 0; d < sequence.getDBRef().size(); d++)
6140 DBRef dr = sequence.getDBRef().get(d);
6144 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6145 dr.getAccessionId());
6149 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6150 dr.getAccessionId());
6152 if (dr.getMapping() != null)
6154 entry.setMap(addMapping(dr.getMapping()));
6156 entry.setCanonical(dr.isCanonical());
6157 datasetSequence.addDBRef(entry);
6161 private jalview.datamodel.Mapping addMapping(Mapping m)
6163 SequenceI dsto = null;
6164 // Mapping m = dr.getMapping();
6165 int fr[] = new int[m.getMapListFrom().size() * 2];
6166 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6167 for (int _i = 0; from.hasNext(); _i += 2)
6169 MapListFrom mf = from.next();
6170 fr[_i] = mf.getStart();
6171 fr[_i + 1] = mf.getEnd();
6173 int fto[] = new int[m.getMapListTo().size() * 2];
6174 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6175 for (int _i = 0; to.hasNext(); _i += 2)
6177 MapListTo mf = to.next();
6178 fto[_i] = mf.getStart();
6179 fto[_i + 1] = mf.getEnd();
6181 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6182 fto, m.getMapFromUnit().intValue(),
6183 m.getMapToUnit().intValue());
6186 * (optional) choice of dseqFor or Sequence
6188 if (m.getDseqFor() != null)
6190 String dsfor = m.getDseqFor();
6191 if (seqRefIds.containsKey(dsfor))
6196 jmap.setTo(seqRefIds.get(dsfor));
6200 frefedSequence.add(newMappingRef(dsfor, jmap));
6203 else if (m.getSequence() != null)
6206 * local sequence definition
6208 Sequence ms = m.getSequence();
6209 SequenceI djs = null;
6210 String sqid = ms.getDsseqid();
6211 if (sqid != null && sqid.length() > 0)
6214 * recover dataset sequence
6216 djs = seqRefIds.get(sqid);
6220 jalview.bin.Console.errPrintln(
6221 "Warning - making up dataset sequence id for DbRef sequence map reference");
6222 sqid = ((Object) ms).toString(); // make up a new hascode for
6223 // undefined dataset sequence hash
6224 // (unlikely to happen)
6230 * make a new dataset sequence and add it to refIds hash
6232 djs = new jalview.datamodel.Sequence(ms.getName(),
6234 djs.setStart(jmap.getMap().getToLowest());
6235 djs.setEnd(jmap.getMap().getToHighest());
6236 djs.setVamsasId(uniqueSetSuffix + sqid);
6238 incompleteSeqs.put(sqid, djs);
6239 seqRefIds.put(sqid, djs);
6242 Console.debug("about to recurse on addDBRefs.");
6251 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6252 * view as XML (but not to file), and then reloading it
6257 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6260 JalviewModel jm = saveState(ap, null, null, null);
6263 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6264 ap.getAlignment().getDataset());
6266 uniqueSetSuffix = "";
6267 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6268 jm.getViewport().get(0).setId(null);
6269 // we don't overwrite the view we just copied
6271 if (this.frefedSequence == null)
6273 frefedSequence = new Vector<>();
6276 viewportsAdded.clear();
6278 AlignFrame af = loadFromObject(jm, null, false, null);
6279 af.getAlignPanels().clear();
6280 af.closeMenuItem_actionPerformed(true);
6283 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6284 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6285 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6286 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6287 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6290 return af.alignPanel;
6293 private Hashtable jvids2vobj;
6296 * set the object to ID mapping tables used to write/recover objects and XML
6297 * ID strings for the jalview project. If external tables are provided then
6298 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6299 * object goes out of scope. - also populates the datasetIds hashtable with
6300 * alignment objects containing dataset sequences
6303 * Map from ID strings to jalview datamodel
6305 * Map from jalview datamodel to ID strings
6309 public void setObjectMappingTables(Hashtable vobj2jv,
6310 IdentityHashMap jv2vobj)
6312 this.jv2vobj = jv2vobj;
6313 this.vobj2jv = vobj2jv;
6314 Iterator ds = jv2vobj.keySet().iterator();
6316 while (ds.hasNext())
6318 Object jvobj = ds.next();
6319 id = jv2vobj.get(jvobj).toString();
6320 if (jvobj instanceof jalview.datamodel.Alignment)
6322 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6324 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6327 else if (jvobj instanceof jalview.datamodel.Sequence)
6329 // register sequence object so the XML parser can recover it.
6330 if (seqRefIds == null)
6332 seqRefIds = new HashMap<>();
6334 if (seqsToIds == null)
6336 seqsToIds = new IdentityHashMap<>();
6338 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6339 seqsToIds.put((SequenceI) jvobj, id);
6341 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6344 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6345 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6346 if (jvann.annotationId == null)
6348 jvann.annotationId = anid;
6350 if (!jvann.annotationId.equals(anid))
6352 // TODO verify that this is the correct behaviour
6353 Console.warn("Overriding Annotation ID for " + anid
6354 + " from different id : " + jvann.annotationId);
6355 jvann.annotationId = anid;
6358 else if (jvobj instanceof String)
6360 if (jvids2vobj == null)
6362 jvids2vobj = new Hashtable();
6363 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6368 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6374 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6375 * objects created from the project archive. If string is null (default for
6376 * construction) then suffix will be set automatically.
6380 public void setUniqueSetSuffix(String string)
6382 uniqueSetSuffix = string;
6387 * uses skipList2 as the skipList for skipping views on sequence sets
6388 * associated with keys in the skipList
6392 public void setSkipList(Hashtable skipList2)
6394 skipList = skipList2;
6398 * Reads the jar entry of given name and returns its contents, or null if the
6399 * entry is not found.
6402 * @param jarEntryName
6405 protected String readJarEntry(jarInputStreamProvider jprovider,
6406 String jarEntryName)
6408 String result = null;
6409 BufferedReader in = null;
6414 * Reopen the jar input stream and traverse its entries to find a matching
6417 JarInputStream jin = jprovider.getJarInputStream();
6418 JarEntry entry = null;
6421 entry = jin.getNextJarEntry();
6422 } while (entry != null && !entry.getName().equals(jarEntryName));
6426 StringBuilder out = new StringBuilder(256);
6427 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6430 while ((data = in.readLine()) != null)
6434 result = out.toString();
6439 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6441 } catch (Exception ex)
6443 ex.printStackTrace();
6451 } catch (IOException e)
6462 * Returns an incrementing counter (0, 1, 2...)
6466 private synchronized int nextCounter()
6472 * Loads any saved PCA viewers
6477 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6481 List<PcaViewer> pcaviewers = model.getPcaViewer();
6482 for (PcaViewer viewer : pcaviewers)
6484 String modelName = viewer.getScoreModelName();
6485 SimilarityParamsI params = new SimilarityParams(
6486 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6487 viewer.isIncludeGaps(),
6488 viewer.isDenominateByShortestLength());
6491 * create the panel (without computing the PCA)
6493 PCAPanel panel = new PCAPanel(ap, modelName, params);
6495 panel.setTitle(viewer.getTitle());
6496 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6497 viewer.getWidth(), viewer.getHeight()));
6499 boolean showLabels = viewer.isShowLabels();
6500 panel.setShowLabels(showLabels);
6501 panel.getRotatableCanvas().setShowLabels(showLabels);
6502 panel.getRotatableCanvas()
6503 .setBgColour(new Color(viewer.getBgColour()));
6504 panel.getRotatableCanvas()
6505 .setApplyToAllViews(viewer.isLinkToAllViews());
6508 * load PCA output data
6510 ScoreModelI scoreModel = ScoreModels.getInstance()
6511 .getScoreModel(modelName, ap);
6512 PCA pca = new PCA(null, scoreModel, params);
6513 PcaDataType pcaData = viewer.getPcaData();
6515 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6516 pca.setPairwiseScores(pairwise);
6518 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6519 pca.setTridiagonal(triDiag);
6521 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6522 pca.setEigenmatrix(result);
6524 panel.getPcaModel().setPCA(pca);
6527 * we haven't saved the input data! (JAL-2647 to do)
6529 panel.setInputData(null);
6532 * add the sequence points for the PCA display
6534 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6535 for (SequencePoint sp : viewer.getSequencePoint())
6537 String seqId = sp.getSequenceRef();
6538 SequenceI seq = seqRefIds.get(seqId);
6541 throw new IllegalStateException(
6542 "Unmatched seqref for PCA: " + seqId);
6544 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6545 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6547 seqPoints.add(seqPoint);
6549 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6552 * set min-max ranges and scale after setPoints (which recomputes them)
6554 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6555 SeqPointMin spMin = viewer.getSeqPointMin();
6556 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6558 SeqPointMax spMax = viewer.getSeqPointMax();
6559 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6561 panel.getRotatableCanvas().setSeqMinMax(min, max);
6563 // todo: hold points list in PCAModel only
6564 panel.getPcaModel().setSequencePoints(seqPoints);
6566 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6567 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6568 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6570 // is this duplication needed?
6571 panel.setTop(seqPoints.size() - 1);
6572 panel.getPcaModel().setTop(seqPoints.size() - 1);
6575 * add the axes' end points for the display
6577 for (int i = 0; i < 3; i++)
6579 Axis axis = viewer.getAxis().get(i);
6580 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6581 axis.getXPos(), axis.getYPos(), axis.getZPos());
6584 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6585 "label.calc_title", "PCA", modelName), 475, 450);
6587 } catch (Exception ex)
6589 Console.error("Error loading PCA: " + ex.toString());
6594 * Creates a new structure viewer window
6601 protected void createStructureViewer(ViewerType viewerType,
6602 final Entry<String, StructureViewerModel> viewerData,
6603 AlignFrame af, jarInputStreamProvider jprovider)
6605 final StructureViewerModel viewerModel = viewerData.getValue();
6606 String sessionFilePath = null;
6608 if (viewerType == ViewerType.JMOL)
6610 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6614 String viewerJarEntryName = getViewerJarEntryName(
6615 viewerModel.getViewId());
6616 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6617 "viewerSession", ".tmp");
6619 final String sessionPath = sessionFilePath;
6620 final String sviewid = viewerData.getKey();
6623 SwingUtilities.invokeAndWait(new Runnable()
6628 JalviewStructureDisplayI sview = null;
6631 sview = StructureViewer.createView(viewerType, af.alignPanel,
6632 viewerModel, sessionPath, sviewid);
6633 addNewStructureViewer(sview);
6634 } catch (OutOfMemoryError ex)
6636 new OOMWarning("Restoring structure view for " + viewerType,
6637 (OutOfMemoryError) ex.getCause());
6638 if (sview != null && sview.isVisible())
6640 sview.closeViewer(false);
6641 sview.setVisible(false);
6647 } catch (InvocationTargetException | InterruptedException ex)
6649 Console.warn("Unexpected error when opening " + viewerType
6650 + " structure viewer", ex);
6655 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6656 * the path of the file. "load file" commands are rewritten to change the
6657 * original PDB file names to those created as the Jalview project is loaded.
6663 private String rewriteJmolSession(StructureViewerModel svattrib,
6664 jarInputStreamProvider jprovider)
6666 String state = svattrib.getStateData(); // Jalview < 2.9
6667 if (state == null || state.isEmpty()) // Jalview >= 2.9
6669 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6670 state = readJarEntry(jprovider, jarEntryName);
6672 // TODO or simpler? for each key in oldFiles,
6673 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6674 // (allowing for different path escapings)
6675 StringBuilder rewritten = new StringBuilder(state.length());
6676 int cp = 0, ncp, ecp;
6677 Map<File, StructureData> oldFiles = svattrib.getFileData();
6678 while ((ncp = state.indexOf("load ", cp)) > -1)
6682 // look for next filename in load statement
6683 rewritten.append(state.substring(cp,
6684 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6685 String oldfilenam = state.substring(ncp,
6686 ecp = state.indexOf("\"", ncp));
6687 // recover the new mapping data for this old filename
6688 // have to normalize filename - since Jmol and jalview do
6689 // filename translation differently.
6690 StructureData filedat = oldFiles.get(new File(oldfilenam));
6691 if (filedat == null)
6693 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6694 filedat = oldFiles.get(new File(reformatedOldFilename));
6696 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6697 rewritten.append("\"");
6698 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6699 // look for next file statement.
6700 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6704 // just append rest of state
6705 rewritten.append(state.substring(cp));
6709 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6710 rewritten = new StringBuilder(state);
6711 rewritten.append("; load append ");
6712 for (File id : oldFiles.keySet())
6714 // add pdb files that should be present in the viewer
6715 StructureData filedat = oldFiles.get(id);
6716 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6718 rewritten.append(";");
6721 if (rewritten.length() == 0)
6725 final String history = "history = ";
6726 int historyIndex = rewritten.indexOf(history);
6727 if (historyIndex > -1)
6730 * change "history = [true|false];" to "history = [1|0];"
6732 historyIndex += history.length();
6733 String val = rewritten.substring(historyIndex, historyIndex + 5);
6734 if (val.startsWith("true"))
6736 rewritten.replace(historyIndex, historyIndex + 4, "1");
6738 else if (val.startsWith("false"))
6740 rewritten.replace(historyIndex, historyIndex + 5, "0");
6746 File tmp = File.createTempFile("viewerSession", ".tmp");
6747 try (OutputStream os = new FileOutputStream(tmp))
6749 InputStream is = new ByteArrayInputStream(
6750 rewritten.toString().getBytes());
6752 return tmp.getAbsolutePath();
6754 } catch (IOException e)
6756 Console.error("Error restoring Jmol session: " + e.toString());
6762 * Populates an XML model of the feature colour scheme for one feature type
6764 * @param featureType
6768 public static Colour marshalColour(String featureType,
6769 FeatureColourI fcol)
6771 Colour col = new Colour();
6772 if (fcol.isSimpleColour())
6774 col.setRGB(Format.getHexString(fcol.getColour()));
6778 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6779 col.setMin(fcol.getMin());
6780 col.setMax(fcol.getMax());
6781 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6782 col.setAutoScale(fcol.isAutoScaled());
6783 col.setThreshold(fcol.getThreshold());
6784 col.setColourByLabel(fcol.isColourByLabel());
6785 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6786 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6787 : ThresholdType.NONE));
6788 if (fcol.isColourByAttribute())
6790 final String[] attName = fcol.getAttributeName();
6791 col.getAttributeName().add(attName[0]);
6792 if (attName.length > 1)
6794 col.getAttributeName().add(attName[1]);
6797 Color noColour = fcol.getNoColour();
6798 if (noColour == null)
6800 col.setNoValueColour(NoValueColour.NONE);
6802 else if (noColour == fcol.getMaxColour())
6804 col.setNoValueColour(NoValueColour.MAX);
6808 col.setNoValueColour(NoValueColour.MIN);
6811 col.setName(featureType);
6816 * Populates an XML model of the feature filter(s) for one feature type
6818 * @param firstMatcher
6819 * the first (or only) match condition)
6821 * remaining match conditions (if any)
6823 * if true, conditions are and-ed, else or-ed
6825 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6826 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6829 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6831 if (filters.hasNext())
6836 CompoundMatcher compound = new CompoundMatcher();
6837 compound.setAnd(and);
6838 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6839 firstMatcher, Collections.emptyIterator(), and);
6840 // compound.addMatcherSet(matcher1);
6841 compound.getMatcherSet().add(matcher1);
6842 FeatureMatcherI nextMatcher = filters.next();
6843 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6844 nextMatcher, filters, and);
6845 // compound.addMatcherSet(matcher2);
6846 compound.getMatcherSet().add(matcher2);
6847 result.setCompoundMatcher(compound);
6852 * single condition matcher
6854 // MatchCondition matcherModel = new MatchCondition();
6855 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6856 matcherModel.setCondition(
6857 firstMatcher.getMatcher().getCondition().getStableName());
6858 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6859 if (firstMatcher.isByAttribute())
6861 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6862 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6863 String[] attName = firstMatcher.getAttribute();
6864 matcherModel.getAttributeName().add(attName[0]); // attribute
6865 if (attName.length > 1)
6867 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6870 else if (firstMatcher.isByLabel())
6872 matcherModel.setBy(FilterBy.BY_LABEL);
6874 else if (firstMatcher.isByScore())
6876 matcherModel.setBy(FilterBy.BY_SCORE);
6878 result.setMatchCondition(matcherModel);
6885 * Loads one XML model of a feature filter to a Jalview object
6887 * @param featureType
6888 * @param matcherSetModel
6891 public static FeatureMatcherSetI parseFilter(String featureType,
6892 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6894 FeatureMatcherSetI result = new FeatureMatcherSet();
6897 parseFilterConditions(result, matcherSetModel, true);
6898 } catch (IllegalStateException e)
6900 // mixing AND and OR conditions perhaps
6901 jalview.bin.Console.errPrintln(
6902 String.format("Error reading filter conditions for '%s': %s",
6903 featureType, e.getMessage()));
6904 // return as much as was parsed up to the error
6911 * Adds feature match conditions to matcherSet as unmarshalled from XML
6912 * (possibly recursively for compound conditions)
6915 * @param matcherSetModel
6917 * if true, multiple conditions are AND-ed, else they are OR-ed
6918 * @throws IllegalStateException
6919 * if AND and OR conditions are mixed
6921 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6922 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6925 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6926 .getMatchCondition();
6932 FilterBy filterBy = mc.getBy();
6933 Condition cond = Condition.fromString(mc.getCondition());
6934 String pattern = mc.getValue();
6935 FeatureMatcherI matchCondition = null;
6936 if (filterBy == FilterBy.BY_LABEL)
6938 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6940 else if (filterBy == FilterBy.BY_SCORE)
6942 matchCondition = FeatureMatcher.byScore(cond, pattern);
6945 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6947 final List<String> attributeName = mc.getAttributeName();
6948 String[] attNames = attributeName
6949 .toArray(new String[attributeName.size()]);
6950 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6955 * note this throws IllegalStateException if AND-ing to a
6956 * previously OR-ed compound condition, or vice versa
6960 matcherSet.and(matchCondition);
6964 matcherSet.or(matchCondition);
6970 * compound condition
6972 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6973 .getCompoundMatcher().getMatcherSet();
6974 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6975 if (matchers.size() == 2)
6977 parseFilterConditions(matcherSet, matchers.get(0), anded);
6978 parseFilterConditions(matcherSet, matchers.get(1), anded);
6983 .errPrintln("Malformed compound filter condition");
6989 * Loads one XML model of a feature colour to a Jalview object
6991 * @param colourModel
6994 public static FeatureColourI parseColour(Colour colourModel)
6996 FeatureColourI colour = null;
6998 if (colourModel.getMax() != null)
7000 Color mincol = null;
7001 Color maxcol = null;
7002 Color noValueColour = null;
7006 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
7007 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7008 } catch (Exception e)
7010 Console.warn("Couldn't parse out graduated feature color.", e);
7013 NoValueColour noCol = colourModel.getNoValueColour();
7014 if (noCol == NoValueColour.MIN)
7016 noValueColour = mincol;
7018 else if (noCol == NoValueColour.MAX)
7020 noValueColour = maxcol;
7023 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
7024 safeFloat(colourModel.getMin()),
7025 safeFloat(colourModel.getMax()));
7026 final List<String> attributeName = colourModel.getAttributeName();
7027 String[] attributes = attributeName
7028 .toArray(new String[attributeName.size()]);
7029 if (attributes != null && attributes.length > 0)
7031 colour.setAttributeName(attributes);
7033 if (colourModel.isAutoScale() != null)
7035 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7037 if (colourModel.isColourByLabel() != null)
7039 colour.setColourByLabel(
7040 colourModel.isColourByLabel().booleanValue());
7042 if (colourModel.getThreshold() != null)
7044 colour.setThreshold(colourModel.getThreshold().floatValue());
7046 ThresholdType ttyp = colourModel.getThreshType();
7047 if (ttyp == ThresholdType.ABOVE)
7049 colour.setAboveThreshold(true);
7051 else if (ttyp == ThresholdType.BELOW)
7053 colour.setBelowThreshold(true);
7058 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7059 colour = new FeatureColour(color);
7065 public static void setStateSavedUpToDate(boolean s)
7067 Console.debug("Setting overall stateSavedUpToDate to " + s);
7068 stateSavedUpToDate = s;
7071 public static boolean stateSavedUpToDate()
7073 Console.debug("Returning overall stateSavedUpToDate value: "
7074 + stateSavedUpToDate);
7075 return stateSavedUpToDate;
7078 public static boolean allSavedUpToDate()
7080 if (stateSavedUpToDate()) // nothing happened since last project save
7083 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7086 for (int i = 0; i < frames.length; i++)
7088 if (frames[i] == null)
7090 if (!frames[i].getViewport().savedUpToDate())
7091 return false; // at least one alignment is not individually saved
7097 // used for debugging and tests
7098 private static int debugDelaySave = 20;
7100 public static void setDebugDelaySave(int n)