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;
24 import static jalview.math.RotatableMatrix.Axis.X;
25 import static jalview.math.RotatableMatrix.Axis.Y;
26 import static jalview.math.RotatableMatrix.Axis.Z;
29 import jalview.analysis.Conservation;
30 import jalview.analysis.PCA;
31 import jalview.analysis.scoremodels.ScoreModels;
32 import jalview.analysis.scoremodels.SimilarityParams;
33 import jalview.api.AlignmentViewPanel;
34 import jalview.api.FeatureColourI;
35 import jalview.api.ViewStyleI;
36 import jalview.api.analysis.ScoreModelI;
37 import jalview.api.analysis.SimilarityParamsI;
38 import jalview.api.structures.JalviewStructureDisplayI;
39 import jalview.bin.Cache;
40 import jalview.bin.Console;
41 import jalview.datamodel.AlignedCodonFrame;
42 import jalview.datamodel.Alignment;
43 import jalview.datamodel.AlignmentAnnotation;
44 import jalview.datamodel.AlignmentI;
45 import jalview.datamodel.DBRefEntry;
46 import jalview.datamodel.GeneLocus;
47 import jalview.datamodel.GraphLine;
48 import jalview.datamodel.HiddenMarkovModel;
49 import jalview.datamodel.PDBEntry;
50 import jalview.datamodel.Point;
51 import jalview.datamodel.RnaViewerModel;
52 import jalview.datamodel.SequenceFeature;
53 import jalview.datamodel.SequenceGroup;
54 import jalview.datamodel.SequenceI;
55 import jalview.datamodel.StructureViewerModel;
56 import jalview.datamodel.StructureViewerModel.StructureData;
57 import jalview.datamodel.features.FeatureMatcher;
58 import jalview.datamodel.features.FeatureMatcherI;
59 import jalview.datamodel.features.FeatureMatcherSet;
60 import jalview.datamodel.features.FeatureMatcherSetI;
61 import jalview.ext.varna.RnaModel;
62 import jalview.gui.AlignFrame;
63 import jalview.gui.AlignViewport;
64 import jalview.gui.AlignmentPanel;
65 import jalview.gui.AppVarna;
66 import jalview.gui.ChimeraViewFrame;
67 import jalview.gui.Desktop;
68 import jalview.gui.FeatureRenderer;
69 import jalview.gui.JvOptionPane;
70 import jalview.gui.OOMWarning;
71 import jalview.gui.PCAPanel;
72 import jalview.gui.PaintRefresher;
73 import jalview.gui.SplitFrame;
74 import jalview.gui.StructureViewer;
75 import jalview.gui.StructureViewer.ViewerType;
76 import jalview.gui.StructureViewerBase;
77 import jalview.gui.TreePanel;
78 import jalview.io.BackupFiles;
79 import jalview.io.DataSourceType;
80 import jalview.io.FileFormat;
81 import jalview.io.HMMFile;
82 import jalview.io.NewickFile;
83 import jalview.math.Matrix;
84 import jalview.math.MatrixI;
85 import jalview.renderer.ResidueShaderI;
86 import jalview.schemes.AnnotationColourGradient;
87 import jalview.schemes.ColourSchemeI;
88 import jalview.schemes.ColourSchemeProperty;
89 import jalview.schemes.FeatureColour;
90 import jalview.schemes.ResidueProperties;
91 import jalview.schemes.UserColourScheme;
92 import jalview.structure.StructureSelectionManager;
93 import jalview.structures.models.AAStructureBindingModel;
94 import jalview.util.Format;
95 import jalview.util.HttpUtils;
96 import jalview.util.MessageManager;
97 import jalview.util.Platform;
98 import jalview.util.StringUtils;
99 import jalview.util.jarInputStreamProvider;
100 import jalview.util.matcher.Condition;
101 import jalview.viewmodel.AlignmentViewport;
102 import jalview.viewmodel.PCAModel;
103 import jalview.viewmodel.ViewportRanges;
104 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
105 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
106 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
107 import jalview.ws.api.ServiceWithParameters;
108 import jalview.ws.jws2.PreferredServiceRegistry;
109 import jalview.ws.jws2.dm.AAConSettings;
110 import jalview.ws.params.ArgumentI;
111 import jalview.ws.params.AutoCalcSetting;
112 import jalview.ws.params.WsParamSetI;
113 import jalview.xml.binding.jalview.AlcodonFrame;
114 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
115 import jalview.xml.binding.jalview.Annotation;
116 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
117 import jalview.xml.binding.jalview.AnnotationColourScheme;
118 import jalview.xml.binding.jalview.AnnotationElement;
119 import jalview.xml.binding.jalview.DoubleMatrix;
120 import jalview.xml.binding.jalview.DoubleVector;
121 import jalview.xml.binding.jalview.Feature;
122 import jalview.xml.binding.jalview.Feature.OtherData;
123 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
124 import jalview.xml.binding.jalview.FilterBy;
125 import jalview.xml.binding.jalview.JalviewModel;
126 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
127 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
128 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
129 import jalview.xml.binding.jalview.JalviewModel.JGroup;
130 import jalview.xml.binding.jalview.JalviewModel.JSeq;
131 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
132 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
133 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
134 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
135 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
136 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
137 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
138 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
139 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
140 import jalview.xml.binding.jalview.JalviewModel.Tree;
141 import jalview.xml.binding.jalview.JalviewModel.UserColours;
142 import jalview.xml.binding.jalview.JalviewModel.Viewport;
143 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
144 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
145 import jalview.xml.binding.jalview.JalviewUserColours;
146 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
147 import jalview.xml.binding.jalview.MapListType.MapListFrom;
148 import jalview.xml.binding.jalview.MapListType.MapListTo;
149 import jalview.xml.binding.jalview.Mapping;
150 import jalview.xml.binding.jalview.NoValueColour;
151 import jalview.xml.binding.jalview.ObjectFactory;
152 import jalview.xml.binding.jalview.PcaDataType;
153 import jalview.xml.binding.jalview.Pdbentry.Property;
154 import jalview.xml.binding.jalview.Sequence;
155 import jalview.xml.binding.jalview.Sequence.DBRef;
156 import jalview.xml.binding.jalview.SequenceSet;
157 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
158 import jalview.xml.binding.jalview.ThresholdType;
159 import jalview.xml.binding.jalview.VAMSAS;
161 import java.awt.Color;
162 import java.awt.Dimension;
163 import java.awt.Font;
164 import java.awt.Rectangle;
165 import java.io.BufferedReader;
166 import java.io.ByteArrayInputStream;
167 import java.io.DataInputStream;
168 import java.io.DataOutputStream;
170 import java.io.FileInputStream;
171 import java.io.FileOutputStream;
172 import java.io.IOException;
173 import java.io.InputStream;
174 import java.io.InputStreamReader;
175 import java.io.OutputStream;
176 import java.io.OutputStreamWriter;
177 import java.io.PrintWriter;
178 import java.math.BigInteger;
179 import java.net.MalformedURLException;
181 import java.util.ArrayList;
182 import java.util.Arrays;
183 import java.util.Collections;
184 import java.util.Enumeration;
185 import java.util.GregorianCalendar;
186 import java.util.HashMap;
187 import java.util.HashSet;
188 import java.util.Hashtable;
189 import java.util.IdentityHashMap;
190 import java.util.Iterator;
191 import java.util.LinkedHashMap;
192 import java.util.List;
193 import java.util.Locale;
194 import java.util.Map;
195 import java.util.Map.Entry;
196 import java.util.Set;
197 import java.util.Vector;
198 import java.util.jar.JarEntry;
199 import java.util.jar.JarInputStream;
200 import java.util.jar.JarOutputStream;
202 import javax.swing.JInternalFrame;
203 import javax.swing.SwingUtilities;
204 import javax.xml.bind.JAXBContext;
205 import javax.xml.bind.JAXBElement;
206 import javax.xml.bind.Marshaller;
207 import javax.xml.datatype.DatatypeConfigurationException;
208 import javax.xml.datatype.DatatypeFactory;
209 import javax.xml.datatype.XMLGregorianCalendar;
210 import javax.xml.stream.XMLInputFactory;
211 import javax.xml.stream.XMLStreamReader;
213 * Write out the current jalview desktop state as a Jalview XML stream.
215 * Note: the vamsas objects referred to here are primitive versions of the
216 * VAMSAS project schema elements - they are not the same and most likely never
220 * @version $Revision: 1.134 $
222 public class Jalview2XML
225 // BH 2018 we add the .jvp binary extension to J2S so that
226 // it will declare that binary when we do the file save from the browser
230 Platform.addJ2SBinaryType(".jvp?");
233 private static final String VIEWER_PREFIX = "viewer_";
235 private static final String RNA_PREFIX = "rna_";
237 private static final String HMMER_PREFIX = "hmmer_";
238 private static final String UTF_8 = "UTF-8";
241 * prefix for recovering datasets for alignments with multiple views where
242 * non-existent dataset IDs were written for some views
244 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
246 // use this with nextCounter() to make unique names for entities
247 private int counter = 0;
250 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
251 * of sequence objects are created.
253 IdentityHashMap<SequenceI, String> seqsToIds = null;
256 * jalview XML Sequence ID to jalview sequence object reference (both dataset
257 * and alignment sequences. Populated as XML reps of sequence objects are
260 Map<String, SequenceI> seqRefIds = null;
262 Map<String, SequenceI> incompleteSeqs = null;
264 List<SeqFref> frefedSequence = null;
266 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
269 * Map of reconstructed AlignFrame objects that appear to have come from
270 * SplitFrame objects (have a dna/protein complement view).
272 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
275 * Map from displayed rna structure models to their saved session state jar
278 private Map<RnaModel, String> rnaSessions = new HashMap<>();
281 * contains last error message (if any) encountered by XML loader.
283 String errorMessage = null;
286 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
287 * exceptions are raised during project XML parsing
289 public boolean attemptversion1parse = false;
292 * JalviewJS only -- to allow read file bytes to be saved in the
293 * created AlignFrame, allowing File | Reload of a project file to work
297 private File jarFile;
300 * A helper method for safely using the value of an optional attribute that
301 * may be null if not present in the XML. Answers the boolean value, or false
307 public static boolean safeBoolean(Boolean b)
309 return b == null ? false : b.booleanValue();
313 * A helper method for safely using the value of an optional attribute that
314 * may be null if not present in the XML. Answers the integer value, or zero
320 public static int safeInt(Integer i)
322 return i == null ? 0 : i.intValue();
326 * A helper method for safely using the value of an optional attribute that
327 * may be null if not present in the XML. Answers the float value, or zero if
333 public static float safeFloat(Float f)
335 return f == null ? 0f : f.floatValue();
339 * create/return unique hash string for sq
342 * @return new or existing unique string for sq
344 String seqHash(SequenceI sq)
346 if (seqsToIds == null)
350 if (seqsToIds.containsKey(sq))
352 return seqsToIds.get(sq);
356 // create sequential key
357 String key = "sq" + (seqsToIds.size() + 1);
358 key = makeHashCode(sq, key); // check we don't have an external reference
360 seqsToIds.put(sq, key);
367 if (seqsToIds == null)
369 seqsToIds = new IdentityHashMap<>();
371 if (seqRefIds == null)
373 seqRefIds = new HashMap<>();
375 if (incompleteSeqs == null)
377 incompleteSeqs = new HashMap<>();
379 if (frefedSequence == null)
381 frefedSequence = new ArrayList<>();
389 public Jalview2XML(boolean raiseGUI)
391 this.raiseGUI = raiseGUI;
395 * base class for resolving forward references to sequences by their ID
400 abstract class SeqFref
406 public SeqFref(String _sref, String type)
412 public String getSref()
417 public SequenceI getSrefSeq()
419 return seqRefIds.get(sref);
422 public boolean isResolvable()
424 return seqRefIds.get(sref) != null;
427 public SequenceI getSrefDatasetSeq()
429 SequenceI sq = seqRefIds.get(sref);
432 while (sq.getDatasetSequence() != null)
434 sq = sq.getDatasetSequence();
441 * @return true if the forward reference was fully resolved
443 abstract boolean resolve();
446 public String toString()
448 return type + " reference to " + sref;
453 * create forward reference for a mapping
459 protected SeqFref newMappingRef(final String sref,
460 final jalview.datamodel.Mapping _jmap)
462 SeqFref fref = new SeqFref(sref, "Mapping")
464 public jalview.datamodel.Mapping jmap = _jmap;
469 SequenceI seq = getSrefDatasetSeq();
481 protected SeqFref newAlcodMapRef(final String sref,
482 final AlignedCodonFrame _cf,
483 final jalview.datamodel.Mapping _jmap)
486 SeqFref fref = new SeqFref(sref, "Codon Frame")
488 AlignedCodonFrame cf = _cf;
490 public jalview.datamodel.Mapping mp = _jmap;
493 public boolean isResolvable()
495 return super.isResolvable() && mp.getTo() != null;
501 SequenceI seq = getSrefDatasetSeq();
506 cf.addMap(seq, mp.getTo(), mp.getMap());
513 protected void resolveFrefedSequences()
515 Iterator<SeqFref> nextFref = frefedSequence.iterator();
516 int toresolve = frefedSequence.size();
517 int unresolved = 0, failedtoresolve = 0;
518 while (nextFref.hasNext())
520 SeqFref ref = nextFref.next();
521 if (ref.isResolvable())
533 } catch (Exception x)
536 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
549 System.err.println("Jalview Project Import: There were " + unresolved
550 + " forward references left unresolved on the stack.");
552 if (failedtoresolve > 0)
554 System.err.println("SERIOUS! " + failedtoresolve
555 + " resolvable forward references failed to resolve.");
557 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
560 "Jalview Project Import: There are " + incompleteSeqs.size()
561 + " sequences which may have incomplete metadata.");
562 if (incompleteSeqs.size() < 10)
564 for (SequenceI s : incompleteSeqs.values())
566 System.err.println(s.toString());
572 "Too many to report. Skipping output of incomplete sequences.");
578 * This maintains a map of viewports, the key being the seqSetId. Important to
579 * set historyItem and redoList for multiple views
581 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
583 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
585 String uniqueSetSuffix = "";
588 * List of pdbfiles added to Jar
590 List<String> pdbfiles = null;
592 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
593 public void saveState(File statefile)
595 FileOutputStream fos = null;
600 fos = new FileOutputStream(statefile);
602 JarOutputStream jout = new JarOutputStream(fos);
606 } catch (Exception e)
608 Console.error("Couln't write Jalview state to " + statefile, e);
609 // TODO: inform user of the problem - they need to know if their data was
611 if (errorMessage == null)
613 errorMessage = "Did't write Jalview Archive to output file '"
614 + statefile + "' - See console error log for details";
618 errorMessage += "(Didn't write Jalview Archive to output file '"
629 } catch (IOException e)
639 * Writes a jalview project archive to the given Jar output stream.
643 public void saveState(JarOutputStream jout)
645 AlignFrame[] frames = Desktop.getAlignFrames();
651 saveAllFrames(Arrays.asList(frames), jout);
655 * core method for storing state for a set of AlignFrames.
658 * - frames involving all data to be exported (including those
659 * contained in splitframes, though not the split frames themselves)
661 * - project output stream
663 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
665 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
668 * ensure cached data is clear before starting
670 // todo tidy up seqRefIds, seqsToIds initialisation / reset
672 splitFrameCandidates.clear();
677 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
678 // //////////////////////////////////////////////////
680 List<String> shortNames = new ArrayList<>();
681 List<String> viewIds = new ArrayList<>();
684 for (int i = frames.size() - 1; i > -1; i--)
686 AlignFrame af = frames.get(i);
687 AlignViewport vp = af.getViewport();
689 if (skipList != null && skipList
690 .containsKey(vp.getSequenceSetId()))
695 String shortName = makeFilename(af, shortNames);
697 AlignmentI alignment = vp.getAlignment();
698 List<? extends AlignmentViewPanel> panels = af.getAlignPanels();
699 int apSize = panels.size();
701 for (int ap = 0; ap < apSize; ap++)
703 AlignmentPanel apanel = (AlignmentPanel) panels.get(ap);
704 String fileName = apSize == 1 ? shortName : ap + shortName;
705 if (!fileName.endsWith(".xml"))
707 fileName = fileName + ".xml";
710 saveState(apanel, fileName, jout, viewIds);
715 // BH moved next bit out of inner loop, not that it really matters.
716 // so we are testing to make sure we actually have an alignment,
718 String dssid = getDatasetIdRef(alignment.getDataset());
719 if (!dsses.containsKey(dssid))
721 // We have not already covered this data by reference from another
723 dsses.put(dssid, af);
728 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
734 } catch (Exception foo)
738 } catch (Exception ex)
740 // TODO: inform user of the problem - they need to know if their data was
742 if (errorMessage == null)
744 errorMessage = "Couldn't write Jalview Archive - see error output for details";
746 ex.printStackTrace();
751 * Generates a distinct file name, based on the title of the AlignFrame, by
752 * appending _n for increasing n until an unused name is generated. The new
753 * name (without its extension) is added to the list.
757 * @return the generated name, with .xml extension
759 protected String makeFilename(AlignFrame af, List<String> namesUsed)
761 String shortName = af.getTitle();
763 if (shortName.indexOf(File.separatorChar) > -1)
765 shortName = shortName
766 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
771 while (namesUsed.contains(shortName))
773 if (shortName.endsWith("_" + (count - 1)))
775 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
778 shortName = shortName.concat("_" + count);
782 namesUsed.add(shortName);
784 if (!shortName.endsWith(".xml"))
786 shortName = shortName + ".xml";
791 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
792 public boolean saveAlignment(AlignFrame af, String jarFile,
797 // create backupfiles object and get new temp filename destination
798 boolean doBackup = BackupFiles.getEnabled();
799 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
800 FileOutputStream fos = new FileOutputStream(doBackup ?
801 backupfiles.getTempFilePath() : jarFile);
803 JarOutputStream jout = new JarOutputStream(fos);
804 List<AlignFrame> frames = new ArrayList<>();
806 // resolve splitframes
807 if (af.getViewport().getCodingComplement() != null)
809 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
815 saveAllFrames(frames, jout);
819 } catch (Exception foo)
823 boolean success = true;
827 backupfiles.setWriteSuccess(success);
828 success = backupfiles.rollBackupsAndRenameTempFile();
832 } catch (Exception ex)
834 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
835 ex.printStackTrace();
841 * Each AlignFrame has a single data set associated with it. Note that none of
842 * these frames are split frames, because Desktop.getAlignFrames() collects
843 * top and bottom separately here.
849 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
850 String fileName, JarOutputStream jout)
853 // Note that in saveAllFrames we have associated each specific dataset to
854 // ONE of its associated frames.
855 for (String dssids : dsses.keySet())
857 AlignFrame _af = dsses.get(dssids);
858 String jfileName = fileName + " Dataset for " + _af.getTitle();
859 if (!jfileName.endsWith(".xml"))
861 jfileName = jfileName + ".xml";
863 saveState(_af.alignPanel, jfileName, true, jout, null);
868 * create a JalviewModel from an alignment view and marshall it to a
872 * panel to create jalview model for
874 * name of alignment panel written to output stream
881 protected JalviewModel saveState(AlignmentPanel ap, String fileName,
882 JarOutputStream jout, List<String> viewIds)
884 return saveState(ap, fileName, false, jout, viewIds);
888 * create a JalviewModel from an alignment view and marshall it to a
892 * panel to create jalview model for
894 * name of alignment panel written to output stream
896 * when true, only write the dataset for the alignment, not the data
897 * associated with the view.
903 protected JalviewModel saveState(AlignmentPanel ap, String fileName,
904 boolean storeDS, JarOutputStream jout, List<String> viewIds)
908 viewIds = new ArrayList<>();
913 List<UserColourScheme> userColours = new ArrayList<>();
915 AlignViewport av = ap.av;
916 ViewportRanges vpRanges = av.getRanges();
918 final ObjectFactory objectFactory = new ObjectFactory();
919 JalviewModel object = objectFactory.createJalviewModel();
920 object.setVamsasModel(new VAMSAS());
922 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
925 GregorianCalendar c = new GregorianCalendar();
926 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
927 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
928 object.setCreationDate(now);
929 } catch (DatatypeConfigurationException e)
931 System.err.println("error writing date: " + e.toString());
933 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
936 * rjal is full height alignment, jal is actual alignment with full metadata
937 * but excludes hidden sequences.
939 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
941 if (av.hasHiddenRows())
943 rjal = jal.getHiddenSequences().getFullAlignment();
946 SequenceSet vamsasSet = new SequenceSet();
948 // JalviewModelSequence jms = new JalviewModelSequence();
950 vamsasSet.setGapChar(jal.getGapCharacter() + "");
952 if (jal.getDataset() != null)
954 // dataset id is the dataset's hashcode
955 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
958 // switch jal and the dataset
959 jal = jal.getDataset();
963 if (jal.getProperties() != null)
965 Enumeration en = jal.getProperties().keys();
966 while (en.hasMoreElements())
968 String key = en.nextElement().toString();
969 SequenceSetProperties ssp = new SequenceSetProperties();
971 ssp.setValue(jal.getProperties().get(key).toString());
972 // vamsasSet.addSequenceSetProperties(ssp);
973 vamsasSet.getSequenceSetProperties().add(ssp);
978 Set<String> calcIdSet = new HashSet<>();
979 // record the set of vamsas sequence XML POJO we create.
980 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
982 for (final SequenceI jds : rjal.getSequences())
984 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
985 : jds.getDatasetSequence();
986 String id = seqHash(jds);
987 if (vamsasSetIds.get(id) == null)
989 if (seqRefIds.get(id) != null && !storeDS)
991 // This happens for two reasons: 1. multiple views are being
993 // 2. the hashCode has collided with another sequence's code. This
995 // HAPPEN! (PF00072.15.stk does this)
996 // JBPNote: Uncomment to debug writing out of files that do not read
997 // back in due to ArrayOutOfBoundExceptions.
998 // System.err.println("vamsasSeq backref: "+id+"");
999 // System.err.println(jds.getName()+"
1000 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1001 // System.err.println("Hashcode: "+seqHash(jds));
1002 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1003 // System.err.println(rsq.getName()+"
1004 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1005 // System.err.println("Hashcode: "+seqHash(rsq));
1009 vamsasSeq = createVamsasSequence(id, jds);
1010 // vamsasSet.addSequence(vamsasSeq);
1011 vamsasSet.getSequence().add(vamsasSeq);
1012 vamsasSetIds.put(id, vamsasSeq);
1013 seqRefIds.put(id, jds);
1017 jseq.setStart(jds.getStart());
1018 jseq.setEnd(jds.getEnd());
1019 jseq.setColour(av.getSequenceColour(jds).getRGB());
1021 jseq.setId(id); // jseq id should be a string not a number
1024 // Store any sequences this sequence represents
1025 if (av.hasHiddenRows())
1027 // use rjal, contains the full height alignment
1029 av.getAlignment().getHiddenSequences().isHidden(jds));
1031 if (av.isHiddenRepSequence(jds))
1033 jalview.datamodel.SequenceI[] reps = av
1034 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1036 for (int h = 0; h < reps.length; h++)
1040 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1041 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1046 // mark sequence as reference - if it is the reference for this view
1047 if (jal.hasSeqrep())
1049 jseq.setViewreference(jds == jal.getSeqrep());
1053 // TODO: omit sequence features from each alignment view's XML dump if we
1054 // are storing dataset
1055 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1056 for (SequenceFeature sf : sfs)
1058 // Features features = new Features();
1059 Feature features = new Feature();
1061 features.setBegin(sf.getBegin());
1062 features.setEnd(sf.getEnd());
1063 features.setDescription(sf.getDescription());
1064 features.setType(sf.getType());
1065 features.setFeatureGroup(sf.getFeatureGroup());
1066 features.setScore(sf.getScore());
1067 if (sf.links != null)
1069 for (int l = 0; l < sf.links.size(); l++)
1071 OtherData keyValue = new OtherData();
1072 keyValue.setKey("LINK_" + l);
1073 keyValue.setValue(sf.links.elementAt(l).toString());
1074 // features.addOtherData(keyValue);
1075 features.getOtherData().add(keyValue);
1078 if (sf.otherDetails != null)
1081 * save feature attributes, which may be simple strings or
1082 * map valued (have sub-attributes)
1084 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1086 String key = entry.getKey();
1087 Object value = entry.getValue();
1088 if (value instanceof Map<?, ?>)
1090 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1093 OtherData otherData = new OtherData();
1094 otherData.setKey(key);
1095 otherData.setKey2(subAttribute.getKey());
1096 otherData.setValue(subAttribute.getValue().toString());
1097 // features.addOtherData(otherData);
1098 features.getOtherData().add(otherData);
1103 OtherData otherData = new OtherData();
1104 otherData.setKey(key);
1105 otherData.setValue(value.toString());
1106 // features.addOtherData(otherData);
1107 features.getOtherData().add(otherData);
1112 // jseq.addFeatures(features);
1113 jseq.getFeatures().add(features);
1117 * save PDB entries for sequence
1119 if (jdatasq.getAllPDBEntries() != null)
1121 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1122 while (en.hasMoreElements())
1124 Pdbids pdb = new Pdbids();
1125 jalview.datamodel.PDBEntry entry = en.nextElement();
1127 String pdbId = entry.getId();
1129 pdb.setType(entry.getType());
1132 * Store any structure views associated with this sequence. This
1133 * section copes with duplicate entries in the project, so a dataset
1134 * only view *should* be coped with sensibly.
1136 // This must have been loaded, is it still visible?
1137 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1138 String matchedFile = null;
1139 for (int f = frames.length - 1; f > -1; f--)
1141 if (frames[f] instanceof StructureViewerBase)
1143 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1144 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1145 viewIds, matchedFile, viewFrame);
1147 * Only store each structure viewer's state once in the project
1148 * jar. First time through only (storeDS==false)
1150 String viewId = viewFrame.getViewId();
1151 String viewerType = viewFrame.getViewerType().toString();
1152 if (!storeDS && !viewIds.contains(viewId))
1154 viewIds.add(viewId);
1155 File viewerState = viewFrame.saveSession();
1156 if (viewerState != null)
1158 copyFileToJar(jout, viewerState.getPath(),
1159 getViewerJarEntryName(viewId), viewerType);
1164 "Failed to save viewer state for " + viewerType);
1170 if (matchedFile != null || entry.getFile() != null)
1172 if (entry.getFile() != null)
1175 matchedFile = entry.getFile();
1177 pdb.setFile(matchedFile); // entry.getFile());
1178 if (pdbfiles == null)
1180 pdbfiles = new ArrayList<>();
1183 if (!pdbfiles.contains(pdbId))
1185 pdbfiles.add(pdbId);
1186 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1190 Enumeration<String> props = entry.getProperties();
1191 if (props.hasMoreElements())
1193 // PdbentryItem item = new PdbentryItem();
1194 while (props.hasMoreElements())
1196 Property prop = new Property();
1197 String key = props.nextElement();
1199 prop.setValue(entry.getProperty(key).toString());
1200 // item.addProperty(prop);
1201 pdb.getProperty().add(prop);
1203 // pdb.addPdbentryItem(item);
1206 // jseq.addPdbids(pdb);
1207 jseq.getPdbids().add(pdb);
1211 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1213 if (jds.hasHMMProfile())
1215 saveHmmerProfile(jout, jseq, jds);
1217 // jms.addJSeq(jseq);
1218 object.getJSeq().add(jseq);
1221 if (!storeDS && av.hasHiddenRows())
1223 jal = av.getAlignment();
1227 if (storeDS && jal.getCodonFrames() != null)
1229 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1230 for (AlignedCodonFrame acf : jac)
1232 AlcodonFrame alc = new AlcodonFrame();
1233 if (acf.getProtMappings() != null
1234 && acf.getProtMappings().length > 0)
1236 boolean hasMap = false;
1237 SequenceI[] dnas = acf.getdnaSeqs();
1238 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1239 for (int m = 0; m < pmaps.length; m++)
1241 AlcodMap alcmap = new AlcodMap();
1242 alcmap.setDnasq(seqHash(dnas[m]));
1244 createVamsasMapping(pmaps[m], dnas[m], null, false));
1245 // alc.addAlcodMap(alcmap);
1246 alc.getAlcodMap().add(alcmap);
1251 // vamsasSet.addAlcodonFrame(alc);
1252 vamsasSet.getAlcodonFrame().add(alc);
1255 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1257 // AlcodonFrame alc = new AlcodonFrame();
1258 // vamsasSet.addAlcodonFrame(alc);
1259 // for (int p = 0; p < acf.aaWidth; p++)
1261 // Alcodon cmap = new Alcodon();
1262 // if (acf.codons[p] != null)
1264 // // Null codons indicate a gapped column in the translated peptide
1266 // cmap.setPos1(acf.codons[p][0]);
1267 // cmap.setPos2(acf.codons[p][1]);
1268 // cmap.setPos3(acf.codons[p][2]);
1270 // alc.addAlcodon(cmap);
1272 // if (acf.getProtMappings() != null
1273 // && acf.getProtMappings().length > 0)
1275 // SequenceI[] dnas = acf.getdnaSeqs();
1276 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1277 // for (int m = 0; m < pmaps.length; m++)
1279 // AlcodMap alcmap = new AlcodMap();
1280 // alcmap.setDnasq(seqHash(dnas[m]));
1281 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1283 // alc.addAlcodMap(alcmap);
1290 // /////////////////////////////////
1291 if (!storeDS && av.getCurrentTree() != null)
1293 // FIND ANY ASSOCIATED TREES
1294 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1295 if (Desktop.getDesktopPane() != null)
1297 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1299 for (int t = 0; t < frames.length; t++)
1301 if (frames[t] instanceof TreePanel)
1303 TreePanel tp = (TreePanel) frames[t];
1305 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1307 JalviewModel.Tree tree = new JalviewModel.Tree();
1308 tree.setTitle(tp.getTitle());
1309 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1310 tree.setNewick(tp.getTree().print());
1311 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1313 tree.setFitToWindow(tp.fitToWindow.getState());
1314 tree.setFontName(tp.getTreeFont().getName());
1315 tree.setFontSize(tp.getTreeFont().getSize());
1316 tree.setFontStyle(tp.getTreeFont().getStyle());
1317 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1319 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1320 tree.setShowDistances(tp.distanceMenu.getState());
1322 tree.setHeight(tp.getHeight());
1323 tree.setWidth(tp.getWidth());
1324 tree.setXpos(tp.getX());
1325 tree.setYpos(tp.getY());
1326 tree.setId(makeHashCode(tp, null));
1327 tree.setLinkToAllViews(
1328 tp.getTreeCanvas().isApplyToAllViews());
1330 // jms.addTree(tree);
1331 object.getTree().add(tree);
1341 if (!storeDS && Desktop.getDesktopPane() != null)
1343 for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames())
1345 if (frame instanceof PCAPanel)
1347 PCAPanel panel = (PCAPanel) frame;
1348 if (panel.getAlignViewport().getAlignment() == jal)
1350 savePCA(panel, object);
1358 * store forward refs from an annotationRow to any groups
1360 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1363 for (SequenceI sq : jal.getSequences())
1365 // Store annotation on dataset sequences only
1366 AlignmentAnnotation[] aa = sq.getAnnotation();
1367 if (aa != null && aa.length > 0)
1369 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1376 if (jal.getAlignmentAnnotation() != null)
1378 // Store the annotation shown on the alignment.
1379 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1380 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1385 if (jal.getGroups() != null)
1387 JGroup[] groups = new JGroup[jal.getGroups().size()];
1389 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1391 JGroup jGroup = new JGroup();
1392 groups[++i] = jGroup;
1394 jGroup.setStart(sg.getStartRes());
1395 jGroup.setEnd(sg.getEndRes());
1396 jGroup.setName(sg.getName());
1397 if (groupRefs.containsKey(sg))
1399 // group has references so set its ID field
1400 jGroup.setId(groupRefs.get(sg));
1402 ColourSchemeI colourScheme = sg.getColourScheme();
1403 if (colourScheme != null)
1405 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1406 if (groupColourScheme.conservationApplied())
1408 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1410 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1413 setUserColourScheme(colourScheme, userColours,
1418 jGroup.setColour(colourScheme.getSchemeName());
1421 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1423 jGroup.setColour("AnnotationColourGradient");
1424 jGroup.setAnnotationColours(constructAnnotationColours(
1425 (jalview.schemes.AnnotationColourGradient) colourScheme,
1426 userColours, object));
1428 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1431 setUserColourScheme(colourScheme, userColours, object));
1435 jGroup.setColour(colourScheme.getSchemeName());
1438 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1441 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1442 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1443 jGroup.setDisplayText(sg.getDisplayText());
1444 jGroup.setColourText(sg.getColourText());
1445 jGroup.setTextCol1(sg.textColour.getRGB());
1446 jGroup.setTextCol2(sg.textColour2.getRGB());
1447 jGroup.setTextColThreshold(sg.thresholdTextColour);
1448 jGroup.setShowUnconserved(sg.getShowNonconserved());
1449 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1450 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1451 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1452 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1453 for (SequenceI seq : sg.getSequences())
1455 // jGroup.addSeq(seqHash(seq));
1456 jGroup.getSeq().add(seqHash(seq));
1460 //jms.setJGroup(groups);
1462 for (JGroup grp : groups)
1464 object.getJGroup().add(grp);
1469 // /////////SAVE VIEWPORT
1470 Viewport view = new Viewport();
1471 view.setTitle(ap.alignFrame.getTitle());
1472 view.setSequenceSetId(
1473 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1474 view.setId(av.getViewId());
1475 if (av.getCodingComplement() != null)
1477 view.setComplementId(av.getCodingComplement().getViewId());
1479 view.setViewName(av.getViewName());
1480 view.setGatheredViews(av.isGatherViewsHere());
1482 Rectangle size = ap.av.getExplodedGeometry();
1483 Rectangle position = size;
1486 size = ap.alignFrame.getBounds();
1487 if (av.getCodingComplement() != null)
1489 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1497 view.setXpos(position.x);
1498 view.setYpos(position.y);
1500 view.setWidth(size.width);
1501 view.setHeight(size.height);
1503 view.setStartRes(vpRanges.getStartRes());
1504 view.setStartSeq(vpRanges.getStartSeq());
1506 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1508 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1509 userColours, object));
1512 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1514 AnnotationColourScheme ac = constructAnnotationColours(
1515 (jalview.schemes.AnnotationColourGradient) av
1516 .getGlobalColourScheme(),
1517 userColours, object);
1519 view.setAnnotationColours(ac);
1520 view.setBgColour("AnnotationColourGradient");
1524 view.setBgColour(ColourSchemeProperty
1525 .getColourName(av.getGlobalColourScheme()));
1528 ResidueShaderI vcs = av.getResidueShading();
1529 ColourSchemeI cs = av.getGlobalColourScheme();
1533 if (vcs.conservationApplied())
1535 view.setConsThreshold(vcs.getConservationInc());
1536 if (cs instanceof jalview.schemes.UserColourScheme)
1538 view.setBgColour(setUserColourScheme(cs, userColours, object));
1541 view.setPidThreshold(vcs.getThreshold());
1544 view.setConservationSelected(av.getConservationSelected());
1545 view.setPidSelected(av.getAbovePIDThreshold());
1546 final Font font = av.getFont();
1547 view.setFontName(font.getName());
1548 view.setFontSize(font.getSize());
1549 view.setFontStyle(font.getStyle());
1550 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1551 view.setRenderGaps(av.isRenderGaps());
1552 view.setShowAnnotation(av.isShowAnnotation());
1553 view.setShowBoxes(av.getShowBoxes());
1554 view.setShowColourText(av.getColourText());
1555 view.setShowFullId(av.getShowJVSuffix());
1556 view.setRightAlignIds(av.isRightAlignIds());
1557 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1558 view.setShowText(av.getShowText());
1559 view.setShowUnconserved(av.getShowUnconserved());
1560 view.setWrapAlignment(av.getWrapAlignment());
1561 view.setTextCol1(av.getTextColour().getRGB());
1562 view.setTextCol2(av.getTextColour2().getRGB());
1563 view.setTextColThreshold(av.getThresholdTextColour());
1564 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1565 view.setShowSequenceLogo(av.isShowSequenceLogo());
1566 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1567 view.setShowGroupConsensus(av.isShowGroupConsensus());
1568 view.setShowGroupConservation(av.isShowGroupConservation());
1569 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1570 view.setShowDbRefTooltip(av.isShowDBRefs());
1571 view.setFollowHighlight(av.isFollowHighlight());
1572 view.setFollowSelection(av.followSelection);
1573 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1574 view.setShowComplementFeatures(av.isShowComplementFeatures());
1575 view.setShowComplementFeaturesOnTop(
1576 av.isShowComplementFeaturesOnTop());
1577 if (av.getFeaturesDisplayed() != null)
1579 FeatureSettings fs = new FeatureSettings();
1581 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1582 .getFeatureRenderer();
1583 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1585 Vector<String> settingsAdded = new Vector<>();
1586 if (renderOrder != null)
1588 for (String featureType : renderOrder)
1590 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1591 setting.setType(featureType);
1594 * save any filter for the feature type
1596 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1597 if (filter != null) {
1598 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1599 FeatureMatcherI firstFilter = filters.next();
1600 setting.setMatcherSet(Jalview2XML.marshalFilter(
1601 firstFilter, filters, filter.isAnded()));
1605 * save colour scheme for the feature type
1607 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1608 if (!fcol.isSimpleColour())
1610 setting.setColour(fcol.getMaxColour().getRGB());
1611 setting.setMincolour(fcol.getMinColour().getRGB());
1612 setting.setMin(fcol.getMin());
1613 setting.setMax(fcol.getMax());
1614 setting.setColourByLabel(fcol.isColourByLabel());
1615 if (fcol.isColourByAttribute())
1617 String[] attName = fcol.getAttributeName();
1618 setting.getAttributeName().add(attName[0]);
1619 if (attName.length > 1)
1621 setting.getAttributeName().add(attName[1]);
1624 setting.setAutoScale(fcol.isAutoScaled());
1625 setting.setThreshold(fcol.getThreshold());
1626 Color noColour = fcol.getNoColour();
1627 if (noColour == null)
1629 setting.setNoValueColour(NoValueColour.NONE);
1631 else if (noColour.equals(fcol.getMaxColour()))
1633 setting.setNoValueColour(NoValueColour.MAX);
1637 setting.setNoValueColour(NoValueColour.MIN);
1639 // -1 = No threshold, 0 = Below, 1 = Above
1640 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1641 : (fcol.isBelowThreshold() ? 0 : -1));
1645 setting.setColour(fcol.getColour().getRGB());
1649 av.getFeaturesDisplayed().isVisible(featureType));
1651 .getOrder(featureType);
1654 setting.setOrder(rorder);
1656 /// fs.addSetting(setting);
1657 fs.getSetting().add(setting);
1658 settingsAdded.addElement(featureType);
1662 // is groups actually supposed to be a map here ?
1663 Iterator<String> en = fr.getFeatureGroups().iterator();
1664 Vector<String> groupsAdded = new Vector<>();
1665 while (en.hasNext())
1667 String grp = en.next();
1668 if (groupsAdded.contains(grp))
1672 Group g = new Group();
1674 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1677 fs.getGroup().add(g);
1678 groupsAdded.addElement(grp);
1680 // jms.setFeatureSettings(fs);
1681 object.setFeatureSettings(fs);
1684 if (av.hasHiddenColumns())
1686 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1687 .getHiddenColumns();
1691 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1695 Iterator<int[]> hiddenRegions = hidden.iterator();
1696 while (hiddenRegions.hasNext())
1698 int[] region = hiddenRegions.next();
1699 HiddenColumns hc = new HiddenColumns();
1700 hc.setStart(region[0]);
1701 hc.setEnd(region[1]);
1702 // view.addHiddenColumns(hc);
1703 view.getHiddenColumns().add(hc);
1707 if (calcIdSet.size() > 0)
1709 for (String calcId : calcIdSet)
1711 if (calcId.trim().length() > 0)
1713 CalcIdParam cidp = createCalcIdParam(calcId, av);
1714 // Some calcIds have no parameters.
1717 // view.addCalcIdParam(cidp);
1718 view.getCalcIdParam().add(cidp);
1724 // jms.addViewport(view);
1725 object.getViewport().add(view);
1727 // object.setJalviewModelSequence(jms);
1728 // object.getVamsasModel().addSequenceSet(vamsasSet);
1729 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1731 if (jout != null && fileName != null)
1733 // We may not want to write the object to disk,
1734 // eg we can copy the alignViewport to a new view object
1735 // using save and then load
1738 fileName = fileName.replace('\\', '/');
1739 System.out.println("Writing jar entry " + fileName);
1740 JarEntry entry = new JarEntry(fileName);
1741 jout.putNextEntry(entry);
1742 PrintWriter pout = new PrintWriter(
1743 new OutputStreamWriter(jout, UTF_8));
1744 JAXBContext jaxbContext = JAXBContext
1745 .newInstance(JalviewModel.class);
1746 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1748 // output pretty printed
1749 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1750 jaxbMarshaller.marshal(
1751 new ObjectFactory().createJalviewModel(object), pout);
1753 // jaxbMarshaller.marshal(object, pout);
1754 // marshaller.marshal(object);
1757 } catch (Exception ex)
1759 // TODO: raise error in GUI if marshalling failed.
1760 System.err.println("Error writing Jalview project");
1761 ex.printStackTrace();
1767 * Saves the HMMER profile associated with the sequence as a file in the jar,
1768 * in HMMER format, and saves the name of the file as a child element of the
1769 * XML sequence element
1775 protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
1778 HiddenMarkovModel profile = seq.getHMM();
1779 if (profile == null)
1781 Console.warn("Want to save HMM profile for " + seq.getName()
1782 + " but none found");
1785 HMMFile hmmFile = new HMMFile(profile);
1786 String hmmAsString = hmmFile.print();
1787 String jarEntryName = HMMER_PREFIX + nextCounter();
1790 writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
1791 xmlSeq.setHmmerProfile(jarEntryName);
1792 } catch (IOException e)
1794 Console.warn("Error saving HMM profile: " + e.getMessage());
1800 * Writes PCA viewer attributes and computed values to an XML model object and
1801 * adds it to the JalviewModel. Any exceptions are reported by logging.
1803 protected void savePCA(PCAPanel panel, JalviewModel object)
1807 PcaViewer viewer = new PcaViewer();
1808 viewer.setHeight(panel.getHeight());
1809 viewer.setWidth(panel.getWidth());
1810 viewer.setXpos(panel.getX());
1811 viewer.setYpos(panel.getY());
1812 viewer.setTitle(panel.getTitle());
1813 PCAModel pcaModel = panel.getPcaModel();
1814 viewer.setScoreModelName(pcaModel.getScoreModelName());
1815 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1816 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1817 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1819 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1820 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1821 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1822 SeqPointMin spmin = new SeqPointMin();
1823 spmin.setXPos(spMin[0]);
1824 spmin.setYPos(spMin[1]);
1825 spmin.setZPos(spMin[2]);
1826 viewer.setSeqPointMin(spmin);
1827 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1828 SeqPointMax spmax = new SeqPointMax();
1829 spmax.setXPos(spMax[0]);
1830 spmax.setYPos(spMax[1]);
1831 spmax.setZPos(spMax[2]);
1832 viewer.setSeqPointMax(spmax);
1833 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1834 viewer.setLinkToAllViews(
1835 panel.getRotatableCanvas().isApplyToAllViews());
1836 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1837 viewer.setIncludeGaps(sp.includeGaps());
1838 viewer.setMatchGaps(sp.matchGaps());
1839 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1840 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1843 * sequence points on display
1845 for (jalview.datamodel.SequencePoint spt : pcaModel
1846 .getSequencePoints())
1848 SequencePoint point = new SequencePoint();
1849 point.setSequenceRef(seqHash(spt.getSequence()));
1850 point.setXPos(spt.coord.x);
1851 point.setYPos(spt.coord.y);
1852 point.setZPos(spt.coord.z);
1853 viewer.getSequencePoint().add(point);
1857 * (end points of) axes on display
1859 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1862 Axis axis = new Axis();
1866 viewer.getAxis().add(axis);
1870 * raw PCA data (note we are not restoring PCA inputs here -
1871 * alignment view, score model, similarity parameters)
1873 PcaDataType data = new PcaDataType();
1874 viewer.setPcaData(data);
1875 PCA pca = pcaModel.getPcaData();
1877 DoubleMatrix pm = new DoubleMatrix();
1878 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1879 data.setPairwiseMatrix(pm);
1881 DoubleMatrix tm = new DoubleMatrix();
1882 saveDoubleMatrix(pca.getTridiagonal(), tm);
1883 data.setTridiagonalMatrix(tm);
1885 DoubleMatrix eigenMatrix = new DoubleMatrix();
1886 data.setEigenMatrix(eigenMatrix);
1887 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1889 object.getPcaViewer().add(viewer);
1890 } catch (Throwable t)
1892 Console.error("Error saving PCA: " + t.getMessage());
1897 * Stores values from a matrix into an XML element, including (if present) the
1902 * @see #loadDoubleMatrix(DoubleMatrix)
1904 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1906 xmlMatrix.setRows(m.height());
1907 xmlMatrix.setColumns(m.width());
1908 for (int i = 0; i < m.height(); i++)
1910 DoubleVector row = new DoubleVector();
1911 for (int j = 0; j < m.width(); j++)
1913 row.getV().add(m.getValue(i, j));
1915 xmlMatrix.getRow().add(row);
1917 if (m.getD() != null)
1919 DoubleVector dVector = new DoubleVector();
1920 for (double d : m.getD())
1922 dVector.getV().add(d);
1924 xmlMatrix.setD(dVector);
1926 if (m.getE() != null)
1928 DoubleVector eVector = new DoubleVector();
1929 for (double e : m.getE())
1931 eVector.getV().add(e);
1933 xmlMatrix.setE(eVector);
1938 * Loads XML matrix data into a new Matrix object, including the D and/or E
1939 * vectors (if present)
1943 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1945 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1947 int rows = mData.getRows();
1948 double[][] vals = new double[rows][];
1950 for (int i = 0; i < rows; i++)
1952 List<Double> dVector = mData.getRow().get(i).getV();
1953 vals[i] = new double[dVector.size()];
1955 for (Double d : dVector)
1961 MatrixI m = new Matrix(vals);
1963 if (mData.getD() != null)
1965 List<Double> dVector = mData.getD().getV();
1966 double[] vec = new double[dVector.size()];
1968 for (Double d : dVector)
1974 if (mData.getE() != null)
1976 List<Double> dVector = mData.getE().getV();
1977 double[] vec = new double[dVector.size()];
1979 for (Double d : dVector)
1990 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1991 * for each viewer, with
1993 * <li>viewer geometry (position, size, split pane divider location)</li>
1994 * <li>index of the selected structure in the viewer (currently shows gapped
1996 * <li>the id of the annotation holding RNA secondary structure</li>
1997 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1999 * Varna viewer state is also written out (in native Varna XML) to separate
2000 * project jar entries. A separate entry is written for each RNA structure
2001 * displayed, with the naming convention
2003 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2011 * @param storeDataset
2013 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2014 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2015 boolean storeDataset)
2017 if (Desktop.getDesktopPane() == null)
2021 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2022 for (int f = frames.length - 1; f > -1; f--)
2024 if (frames[f] instanceof AppVarna)
2026 AppVarna varna = (AppVarna) frames[f];
2028 * link the sequence to every viewer that is showing it and is linked to
2029 * its alignment panel
2031 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2033 String viewId = varna.getViewId();
2034 RnaViewer rna = new RnaViewer();
2035 rna.setViewId(viewId);
2036 rna.setTitle(varna.getTitle());
2037 rna.setXpos(varna.getX());
2038 rna.setYpos(varna.getY());
2039 rna.setWidth(varna.getWidth());
2040 rna.setHeight(varna.getHeight());
2041 rna.setDividerLocation(varna.getDividerLocation());
2042 rna.setSelectedRna(varna.getSelectedIndex());
2043 // jseq.addRnaViewer(rna);
2044 jseq.getRnaViewer().add(rna);
2047 * Store each Varna panel's state once in the project per sequence.
2048 * First time through only (storeDataset==false)
2050 // boolean storeSessions = false;
2051 // String sequenceViewId = viewId + seqsToIds.get(jds);
2052 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2054 // viewIds.add(sequenceViewId);
2055 // storeSessions = true;
2057 for (RnaModel model : varna.getModels())
2059 if (model.seq == jds)
2062 * VARNA saves each view (sequence or alignment secondary
2063 * structure, gapped or trimmed) as a separate XML file
2065 String jarEntryName = rnaSessions.get(model);
2066 if (jarEntryName == null)
2069 String varnaStateFile = varna.getStateInfo(model.rna);
2070 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2071 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2072 rnaSessions.put(model, jarEntryName);
2074 SecondaryStructure ss = new SecondaryStructure();
2075 String annotationId = varna.getAnnotation(jds).annotationId;
2076 ss.setAnnotationId(annotationId);
2077 ss.setViewerState(jarEntryName);
2078 ss.setGapped(model.gapped);
2079 ss.setTitle(model.title);
2080 // rna.addSecondaryStructure(ss);
2081 rna.getSecondaryStructure().add(ss);
2090 * Copy the contents of a file to a new entry added to the output jar
2094 * @param jarEntryName
2096 * additional identifying info to log to the console
2098 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2099 String jarEntryName, String msg)
2101 try (InputStream is = new FileInputStream(infilePath))
2103 File file = new File(infilePath);
2104 if (file.exists() && jout != null)
2107 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2108 jout.putNextEntry(new JarEntry(jarEntryName));
2111 // dis = new DataInputStream(new FileInputStream(file));
2112 // byte[] data = new byte[(int) file.length()];
2113 // dis.readFully(data);
2114 // writeJarEntry(jout, jarEntryName, data);
2116 } catch (Exception ex)
2118 ex.printStackTrace();
2124 * Write the data to a new entry of given name in the output jar file
2127 * @param jarEntryName
2129 * @throws IOException
2131 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2132 byte[] data) throws IOException
2136 jarEntryName = jarEntryName.replace('\\','/');
2137 System.out.println("Writing jar entry " + jarEntryName);
2138 jout.putNextEntry(new JarEntry(jarEntryName));
2139 DataOutputStream dout = new DataOutputStream(jout);
2140 dout.write(data, 0, data.length);
2147 * Copies input to output, in 4K buffers; handles any data (text or binary)
2151 * @throws IOException
2153 protected void copyAll(InputStream in, OutputStream out)
2156 byte[] buffer = new byte[4096];
2158 while ((bytesRead = in.read(buffer)) != -1)
2160 out.write(buffer, 0, bytesRead);
2165 * Save the state of a structure viewer
2170 * the archive XML element under which to save the state
2173 * @param matchedFile
2177 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2178 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2179 String matchedFile, StructureViewerBase viewFrame)
2181 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2184 * Look for any bindings for this viewer to the PDB file of interest
2185 * (including part matches excluding chain id)
2187 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2189 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2190 final String pdbId = pdbentry.getId();
2191 if (!pdbId.equals(entry.getId())
2192 && !(entry.getId().length() > 4 && entry.getId().toLowerCase(Locale.ROOT)
2193 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2196 * not interested in a binding to a different PDB entry here
2200 if (matchedFile == null)
2202 matchedFile = pdbentry.getFile();
2204 else if (!matchedFile.equals(pdbentry.getFile()))
2207 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2208 + pdbentry.getFile());
2212 // can get at it if the ID
2213 // match is ambiguous (e.g.
2216 for (int smap = 0; smap < viewFrame.getBinding()
2217 .getSequence()[peid].length; smap++)
2219 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2220 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2222 StructureState state = new StructureState();
2223 state.setVisible(true);
2224 state.setXpos(viewFrame.getX());
2225 state.setYpos(viewFrame.getY());
2226 state.setWidth(viewFrame.getWidth());
2227 state.setHeight(viewFrame.getHeight());
2228 final String viewId = viewFrame.getViewId();
2229 state.setViewId(viewId);
2230 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2231 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2232 state.setColourByJmol(viewFrame.isColouredByViewer());
2233 state.setType(viewFrame.getViewerType().toString());
2234 // pdb.addStructureState(state);
2235 pdb.getStructureState().add(state);
2243 * Populates the AnnotationColourScheme xml for save. This captures the
2244 * settings of the options in the 'Colour by Annotation' dialog.
2247 * @param userColours
2251 private AnnotationColourScheme constructAnnotationColours(
2252 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2255 AnnotationColourScheme ac = new AnnotationColourScheme();
2256 ac.setAboveThreshold(acg.getAboveThreshold());
2257 ac.setThreshold(acg.getAnnotationThreshold());
2258 // 2.10.2 save annotationId (unique) not annotation label
2259 ac.setAnnotation(acg.getAnnotation().annotationId);
2260 if (acg.getBaseColour() instanceof UserColourScheme)
2263 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2268 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2271 ac.setMaxColour(acg.getMaxColour().getRGB());
2272 ac.setMinColour(acg.getMinColour().getRGB());
2273 ac.setPerSequence(acg.isSeqAssociated());
2274 ac.setPredefinedColours(acg.isPredefinedColours());
2278 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2279 IdentityHashMap<SequenceGroup, String> groupRefs,
2280 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2281 SequenceSet vamsasSet)
2284 for (int i = 0; i < aa.length; i++)
2286 Annotation an = new Annotation();
2288 AlignmentAnnotation annotation = aa[i];
2289 if (annotation.annotationId != null)
2291 annotationIds.put(annotation.annotationId, annotation);
2294 an.setId(annotation.annotationId);
2296 an.setVisible(annotation.visible);
2298 an.setDescription(annotation.description);
2300 if (annotation.sequenceRef != null)
2302 // 2.9 JAL-1781 xref on sequence id rather than name
2303 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2305 if (annotation.groupRef != null)
2307 String groupIdr = groupRefs.get(annotation.groupRef);
2308 if (groupIdr == null)
2310 // make a locally unique String
2311 groupRefs.put(annotation.groupRef,
2312 groupIdr = ("" + System.currentTimeMillis()
2313 + annotation.groupRef.getName()
2314 + groupRefs.size()));
2316 an.setGroupRef(groupIdr.toString());
2319 // store all visualization attributes for annotation
2320 an.setGraphHeight(annotation.graphHeight);
2321 an.setCentreColLabels(annotation.centreColLabels);
2322 an.setScaleColLabels(annotation.scaleColLabel);
2323 an.setShowAllColLabels(annotation.showAllColLabels);
2324 an.setBelowAlignment(annotation.belowAlignment);
2326 if (annotation.graph > 0)
2329 an.setGraphType(annotation.graph);
2330 an.setGraphGroup(annotation.graphGroup);
2331 if (annotation.getThreshold() != null)
2333 ThresholdLine line = new ThresholdLine();
2334 line.setLabel(annotation.getThreshold().label);
2335 line.setValue(annotation.getThreshold().value);
2336 line.setColour(annotation.getThreshold().colour.getRGB());
2337 an.setThresholdLine(line);
2345 an.setLabel(annotation.label);
2347 if (annotation == av.getAlignmentQualityAnnot()
2348 || annotation == av.getAlignmentConservationAnnotation()
2349 || annotation == av.getAlignmentConsensusAnnotation()
2350 || annotation.autoCalculated)
2352 // new way of indicating autocalculated annotation -
2353 an.setAutoCalculated(annotation.autoCalculated);
2355 if (annotation.hasScore())
2357 an.setScore(annotation.getScore());
2360 if (annotation.getCalcId() != null)
2362 calcIdSet.add(annotation.getCalcId());
2363 an.setCalcId(annotation.getCalcId());
2365 if (annotation.hasProperties())
2367 for (String pr : annotation.getProperties())
2369 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2371 prop.setValue(annotation.getProperty(pr));
2372 // an.addProperty(prop);
2373 an.getProperty().add(prop);
2377 AnnotationElement ae;
2378 if (annotation.annotations != null)
2380 an.setScoreOnly(false);
2381 for (int a = 0; a < annotation.annotations.length; a++)
2383 if ((annotation == null) || (annotation.annotations[a] == null))
2388 ae = new AnnotationElement();
2389 if (annotation.annotations[a].description != null)
2391 ae.setDescription(annotation.annotations[a].description);
2393 if (annotation.annotations[a].displayCharacter != null)
2395 ae.setDisplayCharacter(
2396 annotation.annotations[a].displayCharacter);
2399 if (!Float.isNaN(annotation.annotations[a].value))
2401 ae.setValue(annotation.annotations[a].value);
2405 if (annotation.annotations[a].secondaryStructure > ' ')
2407 ae.setSecondaryStructure(
2408 annotation.annotations[a].secondaryStructure + "");
2411 if (annotation.annotations[a].colour != null
2412 && annotation.annotations[a].colour != java.awt.Color.black)
2414 ae.setColour(annotation.annotations[a].colour.getRGB());
2417 // an.addAnnotationElement(ae);
2418 an.getAnnotationElement().add(ae);
2419 if (annotation.autoCalculated)
2421 // only write one non-null entry into the annotation row -
2422 // sufficient to get the visualization attributes necessary to
2430 an.setScoreOnly(true);
2432 if (!storeDS || (storeDS && !annotation.autoCalculated))
2434 // skip autocalculated annotation - these are only provided for
2436 // vamsasSet.addAnnotation(an);
2437 vamsasSet.getAnnotation().add(an);
2443 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2445 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2446 if (settings != null)
2448 CalcIdParam vCalcIdParam = new CalcIdParam();
2449 vCalcIdParam.setCalcId(calcId);
2450 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2451 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2452 // generic URI allowing a third party to resolve another instance of the
2453 // service used for this calculation
2454 for (String url : settings.getServiceURLs())
2456 // vCalcIdParam.addServiceURL(urls);
2457 vCalcIdParam.getServiceURL().add(url);
2459 vCalcIdParam.setVersion("1.0");
2460 if (settings.getPreset() != null)
2462 WsParamSetI setting = settings.getPreset();
2463 vCalcIdParam.setName(setting.getName());
2464 vCalcIdParam.setDescription(setting.getDescription());
2468 vCalcIdParam.setName("");
2469 vCalcIdParam.setDescription("Last used parameters");
2471 // need to be able to recover 1) settings 2) user-defined presets or
2472 // recreate settings from preset 3) predefined settings provided by
2473 // service - or settings that can be transferred (or discarded)
2474 vCalcIdParam.setParameters(
2475 settings.getWsParamFile().replace("\n", "|\\n|"));
2476 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2477 // todo - decide if updateImmediately is needed for any projects.
2479 return vCalcIdParam;
2484 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2487 if (calcIdParam.getVersion().equals("1.0"))
2489 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2490 ServiceWithParameters service = PreferredServiceRegistry.getRegistry()
2491 .getPreferredServiceFor(calcIds);
2492 if (service != null)
2494 WsParamSetI parmSet = null;
2497 parmSet = service.getParamStore().parseServiceParameterFile(
2498 calcIdParam.getName(), calcIdParam.getDescription(),
2500 calcIdParam.getParameters().replace("|\\n|", "\n"));
2501 } catch (IOException x)
2503 Console.warn("Couldn't parse parameter data for "
2504 + calcIdParam.getCalcId(), x);
2507 List<ArgumentI> argList = null;
2508 if (calcIdParam.getName().length() > 0)
2510 parmSet = service.getParamStore()
2511 .getPreset(calcIdParam.getName());
2512 if (parmSet != null)
2514 // TODO : check we have a good match with settings in AACon -
2515 // otherwise we'll need to create a new preset
2520 argList = parmSet.getArguments();
2523 AutoCalcSetting settings = new AAConSettings(
2524 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2525 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2526 calcIdParam.isNeedsUpdate());
2532 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2536 throw new Error(MessageManager.formatMessage(
2537 "error.unsupported_version_calcIdparam", new Object[]
2538 { calcIdParam.toString() }));
2542 * External mapping between jalview objects and objects yielding a valid and
2543 * unique object ID string. This is null for normal Jalview project IO, but
2544 * non-null when a jalview project is being read or written as part of a
2547 IdentityHashMap jv2vobj = null;
2550 * Construct a unique ID for jvobj using either existing bindings or if none
2551 * exist, the result of the hashcode call for the object.
2554 * jalview data object
2555 * @return unique ID for referring to jvobj
2557 private String makeHashCode(Object jvobj, String altCode)
2559 if (jv2vobj != null)
2561 Object id = jv2vobj.get(jvobj);
2564 return id.toString();
2566 // check string ID mappings
2567 if (jvids2vobj != null && jvobj instanceof String)
2569 id = jvids2vobj.get(jvobj);
2573 return id.toString();
2575 // give up and warn that something has gone wrong
2577 "Cannot find ID for object in external mapping : " + jvobj);
2583 * return local jalview object mapped to ID, if it exists
2587 * @return null or object bound to idcode
2589 private Object retrieveExistingObj(String idcode)
2591 if (idcode != null && vobj2jv != null)
2593 return vobj2jv.get(idcode);
2599 * binding from ID strings from external mapping table to jalview data model
2602 private Hashtable vobj2jv;
2604 private Sequence createVamsasSequence(String id, SequenceI jds)
2606 return createVamsasSequence(true, id, jds, null);
2609 private Sequence createVamsasSequence(boolean recurse, String id,
2610 SequenceI jds, SequenceI parentseq)
2612 Sequence vamsasSeq = new Sequence();
2613 vamsasSeq.setId(id);
2614 vamsasSeq.setName(jds.getName());
2615 vamsasSeq.setSequence(jds.getSequenceAsString());
2616 vamsasSeq.setDescription(jds.getDescription());
2617 List<DBRefEntry> dbrefs = null;
2618 if (jds.getDatasetSequence() != null)
2620 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2624 // seqId==dsseqid so we can tell which sequences really are
2625 // dataset sequences only
2626 vamsasSeq.setDsseqid(id);
2627 dbrefs = jds.getDBRefs();
2628 if (parentseq == null)
2635 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2639 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2641 DBRef dbref = new DBRef();
2642 DBRefEntry ref = dbrefs.get(d);
2643 dbref.setSource(ref.getSource());
2644 dbref.setVersion(ref.getVersion());
2645 dbref.setAccessionId(ref.getAccessionId());
2646 dbref.setCanonical(ref.isCanonical());
2647 if (ref instanceof GeneLocus)
2649 dbref.setLocus(true);
2653 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2655 dbref.setMapping(mp);
2657 vamsasSeq.getDBRef().add(dbref);
2663 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2664 SequenceI parentseq, SequenceI jds, boolean recurse)
2667 if (jmp.getMap() != null)
2671 jalview.util.MapList mlst = jmp.getMap();
2672 List<int[]> r = mlst.getFromRanges();
2673 for (int[] range : r)
2675 MapListFrom mfrom = new MapListFrom();
2676 mfrom.setStart(range[0]);
2677 mfrom.setEnd(range[1]);
2678 // mp.addMapListFrom(mfrom);
2679 mp.getMapListFrom().add(mfrom);
2681 r = mlst.getToRanges();
2682 for (int[] range : r)
2684 MapListTo mto = new MapListTo();
2685 mto.setStart(range[0]);
2686 mto.setEnd(range[1]);
2687 // mp.addMapListTo(mto);
2688 mp.getMapListTo().add(mto);
2690 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2691 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2692 if (jmp.getTo() != null)
2694 // MappingChoice mpc = new MappingChoice();
2696 // check/create ID for the sequence referenced by getTo()
2699 SequenceI ps = null;
2700 if (parentseq != jmp.getTo()
2701 && parentseq.getDatasetSequence() != jmp.getTo())
2703 // chaining dbref rather than a handshaking one
2704 jmpid = seqHash(ps = jmp.getTo());
2708 jmpid = seqHash(ps = parentseq);
2710 // mpc.setDseqFor(jmpid);
2711 mp.setDseqFor(jmpid);
2712 if (!seqRefIds.containsKey(jmpid))
2714 Console.debug("creatign new DseqFor ID");
2715 seqRefIds.put(jmpid, ps);
2719 Console.debug("reusing DseqFor ID");
2722 // mp.setMappingChoice(mpc);
2728 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2729 List<UserColourScheme> userColours, JalviewModel jm)
2732 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2733 boolean newucs = false;
2734 if (!userColours.contains(ucs))
2736 userColours.add(ucs);
2739 id = "ucs" + userColours.indexOf(ucs);
2742 // actually create the scheme's entry in the XML model
2743 java.awt.Color[] colours = ucs.getColours();
2744 UserColours uc = new UserColours();
2745 // UserColourScheme jbucs = new UserColourScheme();
2746 JalviewUserColours jbucs = new JalviewUserColours();
2748 for (int i = 0; i < colours.length; i++)
2750 Colour col = new Colour();
2751 col.setName(ResidueProperties.aa[i]);
2752 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2753 // jbucs.addColour(col);
2754 jbucs.getColour().add(col);
2756 if (ucs.getLowerCaseColours() != null)
2758 colours = ucs.getLowerCaseColours();
2759 for (int i = 0; i < colours.length; i++)
2761 Colour col = new Colour();
2762 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2763 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2764 // jbucs.addColour(col);
2765 jbucs.getColour().add(col);
2770 uc.setUserColourScheme(jbucs);
2771 // jm.addUserColours(uc);
2772 jm.getUserColours().add(uc);
2778 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2781 List<UserColours> uc = jm.getUserColours();
2782 UserColours colours = null;
2784 for (int i = 0; i < uc.length; i++)
2786 if (uc[i].getId().equals(id))
2793 for (UserColours c : uc)
2795 if (c.getId().equals(id))
2802 java.awt.Color[] newColours = new java.awt.Color[24];
2804 for (int i = 0; i < 24; i++)
2806 newColours[i] = new java.awt.Color(Integer.parseInt(
2807 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2808 colours.getUserColourScheme().getColour().get(i).getRGB(),
2812 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2815 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2817 newColours = new java.awt.Color[23];
2818 for (int i = 0; i < 23; i++)
2820 newColours[i] = new java.awt.Color(
2821 Integer.parseInt(colours.getUserColourScheme().getColour()
2822 .get(i + 24).getRGB(), 16));
2824 ucs.setLowerCaseColours(newColours);
2831 * Load a jalview project archive from a jar file
2834 * - HTTP URL or filename
2836 public AlignFrame loadJalviewAlign(final Object file)
2839 jalview.gui.AlignFrame af = null;
2843 // create list to store references for any new Jmol viewers created
2844 newStructureViewers = new Vector<>();
2845 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2846 // Workaround is to make sure caller implements the JarInputStreamProvider
2848 // so we can re-open the jar input stream for each entry.
2850 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2851 af = loadJalviewAlign(jprovider);
2854 af.setMenusForViewport();
2856 } catch (MalformedURLException e)
2858 errorMessage = "Invalid URL format for '" + file + "'";
2864 // was invokeAndWait
2866 // BH 2019 -- can't wait
2867 SwingUtilities.invokeLater(new Runnable()
2872 setLoadingFinishedForNewStructureViewers();
2875 } catch (Exception x)
2877 System.err.println("Error loading alignment: " + x.getMessage());
2880 this.jarFile = null;
2884 @SuppressWarnings("unused")
2885 private jarInputStreamProvider createjarInputStreamProvider(
2886 final Object ofile) throws MalformedURLException
2891 String file = (ofile instanceof File
2892 ? ((File) ofile).getCanonicalPath()
2893 : ofile.toString());
2894 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2898 this.jarFile = (File) ofile;
2901 errorMessage = null;
2902 uniqueSetSuffix = null;
2904 viewportsAdded.clear();
2905 frefedSequence = null;
2907 if (HttpUtils.startsWithHttpOrHttps(file))
2909 url = new URL(file);
2913 return new jarInputStreamProvider()
2917 public JarInputStream getJarInputStream() throws IOException
2919 InputStream is = bytes != null ? new ByteArrayInputStream(bytes)
2920 : (url != null ? url.openStream()
2921 : new FileInputStream(file));
2922 return new JarInputStream(is);
2926 public File getFile()
2932 public String getFilename()
2937 } catch (IOException e)
2939 e.printStackTrace();
2945 * Recover jalview session from a jalview project archive. Caller may
2946 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2947 * themselves. Any null fields will be initialised with default values,
2948 * non-null fields are left alone.
2953 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2955 errorMessage = null;
2956 if (uniqueSetSuffix == null)
2958 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2960 if (seqRefIds == null)
2964 AlignFrame af = null, _af = null;
2965 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2966 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2967 String fileName = jprovider.getFilename();
2968 File file = jprovider.getFile();
2969 List<AlignFrame> alignFrames = new ArrayList<>();
2972 JarInputStream jin = null;
2973 JarEntry jarentry = null;
2976 // Look for all the entry names ending with ".xml"
2977 // This includes all panels and at least one frame.
2978 // Platform.timeCheck(null, Platform.TIME_MARK);
2981 jin = jprovider.getJarInputStream();
2982 for (int i = 0; i < entryCount; i++)
2984 jarentry = jin.getNextJarEntry();
2986 String name = (jarentry == null ? null : jarentry.getName());
2988 // System.out.println("Jalview2XML opening " + name);
2989 if (name != null && name.endsWith(".xml"))
2991 // DataSet for.... is read last.
2994 // The question here is what to do with the two
2995 // .xml files in the jvp file.
2996 // Some number of them, "...Dataset for...", will be the
2997 // Only AlignPanels and will have Viewport.
2998 // One or more will be the source data, with the DBRefs.
3000 // JVP file writing (above) ensures tha the AlignPanels are written
3001 // first, then all relevant datasets (which are
3002 // Jalview.datamodel.Alignment).
3005 // Platform.timeCheck("Jalview2XML JAXB " + name, Platform.TIME_MARK);
3006 JAXBContext jc = JAXBContext
3007 .newInstance("jalview.xml.binding.jalview");
3008 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3009 .createXMLStreamReader(jin);
3010 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3011 JAXBElement<JalviewModel> jbe = um
3012 .unmarshal(streamReader, JalviewModel.class);
3013 JalviewModel model = jbe.getValue();
3015 if (true) // !skipViewport(object))
3017 // Q: Do we have to load from the model, even if it
3018 // does not have a viewport, could we discover that early on?
3019 // Q: Do we need to load this object?
3020 _af = loadFromObject(model, fileName, file, true, jprovider);
3021 // Platform.timeCheck("Jalview2XML.loadFromObject",
3022 // Platform.TIME_MARK);
3026 alignFrames.add(_af);
3028 if (_af != null && model.getViewport().size() > 0)
3031 // That is, this is one of the AlignmentPanel models
3034 // store a reference to the first view
3037 if (_af.getViewport().isGatherViewsHere())
3039 // if this is a gathered view, keep its reference since
3040 // after gathering views, only this frame will remain
3042 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3045 // Save dataset to register mappings once all resolved
3046 importedDatasets.put(
3047 af.getViewport().getAlignment().getDataset(),
3048 af.getViewport().getAlignment().getDataset());
3053 else if (jarentry != null)
3055 // Some other file here.
3058 } while (jarentry != null);
3060 resolveFrefedSequences();
3061 } catch (IOException ex)
3063 ex.printStackTrace();
3064 errorMessage = "Couldn't locate Jalview XML file : " + fileName;
3066 "Exception whilst loading jalview XML file : " + ex + "\n");
3067 } catch (Exception ex)
3069 System.err.println("Parsing as Jalview Version 2 file failed.");
3070 ex.printStackTrace(System.err);
3071 if (attemptversion1parse)
3073 // used to attempt to parse as V1 castor-generated xml
3075 if (Desktop.getInstance() != null)
3077 Desktop.getInstance().stopLoading();
3081 System.out.println("Successfully loaded archive file");
3084 ex.printStackTrace();
3087 "Exception whilst loading jalview XML file : " + ex + "\n");
3088 } catch (OutOfMemoryError e)
3090 // Don't use the OOM Window here
3091 errorMessage = "Out of memory loading jalview XML file";
3092 System.err.println("Out of memory whilst loading jalview XML file");
3093 e.printStackTrace();
3096 for (AlignFrame alf : alignFrames)
3098 alf.alignPanel.setHoldRepaint(false);
3103 * Regather multiple views (with the same sequence set id) to the frame (if
3104 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3105 * views instead of separate frames. Note this doesn't restore a state where
3106 * some expanded views in turn have tabbed views - the last "first tab" read
3107 * in will play the role of gatherer for all.
3109 for (AlignFrame fr : gatherToThisFrame.values())
3111 Desktop.getInstance().gatherViews(fr);
3114 restoreSplitFrames();
3115 for (AlignmentI ds : importedDatasets.keySet())
3117 if (ds.getCodonFrames() != null)
3119 Desktop.getStructureSelectionManager()
3120 .registerMappings(ds.getCodonFrames());
3123 if (errorMessage != null)
3128 if (Desktop.getInstance() != null)
3130 Desktop.getInstance().stopLoading();
3137 * Try to reconstruct and display SplitFrame windows, where each contains
3138 * complementary dna and protein alignments. Done by pairing up AlignFrame
3139 * objects (created earlier) which have complementary viewport ids associated.
3141 protected void restoreSplitFrames()
3143 List<SplitFrame> gatherTo = new ArrayList<>();
3144 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3145 Map<String, AlignFrame> dna = new HashMap<>();
3148 * Identify the DNA alignments
3150 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3153 AlignFrame af = candidate.getValue();
3154 if (af.getViewport().getAlignment().isNucleotide())
3156 dna.put(candidate.getKey().getId(), af);
3161 * Try to match up the protein complements
3163 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3166 AlignFrame af = candidate.getValue();
3167 if (!af.getViewport().getAlignment().isNucleotide())
3169 String complementId = candidate.getKey().getComplementId();
3170 // only non-null complements should be in the Map
3171 if (complementId != null && dna.containsKey(complementId))
3173 final AlignFrame dnaFrame = dna.get(complementId);
3174 SplitFrame sf = createSplitFrame(dnaFrame, af);
3175 addedToSplitFrames.add(dnaFrame);
3176 addedToSplitFrames.add(af);
3177 dnaFrame.setMenusForViewport();
3178 af.setMenusForViewport();
3179 if (af.getViewport().isGatherViewsHere())
3188 * Open any that we failed to pair up (which shouldn't happen!) as
3189 * standalone AlignFrame's.
3191 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3194 AlignFrame af = candidate.getValue();
3195 if (!addedToSplitFrames.contains(af))
3197 Viewport view = candidate.getKey();
3198 Desktop.addInternalFrame(af, view.getTitle(),
3199 safeInt(view.getWidth()), safeInt(view.getHeight()));
3200 af.setMenusForViewport();
3201 System.err.println("Failed to restore view " + view.getTitle()
3202 + " to split frame");
3207 * Gather back into tabbed views as flagged.
3209 for (SplitFrame sf : gatherTo)
3211 Desktop.getInstance().gatherViews(sf);
3214 splitFrameCandidates.clear();
3218 * Construct and display one SplitFrame holding DNA and protein alignments.
3221 * @param proteinFrame
3224 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3225 AlignFrame proteinFrame)
3227 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3228 String title = MessageManager.getString("label.linked_view_title");
3229 int width = (int) dnaFrame.getBounds().getWidth();
3230 int height = (int) (dnaFrame.getBounds().getHeight()
3231 + proteinFrame.getBounds().getHeight() + 50);
3234 * SplitFrame location is saved to both enclosed frames
3236 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3237 Desktop.addInternalFrame(splitFrame, title, width, height);
3240 * And compute cDNA consensus (couldn't do earlier with consensus as
3241 * mappings were not yet present)
3243 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3249 * check errorMessage for a valid error message and raise an error box in the
3250 * GUI or write the current errorMessage to stderr and then clear the error
3253 protected void reportErrors()
3255 reportErrors(false);
3258 protected void reportErrors(final boolean saving)
3260 if (errorMessage != null)
3262 final String finalErrorMessage = errorMessage;
3265 javax.swing.SwingUtilities.invokeLater(new Runnable()
3270 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3272 "Error " + (saving ? "saving" : "loading")
3274 JvOptionPane.WARNING_MESSAGE);
3280 System.err.println("Problem loading Jalview file: " + errorMessage);
3283 errorMessage = null;
3286 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3289 * when set, local views will be updated from view stored in JalviewXML
3290 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3291 * sync if this is set to true.
3293 private final boolean updateLocalViews = false;
3296 * Returns the path to a temporary file holding the PDB file for the given PDB
3297 * id. The first time of asking, searches for a file of that name in the
3298 * Jalview project jar, and copies it to a new temporary file. Any repeat
3299 * requests just return the path to the file previously created.
3305 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3308 if (alreadyLoadedPDB.containsKey(pdbId))
3310 return alreadyLoadedPDB.get(pdbId).toString();
3313 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3315 if (tempFile != null)
3317 alreadyLoadedPDB.put(pdbId, tempFile);
3323 * Copies the jar entry of given name to a new temporary file and returns the
3324 * path to the file, or null if the entry is not found.
3327 * @param jarEntryName
3329 * a prefix for the temporary file name, must be at least three
3331 * @param suffixModel
3332 * null or original file - so new file can be given the same suffix
3336 protected String copyJarEntry(jarInputStreamProvider jprovider,
3337 String jarEntryName, String prefix, String suffixModel)
3339 BufferedReader in = null;
3340 PrintWriter out = null;
3341 String suffix = ".tmp";
3342 if (suffixModel == null)
3344 suffixModel = jarEntryName;
3346 int sfpos = suffixModel.lastIndexOf(".");
3347 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3349 suffix = "." + suffixModel.substring(sfpos + 1);
3352 try (JarInputStream jin = jprovider.getJarInputStream())
3354 JarEntry entry = null;
3357 entry = jin.getNextJarEntry();
3358 } while (entry != null && !entry.getName().equals(jarEntryName));
3362 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3363 File outFile = File.createTempFile(prefix, suffix);
3364 outFile.deleteOnExit();
3365 try (OutputStream os = new FileOutputStream(outFile))
3369 String t = outFile.getAbsolutePath();
3375 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3377 } catch (Exception ex)
3379 ex.printStackTrace();
3385 private class JvAnnotRow
3387 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3394 * persisted version of annotation row from which to take vis properties
3396 public jalview.datamodel.AlignmentAnnotation template;
3399 * original position of the annotation row in the alignment
3405 * Load alignment frame from jalview XML DOM object. For a DOM object that
3406 * includes one or more Viewport elements (one with a title that does NOT
3407 * contain "Dataset for"), create the frame.
3409 * @param jalviewModel
3412 * filename source string
3414 * @param loadTreesAndStructures
3415 * when false only create Viewport
3417 * data source provider
3418 * @return alignment frame created from view stored in DOM
3420 AlignFrame loadFromObject(JalviewModel jalviewModel, String fileName,
3421 File file, boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3423 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3424 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3426 // JalviewModelSequence jms = object.getJalviewModelSequence();
3428 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3430 Viewport view = (jalviewModel.getViewport().size() > 0)
3431 ? jalviewModel.getViewport().get(0)
3434 // ////////////////////////////////
3435 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3438 // If we just load in the same jar file again, the sequenceSetId
3439 // will be the same, and we end up with multiple references
3440 // to the same sequenceSet. We must modify this id on load
3441 // so that each load of the file gives a unique id
3444 * used to resolve correct alignment dataset for alignments with multiple
3447 String uniqueSeqSetId = null;
3448 String viewId = null;
3451 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3452 viewId = (view.getId() == null ? null
3453 : view.getId() + uniqueSetSuffix);
3456 // ////////////////////////////////
3459 List<SequenceI> hiddenSeqs = null;
3461 List<SequenceI> tmpseqs = new ArrayList<>();
3463 boolean multipleView = false;
3464 SequenceI referenceseqForView = null;
3465 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3466 List<JSeq> jseqs = jalviewModel.getJSeq();
3467 int vi = 0; // counter in vamsasSeq array
3468 for (int i = 0; i < jseqs.size(); i++)
3470 JSeq jseq = jseqs.get(i);
3471 String seqId = jseq.getId();
3473 SequenceI tmpSeq = seqRefIds.get(seqId);
3476 if (!incompleteSeqs.containsKey(seqId))
3478 // may not need this check, but keep it for at least 2.9,1 release
3479 if (tmpSeq.getStart() != jseq.getStart()
3480 || tmpSeq.getEnd() != jseq.getEnd())
3483 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3484 tmpSeq.getName(), tmpSeq.getStart(),
3485 tmpSeq.getEnd(), jseq.getStart(),
3491 incompleteSeqs.remove(seqId);
3493 if (vamsasSeqs.size() > vi
3494 && vamsasSeqs.get(vi).getId().equals(seqId))
3496 // most likely we are reading a dataset XML document so
3497 // update from vamsasSeq section of XML for this sequence
3498 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3499 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3500 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3505 // reading multiple views, so vamsasSeq set is a subset of JSeq
3506 multipleView = true;
3508 tmpSeq.setStart(jseq.getStart());
3509 tmpSeq.setEnd(jseq.getEnd());
3510 tmpseqs.add(tmpSeq);
3514 Sequence vamsasSeq = vamsasSeqs.get(vi);
3515 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3516 vamsasSeq.getSequence());
3517 tmpSeq.setDescription(vamsasSeq.getDescription());
3518 tmpSeq.setStart(jseq.getStart());
3519 tmpSeq.setEnd(jseq.getEnd());
3520 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3521 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3522 tmpseqs.add(tmpSeq);
3526 if (safeBoolean(jseq.isViewreference()))
3528 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3531 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3533 if (hiddenSeqs == null)
3535 hiddenSeqs = new ArrayList<>();
3538 hiddenSeqs.add(tmpSeq);
3543 // Create the alignment object from the sequence set
3544 // ///////////////////////////////
3545 SequenceI[] orderedSeqs = tmpseqs
3546 .toArray(new SequenceI[tmpseqs.size()]);
3548 AlignmentI al = null;
3549 // so we must create or recover the dataset alignment before going further
3550 // ///////////////////////////////
3551 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3553 // older jalview projects do not have a dataset - so creat alignment and
3555 al = new Alignment(orderedSeqs);
3556 al.setDataset(null);
3560 boolean isdsal = jalviewModel.getViewport().isEmpty();
3563 // we are importing a dataset record, so
3564 // recover reference to an alignment already materialsed as dataset
3565 al = getDatasetFor(vamsasSet.getDatasetId());
3569 // materialse the alignment
3570 al = new Alignment(orderedSeqs);
3574 addDatasetRef(vamsasSet.getDatasetId(), al);
3577 // finally, verify all data in vamsasSet is actually present in al
3578 // passing on flag indicating if it is actually a stored dataset
3579 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3582 if (referenceseqForView != null)
3584 al.setSeqrep(referenceseqForView);
3586 // / Add the alignment properties
3587 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3589 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3591 al.setProperty(ssp.getKey(), ssp.getValue());
3594 // ///////////////////////////////
3596 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3599 // load sequence features, database references and any associated PDB
3600 // structures for the alignment
3602 // prior to 2.10, this part would only be executed the first time a
3603 // sequence was encountered, but not afterwards.
3604 // now, for 2.10 projects, this is also done if the xml doc includes
3605 // dataset sequences not actually present in any particular view.
3607 for (int i = 0; i < vamsasSeqs.size(); i++)
3609 JSeq jseq = jseqs.get(i);
3610 if (jseq.getFeatures().size() > 0)
3612 List<Feature> features = jseq.getFeatures();
3613 for (int f = 0; f < features.size(); f++)
3615 Feature feat = features.get(f);
3616 SequenceFeature sf = new SequenceFeature(feat.getType(),
3617 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3618 safeFloat(feat.getScore()), feat.getFeatureGroup());
3619 sf.setStatus(feat.getStatus());
3622 * load any feature attributes - include map-valued attributes
3624 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3625 for (int od = 0; od < feat.getOtherData().size(); od++)
3627 OtherData keyValue = feat.getOtherData().get(od);
3628 String attributeName = keyValue.getKey();
3629 String attributeValue = keyValue.getValue();
3630 if (attributeName.startsWith("LINK"))
3632 sf.addLink(attributeValue);
3636 String subAttribute = keyValue.getKey2();
3637 if (subAttribute == null)
3639 // simple string-valued attribute
3640 sf.setValue(attributeName, attributeValue);
3644 // attribute 'key' has sub-attribute 'key2'
3645 if (!mapAttributes.containsKey(attributeName))
3647 mapAttributes.put(attributeName, new HashMap<>());
3649 mapAttributes.get(attributeName).put(subAttribute,
3654 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3657 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3660 // adds feature to datasequence's feature set (since Jalview 2.10)
3661 al.getSequenceAt(i).addSequenceFeature(sf);
3664 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3666 // adds dbrefs to datasequence's set (since Jalview 2.10)
3668 al.getSequenceAt(i).getDatasetSequence() == null
3669 ? al.getSequenceAt(i)
3670 : al.getSequenceAt(i).getDatasetSequence(),
3673 if (jseq.getPdbids().size() > 0)
3675 List<Pdbids> ids = jseq.getPdbids();
3676 for (int p = 0; p < ids.size(); p++)
3678 Pdbids pdbid = ids.get(p);
3679 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3680 entry.setId(pdbid.getId());
3681 if (pdbid.getType() != null)
3683 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3685 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3689 entry.setType(PDBEntry.Type.FILE);
3692 // jprovider is null when executing 'New View'
3693 if (pdbid.getFile() != null && jprovider != null)
3695 if (!pdbloaded.containsKey(pdbid.getFile()))
3697 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3702 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3706 if (pdbid.getPdbentryItem() != null)
3708 for (PdbentryItem item : pdbid.getPdbentryItem())
3710 for (Property pr : item.getProperty())
3712 entry.setProperty(pr.getName(), pr.getValue());
3717 for (Property prop : pdbid.getProperty())
3719 entry.setProperty(prop.getName(), prop.getValue());
3721 Desktop.getStructureSelectionManager()
3722 .registerPDBEntry(entry);
3723 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3724 if (al.getSequenceAt(i).getDatasetSequence() != null)
3726 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3730 al.getSequenceAt(i).addPDBId(entry);
3735 * load any HMMER profile
3739 String hmmJarFile = jseqs.get(i).getHmmerProfile();
3740 if (hmmJarFile != null && jprovider != null)
3742 loadHmmerProfile(jprovider, hmmJarFile, al.getSequenceAt(i));
3745 } // end !multipleview
3747 // ///////////////////////////////
3748 // LOAD SEQUENCE MAPPINGS
3750 if (vamsasSet.getAlcodonFrame().size() > 0)
3752 // TODO Potentially this should only be done once for all views of an
3754 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3755 for (int i = 0; i < alc.size(); i++)
3757 AlignedCodonFrame cf = new AlignedCodonFrame();
3758 if (alc.get(i).getAlcodMap().size() > 0)
3760 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3761 for (int m = 0; m < maps.size(); m++)
3763 AlcodMap map = maps.get(m);
3764 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3766 jalview.datamodel.Mapping mapping = null;
3767 // attach to dna sequence reference.
3768 if (map.getMapping() != null)
3770 mapping = addMapping(map.getMapping());
3771 if (dnaseq != null && mapping.getTo() != null)
3773 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3779 newAlcodMapRef(map.getDnasq(), cf, mapping));
3783 al.addCodonFrame(cf);
3788 // ////////////////////////////////
3790 List<JvAnnotRow> autoAlan = new ArrayList<>();
3793 * store any annotations which forward reference a group's ID
3795 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3797 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3799 List<Annotation> an = vamsasSet.getAnnotation();
3801 for (int i = 0; i < an.size(); i++)
3803 Annotation annotation = an.get(i);
3806 * test if annotation is automatically calculated for this view only
3808 boolean autoForView = false;
3809 if (annotation.getLabel().equals("Quality")
3810 || annotation.getLabel().equals("Conservation")
3811 || annotation.getLabel().equals("Consensus"))
3813 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3815 // JAXB has no has() test; schema defaults value to false
3816 // if (!annotation.hasAutoCalculated())
3818 // annotation.setAutoCalculated(true);
3821 if (autoForView || annotation.isAutoCalculated())
3823 // remove ID - we don't recover annotation from other views for
3824 // view-specific annotation
3825 annotation.setId(null);
3828 // set visibility for other annotation in this view
3829 String annotationId = annotation.getId();
3830 if (annotationId != null && annotationIds.containsKey(annotationId))
3832 AlignmentAnnotation jda = annotationIds.get(annotationId);
3833 // in principle Visible should always be true for annotation displayed
3834 // in multiple views
3835 if (annotation.isVisible() != null)
3837 jda.visible = annotation.isVisible();
3840 al.addAnnotation(jda);
3844 // Construct new annotation from model.
3845 List<AnnotationElement> ae = annotation.getAnnotationElement();
3846 jalview.datamodel.Annotation[] anot = null;
3847 java.awt.Color firstColour = null;
3849 if (!annotation.isScoreOnly())
3851 anot = new jalview.datamodel.Annotation[al.getWidth()];
3852 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3854 AnnotationElement annElement = ae.get(aa);
3855 anpos = annElement.getPosition();
3857 if (anpos >= anot.length)
3862 float value = safeFloat(annElement.getValue());
3863 anot[anpos] = new jalview.datamodel.Annotation(
3864 annElement.getDisplayCharacter(),
3865 annElement.getDescription(),
3866 (annElement.getSecondaryStructure() == null
3867 || annElement.getSecondaryStructure()
3871 .getSecondaryStructure()
3874 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3875 if (firstColour == null)
3877 firstColour = anot[anpos].colour;
3881 // create the new AlignmentAnnotation
3882 jalview.datamodel.AlignmentAnnotation jaa = null;
3884 if (annotation.isGraph())
3886 float llim = 0, hlim = 0;
3887 // if (autoForView || an[i].isAutoCalculated()) {
3890 jaa = new jalview.datamodel.AlignmentAnnotation(
3891 annotation.getLabel(), annotation.getDescription(), anot,
3892 llim, hlim, safeInt(annotation.getGraphType()));
3894 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3895 jaa._linecolour = firstColour;
3896 if (annotation.getThresholdLine() != null)
3898 jaa.setThreshold(new jalview.datamodel.GraphLine(
3899 safeFloat(annotation.getThresholdLine().getValue()),
3900 annotation.getThresholdLine().getLabel(),
3901 new java.awt.Color(safeInt(
3902 annotation.getThresholdLine().getColour()))));
3904 if (autoForView || annotation.isAutoCalculated())
3906 // Hardwire the symbol display line to ensure that labels for
3907 // histograms are displayed
3913 jaa = new jalview.datamodel.AlignmentAnnotation(
3914 annotation.getLabel(), annotation.getDescription(), anot);
3915 jaa._linecolour = firstColour;
3917 // register new annotation
3918 // Annotation graphs such as Conservation will not have id.
3919 if (annotation.getId() != null)
3921 annotationIds.put(annotation.getId(), jaa);
3922 jaa.annotationId = annotation.getId();
3924 // recover sequence association
3925 String sequenceRef = annotation.getSequenceRef();
3926 if (sequenceRef != null)
3928 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3929 SequenceI sequence = seqRefIds.get(sequenceRef);
3930 if (sequence == null)
3932 // in pre-2.9 projects sequence ref is to sequence name
3933 sequence = al.findName(sequenceRef);
3935 if (sequence != null)
3937 jaa.createSequenceMapping(sequence, 1, true);
3938 sequence.addAlignmentAnnotation(jaa);
3941 // and make a note of any group association
3942 if (annotation.getGroupRef() != null
3943 && annotation.getGroupRef().length() > 0)
3945 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3946 .get(annotation.getGroupRef());
3949 aal = new ArrayList<>();
3950 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3955 if (annotation.getScore() != null)
3957 jaa.setScore(annotation.getScore().doubleValue());
3959 if (annotation.isVisible() != null)
3961 jaa.visible = annotation.isVisible().booleanValue();
3964 if (annotation.isCentreColLabels() != null)
3966 jaa.centreColLabels = annotation.isCentreColLabels()
3970 if (annotation.isScaleColLabels() != null)
3972 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3974 if (annotation.isAutoCalculated())
3976 // newer files have an 'autoCalculated' flag and store calculation
3977 // state in viewport properties
3978 jaa.autoCalculated = true; // means annotation will be marked for
3979 // update at end of load.
3981 if (annotation.getGraphHeight() != null)
3983 jaa.graphHeight = annotation.getGraphHeight().intValue();
3985 jaa.belowAlignment = annotation.isBelowAlignment();
3986 jaa.setCalcId(annotation.getCalcId());
3987 if (annotation.getProperty().size() > 0)
3989 for (Annotation.Property prop : annotation
3992 jaa.setProperty(prop.getName(), prop.getValue());
3995 if (jaa.autoCalculated)
3997 autoAlan.add(new JvAnnotRow(i, jaa));
4000 // if (!autoForView)
4002 // add autocalculated group annotation and any user created annotation
4004 al.addAnnotation(jaa);
4008 // ///////////////////////
4010 // Create alignment markup and styles for this view
4011 if (jalviewModel.getJGroup().size() > 0)
4013 List<JGroup> groups = jalviewModel.getJGroup();
4014 boolean addAnnotSchemeGroup = false;
4015 for (int i = 0; i < groups.size(); i++)
4017 JGroup jGroup = groups.get(i);
4018 ColourSchemeI cs = null;
4019 if (jGroup.getColour() != null)
4021 if (jGroup.getColour().startsWith("ucs"))
4023 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4025 else if (jGroup.getColour().equals("AnnotationColourGradient")
4026 && jGroup.getAnnotationColours() != null)
4028 addAnnotSchemeGroup = true;
4032 cs = ColourSchemeProperty.getColourScheme(null, al,
4033 jGroup.getColour());
4036 int pidThreshold = safeInt(jGroup.getPidThreshold());
4038 Vector<SequenceI> seqs = new Vector<>();
4040 for (int s = 0; s < jGroup.getSeq().size(); s++)
4042 String seqId = jGroup.getSeq().get(s);
4043 SequenceI ts = seqRefIds.get(seqId);
4047 seqs.addElement(ts);
4051 if (seqs.size() < 1)
4056 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4057 safeBoolean(jGroup.isDisplayBoxes()),
4058 safeBoolean(jGroup.isDisplayText()),
4059 safeBoolean(jGroup.isColourText()),
4060 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4061 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4062 sg.getGroupColourScheme()
4063 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4064 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4066 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4067 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4068 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4069 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4070 // attributes with a default in the schema are never null
4071 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4072 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4073 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4074 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4075 if (jGroup.getConsThreshold() != null
4076 && jGroup.getConsThreshold().intValue() != 0)
4078 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4081 c.verdict(false, 25);
4082 sg.cs.setConservation(c);
4085 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4087 // re-instate unique group/annotation row reference
4088 List<AlignmentAnnotation> jaal = groupAnnotRefs
4089 .get(jGroup.getId());
4092 for (AlignmentAnnotation jaa : jaal)
4095 if (jaa.autoCalculated)
4097 // match up and try to set group autocalc alignment row for this
4099 if (jaa.label.startsWith("Consensus for "))
4101 sg.setConsensus(jaa);
4103 // match up and try to set group autocalc alignment row for this
4105 if (jaa.label.startsWith("Conservation for "))
4107 sg.setConservationRow(jaa);
4114 if (addAnnotSchemeGroup)
4116 // reconstruct the annotation colourscheme
4118 constructAnnotationColour(jGroup.getAnnotationColours(),
4119 null, al, jalviewModel, false));
4125 // only dataset in this model, so just return.
4128 // ///////////////////////////////
4131 // now check to see if we really need to create a new viewport.
4132 if (multipleView && viewportsAdded.size() == 0)
4134 // We recovered an alignment for which a viewport already exists.
4135 // TODO: fix up any settings necessary for overlaying stored state onto
4136 // state recovered from another document. (may not be necessary).
4137 // we may need a binding from a viewport in memory to one recovered from
4139 // and then recover its containing af to allow the settings to be applied.
4140 // TODO: fix for vamsas demo
4142 "About to recover a viewport for existing alignment: Sequence set ID is "
4144 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4145 if (seqsetobj != null)
4147 if (seqsetobj instanceof String)
4149 uniqueSeqSetId = (String) seqsetobj;
4151 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4157 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4163 * indicate that annotation colours are applied across all groups (pre
4164 * Jalview 2.8.1 behaviour)
4166 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4167 jalviewModel.getVersion());
4169 AlignFrame af = null;
4170 AlignmentPanel ap = null;
4171 AlignViewport av = null;
4174 // Check to see if this alignment already has a view id == viewId
4175 jalview.gui.AlignmentPanel views[] = Desktop
4176 .getAlignmentPanels(uniqueSeqSetId);
4177 if (views != null && views.length > 0)
4179 for (int v = 0; v < views.length; v++)
4183 if (av.getViewId().equalsIgnoreCase(viewId))
4185 // recover the existing alignpanel, alignframe, viewport
4188 // TODO: could even skip resetting view settings if we don't want to
4189 // change the local settings from other jalview processes
4197 af = loadViewport(fileName, file, jseqs, hiddenSeqs, al, jalviewModel, view,
4198 uniqueSeqSetId, viewId, autoAlan);
4199 av = af.getViewport();
4200 // note that this only retrieves the most recently accessed
4201 // tab of an AlignFrame.
4206 * Load any trees, PDB structures and viewers
4208 * Not done if flag is false (when this method is used for New View)
4210 final AlignFrame af0 = af;
4211 final AlignViewport av0 = av;
4212 final AlignmentPanel ap0 = ap;
4213 // Platform.timeCheck("Jalview2XML.loadFromObject-beforetree",
4214 // Platform.TIME_MARK);
4215 if (loadTreesAndStructures)
4217 if (!jalviewModel.getTree().isEmpty())
4219 SwingUtilities.invokeLater(new Runnable()
4224 // Platform.timeCheck(null, Platform.TIME_MARK);
4225 loadTrees(jalviewModel, view, af0, av0, ap0);
4226 // Platform.timeCheck("Jalview2XML.loadTrees", Platform.TIME_MARK);
4230 if (!jalviewModel.getPcaViewer().isEmpty())
4232 SwingUtilities.invokeLater(new Runnable()
4237 // Platform.timeCheck(null, Platform.TIME_MARK);
4238 loadPCAViewers(jalviewModel, ap0);
4239 // Platform.timeCheck("Jalview2XML.loadPCA", Platform.TIME_MARK);
4243 SwingUtilities.invokeLater(new Runnable()
4248 // Platform.timeCheck(null, Platform.TIME_MARK);
4249 loadPDBStructures(jprovider, jseqs, af0, ap0);
4250 // Platform.timeCheck("Jalview2XML.loadPDB", Platform.TIME_MARK);
4253 SwingUtilities.invokeLater(new Runnable()
4258 loadRnaViewers(jprovider, jseqs, ap0);
4262 // and finally return.
4263 // but do not set holdRepaint true just yet, because this could be the
4264 // initial frame with just its dataset.
4269 * Loads a HMMER profile from a file stored in the project, and associates it
4270 * with the specified sequence
4276 protected void loadHmmerProfile(jarInputStreamProvider jprovider,
4277 String hmmJarFile, SequenceI seq)
4281 String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
4282 HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
4283 HiddenMarkovModel hmmModel = parser.getHMM();
4284 hmmModel = new HiddenMarkovModel(hmmModel, seq);
4285 seq.setHMM(hmmModel);
4286 } catch (IOException e)
4288 Console.warn("Error loading HMM profile for " + seq.getName() + ": "
4294 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4295 * panel is restored from separate jar entries, two (gapped and trimmed) per
4296 * sequence and secondary structure.
4298 * Currently each viewer shows just one sequence and structure (gapped and
4299 * trimmed), however this method is designed to support multiple sequences or
4300 * structures in viewers if wanted in future.
4306 protected void loadRnaViewers(jarInputStreamProvider jprovider,
4307 List<JSeq> jseqs, AlignmentPanel ap)
4310 * scan the sequences for references to viewers; create each one the first
4311 * time it is referenced, add Rna models to existing viewers
4313 for (JSeq jseq : jseqs)
4315 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4317 RnaViewer viewer = jseq.getRnaViewer().get(i);
4318 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4321 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4323 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4324 SequenceI seq = seqRefIds.get(jseq.getId());
4325 AlignmentAnnotation ann = this.annotationIds
4326 .get(ss.getAnnotationId());
4329 * add the structure to the Varna display (with session state copied
4330 * from the jar to a temporary file)
4332 boolean gapped = safeBoolean(ss.isGapped());
4333 String rnaTitle = ss.getTitle();
4334 String sessionState = ss.getViewerState();
4335 String tempStateFile = copyJarEntry(jprovider, sessionState,
4337 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4338 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4340 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4346 * Locate and return an already instantiated matching AppVarna, or create one
4350 * @param viewIdSuffix
4354 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4355 String viewIdSuffix, AlignmentPanel ap)
4358 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4359 * if load is repeated
4361 String postLoadId = viewer.getViewId() + viewIdSuffix;
4362 for (JInternalFrame frame : getAllFrames())
4364 if (frame instanceof AppVarna)
4366 AppVarna varna = (AppVarna) frame;
4367 if (postLoadId.equals(varna.getViewId()))
4369 // this viewer is already instantiated
4370 // could in future here add ap as another 'parent' of the
4371 // AppVarna window; currently just 1-to-many
4378 * viewer not found - make it
4380 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4381 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4382 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4383 safeInt(viewer.getDividerLocation()));
4384 AppVarna varna = new AppVarna(model, ap);
4390 * Load any saved trees
4398 protected void loadTrees(JalviewModel jm, Viewport view,
4399 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4401 // TODO result of automated refactoring - are all these parameters needed?
4404 for (int t = 0; t < jm.getTree().size(); t++)
4407 Tree tree = jm.getTree().get(t);
4409 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4412 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4413 tree.getTitle(), safeInt(tree.getWidth()),
4414 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4415 safeInt(tree.getYpos()));
4418 Console.warn("There was a problem recovering stored Newick tree: \n"
4419 + tree.getNewick());
4422 if (tree.getId() != null)
4424 // perhaps bind the tree id to something ?
4429 // update local tree attributes ?
4430 // TODO: should check if tp has been manipulated by user - if so its
4431 // settings shouldn't be modified
4432 tp.setTitle(tree.getTitle());
4433 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4434 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4435 safeInt(tree.getHeight())));
4436 tp.setViewport(av); // af.viewport;
4437 // TODO: verify 'associate with all views' works still
4438 tp.getTreeCanvas().setViewport(av); // af.viewport;
4439 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4441 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4443 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4444 tp.fitToWindow_actionPerformed(null);
4446 if (tree.getFontName() != null)
4449 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4450 safeInt(tree.getFontSize())));
4455 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4456 safeInt(view.getFontSize())));
4459 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4460 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4461 tp.showDistances(safeBoolean(tree.isShowDistances()));
4463 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4465 if (safeBoolean(tree.isCurrentTree()))
4467 af.getViewport().setCurrentTree(tp.getTree());
4471 } catch (Exception ex)
4473 ex.printStackTrace();
4478 * Load and link any saved structure viewers.
4485 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4486 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4489 * Run through all PDB ids on the alignment, and collect mappings between
4490 * distinct view ids and all sequences referring to that view.
4492 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4494 for (int i = 0; i < jseqs.size(); i++)
4496 JSeq jseq = jseqs.get(i);
4497 if (jseq.getPdbids().size() > 0)
4499 List<Pdbids> ids = jseq.getPdbids();
4500 for (int p = 0; p < ids.size(); p++)
4502 Pdbids pdbid = ids.get(p);
4503 final int structureStateCount = pdbid.getStructureState().size();
4504 for (int s = 0; s < structureStateCount; s++)
4506 // check to see if we haven't already created this structure view
4507 final StructureState structureState = pdbid
4508 .getStructureState().get(s);
4509 String sviewid = (structureState.getViewId() == null) ? null
4510 : structureState.getViewId() + uniqueSetSuffix;
4511 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4512 // Originally : pdbid.getFile()
4513 // : TODO: verify external PDB file recovery still works in normal
4514 // jalview project load
4516 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4517 jpdb.setId(pdbid.getId());
4519 int x = safeInt(structureState.getXpos());
4520 int y = safeInt(structureState.getYpos());
4521 int width = safeInt(structureState.getWidth());
4522 int height = safeInt(structureState.getHeight());
4524 // Probably don't need to do this anymore...
4525 // Desktop.getDesktop().getComponentAt(x, y);
4526 // TODO: NOW: check that this recovers the PDB file correctly.
4527 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4529 jalview.datamodel.SequenceI seq = seqRefIds
4530 .get(jseq.getId() + "");
4531 if (sviewid == null)
4533 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4536 if (!structureViewers.containsKey(sviewid))
4538 String viewerType = structureState.getType();
4539 if (viewerType == null) // pre Jalview 2.9
4541 viewerType = ViewerType.JMOL.toString();
4543 structureViewers.put(sviewid,
4544 new StructureViewerModel(x, y, width, height, false,
4545 false, true, structureState.getViewId(),
4547 // Legacy pre-2.7 conversion JAL-823 :
4548 // do not assume any view has to be linked for colour by
4552 // assemble String[] { pdb files }, String[] { id for each
4553 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4554 // seqs_file 2}, boolean[] {
4555 // linkAlignPanel,superposeWithAlignpanel}} from hash
4556 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4557 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4558 || structureState.isAlignwithAlignPanel());
4561 * Default colour by linked panel to false if not specified (e.g.
4562 * for pre-2.7 projects)
4564 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4565 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4566 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4569 * Default colour by viewer to true if not specified (e.g. for
4572 boolean colourByViewer = jmoldat.isColourByViewer();
4573 colourByViewer &= structureState.isColourByJmol();
4574 jmoldat.setColourByViewer(colourByViewer);
4576 if (jmoldat.getStateData().length() < structureState
4577 .getValue()/*Content()*/.length())
4579 jmoldat.setStateData(structureState.getValue());// Content());
4581 if (pdbid.getFile() != null)
4583 File mapkey = new File(pdbid.getFile());
4584 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4585 if (seqstrmaps == null)
4587 jmoldat.getFileData().put(mapkey,
4588 seqstrmaps = jmoldat.new StructureData(pdbFile,
4591 if (!seqstrmaps.getSeqList().contains(seq))
4593 seqstrmaps.getSeqList().add(seq);
4599 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");
4600 Console.warn(errorMessage);
4606 // Instantiate the associated structure views
4607 for (Entry<String, StructureViewerModel> entry : structureViewers
4612 createOrLinkStructureViewer(entry, af, ap, jprovider);
4613 } catch (Exception e)
4616 "Error loading structure viewer: " + e.getMessage());
4617 // failed - try the next one
4629 protected void createOrLinkStructureViewer(
4630 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4631 AlignmentPanel ap, jarInputStreamProvider jprovider)
4633 final StructureViewerModel stateData = viewerData.getValue();
4636 * Search for any viewer windows already open from other alignment views
4637 * that exactly match the stored structure state
4639 StructureViewerBase comp = findMatchingViewer(viewerData);
4643 linkStructureViewer(ap, comp, stateData);
4647 String type = stateData.getType();
4650 ViewerType viewerType = ViewerType.valueOf(type);
4651 createStructureViewer(viewerType, viewerData, af, jprovider);
4652 } catch (IllegalArgumentException | NullPointerException e)
4654 // TODO JAL-3619 show error dialog / offer an alternative viewer
4655 Console.error("Invalid structure viewer type: " + type);
4659 * Generates a name for the entry in the project jar file to hold state
4660 * information for a structure viewer
4665 protected String getViewerJarEntryName(String viewId)
4667 return VIEWER_PREFIX + viewId;
4671 * Returns any open frame that matches given structure viewer data. The match
4672 * is based on the unique viewId, or (for older project versions) the frame's
4678 protected StructureViewerBase findMatchingViewer(
4679 Entry<String, StructureViewerModel> viewerData)
4681 final String sviewid = viewerData.getKey();
4682 final StructureViewerModel svattrib = viewerData.getValue();
4683 StructureViewerBase comp = null;
4684 JInternalFrame[] frames = getAllFrames();
4685 for (JInternalFrame frame : frames)
4687 if (frame instanceof StructureViewerBase)
4690 * Post jalview 2.4 schema includes structure view id
4692 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4695 comp = (StructureViewerBase) frame;
4696 break; // break added in 2.9
4699 * Otherwise test for matching position and size of viewer frame
4701 else if (frame.getX() == svattrib.getX()
4702 && frame.getY() == svattrib.getY()
4703 && frame.getHeight() == svattrib.getHeight()
4704 && frame.getWidth() == svattrib.getWidth())
4706 comp = (StructureViewerBase) frame;
4707 // no break in faint hope of an exact match on viewId
4715 * Link an AlignmentPanel to an existing structure viewer.
4720 * @param useinViewerSuperpos
4721 * @param usetoColourbyseq
4722 * @param viewerColouring
4724 protected void linkStructureViewer(AlignmentPanel ap,
4725 StructureViewerBase viewer, StructureViewerModel stateData)
4727 // NOTE: if the jalview project is part of a shared session then
4728 // view synchronization should/could be done here.
4730 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4731 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4732 final boolean viewerColouring = stateData.isColourByViewer();
4733 Map<File, StructureData> oldFiles = stateData.getFileData();
4736 * Add mapping for sequences in this view to an already open viewer
4738 final AAStructureBindingModel binding = viewer.getBinding();
4739 for (File id : oldFiles.keySet())
4741 // add this and any other pdb files that should be present in the
4743 StructureData filedat = oldFiles.get(id);
4744 String pdbFile = filedat.getFilePath();
4745 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4746 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4748 binding.addSequenceForStructFile(pdbFile, seq);
4750 // and add the AlignmentPanel's reference to the view panel
4751 viewer.addAlignmentPanel(ap);
4752 if (useinViewerSuperpos)
4754 viewer.useAlignmentPanelForSuperposition(ap);
4758 viewer.excludeAlignmentPanelForSuperposition(ap);
4760 if (usetoColourbyseq)
4762 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4766 viewer.excludeAlignmentPanelForColourbyseq(ap);
4771 * Get all frames within the Desktop.
4775 protected JInternalFrame[] getAllFrames()
4777 JInternalFrame[] frames = null;
4778 // TODO is this necessary - is it safe - risk of hanging?
4783 frames = Desktop.getDesktopPane().getAllFrames();
4784 } catch (ArrayIndexOutOfBoundsException e)
4786 // occasional No such child exceptions are thrown here...
4790 } catch (InterruptedException f)
4794 } while (frames == null);
4799 * Answers true if 'version' is equal to or later than 'supported', where each
4800 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4801 * changes. Development and test values for 'version' are leniently treated
4805 * - minimum version we are comparing against
4807 * - version of data being processsed
4810 public static boolean isVersionStringLaterThan(String supported,
4813 if (supported == null || version == null
4814 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4815 || version.equalsIgnoreCase("Test")
4816 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4818 System.err.println("Assuming project file with "
4819 + (version == null ? "null" : version)
4820 + " is compatible with Jalview version " + supported);
4825 return StringUtils.compareVersions(version, supported, "b") >= 0;
4829 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4831 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4833 if (newStructureViewers != null)
4835 sview.getBinding().setFinishedLoadingFromArchive(false);
4836 newStructureViewers.add(sview);
4840 protected void setLoadingFinishedForNewStructureViewers()
4842 if (newStructureViewers != null)
4844 for (JalviewStructureDisplayI sview : newStructureViewers)
4846 sview.getBinding().setFinishedLoadingFromArchive(true);
4848 newStructureViewers.clear();
4849 newStructureViewers = null;
4853 AlignFrame loadViewport(String fileName, File file, List<JSeq> JSEQ,
4854 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4855 Viewport view, String uniqueSeqSetId, String viewId,
4856 List<JvAnnotRow> autoAlan)
4858 AlignFrame af = null;
4859 af = new AlignFrame(al, safeInt(view.getWidth()),
4860 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4864 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4865 // System.out.println("Jalview2XML AF " + e);
4866 // super.processKeyEvent(e);
4873 af.alignPanel.setHoldRepaint(true);
4874 af.setFile(fileName, file, null, FileFormat.Jalview);
4875 af.setFileObject(jarFile); // BH 2019 JAL-3436
4877 final AlignViewport viewport = af.getViewport();
4878 for (int i = 0; i < JSEQ.size(); i++)
4880 int colour = safeInt(JSEQ.get(i).getColour());
4881 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4887 viewport.setColourByReferenceSeq(true);
4888 viewport.setDisplayReferenceSeq(true);
4891 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4893 if (view.getSequenceSetId() != null)
4895 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4897 viewport.setSequenceSetId(uniqueSeqSetId);
4900 // propagate shared settings to this new view
4901 viewport.setHistoryList(av.getHistoryList());
4902 viewport.setRedoList(av.getRedoList());
4906 viewportsAdded.put(uniqueSeqSetId, viewport);
4908 // TODO: check if this method can be called repeatedly without
4909 // side-effects if alignpanel already registered.
4910 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4912 // apply Hidden regions to view.
4913 if (hiddenSeqs != null)
4915 for (int s = 0; s < JSEQ.size(); s++)
4917 SequenceGroup hidden = new SequenceGroup();
4918 boolean isRepresentative = false;
4919 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4921 isRepresentative = true;
4922 SequenceI sequenceToHide = al
4923 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4924 hidden.addSequence(sequenceToHide, false);
4925 // remove from hiddenSeqs list so we don't try to hide it twice
4926 hiddenSeqs.remove(sequenceToHide);
4928 if (isRepresentative)
4930 SequenceI representativeSequence = al.getSequenceAt(s);
4931 hidden.addSequence(representativeSequence, false);
4932 viewport.hideRepSequences(representativeSequence, hidden);
4936 SequenceI[] hseqs = hiddenSeqs
4937 .toArray(new SequenceI[hiddenSeqs.size()]);
4938 viewport.hideSequence(hseqs);
4941 // recover view properties and display parameters
4943 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4944 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4945 final int pidThreshold = safeInt(view.getPidThreshold());
4946 viewport.setThreshold(pidThreshold);
4948 viewport.setColourText(safeBoolean(view.isShowColourText()));
4950 viewport.setConservationSelected(
4951 safeBoolean(view.isConservationSelected()));
4952 viewport.setIncrement(safeInt(view.getConsThreshold()));
4953 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4954 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4955 viewport.setFont(new Font(view.getFontName(),
4956 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4958 ViewStyleI vs = viewport.getViewStyle();
4959 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4960 viewport.setViewStyle(vs);
4961 // TODO: allow custom charWidth/Heights to be restored by updating them
4962 // after setting font - which means set above to false
4963 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4964 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4965 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4967 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4969 viewport.setShowText(safeBoolean(view.isShowText()));
4971 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4972 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4973 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4974 viewport.setShowUnconserved(view.isShowUnconserved());
4975 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4977 if (view.getViewName() != null)
4979 viewport.setViewName(view.getViewName());
4980 af.setInitialTabVisible();
4982 int x = safeInt(view.getXpos());
4983 int y = safeInt(view.getYpos());
4984 int w = safeInt(view.getWidth());
4985 int h = safeInt(view.getHeight());
4986 // // BH we cannot let the title bar go off the top
4987 // if (Platform.isJS())
4989 // x = Math.max(50 - w, x);
4990 // y = Math.max(0, y);
4993 af.setBounds(x, y, w, h);
4994 // startSeq set in af.alignPanel.updateLayout below
4995 af.alignPanel.updateLayout();
4996 ColourSchemeI cs = null;
4997 // apply colourschemes
4998 if (view.getBgColour() != null)
5000 if (view.getBgColour().startsWith("ucs"))
5002 cs = getUserColourScheme(jm, view.getBgColour());
5004 else if (view.getBgColour().startsWith("Annotation"))
5006 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5007 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5014 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5015 view.getBgColour());
5020 * turn off 'alignment colour applies to all groups'
5021 * while restoring global colour scheme
5023 viewport.setColourAppliesToAllGroups(false);
5024 viewport.setGlobalColourScheme(cs);
5025 viewport.getResidueShading().setThreshold(pidThreshold,
5026 view.isIgnoreGapsinConsensus());
5027 viewport.getResidueShading()
5028 .setConsensus(viewport.getSequenceConsensusHash());
5029 if (safeBoolean(view.isConservationSelected()) && cs != null)
5031 viewport.getResidueShading()
5032 .setConservationInc(safeInt(view.getConsThreshold()));
5034 af.changeColour(cs);
5035 viewport.setColourAppliesToAllGroups(true);
5037 viewport.setShowSequenceFeatures(
5038 safeBoolean(view.isShowSequenceFeatures()));
5040 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5041 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5042 viewport.setFollowHighlight(view.isFollowHighlight());
5043 viewport.followSelection = view.isFollowSelection();
5044 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5045 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5046 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5047 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5048 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5049 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5050 viewport.setShowGroupConservation(view.isShowGroupConservation());
5051 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5052 viewport.setShowComplementFeaturesOnTop(
5053 view.isShowComplementFeaturesOnTop());
5055 // recover feature settings
5056 if (jm.getFeatureSettings() != null)
5058 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5059 .getFeatureRenderer();
5060 FeaturesDisplayed fdi;
5061 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5062 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5064 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5065 Map<String, Float> featureOrder = new Hashtable<>();
5067 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5070 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5071 String featureType = setting.getType();
5074 * restore feature filters (if any)
5076 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5078 if (filters != null)
5080 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5082 if (!filter.isEmpty())
5084 fr.setFeatureFilter(featureType, filter);
5089 * restore feature colour scheme
5091 Color maxColour = new Color(setting.getColour());
5092 if (setting.getMincolour() != null)
5095 * minColour is always set unless a simple colour
5096 * (including for colour by label though it doesn't use it)
5098 Color minColour = new Color(setting.getMincolour().intValue());
5099 Color noValueColour = minColour;
5100 NoValueColour noColour = setting.getNoValueColour();
5101 if (noColour == NoValueColour.NONE)
5103 noValueColour = null;
5105 else if (noColour == NoValueColour.MAX)
5107 noValueColour = maxColour;
5109 float min = safeFloat(safeFloat(setting.getMin()));
5110 float max = setting.getMax() == null ? 1f
5111 : setting.getMax().floatValue();
5112 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5113 maxColour, noValueColour, min, max);
5114 if (setting.getAttributeName().size() > 0)
5116 gc.setAttributeName(setting.getAttributeName().toArray(
5117 new String[setting.getAttributeName().size()]));
5119 if (setting.getThreshold() != null)
5121 gc.setThreshold(setting.getThreshold().floatValue());
5122 int threshstate = safeInt(setting.getThreshstate());
5123 // -1 = None, 0 = Below, 1 = Above threshold
5124 if (threshstate == 0)
5126 gc.setBelowThreshold(true);
5128 else if (threshstate == 1)
5130 gc.setAboveThreshold(true);
5133 gc.setAutoScaled(true); // default
5134 if (setting.isAutoScale() != null)
5136 gc.setAutoScaled(setting.isAutoScale());
5138 if (setting.isColourByLabel() != null)
5140 gc.setColourByLabel(setting.isColourByLabel());
5142 // and put in the feature colour table.
5143 featureColours.put(featureType, gc);
5147 featureColours.put(featureType, new FeatureColour(maxColour));
5149 renderOrder[fs] = featureType;
5150 if (setting.getOrder() != null)
5152 featureOrder.put(featureType, setting.getOrder().floatValue());
5156 featureOrder.put(featureType, Float.valueOf(
5157 fs / jm.getFeatureSettings().getSetting().size()));
5159 if (safeBoolean(setting.isDisplay()))
5161 fdi.setVisible(featureType);
5164 Map<String, Boolean> fgtable = new Hashtable<>();
5165 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5167 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5168 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5170 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5171 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5172 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5173 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5174 fgtable, featureColours, 1.0f, featureOrder);
5175 fr.transferSettings(frs);
5178 if (view.getHiddenColumns().size() > 0)
5180 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5182 final HiddenColumns hc = view.getHiddenColumns().get(c);
5183 viewport.hideColumns(safeInt(hc.getStart()),
5184 safeInt(hc.getEnd()) /* +1 */);
5187 if (view.getCalcIdParam() != null)
5189 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5191 if (calcIdParam != null)
5193 if (recoverCalcIdParam(calcIdParam, viewport))
5198 Console.warn("Couldn't recover parameters for "
5199 + calcIdParam.getCalcId());
5204 af.setMenusFromViewport(viewport);
5205 af.setTitle(view.getTitle());
5206 // TODO: we don't need to do this if the viewport is aready visible.
5208 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5209 * has a 'cdna/protein complement' view, in which case save it in order to
5210 * populate a SplitFrame once all views have been read in.
5212 String complementaryViewId = view.getComplementId();
5213 if (complementaryViewId == null)
5215 Dimension dim = Platform.getDimIfEmbedded(af,
5216 safeInt(view.getWidth()), safeInt(view.getHeight()));
5217 Desktop.addInternalFrame(af, view.getTitle(), dim.width, dim.height);
5218 // recompute any autoannotation
5219 af.alignPanel.updateAnnotation(false, true);
5220 reorderAutoannotation(af, al, autoAlan);
5221 af.alignPanel.alignmentChanged();
5225 splitFrameCandidates.put(view, af);
5231 * Reads saved data to restore Colour by Annotation settings
5233 * @param viewAnnColour
5237 * @param checkGroupAnnColour
5240 private ColourSchemeI constructAnnotationColour(
5241 AnnotationColourScheme viewAnnColour, AlignFrame af,
5242 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5244 boolean propagateAnnColour = false;
5245 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5247 if (checkGroupAnnColour && al.getGroups() != null
5248 && al.getGroups().size() > 0)
5250 // pre 2.8.1 behaviour
5251 // check to see if we should transfer annotation colours
5252 propagateAnnColour = true;
5253 for (SequenceGroup sg : al.getGroups())
5255 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5257 propagateAnnColour = false;
5263 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5265 String annotationId = viewAnnColour.getAnnotation();
5266 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5269 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5271 if (matchedAnnotation == null
5272 && annAlignment.getAlignmentAnnotation() != null)
5274 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5277 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5279 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5284 if (matchedAnnotation == null)
5286 System.err.println("Failed to match annotation colour scheme for "
5290 if (matchedAnnotation.getThreshold() == null)
5292 matchedAnnotation.setThreshold(
5293 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5294 "Threshold", Color.black));
5297 AnnotationColourGradient cs = null;
5298 if (viewAnnColour.getColourScheme().equals("None"))
5300 cs = new AnnotationColourGradient(matchedAnnotation,
5301 new Color(safeInt(viewAnnColour.getMinColour())),
5302 new Color(safeInt(viewAnnColour.getMaxColour())),
5303 safeInt(viewAnnColour.getAboveThreshold()));
5305 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5307 cs = new AnnotationColourGradient(matchedAnnotation,
5308 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5309 safeInt(viewAnnColour.getAboveThreshold()));
5313 cs = new AnnotationColourGradient(matchedAnnotation,
5314 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5315 viewAnnColour.getColourScheme()),
5316 safeInt(viewAnnColour.getAboveThreshold()));
5319 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5320 boolean useOriginalColours = safeBoolean(
5321 viewAnnColour.isPredefinedColours());
5322 cs.setSeqAssociated(perSequenceOnly);
5323 cs.setPredefinedColours(useOriginalColours);
5325 if (propagateAnnColour && al.getGroups() != null)
5327 // Also use these settings for all the groups
5328 for (int g = 0; g < al.getGroups().size(); g++)
5330 SequenceGroup sg = al.getGroups().get(g);
5331 if (sg.getGroupColourScheme() == null)
5336 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5337 matchedAnnotation, sg.getColourScheme(),
5338 safeInt(viewAnnColour.getAboveThreshold()));
5339 sg.setColourScheme(groupScheme);
5340 groupScheme.setSeqAssociated(perSequenceOnly);
5341 groupScheme.setPredefinedColours(useOriginalColours);
5347 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5348 List<JvAnnotRow> autoAlan)
5350 // copy over visualization settings for autocalculated annotation in the
5352 if (al.getAlignmentAnnotation() != null)
5355 * Kludge for magic autoannotation names (see JAL-811)
5357 String[] magicNames = new String[] { "Consensus", "Quality",
5359 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5360 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5361 for (String nm : magicNames)
5363 visan.put(nm, nullAnnot);
5365 for (JvAnnotRow auan : autoAlan)
5367 visan.put(auan.template.label
5368 + (auan.template.getCalcId() == null ? ""
5369 : "\t" + auan.template.getCalcId()),
5372 int hSize = al.getAlignmentAnnotation().length;
5373 List<JvAnnotRow> reorder = new ArrayList<>();
5374 // work through any autoCalculated annotation already on the view
5375 // removing it if it should be placed in a different location on the
5376 // annotation panel.
5377 List<String> remains = new ArrayList<>(visan.keySet());
5378 for (int h = 0; h < hSize; h++)
5380 jalview.datamodel.AlignmentAnnotation jalan = al
5381 .getAlignmentAnnotation()[h];
5382 if (jalan.autoCalculated)
5385 JvAnnotRow valan = visan.get(k = jalan.label);
5386 if (jalan.getCalcId() != null)
5388 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5393 // delete the auto calculated row from the alignment
5394 al.deleteAnnotation(jalan, false);
5398 if (valan != nullAnnot)
5400 if (jalan != valan.template)
5402 // newly created autoannotation row instance
5403 // so keep a reference to the visible annotation row
5404 // and copy over all relevant attributes
5405 if (valan.template.graphHeight >= 0)
5408 jalan.graphHeight = valan.template.graphHeight;
5410 jalan.visible = valan.template.visible;
5412 reorder.add(new JvAnnotRow(valan.order, jalan));
5417 // Add any (possibly stale) autocalculated rows that were not appended to
5418 // the view during construction
5419 for (String other : remains)
5421 JvAnnotRow othera = visan.get(other);
5422 if (othera != nullAnnot && othera.template.getCalcId() != null
5423 && othera.template.getCalcId().length() > 0)
5425 reorder.add(othera);
5428 // now put the automatic annotation in its correct place
5429 int s = 0, srt[] = new int[reorder.size()];
5430 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5431 for (JvAnnotRow jvar : reorder)
5434 srt[s++] = jvar.order;
5437 jalview.util.QuickSort.sort(srt, rws);
5438 // and re-insert the annotation at its correct position
5439 for (JvAnnotRow jvar : rws)
5441 al.addAnnotation(jvar.template, jvar.order);
5443 af.alignPanel.adjustAnnotationHeight();
5447 Hashtable skipList = null;
5450 * TODO remove this method
5453 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5454 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5455 * throw new Error("Implementation Error. No skipList defined for this
5456 * Jalview2XML instance."); } return (AlignFrame)
5457 * skipList.get(view.getSequenceSetId()); }
5461 * Check if the Jalview view contained in object should be skipped or not.
5464 * @return true if view's sequenceSetId is a key in skipList
5466 private boolean skipViewport(JalviewModel object)
5468 if (skipList == null)
5472 String id = object.getViewport().get(0).getSequenceSetId();
5473 if (skipList.containsKey(id))
5475 Console.debug("Skipping seuqence set id " + id);
5481 protected void addToSkipList(AlignFrame af)
5483 if (skipList == null)
5485 skipList = new Hashtable();
5487 skipList.put(af.getViewport().getSequenceSetId(), af);
5490 protected void clearSkipList()
5492 if (skipList != null)
5499 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5500 boolean ignoreUnrefed, String uniqueSeqSetId)
5502 jalview.datamodel.AlignmentI ds = getDatasetFor(
5503 vamsasSet.getDatasetId());
5504 AlignmentI xtant_ds = ds;
5505 if (xtant_ds == null)
5507 // good chance we are about to create a new dataset, but check if we've
5508 // seen some of the dataset sequence IDs before.
5509 // TODO: skip this check if we are working with project generated by
5510 // version 2.11 or later
5511 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5512 if (xtant_ds != null)
5515 addDatasetRef(vamsasSet.getDatasetId(), ds);
5518 Vector<SequenceI> dseqs = null;
5521 // recovering an alignment View
5522 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5523 if (seqSetDS != null)
5525 if (ds != null && ds != seqSetDS)
5528 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5529 + " - CDS/Protein crossreference data may be lost");
5530 if (xtant_ds != null)
5532 // This can only happen if the unique sequence set ID was bound to a
5533 // dataset that did not contain any of the sequences in the view
5534 // currently being restored.
5536 "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.");
5540 addDatasetRef(vamsasSet.getDatasetId(), ds);
5545 // try even harder to restore dataset
5546 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5547 // create a list of new dataset sequences
5548 dseqs = new Vector<>();
5550 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5552 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5553 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5555 // create a new dataset
5558 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5559 dseqs.copyInto(dsseqs);
5560 ds = new jalview.datamodel.Alignment(dsseqs);
5561 // Console.debug("Jalview2XML Created new dataset " + vamsasSet.getDatasetId()
5562 // + " for alignment " + System.identityHashCode(al));
5563 addDatasetRef(vamsasSet.getDatasetId(), ds);
5565 // set the dataset for the newly imported alignment.
5566 if (al.getDataset() == null && !ignoreUnrefed)
5569 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5570 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5572 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5576 * XML dataset sequence ID to materialised dataset reference
5578 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5581 * @return the first materialised dataset reference containing a dataset
5582 * sequence referenced in the given view
5584 * - sequences from the view
5586 AlignmentI checkIfHasDataset(List<Sequence> list)
5588 for (Sequence restoredSeq : list)
5590 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5591 if (datasetFor != null)
5600 * Register ds as the containing dataset for the dataset sequences referenced
5601 * by sequences in list
5604 * - sequences in a view
5607 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5609 for (Sequence restoredSeq : list)
5611 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5612 if (prevDS != null && prevDS != ds)
5614 Console.warn("Dataset sequence appears in many datasets: "
5615 + restoredSeq.getDsseqid());
5616 // TODO: try to merge!
5624 * sequence definition to create/merge dataset sequence for
5628 * vector to add new dataset sequence to
5629 * @param ignoreUnrefed
5630 * - when true, don't create new sequences from vamsasSeq if it's id
5631 * doesn't already have an asssociated Jalview sequence.
5633 * - used to reorder the sequence in the alignment according to the
5634 * vamsasSeq array ordering, to preserve ordering of dataset
5636 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5637 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5640 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5642 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5643 boolean reorder = false;
5644 SequenceI dsq = null;
5645 if (sq != null && sq.getDatasetSequence() != null)
5647 dsq = sq.getDatasetSequence();
5653 if (sq == null && ignoreUnrefed)
5657 String sqid = vamsasSeq.getDsseqid();
5660 // need to create or add a new dataset sequence reference to this sequence
5663 dsq = seqRefIds.get(sqid);
5668 // make a new dataset sequence
5669 dsq = sq.createDatasetSequence();
5672 // make up a new dataset reference for this sequence
5673 sqid = seqHash(dsq);
5675 dsq.setVamsasId(uniqueSetSuffix + sqid);
5676 seqRefIds.put(sqid, dsq);
5681 dseqs.addElement(dsq);
5686 ds.addSequence(dsq);
5692 { // make this dataset sequence sq's dataset sequence
5693 sq.setDatasetSequence(dsq);
5694 // and update the current dataset alignment
5699 if (!dseqs.contains(dsq))
5706 if (ds.findIndex(dsq) < 0)
5708 ds.addSequence(dsq);
5715 // TODO: refactor this as a merge dataset sequence function
5716 // now check that sq (the dataset sequence) sequence really is the union of
5717 // all references to it
5718 // boolean pre = sq.getStart() < dsq.getStart();
5719 // boolean post = sq.getEnd() > dsq.getEnd();
5723 // StringBuffer sb = new StringBuffer();
5724 String newres = jalview.analysis.AlignSeq.extractGaps(
5725 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5726 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5727 && newres.length() > dsq.getLength())
5729 // Update with the longer sequence.
5733 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5734 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5735 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5736 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5738 dsq.setSequence(newres);
5740 // TODO: merges will never happen if we 'know' we have the real dataset
5741 // sequence - this should be detected when id==dssid
5743 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5744 // + (pre ? "prepended" : "") + " "
5745 // + (post ? "appended" : ""));
5750 // sequence refs are identical. We may need to update the existing dataset
5751 // alignment with this one, though.
5752 if (ds != null && dseqs == null)
5754 int opos = ds.findIndex(dsq);
5755 SequenceI tseq = null;
5756 if (opos != -1 && vseqpos != opos)
5758 // remove from old position
5759 ds.deleteSequence(dsq);
5761 if (vseqpos < ds.getHeight())
5763 if (vseqpos != opos)
5765 // save sequence at destination position
5766 tseq = ds.getSequenceAt(vseqpos);
5767 ds.replaceSequenceAt(vseqpos, dsq);
5768 ds.addSequence(tseq);
5773 ds.addSequence(dsq);
5780 * TODO use AlignmentI here and in related methods - needs
5781 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5783 Hashtable<String, AlignmentI> datasetIds = null;
5785 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5787 private AlignmentI getDatasetFor(String datasetId)
5789 if (datasetIds == null)
5791 datasetIds = new Hashtable<>();
5794 if (datasetIds.containsKey(datasetId))
5796 return datasetIds.get(datasetId);
5801 private void addDatasetRef(String datasetId, AlignmentI dataset)
5803 if (datasetIds == null)
5805 datasetIds = new Hashtable<>();
5807 datasetIds.put(datasetId, dataset);
5811 * make a new dataset ID for this jalview dataset alignment
5816 private String getDatasetIdRef(AlignmentI dataset)
5818 if (dataset.getDataset() != null)
5821 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5823 String datasetId = makeHashCode(dataset, null);
5824 if (datasetId == null)
5826 // make a new datasetId and record it
5827 if (dataset2Ids == null)
5829 dataset2Ids = new IdentityHashMap<>();
5833 datasetId = dataset2Ids.get(dataset);
5835 if (datasetId == null)
5837 datasetId = "ds" + dataset2Ids.size() + 1;
5838 dataset2Ids.put(dataset, datasetId);
5845 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5846 * constructed as a special subclass GeneLocus.
5848 * @param datasetSequence
5851 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5853 for (int d = 0; d < sequence.getDBRef().size(); d++)
5855 DBRef dr = sequence.getDBRef().get(d);
5859 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5860 dr.getAccessionId());
5864 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5865 dr.getAccessionId());
5867 if (dr.getMapping() != null)
5869 entry.setMap(addMapping(dr.getMapping()));
5871 entry.setCanonical(dr.isCanonical());
5872 datasetSequence.addDBRef(entry);
5876 private jalview.datamodel.Mapping addMapping(Mapping m)
5878 SequenceI dsto = null;
5879 // Mapping m = dr.getMapping();
5880 int fr[] = new int[m.getMapListFrom().size() * 2];
5881 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5882 for (int _i = 0; from.hasNext(); _i += 2)
5884 MapListFrom mf = from.next();
5885 fr[_i] = mf.getStart();
5886 fr[_i + 1] = mf.getEnd();
5888 int fto[] = new int[m.getMapListTo().size() * 2];
5889 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5890 for (int _i = 0; to.hasNext(); _i += 2)
5892 MapListTo mf = to.next();
5893 fto[_i] = mf.getStart();
5894 fto[_i + 1] = mf.getEnd();
5896 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5897 fto, m.getMapFromUnit().intValue(),
5898 m.getMapToUnit().intValue());
5901 * (optional) choice of dseqFor or Sequence
5903 if (m.getDseqFor() != null)
5905 String dsfor = m.getDseqFor();
5906 if (seqRefIds.containsKey(dsfor))
5911 jmap.setTo(seqRefIds.get(dsfor));
5915 frefedSequence.add(newMappingRef(dsfor, jmap));
5918 else if (m.getSequence() != null)
5921 * local sequence definition
5923 Sequence ms = m.getSequence();
5924 SequenceI djs = null;
5925 String sqid = ms.getDsseqid();
5926 if (sqid != null && sqid.length() > 0)
5929 * recover dataset sequence
5931 djs = seqRefIds.get(sqid);
5936 "Warning - making up dataset sequence id for DbRef sequence map reference");
5937 sqid = ((Object) ms).toString(); // make up a new hascode for
5938 // undefined dataset sequence hash
5939 // (unlikely to happen)
5945 * make a new dataset sequence and add it to refIds hash
5947 djs = new jalview.datamodel.Sequence(ms.getName(),
5949 djs.setStart(jmap.getMap().getToLowest());
5950 djs.setEnd(jmap.getMap().getToHighest());
5951 djs.setVamsasId(uniqueSetSuffix + sqid);
5953 incompleteSeqs.put(sqid, djs);
5954 seqRefIds.put(sqid, djs);
5957 Console.debug("about to recurse on addDBRefs.");
5966 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5967 * view as XML (but not to file), and then reloading it
5972 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5975 JalviewModel jm = saveState(ap, null, null, null);
5978 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5979 ap.getAlignment().getDataset());
5981 uniqueSetSuffix = "";
5982 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5983 jm.getViewport().get(0).setId(null);
5984 // we don't overwrite the view we just copied
5986 if (this.frefedSequence == null)
5988 frefedSequence = new Vector<>();
5991 viewportsAdded.clear();
5993 AlignFrame af = loadFromObject(jm, null, null, false, null);
5994 af.getAlignPanels().clear();
5995 af.closeMenuItem_actionPerformed(true);
5996 af.alignPanel.setHoldRepaint(false);
5997 this.jarFile = null;
6000 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6001 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6002 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6003 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6004 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6007 return af.alignPanel;
6010 private Hashtable jvids2vobj;
6013 * set the object to ID mapping tables used to write/recover objects and XML
6014 * ID strings for the jalview project. If external tables are provided then
6015 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6016 * object goes out of scope. - also populates the datasetIds hashtable with
6017 * alignment objects containing dataset sequences
6020 * Map from ID strings to jalview datamodel
6022 * Map from jalview datamodel to ID strings
6026 public void setObjectMappingTables(Hashtable vobj2jv,
6027 IdentityHashMap jv2vobj)
6029 this.jv2vobj = jv2vobj;
6030 this.vobj2jv = vobj2jv;
6031 Iterator ds = jv2vobj.keySet().iterator();
6033 while (ds.hasNext())
6035 Object jvobj = ds.next();
6036 id = jv2vobj.get(jvobj).toString();
6037 if (jvobj instanceof jalview.datamodel.Alignment)
6039 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6041 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6044 else if (jvobj instanceof jalview.datamodel.Sequence)
6046 // register sequence object so the XML parser can recover it.
6047 if (seqRefIds == null)
6049 seqRefIds = new HashMap<>();
6051 if (seqsToIds == null)
6053 seqsToIds = new IdentityHashMap<>();
6055 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6056 seqsToIds.put((SequenceI) jvobj, id);
6058 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6061 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6062 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6063 if (jvann.annotationId == null)
6065 jvann.annotationId = anid;
6067 if (!jvann.annotationId.equals(anid))
6069 // TODO verify that this is the correct behaviour
6070 Console.warn("Overriding Annotation ID for " + anid
6071 + " from different id : " + jvann.annotationId);
6072 jvann.annotationId = anid;
6075 else if (jvobj instanceof String)
6077 if (jvids2vobj == null)
6079 jvids2vobj = new Hashtable();
6080 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6085 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6091 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6092 * objects created from the project archive. If string is null (default for
6093 * construction) then suffix will be set automatically.
6097 public void setUniqueSetSuffix(String string)
6099 uniqueSetSuffix = string;
6104 * uses skipList2 as the skipList for skipping views on sequence sets
6105 * associated with keys in the skipList
6109 public void setSkipList(Hashtable skipList2)
6111 skipList = skipList2;
6115 * Reads the jar entry of given name and returns its contents, or null if the
6116 * entry is not found.
6119 * @param jarEntryName
6122 protected String readJarEntry(jarInputStreamProvider jprovider,
6123 String jarEntryName)
6125 String result = null;
6126 BufferedReader in = null;
6131 * Reopen the jar input stream and traverse its entries to find a matching
6134 JarInputStream jin = jprovider.getJarInputStream();
6135 JarEntry entry = null;
6138 entry = jin.getNextJarEntry();
6139 } while (entry != null && !entry.getName().equals(jarEntryName));
6143 StringBuilder out = new StringBuilder(256);
6144 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6147 while ((data = in.readLine()) != null)
6151 result = out.toString();
6156 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6158 } catch (Exception ex)
6160 ex.printStackTrace();
6168 } catch (IOException e)
6179 * Returns an incrementing counter (0, 1, 2...)
6183 private synchronized int nextCounter()
6189 * Loads any saved PCA viewers
6194 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6198 List<PcaViewer> pcaviewers = model.getPcaViewer();
6199 for (PcaViewer viewer : pcaviewers)
6201 String modelName = viewer.getScoreModelName();
6202 SimilarityParamsI params = new SimilarityParams(
6203 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6204 viewer.isIncludeGaps(),
6205 viewer.isDenominateByShortestLength());
6208 * create the panel (without computing the PCA)
6210 PCAPanel panel = new PCAPanel(ap, modelName, params);
6212 panel.setTitle(viewer.getTitle());
6213 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6214 viewer.getWidth(), viewer.getHeight()));
6216 boolean showLabels = viewer.isShowLabels();
6217 panel.setShowLabels(showLabels);
6218 panel.getRotatableCanvas().setShowLabels(showLabels);
6219 panel.getRotatableCanvas()
6220 .setBgColour(new Color(viewer.getBgColour()));
6221 panel.getRotatableCanvas()
6222 .setApplyToAllViews(viewer.isLinkToAllViews());
6225 * load PCA output data
6227 ScoreModelI scoreModel = ScoreModels.getInstance()
6228 .getScoreModel(modelName, ap);
6229 PCA pca = new PCA(null, scoreModel, params);
6230 PcaDataType pcaData = viewer.getPcaData();
6232 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6233 pca.setPairwiseScores(pairwise);
6235 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6236 pca.setTridiagonal(triDiag);
6238 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6239 pca.setEigenmatrix(result);
6241 panel.getPcaModel().setPCA(pca);
6244 * we haven't saved the input data! (JAL-2647 to do)
6246 panel.setInputData(null);
6249 * add the sequence points for the PCA display
6251 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6252 for (SequencePoint sp : viewer.getSequencePoint())
6254 String seqId = sp.getSequenceRef();
6255 SequenceI seq = seqRefIds.get(seqId);
6258 throw new IllegalStateException(
6259 "Unmatched seqref for PCA: " + seqId);
6261 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6262 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6264 seqPoints.add(seqPoint);
6266 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6269 * set min-max ranges and scale after setPoints (which recomputes them)
6271 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6272 SeqPointMin spMin = viewer.getSeqPointMin();
6273 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6275 SeqPointMax spMax = viewer.getSeqPointMax();
6276 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6278 panel.getRotatableCanvas().setSeqMinMax(min, max);
6280 // todo: hold points list in PCAModel only
6281 panel.getPcaModel().setSequencePoints(seqPoints);
6283 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6284 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6285 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6287 // is this duplication needed?
6288 panel.setTop(seqPoints.size() - 1);
6289 panel.getPcaModel().setTop(seqPoints.size() - 1);
6292 * add the axes' end points for the display
6294 for (int i = 0; i < 3; i++)
6296 Axis axis = viewer.getAxis().get(i);
6297 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6298 axis.getXPos(), axis.getYPos(), axis.getZPos());
6301 Dimension dim = Platform.getDimIfEmbedded(panel, 475, 450);
6302 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6303 "label.calc_title", "PCA", modelName), dim.width,
6306 } catch (Exception ex)
6308 Console.error("Error loading PCA: " + ex.toString());
6313 * Creates a new structure viewer window
6320 protected void createStructureViewer(ViewerType viewerType,
6321 final Entry<String, StructureViewerModel> viewerData,
6322 AlignFrame af, jarInputStreamProvider jprovider)
6324 final StructureViewerModel viewerModel = viewerData.getValue();
6325 String sessionFilePath = null;
6327 if (viewerType == ViewerType.JMOL)
6329 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6333 String viewerJarEntryName = getViewerJarEntryName(
6334 viewerModel.getViewId());
6335 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6336 "viewerSession", ".tmp");
6338 final String sessionPath = sessionFilePath;
6339 final String sviewid = viewerData.getKey();
6340 // BH again was invokeAndWait
6343 javax.swing.SwingUtilities.invokeLater(new Runnable()
6348 JalviewStructureDisplayI sview = null;
6351 sview = StructureViewer.createView(viewerType, af.alignPanel,
6352 viewerModel, sessionPath, sviewid);
6353 addNewStructureViewer(sview);
6354 } catch (OutOfMemoryError ex)
6356 new OOMWarning("Restoring structure view for " + viewerType,
6357 (OutOfMemoryError) ex.getCause());
6358 if (sview != null && sview.isVisible())
6360 sview.closeViewer(false);
6361 sview.setVisible(false);
6367 // } catch (InvocationTargetException | InterruptedException ex)
6369 // Console.warn("Unexpected error when opening " + viewerType
6370 // + " structure viewer", ex);
6375 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6376 * the path of the file. "load file" commands are rewritten to change the
6377 * original PDB file names to those created as the Jalview project is loaded.
6383 private String rewriteJmolSession(StructureViewerModel svattrib,
6384 jarInputStreamProvider jprovider)
6386 String state = svattrib.getStateData(); // Jalview < 2.9
6387 if (state == null || state.isEmpty()) // Jalview >= 2.9
6389 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6390 state = readJarEntry(jprovider, jarEntryName);
6392 // TODO or simpler? for each key in oldFiles,
6393 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6394 // (allowing for different path escapings)
6395 StringBuilder rewritten = new StringBuilder(state.length());
6396 int cp = 0, ncp, ecp;
6397 Map<File, StructureData> oldFiles = svattrib.getFileData();
6398 while ((ncp = state.indexOf("load ", cp)) > -1)
6402 // look for next filename in load statement
6403 rewritten.append(state.substring(cp,
6404 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6405 String oldfilenam = state.substring(ncp,
6406 ecp = state.indexOf("\"", ncp));
6407 // recover the new mapping data for this old filename
6408 // have to normalize filename - since Jmol and jalview do
6409 // filename translation differently.
6410 StructureData filedat = oldFiles.get(new File(oldfilenam));
6411 if (filedat == null)
6413 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6414 filedat = oldFiles.get(new File(reformatedOldFilename));
6416 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6417 rewritten.append("\"");
6418 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6419 // look for next file statement.
6420 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6424 // just append rest of state
6425 rewritten.append(state.substring(cp));
6429 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6430 rewritten = new StringBuilder(state);
6431 rewritten.append("; load append ");
6432 for (File id : oldFiles.keySet())
6434 // add pdb files that should be present in the viewer
6435 StructureData filedat = oldFiles.get(id);
6436 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6438 rewritten.append(";");
6441 if (rewritten.length() == 0)
6445 final String history = "history = ";
6446 int historyIndex = rewritten.indexOf(history);
6447 if (historyIndex > -1)
6450 * change "history = [true|false];" to "history = [1|0];"
6452 historyIndex += history.length();
6453 String val = rewritten.substring(historyIndex, historyIndex + 5);
6454 if (val.startsWith("true"))
6456 rewritten.replace(historyIndex, historyIndex + 4, "1");
6458 else if (val.startsWith("false"))
6460 rewritten.replace(historyIndex, historyIndex + 5, "0");
6466 File tmp = File.createTempFile("viewerSession", ".tmp");
6467 try (OutputStream os = new FileOutputStream(tmp))
6469 InputStream is = new ByteArrayInputStream(
6470 rewritten.toString().getBytes());
6472 return tmp.getAbsolutePath();
6474 } catch (IOException e)
6476 Console.error("Error restoring Jmol session: " + e.toString());
6482 * Populates an XML model of the feature colour scheme for one feature type
6484 * @param featureType
6488 public static Colour marshalColour(
6489 String featureType, FeatureColourI fcol)
6491 Colour col = new Colour();
6492 if (fcol.isSimpleColour())
6494 col.setRGB(Format.getHexString(fcol.getColour()));
6498 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6499 col.setMin(fcol.getMin());
6500 col.setMax(fcol.getMax());
6501 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6502 col.setAutoScale(fcol.isAutoScaled());
6503 col.setThreshold(fcol.getThreshold());
6504 col.setColourByLabel(fcol.isColourByLabel());
6505 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6506 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6507 : ThresholdType.NONE));
6508 if (fcol.isColourByAttribute())
6510 final String[] attName = fcol.getAttributeName();
6511 col.getAttributeName().add(attName[0]);
6512 if (attName.length > 1)
6514 col.getAttributeName().add(attName[1]);
6517 Color noColour = fcol.getNoColour();
6518 if (noColour == null)
6520 col.setNoValueColour(NoValueColour.NONE);
6522 else if (noColour == fcol.getMaxColour())
6524 col.setNoValueColour(NoValueColour.MAX);
6528 col.setNoValueColour(NoValueColour.MIN);
6531 col.setName(featureType);
6536 * Populates an XML model of the feature filter(s) for one feature type
6538 * @param firstMatcher
6539 * the first (or only) match condition)
6541 * remaining match conditions (if any)
6543 * if true, conditions are and-ed, else or-ed
6545 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6546 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6549 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6551 if (filters.hasNext())
6556 CompoundMatcher compound = new CompoundMatcher();
6557 compound.setAnd(and);
6558 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6559 firstMatcher, Collections.emptyIterator(), and);
6560 // compound.addMatcherSet(matcher1);
6561 compound.getMatcherSet().add(matcher1);
6562 FeatureMatcherI nextMatcher = filters.next();
6563 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6564 nextMatcher, filters, and);
6565 // compound.addMatcherSet(matcher2);
6566 compound.getMatcherSet().add(matcher2);
6567 result.setCompoundMatcher(compound);
6572 * single condition matcher
6574 // MatchCondition matcherModel = new MatchCondition();
6575 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6576 matcherModel.setCondition(
6577 firstMatcher.getMatcher().getCondition().getStableName());
6578 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6579 if (firstMatcher.isByAttribute())
6581 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6582 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6583 String[] attName = firstMatcher.getAttribute();
6584 matcherModel.getAttributeName().add(attName[0]); // attribute
6585 if (attName.length > 1)
6587 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6590 else if (firstMatcher.isByLabel())
6592 matcherModel.setBy(FilterBy.BY_LABEL);
6594 else if (firstMatcher.isByScore())
6596 matcherModel.setBy(FilterBy.BY_SCORE);
6598 result.setMatchCondition(matcherModel);
6605 * Loads one XML model of a feature filter to a Jalview object
6607 * @param featureType
6608 * @param matcherSetModel
6611 public static FeatureMatcherSetI parseFilter(
6613 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6615 FeatureMatcherSetI result = new FeatureMatcherSet();
6618 parseFilterConditions(result, matcherSetModel, true);
6619 } catch (IllegalStateException e)
6621 // mixing AND and OR conditions perhaps
6623 String.format("Error reading filter conditions for '%s': %s",
6624 featureType, e.getMessage()));
6625 // return as much as was parsed up to the error
6632 * Adds feature match conditions to matcherSet as unmarshalled from XML
6633 * (possibly recursively for compound conditions)
6636 * @param matcherSetModel
6638 * if true, multiple conditions are AND-ed, else they are OR-ed
6639 * @throws IllegalStateException
6640 * if AND and OR conditions are mixed
6642 protected static void parseFilterConditions(
6643 FeatureMatcherSetI matcherSet,
6644 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6647 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6648 .getMatchCondition();
6654 FilterBy filterBy = mc.getBy();
6655 Condition cond = Condition.fromString(mc.getCondition());
6656 String pattern = mc.getValue();
6657 FeatureMatcherI matchCondition = null;
6658 if (filterBy == FilterBy.BY_LABEL)
6660 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6662 else if (filterBy == FilterBy.BY_SCORE)
6664 matchCondition = FeatureMatcher.byScore(cond, pattern);
6667 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6669 final List<String> attributeName = mc.getAttributeName();
6670 String[] attNames = attributeName
6671 .toArray(new String[attributeName.size()]);
6672 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6677 * note this throws IllegalStateException if AND-ing to a
6678 * previously OR-ed compound condition, or vice versa
6682 matcherSet.and(matchCondition);
6686 matcherSet.or(matchCondition);
6692 * compound condition
6694 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6695 .getCompoundMatcher().getMatcherSet();
6696 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6697 if (matchers.size() == 2)
6699 parseFilterConditions(matcherSet, matchers.get(0), anded);
6700 parseFilterConditions(matcherSet, matchers.get(1), anded);
6704 System.err.println("Malformed compound filter condition");
6710 * Loads one XML model of a feature colour to a Jalview object
6712 * @param colourModel
6715 public static FeatureColourI parseColour(Colour colourModel)
6717 FeatureColourI colour = null;
6719 if (colourModel.getMax() != null)
6721 Color mincol = null;
6722 Color maxcol = null;
6723 Color noValueColour = null;
6727 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6728 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6729 } catch (Exception e)
6731 Console.warn("Couldn't parse out graduated feature color.", e);
6734 NoValueColour noCol = colourModel.getNoValueColour();
6735 if (noCol == NoValueColour.MIN)
6737 noValueColour = mincol;
6739 else if (noCol == NoValueColour.MAX)
6741 noValueColour = maxcol;
6744 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6745 safeFloat(colourModel.getMin()),
6746 safeFloat(colourModel.getMax()));
6747 final List<String> attributeName = colourModel.getAttributeName();
6748 String[] attributes = attributeName
6749 .toArray(new String[attributeName.size()]);
6750 if (attributes != null && attributes.length > 0)
6752 colour.setAttributeName(attributes);
6754 if (colourModel.isAutoScale() != null)
6756 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6758 if (colourModel.isColourByLabel() != null)
6760 colour.setColourByLabel(
6761 colourModel.isColourByLabel().booleanValue());
6763 if (colourModel.getThreshold() != null)
6765 colour.setThreshold(colourModel.getThreshold().floatValue());
6767 ThresholdType ttyp = colourModel.getThreshType();
6768 if (ttyp == ThresholdType.ABOVE)
6770 colour.setAboveThreshold(true);
6772 else if (ttyp == ThresholdType.BELOW)
6774 colour.setBelowThreshold(true);
6779 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6780 colour = new FeatureColour(color);