2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Enumeration;
49 import java.util.GregorianCalendar;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Hashtable;
53 import java.util.IdentityHashMap;
54 import java.util.Iterator;
55 import java.util.LinkedHashMap;
56 import java.util.List;
57 import java.util.Locale;
59 import java.util.Map.Entry;
61 import java.util.Vector;
62 import java.util.jar.JarEntry;
63 import java.util.jar.JarInputStream;
64 import java.util.jar.JarOutputStream;
66 import javax.swing.JInternalFrame;
67 import javax.swing.SwingUtilities;
68 import javax.xml.bind.JAXBContext;
69 import javax.xml.bind.JAXBElement;
70 import javax.xml.bind.Marshaller;
71 import javax.xml.datatype.DatatypeConfigurationException;
72 import javax.xml.datatype.DatatypeFactory;
73 import javax.xml.datatype.XMLGregorianCalendar;
74 import javax.xml.stream.XMLInputFactory;
75 import javax.xml.stream.XMLStreamReader;
77 import jalview.analysis.Conservation;
78 import jalview.analysis.PCA;
79 import jalview.analysis.scoremodels.ScoreModels;
80 import jalview.analysis.scoremodels.SimilarityParams;
81 import jalview.api.FeatureColourI;
82 import jalview.api.ViewStyleI;
83 import jalview.api.analysis.ScoreModelI;
84 import jalview.api.analysis.SimilarityParamsI;
85 import jalview.api.structures.JalviewStructureDisplayI;
86 import jalview.bin.Cache;
87 import jalview.bin.Console;
88 import jalview.datamodel.AlignedCodonFrame;
89 import jalview.datamodel.Alignment;
90 import jalview.datamodel.AlignmentAnnotation;
91 import jalview.datamodel.AlignmentI;
92 import jalview.datamodel.DBRefEntry;
93 import jalview.datamodel.GeneLocus;
94 import jalview.datamodel.GraphLine;
95 import jalview.datamodel.PDBEntry;
96 import jalview.datamodel.Point;
97 import jalview.datamodel.RnaViewerModel;
98 import jalview.datamodel.SequenceFeature;
99 import jalview.datamodel.SequenceGroup;
100 import jalview.datamodel.SequenceI;
101 import jalview.datamodel.StructureViewerModel;
102 import jalview.datamodel.StructureViewerModel.StructureData;
103 import jalview.datamodel.features.FeatureMatcher;
104 import jalview.datamodel.features.FeatureMatcherI;
105 import jalview.datamodel.features.FeatureMatcherSet;
106 import jalview.datamodel.features.FeatureMatcherSetI;
107 import jalview.ext.archaeopteryx.AptxInit;
108 import jalview.ext.treeviewer.TreeFrameI;
109 import jalview.ext.treeviewer.TreeI;
110 import jalview.ext.treeviewer.TreeViewerUtils;
111 import jalview.ext.varna.RnaModel;
112 import jalview.gui.AlignFrame;
113 import jalview.gui.AlignViewport;
114 import jalview.gui.AlignmentPanel;
115 import jalview.gui.AppVarna;
116 import jalview.gui.Desktop;
117 import jalview.gui.JvOptionPane;
118 import jalview.gui.OOMWarning;
119 import jalview.gui.PCAPanel;
120 import jalview.gui.PaintRefresher;
121 import jalview.gui.SplitFrame;
122 import jalview.gui.StructureViewer;
123 import jalview.gui.StructureViewer.ViewerType;
124 import jalview.gui.StructureViewerBase;
125 import jalview.gui.TreePanel;
126 import jalview.io.BackupFiles;
127 import jalview.io.DataSourceType;
128 import jalview.io.FileFormat;
129 import jalview.io.NewickFile;
130 import jalview.math.Matrix;
131 import jalview.math.MatrixI;
132 import jalview.renderer.ResidueShaderI;
133 import jalview.schemes.AnnotationColourGradient;
134 import jalview.schemes.ColourSchemeI;
135 import jalview.schemes.ColourSchemeProperty;
136 import jalview.schemes.FeatureColour;
137 import jalview.schemes.ResidueProperties;
138 import jalview.schemes.UserColourScheme;
139 import jalview.structure.StructureSelectionManager;
140 import jalview.structures.models.AAStructureBindingModel;
141 import jalview.util.Format;
142 import jalview.util.HttpUtils;
143 import jalview.util.MessageManager;
144 import jalview.util.Platform;
145 import jalview.util.StringUtils;
146 import jalview.util.jarInputStreamProvider;
147 import jalview.util.matcher.Condition;
148 import jalview.viewmodel.AlignmentViewport;
149 import jalview.viewmodel.PCAModel;
150 import jalview.viewmodel.ViewportRanges;
151 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
152 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
153 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
154 import jalview.ws.jws2.Jws2Discoverer;
155 import jalview.ws.jws2.dm.AAConSettings;
156 import jalview.ws.jws2.jabaws2.Jws2Instance;
157 import jalview.ws.params.ArgumentI;
158 import jalview.ws.params.AutoCalcSetting;
159 import jalview.ws.params.WsParamSetI;
160 import jalview.xml.binding.jalview.AlcodonFrame;
161 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
162 import jalview.xml.binding.jalview.Annotation;
163 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
164 import jalview.xml.binding.jalview.AnnotationColourScheme;
165 import jalview.xml.binding.jalview.AnnotationElement;
166 import jalview.xml.binding.jalview.DoubleMatrix;
167 import jalview.xml.binding.jalview.DoubleVector;
168 import jalview.xml.binding.jalview.Feature;
169 import jalview.xml.binding.jalview.Feature.OtherData;
170 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
171 import jalview.xml.binding.jalview.FilterBy;
172 import jalview.xml.binding.jalview.JalviewModel;
173 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
174 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
175 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
176 import jalview.xml.binding.jalview.JalviewModel.JGroup;
177 import jalview.xml.binding.jalview.JalviewModel.JSeq;
178 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
179 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
180 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
181 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
182 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
183 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
184 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
185 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
186 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
187 import jalview.xml.binding.jalview.JalviewModel.Tree;
188 import jalview.xml.binding.jalview.JalviewModel.UserColours;
189 import jalview.xml.binding.jalview.JalviewModel.Viewport;
190 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
191 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
192 import jalview.xml.binding.jalview.JalviewUserColours;
193 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
194 import jalview.xml.binding.jalview.MapListType.MapListFrom;
195 import jalview.xml.binding.jalview.MapListType.MapListTo;
196 import jalview.xml.binding.jalview.Mapping;
197 import jalview.xml.binding.jalview.NoValueColour;
198 import jalview.xml.binding.jalview.ObjectFactory;
199 import jalview.xml.binding.jalview.PcaDataType;
200 import jalview.xml.binding.jalview.Pdbentry.Property;
201 import jalview.xml.binding.jalview.Sequence;
202 import jalview.xml.binding.jalview.Sequence.DBRef;
203 import jalview.xml.binding.jalview.SequenceSet;
204 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
205 import jalview.xml.binding.jalview.ThresholdType;
206 import jalview.xml.binding.jalview.VAMSAS;
209 * Write out the current jalview desktop state as a Jalview XML stream.
211 * Note: the vamsas objects referred to here are primitive versions of the
212 * VAMSAS project schema elements - they are not the same and most likely never
216 * @version $Revision: 1.134 $
218 public class Jalview2XML
221 // BH 2018 we add the .jvp binary extension to J2S so that
222 // it will declare that binary when we do the file save from the browser
226 Platform.addJ2SBinaryType(".jvp?");
229 private static final String VIEWER_PREFIX = "viewer_";
231 private static final String RNA_PREFIX = "rna_";
233 private static final String UTF_8 = "UTF-8";
236 * prefix for recovering datasets for alignments with multiple views where
237 * non-existent dataset IDs were written for some views
239 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
241 // use this with nextCounter() to make unique names for entities
242 private int counter = 0;
245 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
246 * of sequence objects are created.
248 IdentityHashMap<SequenceI, String> seqsToIds = null;
251 * jalview XML Sequence ID to jalview sequence object reference (both dataset
252 * and alignment sequences. Populated as XML reps of sequence objects are
255 Map<String, SequenceI> seqRefIds = null;
257 Map<String, SequenceI> incompleteSeqs = null;
259 List<SeqFref> frefedSequence = null;
261 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
264 * Map of reconstructed AlignFrame objects that appear to have come from
265 * SplitFrame objects (have a dna/protein complement view).
267 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
270 * Map from displayed rna structure models to their saved session state jar
273 private Map<RnaModel, String> rnaSessions = new HashMap<>();
276 * A helper method for safely using the value of an optional attribute that
277 * may be null if not present in the XML. Answers the boolean value, or false
283 public static boolean safeBoolean(Boolean b)
285 return b == null ? false : b.booleanValue();
289 * A helper method for safely using the value of an optional attribute that
290 * may be null if not present in the XML. Answers the integer value, or zero
296 public static int safeInt(Integer i)
298 return i == null ? 0 : i.intValue();
302 * A helper method for safely using the value of an optional attribute that
303 * may be null if not present in the XML. Answers the float value, or zero if
309 public static float safeFloat(Float f)
311 return f == null ? 0f : f.floatValue();
315 * create/return unique hash string for sq
318 * @return new or existing unique string for sq
320 String seqHash(SequenceI sq)
322 if (seqsToIds == null)
326 if (seqsToIds.containsKey(sq))
328 return seqsToIds.get(sq);
332 // create sequential key
333 String key = "sq" + (seqsToIds.size() + 1);
334 key = makeHashCode(sq, key); // check we don't have an external reference
336 seqsToIds.put(sq, key);
343 if (seqsToIds == null)
345 seqsToIds = new IdentityHashMap<>();
347 if (seqRefIds == null)
349 seqRefIds = new HashMap<>();
351 if (incompleteSeqs == null)
353 incompleteSeqs = new HashMap<>();
355 if (frefedSequence == null)
357 frefedSequence = new ArrayList<>();
365 public Jalview2XML(boolean raiseGUI)
367 this.raiseGUI = raiseGUI;
371 * base class for resolving forward references to sequences by their ID
376 abstract class SeqFref
382 public SeqFref(String _sref, String type)
388 public String getSref()
393 public SequenceI getSrefSeq()
395 return seqRefIds.get(sref);
398 public boolean isResolvable()
400 return seqRefIds.get(sref) != null;
403 public SequenceI getSrefDatasetSeq()
405 SequenceI sq = seqRefIds.get(sref);
408 while (sq.getDatasetSequence() != null)
410 sq = sq.getDatasetSequence();
417 * @return true if the forward reference was fully resolved
419 abstract boolean resolve();
422 public String toString()
424 return type + " reference to " + sref;
429 * create forward reference for a mapping
435 public SeqFref newMappingRef(final String sref,
436 final jalview.datamodel.Mapping _jmap)
438 SeqFref fref = new SeqFref(sref, "Mapping")
440 public jalview.datamodel.Mapping jmap = _jmap;
445 SequenceI seq = getSrefDatasetSeq();
457 public SeqFref newAlcodMapRef(final String sref,
458 final AlignedCodonFrame _cf,
459 final jalview.datamodel.Mapping _jmap)
462 SeqFref fref = new SeqFref(sref, "Codon Frame")
464 AlignedCodonFrame cf = _cf;
466 public jalview.datamodel.Mapping mp = _jmap;
469 public boolean isResolvable()
471 return super.isResolvable() && mp.getTo() != null;
477 SequenceI seq = getSrefDatasetSeq();
482 cf.addMap(seq, mp.getTo(), mp.getMap());
489 public void resolveFrefedSequences()
491 Iterator<SeqFref> nextFref = frefedSequence.iterator();
492 int toresolve = frefedSequence.size();
493 int unresolved = 0, failedtoresolve = 0;
494 while (nextFref.hasNext())
496 SeqFref ref = nextFref.next();
497 if (ref.isResolvable())
509 } catch (Exception x)
512 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
525 System.err.println("Jalview Project Import: There were " + unresolved
526 + " forward references left unresolved on the stack.");
528 if (failedtoresolve > 0)
530 System.err.println("SERIOUS! " + failedtoresolve
531 + " resolvable forward references failed to resolve.");
533 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
536 "Jalview Project Import: There are " + incompleteSeqs.size()
537 + " sequences which may have incomplete metadata.");
538 if (incompleteSeqs.size() < 10)
540 for (SequenceI s : incompleteSeqs.values())
542 System.err.println(s.toString());
548 "Too many to report. Skipping output of incomplete sequences.");
554 * This maintains a map of viewports, the key being the seqSetId. Important to
555 * set historyItem and redoList for multiple views
557 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
559 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
561 String uniqueSetSuffix = "";
564 * List of pdbfiles added to Jar
566 List<String> pdbfiles = null;
568 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
569 public void saveState(File statefile)
571 FileOutputStream fos = null;
576 fos = new FileOutputStream(statefile);
578 JarOutputStream jout = new JarOutputStream(fos);
582 } catch (Exception e)
584 Console.error("Couln't write Jalview state to " + statefile, e);
585 // TODO: inform user of the problem - they need to know if their data was
587 if (errorMessage == null)
589 errorMessage = "Did't write Jalview Archive to output file '"
590 + statefile + "' - See console error log for details";
594 errorMessage += "(Didn't write Jalview Archive to output file '"
605 } catch (IOException e)
615 * Writes a jalview project archive to the given Jar output stream.
619 public void saveState(JarOutputStream jout)
621 AlignFrame[] frames = Desktop.getAlignFrames();
627 saveAllFrames(Arrays.asList(frames), jout);
631 * core method for storing state for a set of AlignFrames.
634 * - frames involving all data to be exported (including containing
637 * - project output stream
639 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
641 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
644 * ensure cached data is clear before starting
646 // todo tidy up seqRefIds, seqsToIds initialisation / reset
648 splitFrameCandidates.clear();
653 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
654 // //////////////////////////////////////////////////
656 List<String> shortNames = new ArrayList<>();
657 List<String> viewIds = new ArrayList<>();
660 for (int i = frames.size() - 1; i > -1; i--)
662 AlignFrame af = frames.get(i);
664 if (skipList != null && skipList
665 .containsKey(af.getViewport().getSequenceSetId()))
670 String shortName = makeFilename(af, shortNames);
672 int apSize = af.getAlignPanels().size();
674 for (int ap = 0; ap < apSize; ap++)
676 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
678 String fileName = apSize == 1 ? shortName : ap + shortName;
679 if (!fileName.endsWith(".xml"))
681 fileName = fileName + ".xml";
684 saveState(apanel, fileName, jout, viewIds);
686 String dssid = getDatasetIdRef(
687 af.getViewport().getAlignment().getDataset());
688 if (!dsses.containsKey(dssid))
690 dsses.put(dssid, af);
695 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
701 } catch (Exception foo)
705 } catch (Exception ex)
707 // TODO: inform user of the problem - they need to know if their data was
709 if (errorMessage == null)
711 errorMessage = "Couldn't write Jalview Archive - see error output for details";
713 ex.printStackTrace();
718 * Generates a distinct file name, based on the title of the AlignFrame, by
719 * appending _n for increasing n until an unused name is generated. The new
720 * name (without its extension) is added to the list.
724 * @return the generated name, with .xml extension
726 protected String makeFilename(AlignFrame af, List<String> namesUsed)
728 String shortName = af.getTitle();
730 if (shortName.indexOf(File.separatorChar) > -1)
732 shortName = shortName
733 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
738 while (namesUsed.contains(shortName))
740 if (shortName.endsWith("_" + (count - 1)))
742 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
745 shortName = shortName.concat("_" + count);
749 namesUsed.add(shortName);
751 if (!shortName.endsWith(".xml"))
753 shortName = shortName + ".xml";
758 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
759 public boolean saveAlignment(AlignFrame af, String jarFile,
764 // create backupfiles object and get new temp filename destination
765 boolean doBackup = BackupFiles.getEnabled();
766 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
767 FileOutputStream fos = new FileOutputStream(
768 doBackup ? backupfiles.getTempFilePath() : jarFile);
770 JarOutputStream jout = new JarOutputStream(fos);
771 List<AlignFrame> frames = new ArrayList<>();
773 // resolve splitframes
774 if (af.getViewport().getCodingComplement() != null)
776 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
782 saveAllFrames(frames, jout);
786 } catch (Exception foo)
790 boolean success = true;
794 backupfiles.setWriteSuccess(success);
795 success = backupfiles.rollBackupsAndRenameTempFile();
799 } catch (Exception ex)
801 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
802 ex.printStackTrace();
807 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
808 String fileName, JarOutputStream jout)
811 for (String dssids : dsses.keySet())
813 AlignFrame _af = dsses.get(dssids);
814 String jfileName = fileName + " Dataset for " + _af.getTitle();
815 if (!jfileName.endsWith(".xml"))
817 jfileName = jfileName + ".xml";
819 saveState(_af.alignPanel, jfileName, true, jout, null);
824 * create a JalviewModel from an alignment view and marshall it to a
828 * panel to create jalview model for
830 * name of alignment panel written to output stream
837 public JalviewModel saveState(AlignmentPanel ap, String fileName,
838 JarOutputStream jout, List<String> viewIds)
840 return saveState(ap, fileName, false, jout, viewIds);
844 * create a JalviewModel from an alignment view and marshall it to a
848 * panel to create jalview model for
850 * name of alignment panel written to output stream
852 * when true, only write the dataset for the alignment, not the data
853 * associated with the view.
859 public JalviewModel saveState(AlignmentPanel ap, String fileName,
860 boolean storeDS, JarOutputStream jout, List<String> viewIds)
864 viewIds = new ArrayList<>();
869 List<UserColourScheme> userColours = new ArrayList<>();
871 AlignViewport av = ap.av;
872 ViewportRanges vpRanges = av.getRanges();
874 final ObjectFactory objectFactory = new ObjectFactory();
875 JalviewModel object = objectFactory.createJalviewModel();
876 object.setVamsasModel(new VAMSAS());
878 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
881 GregorianCalendar c = new GregorianCalendar();
882 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
883 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
884 object.setCreationDate(now);
885 } catch (DatatypeConfigurationException e)
887 System.err.println("error writing date: " + e.toString());
889 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
892 * rjal is full height alignment, jal is actual alignment with full metadata
893 * but excludes hidden sequences.
895 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
897 if (av.hasHiddenRows())
899 rjal = jal.getHiddenSequences().getFullAlignment();
902 SequenceSet vamsasSet = new SequenceSet();
904 // JalviewModelSequence jms = new JalviewModelSequence();
906 vamsasSet.setGapChar(jal.getGapCharacter() + "");
908 if (jal.getDataset() != null)
910 // dataset id is the dataset's hashcode
911 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
914 // switch jal and the dataset
915 jal = jal.getDataset();
919 if (jal.getProperties() != null)
921 Enumeration en = jal.getProperties().keys();
922 while (en.hasMoreElements())
924 String key = en.nextElement().toString();
925 SequenceSetProperties ssp = new SequenceSetProperties();
927 ssp.setValue(jal.getProperties().get(key).toString());
928 // vamsasSet.addSequenceSetProperties(ssp);
929 vamsasSet.getSequenceSetProperties().add(ssp);
934 Set<String> calcIdSet = new HashSet<>();
935 // record the set of vamsas sequence XML POJO we create.
936 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
938 for (final SequenceI jds : rjal.getSequences())
940 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
941 : jds.getDatasetSequence();
942 String id = seqHash(jds);
943 if (vamsasSetIds.get(id) == null)
945 if (seqRefIds.get(id) != null && !storeDS)
947 // This happens for two reasons: 1. multiple views are being
949 // 2. the hashCode has collided with another sequence's code. This
951 // HAPPEN! (PF00072.15.stk does this)
952 // JBPNote: Uncomment to debug writing out of files that do not read
953 // back in due to ArrayOutOfBoundExceptions.
954 // System.err.println("vamsasSeq backref: "+id+"");
955 // System.err.println(jds.getName()+"
956 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
957 // System.err.println("Hashcode: "+seqHash(jds));
958 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
959 // System.err.println(rsq.getName()+"
960 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
961 // System.err.println("Hashcode: "+seqHash(rsq));
965 vamsasSeq = createVamsasSequence(id, jds);
966 // vamsasSet.addSequence(vamsasSeq);
967 vamsasSet.getSequence().add(vamsasSeq);
968 vamsasSetIds.put(id, vamsasSeq);
969 seqRefIds.put(id, jds);
973 jseq.setStart(jds.getStart());
974 jseq.setEnd(jds.getEnd());
975 jseq.setColour(av.getSequenceColour(jds).getRGB());
977 jseq.setId(id); // jseq id should be a string not a number
980 // Store any sequences this sequence represents
981 if (av.hasHiddenRows())
983 // use rjal, contains the full height alignment
985 av.getAlignment().getHiddenSequences().isHidden(jds));
987 if (av.isHiddenRepSequence(jds))
989 jalview.datamodel.SequenceI[] reps = av
990 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
992 for (int h = 0; h < reps.length; h++)
996 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
997 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1002 // mark sequence as reference - if it is the reference for this view
1003 if (jal.hasSeqrep())
1005 jseq.setViewreference(jds == jal.getSeqrep());
1009 // TODO: omit sequence features from each alignment view's XML dump if we
1010 // are storing dataset
1011 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1012 for (SequenceFeature sf : sfs)
1014 // Features features = new Features();
1015 Feature features = new Feature();
1017 features.setBegin(sf.getBegin());
1018 features.setEnd(sf.getEnd());
1019 features.setDescription(sf.getDescription());
1020 features.setType(sf.getType());
1021 features.setFeatureGroup(sf.getFeatureGroup());
1022 features.setScore(sf.getScore());
1023 if (sf.links != null)
1025 for (int l = 0; l < sf.links.size(); l++)
1027 OtherData keyValue = new OtherData();
1028 keyValue.setKey("LINK_" + l);
1029 keyValue.setValue(sf.links.elementAt(l).toString());
1030 // features.addOtherData(keyValue);
1031 features.getOtherData().add(keyValue);
1034 if (sf.otherDetails != null)
1037 * save feature attributes, which may be simple strings or
1038 * map valued (have sub-attributes)
1040 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1042 String key = entry.getKey();
1043 Object value = entry.getValue();
1044 if (value instanceof Map<?, ?>)
1046 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1049 OtherData otherData = new OtherData();
1050 otherData.setKey(key);
1051 otherData.setKey2(subAttribute.getKey());
1052 otherData.setValue(subAttribute.getValue().toString());
1053 // features.addOtherData(otherData);
1054 features.getOtherData().add(otherData);
1059 OtherData otherData = new OtherData();
1060 otherData.setKey(key);
1061 otherData.setValue(value.toString());
1062 // features.addOtherData(otherData);
1063 features.getOtherData().add(otherData);
1068 // jseq.addFeatures(features);
1069 jseq.getFeatures().add(features);
1072 if (jdatasq.getAllPDBEntries() != null)
1074 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1075 while (en.hasMoreElements())
1077 Pdbids pdb = new Pdbids();
1078 jalview.datamodel.PDBEntry entry = en.nextElement();
1080 String pdbId = entry.getId();
1082 pdb.setType(entry.getType());
1085 * Store any structure views associated with this sequence. This
1086 * section copes with duplicate entries in the project, so a dataset
1087 * only view *should* be coped with sensibly.
1089 // This must have been loaded, is it still visible?
1090 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1091 String matchedFile = null;
1092 for (int f = frames.length - 1; f > -1; f--)
1094 if (frames[f] instanceof StructureViewerBase)
1096 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1097 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1098 viewIds, matchedFile, viewFrame);
1100 * Only store each structure viewer's state once in the project
1101 * jar. First time through only (storeDS==false)
1103 String viewId = viewFrame.getViewId();
1104 String viewerType = viewFrame.getViewerType().toString();
1105 if (!storeDS && !viewIds.contains(viewId))
1107 viewIds.add(viewId);
1108 File viewerState = viewFrame.saveSession();
1109 if (viewerState != null)
1111 copyFileToJar(jout, viewerState.getPath(),
1112 getViewerJarEntryName(viewId), viewerType);
1117 "Failed to save viewer state for " + viewerType);
1123 if (matchedFile != null || entry.getFile() != null)
1125 if (entry.getFile() != null)
1128 matchedFile = entry.getFile();
1130 pdb.setFile(matchedFile); // entry.getFile());
1131 if (pdbfiles == null)
1133 pdbfiles = new ArrayList<>();
1136 if (!pdbfiles.contains(pdbId))
1138 pdbfiles.add(pdbId);
1139 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1143 Enumeration<String> props = entry.getProperties();
1144 if (props.hasMoreElements())
1146 // PdbentryItem item = new PdbentryItem();
1147 while (props.hasMoreElements())
1149 Property prop = new Property();
1150 String key = props.nextElement();
1152 prop.setValue(entry.getProperty(key).toString());
1153 // item.addProperty(prop);
1154 pdb.getProperty().add(prop);
1156 // pdb.addPdbentryItem(item);
1159 // jseq.addPdbids(pdb);
1160 jseq.getPdbids().add(pdb);
1164 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1166 // jms.addJSeq(jseq);
1167 object.getJSeq().add(jseq);
1170 if (!storeDS && av.hasHiddenRows())
1172 jal = av.getAlignment();
1176 if (storeDS && jal.getCodonFrames() != null)
1178 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1179 for (AlignedCodonFrame acf : jac)
1181 AlcodonFrame alc = new AlcodonFrame();
1182 if (acf.getProtMappings() != null
1183 && acf.getProtMappings().length > 0)
1185 boolean hasMap = false;
1186 SequenceI[] dnas = acf.getdnaSeqs();
1187 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1188 for (int m = 0; m < pmaps.length; m++)
1190 AlcodMap alcmap = new AlcodMap();
1191 alcmap.setDnasq(seqHash(dnas[m]));
1193 createVamsasMapping(pmaps[m], dnas[m], null, false));
1194 // alc.addAlcodMap(alcmap);
1195 alc.getAlcodMap().add(alcmap);
1200 // vamsasSet.addAlcodonFrame(alc);
1201 vamsasSet.getAlcodonFrame().add(alc);
1204 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1206 // AlcodonFrame alc = new AlcodonFrame();
1207 // vamsasSet.addAlcodonFrame(alc);
1208 // for (int p = 0; p < acf.aaWidth; p++)
1210 // Alcodon cmap = new Alcodon();
1211 // if (acf.codons[p] != null)
1213 // // Null codons indicate a gapped column in the translated peptide
1215 // cmap.setPos1(acf.codons[p][0]);
1216 // cmap.setPos2(acf.codons[p][1]);
1217 // cmap.setPos3(acf.codons[p][2]);
1219 // alc.addAlcodon(cmap);
1221 // if (acf.getProtMappings() != null
1222 // && acf.getProtMappings().length > 0)
1224 // SequenceI[] dnas = acf.getdnaSeqs();
1225 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1226 // for (int m = 0; m < pmaps.length; m++)
1228 // AlcodMap alcmap = new AlcodMap();
1229 // alcmap.setDnasq(seqHash(dnas[m]));
1230 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1232 // alc.addAlcodMap(alcmap);
1239 // /////////////////////////////////
1240 if (!storeDS && av.getCurrentTree() != null)
1242 // FIND ANY ASSOCIATED TREES
1243 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1244 if (Desktop.desktop != null)
1246 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1248 for (int t = 0; t < frames.length; t++)
1250 if (frames[t] instanceof TreePanel)
1252 TreePanel tp = (TreePanel) frames[t];
1254 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1256 JalviewModel.Tree tree = new JalviewModel.Tree();
1257 tree.setTitle(tp.getTitle());
1258 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1259 tree.setNewick(tp.getTree().print());
1260 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1262 tree.setFitToWindow(tp.fitToWindow.getState());
1263 tree.setFontName(tp.getTreeFont().getName());
1264 tree.setFontSize(tp.getTreeFont().getSize());
1265 tree.setFontStyle(tp.getTreeFont().getStyle());
1266 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1268 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1269 tree.setShowDistances(tp.distanceMenu.getState());
1271 tree.setHeight(tp.getHeight());
1272 tree.setWidth(tp.getWidth());
1273 tree.setXpos(tp.getX());
1274 tree.setYpos(tp.getY());
1275 tree.setId(makeHashCode(tp, null));
1276 tree.setLinkToAllViews(
1277 tp.getTreeCanvas().isApplyToAllViews());
1279 // jms.addTree(tree);
1280 object.getTree().add(tree);
1287 if (!storeDS && av.getCurrentExtTree() != null)
1289 Set<TreeFrameI> externalTreeViews = TreeViewerUtils
1290 .getActiveTreeViews()
1292 for (TreeFrameI treeView : externalTreeViews)
1294 TreeI tree = treeView.getTree();
1297 tree.outputAsFile(new File("word"));
1298 copyFileToJar(jout, "word", "aptx-test","Archeopteryx Tree Session");
1301 } catch (IOException e)
1303 // TODO Auto-generated catch block
1304 e.printStackTrace();
1316 if (!storeDS && Desktop.desktop != null)
1318 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1320 if (frame instanceof PCAPanel)
1322 PCAPanel panel = (PCAPanel) frame;
1323 if (panel.getAlignViewport().getAlignment() == jal)
1325 savePCA(panel, object);
1333 * store forward refs from an annotationRow to any groups
1335 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1338 for (SequenceI sq : jal.getSequences())
1340 // Store annotation on dataset sequences only
1341 AlignmentAnnotation[] aa = sq.getAnnotation();
1342 if (aa != null && aa.length > 0)
1344 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1351 if (jal.getAlignmentAnnotation() != null)
1353 // Store the annotation shown on the alignment.
1354 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1355 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1360 if (jal.getGroups() != null)
1362 JGroup[] groups = new JGroup[jal.getGroups().size()];
1364 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1366 JGroup jGroup = new JGroup();
1367 groups[++i] = jGroup;
1369 jGroup.setStart(sg.getStartRes());
1370 jGroup.setEnd(sg.getEndRes());
1371 jGroup.setName(sg.getName());
1372 if (groupRefs.containsKey(sg))
1374 // group has references so set its ID field
1375 jGroup.setId(groupRefs.get(sg));
1377 ColourSchemeI colourScheme = sg.getColourScheme();
1378 if (colourScheme != null)
1380 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1381 if (groupColourScheme.conservationApplied())
1383 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1385 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1387 jGroup.setColour(setUserColourScheme(colourScheme,
1388 userColours, object));
1392 jGroup.setColour(colourScheme.getSchemeName());
1395 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1397 jGroup.setColour("AnnotationColourGradient");
1398 jGroup.setAnnotationColours(constructAnnotationColours(
1399 (jalview.schemes.AnnotationColourGradient) colourScheme,
1400 userColours, object));
1402 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1405 setUserColourScheme(colourScheme, userColours, object));
1409 jGroup.setColour(colourScheme.getSchemeName());
1412 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1415 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1416 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1417 jGroup.setDisplayText(sg.getDisplayText());
1418 jGroup.setColourText(sg.getColourText());
1419 jGroup.setTextCol1(sg.textColour.getRGB());
1420 jGroup.setTextCol2(sg.textColour2.getRGB());
1421 jGroup.setTextColThreshold(sg.thresholdTextColour);
1422 jGroup.setShowUnconserved(sg.getShowNonconserved());
1423 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1424 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1425 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1426 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1427 for (SequenceI seq : sg.getSequences())
1429 // jGroup.addSeq(seqHash(seq));
1430 jGroup.getSeq().add(seqHash(seq));
1434 // jms.setJGroup(groups);
1436 for (JGroup grp : groups)
1438 object.getJGroup().add(grp);
1443 // /////////SAVE VIEWPORT
1444 Viewport view = new Viewport();
1445 view.setTitle(ap.alignFrame.getTitle());
1446 view.setSequenceSetId(
1447 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1448 view.setId(av.getViewId());
1449 if (av.getCodingComplement() != null)
1451 view.setComplementId(av.getCodingComplement().getViewId());
1453 view.setViewName(av.getViewName());
1454 view.setGatheredViews(av.isGatherViewsHere());
1456 Rectangle size = ap.av.getExplodedGeometry();
1457 Rectangle position = size;
1460 size = ap.alignFrame.getBounds();
1461 if (av.getCodingComplement() != null)
1463 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1471 view.setXpos(position.x);
1472 view.setYpos(position.y);
1474 view.setWidth(size.width);
1475 view.setHeight(size.height);
1477 view.setStartRes(vpRanges.getStartRes());
1478 view.setStartSeq(vpRanges.getStartSeq());
1480 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1482 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1483 userColours, object));
1486 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1488 AnnotationColourScheme ac = constructAnnotationColours(
1489 (jalview.schemes.AnnotationColourGradient) av
1490 .getGlobalColourScheme(),
1491 userColours, object);
1493 view.setAnnotationColours(ac);
1494 view.setBgColour("AnnotationColourGradient");
1498 view.setBgColour(ColourSchemeProperty
1499 .getColourName(av.getGlobalColourScheme()));
1502 ResidueShaderI vcs = av.getResidueShading();
1503 ColourSchemeI cs = av.getGlobalColourScheme();
1507 if (vcs.conservationApplied())
1509 view.setConsThreshold(vcs.getConservationInc());
1510 if (cs instanceof jalview.schemes.UserColourScheme)
1512 view.setBgColour(setUserColourScheme(cs, userColours, object));
1515 view.setPidThreshold(vcs.getThreshold());
1518 view.setConservationSelected(av.getConservationSelected());
1519 view.setPidSelected(av.getAbovePIDThreshold());
1520 final Font font = av.getFont();
1521 view.setFontName(font.getName());
1522 view.setFontSize(font.getSize());
1523 view.setFontStyle(font.getStyle());
1524 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1525 view.setRenderGaps(av.isRenderGaps());
1526 view.setShowAnnotation(av.isShowAnnotation());
1527 view.setShowBoxes(av.getShowBoxes());
1528 view.setShowColourText(av.getColourText());
1529 view.setShowFullId(av.getShowJVSuffix());
1530 view.setRightAlignIds(av.isRightAlignIds());
1531 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1532 view.setShowText(av.getShowText());
1533 view.setShowUnconserved(av.getShowUnconserved());
1534 view.setWrapAlignment(av.getWrapAlignment());
1535 view.setTextCol1(av.getTextColour().getRGB());
1536 view.setTextCol2(av.getTextColour2().getRGB());
1537 view.setTextColThreshold(av.getThresholdTextColour());
1538 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1539 view.setShowSequenceLogo(av.isShowSequenceLogo());
1540 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1541 view.setShowGroupConsensus(av.isShowGroupConsensus());
1542 view.setShowGroupConservation(av.isShowGroupConservation());
1543 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1544 view.setShowDbRefTooltip(av.isShowDBRefs());
1545 view.setFollowHighlight(av.isFollowHighlight());
1546 view.setFollowSelection(av.followSelection);
1547 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1548 view.setShowComplementFeatures(av.isShowComplementFeatures());
1549 view.setShowComplementFeaturesOnTop(
1550 av.isShowComplementFeaturesOnTop());
1551 if (av.getFeaturesDisplayed() != null)
1553 FeatureSettings fs = new FeatureSettings();
1555 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1556 .getFeatureRenderer();
1557 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1559 Vector<String> settingsAdded = new Vector<>();
1560 if (renderOrder != null)
1562 for (String featureType : renderOrder)
1564 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1565 setting.setType(featureType);
1568 * save any filter for the feature type
1570 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1573 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1575 FeatureMatcherI firstFilter = filters.next();
1576 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1577 filters, filter.isAnded()));
1581 * save colour scheme for the feature type
1583 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1584 if (!fcol.isSimpleColour())
1586 setting.setColour(fcol.getMaxColour().getRGB());
1587 setting.setMincolour(fcol.getMinColour().getRGB());
1588 setting.setMin(fcol.getMin());
1589 setting.setMax(fcol.getMax());
1590 setting.setColourByLabel(fcol.isColourByLabel());
1591 if (fcol.isColourByAttribute())
1593 String[] attName = fcol.getAttributeName();
1594 setting.getAttributeName().add(attName[0]);
1595 if (attName.length > 1)
1597 setting.getAttributeName().add(attName[1]);
1600 setting.setAutoScale(fcol.isAutoScaled());
1601 setting.setThreshold(fcol.getThreshold());
1602 Color noColour = fcol.getNoColour();
1603 if (noColour == null)
1605 setting.setNoValueColour(NoValueColour.NONE);
1607 else if (noColour.equals(fcol.getMaxColour()))
1609 setting.setNoValueColour(NoValueColour.MAX);
1613 setting.setNoValueColour(NoValueColour.MIN);
1615 // -1 = No threshold, 0 = Below, 1 = Above
1616 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1617 : (fcol.isBelowThreshold() ? 0 : -1));
1621 setting.setColour(fcol.getColour().getRGB());
1625 av.getFeaturesDisplayed().isVisible(featureType));
1626 float rorder = fr.getOrder(featureType);
1629 setting.setOrder(rorder);
1631 /// fs.addSetting(setting);
1632 fs.getSetting().add(setting);
1633 settingsAdded.addElement(featureType);
1637 // is groups actually supposed to be a map here ?
1638 Iterator<String> en = fr.getFeatureGroups().iterator();
1639 Vector<String> groupsAdded = new Vector<>();
1640 while (en.hasNext())
1642 String grp = en.next();
1643 if (groupsAdded.contains(grp))
1647 Group g = new Group();
1649 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1652 fs.getGroup().add(g);
1653 groupsAdded.addElement(grp);
1655 // jms.setFeatureSettings(fs);
1656 object.setFeatureSettings(fs);
1659 if (av.hasHiddenColumns())
1661 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1662 .getHiddenColumns();
1666 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1670 Iterator<int[]> hiddenRegions = hidden.iterator();
1671 while (hiddenRegions.hasNext())
1673 int[] region = hiddenRegions.next();
1674 HiddenColumns hc = new HiddenColumns();
1675 hc.setStart(region[0]);
1676 hc.setEnd(region[1]);
1677 // view.addHiddenColumns(hc);
1678 view.getHiddenColumns().add(hc);
1682 if (calcIdSet.size() > 0)
1684 for (String calcId : calcIdSet)
1686 if (calcId.trim().length() > 0)
1688 CalcIdParam cidp = createCalcIdParam(calcId, av);
1689 // Some calcIds have no parameters.
1692 // view.addCalcIdParam(cidp);
1693 view.getCalcIdParam().add(cidp);
1699 // jms.addViewport(view);
1700 object.getViewport().add(view);
1702 // object.setJalviewModelSequence(jms);
1703 // object.getVamsasModel().addSequenceSet(vamsasSet);
1704 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1706 if (jout != null && fileName != null)
1708 // We may not want to write the object to disk,
1709 // eg we can copy the alignViewport to a new view object
1710 // using save and then load
1713 fileName = fileName.replace('\\', '/');
1714 System.out.println("Writing jar entry " + fileName);
1715 JarEntry entry = new JarEntry(fileName);
1716 jout.putNextEntry(entry);
1717 PrintWriter pout = new PrintWriter(
1718 new OutputStreamWriter(jout, UTF_8));
1719 JAXBContext jaxbContext = JAXBContext
1720 .newInstance(JalviewModel.class);
1721 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1723 // output pretty printed
1724 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1725 jaxbMarshaller.marshal(
1726 new ObjectFactory().createJalviewModel(object), pout);
1728 // jaxbMarshaller.marshal(object, pout);
1729 // marshaller.marshal(object);
1732 } catch (Exception ex)
1734 // TODO: raise error in GUI if marshalling failed.
1735 System.err.println("Error writing Jalview project");
1736 ex.printStackTrace();
1743 * Writes PCA viewer attributes and computed values to an XML model object and
1744 * adds it to the JalviewModel. Any exceptions are reported by logging.
1746 protected void savePCA(PCAPanel panel, JalviewModel object)
1750 PcaViewer viewer = new PcaViewer();
1751 viewer.setHeight(panel.getHeight());
1752 viewer.setWidth(panel.getWidth());
1753 viewer.setXpos(panel.getX());
1754 viewer.setYpos(panel.getY());
1755 viewer.setTitle(panel.getTitle());
1756 PCAModel pcaModel = panel.getPcaModel();
1757 viewer.setScoreModelName(pcaModel.getScoreModelName());
1758 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1759 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1760 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1762 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1763 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1764 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1765 SeqPointMin spmin = new SeqPointMin();
1766 spmin.setXPos(spMin[0]);
1767 spmin.setYPos(spMin[1]);
1768 spmin.setZPos(spMin[2]);
1769 viewer.setSeqPointMin(spmin);
1770 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1771 SeqPointMax spmax = new SeqPointMax();
1772 spmax.setXPos(spMax[0]);
1773 spmax.setYPos(spMax[1]);
1774 spmax.setZPos(spMax[2]);
1775 viewer.setSeqPointMax(spmax);
1776 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1777 viewer.setLinkToAllViews(
1778 panel.getRotatableCanvas().isApplyToAllViews());
1779 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1780 viewer.setIncludeGaps(sp.includeGaps());
1781 viewer.setMatchGaps(sp.matchGaps());
1782 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1783 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1786 * sequence points on display
1788 for (jalview.datamodel.SequencePoint spt : pcaModel
1789 .getSequencePoints())
1791 SequencePoint point = new SequencePoint();
1792 point.setSequenceRef(seqHash(spt.getSequence()));
1793 point.setXPos(spt.coord.x);
1794 point.setYPos(spt.coord.y);
1795 point.setZPos(spt.coord.z);
1796 viewer.getSequencePoint().add(point);
1800 * (end points of) axes on display
1802 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1805 Axis axis = new Axis();
1809 viewer.getAxis().add(axis);
1813 * raw PCA data (note we are not restoring PCA inputs here -
1814 * alignment view, score model, similarity parameters)
1816 PcaDataType data = new PcaDataType();
1817 viewer.setPcaData(data);
1818 PCA pca = pcaModel.getPcaData();
1820 DoubleMatrix pm = new DoubleMatrix();
1821 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1822 data.setPairwiseMatrix(pm);
1824 DoubleMatrix tm = new DoubleMatrix();
1825 saveDoubleMatrix(pca.getTridiagonal(), tm);
1826 data.setTridiagonalMatrix(tm);
1828 DoubleMatrix eigenMatrix = new DoubleMatrix();
1829 data.setEigenMatrix(eigenMatrix);
1830 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1832 object.getPcaViewer().add(viewer);
1833 } catch (Throwable t)
1835 Console.error("Error saving PCA: " + t.getMessage());
1840 * Stores values from a matrix into an XML element, including (if present) the
1845 * @see #loadDoubleMatrix(DoubleMatrix)
1847 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1849 xmlMatrix.setRows(m.height());
1850 xmlMatrix.setColumns(m.width());
1851 for (int i = 0; i < m.height(); i++)
1853 DoubleVector row = new DoubleVector();
1854 for (int j = 0; j < m.width(); j++)
1856 row.getV().add(m.getValue(i, j));
1858 xmlMatrix.getRow().add(row);
1860 if (m.getD() != null)
1862 DoubleVector dVector = new DoubleVector();
1863 for (double d : m.getD())
1865 dVector.getV().add(d);
1867 xmlMatrix.setD(dVector);
1869 if (m.getE() != null)
1871 DoubleVector eVector = new DoubleVector();
1872 for (double e : m.getE())
1874 eVector.getV().add(e);
1876 xmlMatrix.setE(eVector);
1881 * Loads XML matrix data into a new Matrix object, including the D and/or E
1882 * vectors (if present)
1886 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1888 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1890 int rows = mData.getRows();
1891 double[][] vals = new double[rows][];
1893 for (int i = 0; i < rows; i++)
1895 List<Double> dVector = mData.getRow().get(i).getV();
1896 vals[i] = new double[dVector.size()];
1898 for (Double d : dVector)
1904 MatrixI m = new Matrix(vals);
1906 if (mData.getD() != null)
1908 List<Double> dVector = mData.getD().getV();
1909 double[] vec = new double[dVector.size()];
1911 for (Double d : dVector)
1917 if (mData.getE() != null)
1919 List<Double> dVector = mData.getE().getV();
1920 double[] vec = new double[dVector.size()];
1922 for (Double d : dVector)
1933 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1934 * for each viewer, with
1936 * <li>viewer geometry (position, size, split pane divider location)</li>
1937 * <li>index of the selected structure in the viewer (currently shows gapped
1939 * <li>the id of the annotation holding RNA secondary structure</li>
1940 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1942 * Varna viewer state is also written out (in native Varna XML) to separate
1943 * project jar entries. A separate entry is written for each RNA structure
1944 * displayed, with the naming convention
1946 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1954 * @param storeDataset
1956 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1957 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1958 boolean storeDataset)
1960 if (Desktop.desktop == null)
1964 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1965 for (int f = frames.length - 1; f > -1; f--)
1967 if (frames[f] instanceof AppVarna)
1969 AppVarna varna = (AppVarna) frames[f];
1971 * link the sequence to every viewer that is showing it and is linked to
1972 * its alignment panel
1974 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1976 String viewId = varna.getViewId();
1977 RnaViewer rna = new RnaViewer();
1978 rna.setViewId(viewId);
1979 rna.setTitle(varna.getTitle());
1980 rna.setXpos(varna.getX());
1981 rna.setYpos(varna.getY());
1982 rna.setWidth(varna.getWidth());
1983 rna.setHeight(varna.getHeight());
1984 rna.setDividerLocation(varna.getDividerLocation());
1985 rna.setSelectedRna(varna.getSelectedIndex());
1986 // jseq.addRnaViewer(rna);
1987 jseq.getRnaViewer().add(rna);
1990 * Store each Varna panel's state once in the project per sequence.
1991 * First time through only (storeDataset==false)
1993 // boolean storeSessions = false;
1994 // String sequenceViewId = viewId + seqsToIds.get(jds);
1995 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1997 // viewIds.add(sequenceViewId);
1998 // storeSessions = true;
2000 for (RnaModel model : varna.getModels())
2002 if (model.seq == jds)
2005 * VARNA saves each view (sequence or alignment secondary
2006 * structure, gapped or trimmed) as a separate XML file
2008 String jarEntryName = rnaSessions.get(model);
2009 if (jarEntryName == null)
2012 String varnaStateFile = varna.getStateInfo(model.rna);
2013 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2014 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2015 rnaSessions.put(model, jarEntryName);
2017 SecondaryStructure ss = new SecondaryStructure();
2018 String annotationId = varna.getAnnotation(jds).annotationId;
2019 ss.setAnnotationId(annotationId);
2020 ss.setViewerState(jarEntryName);
2021 ss.setGapped(model.gapped);
2022 ss.setTitle(model.title);
2023 // rna.addSecondaryStructure(ss);
2024 rna.getSecondaryStructure().add(ss);
2033 * Copy the contents of a file to a new entry added to the output jar
2037 * @param jarEntryName
2039 * additional identifying info to log to the console
2041 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2042 String jarEntryName, String msg)
2044 try (InputStream is = new FileInputStream(infilePath))
2046 File file = new File(infilePath);
2047 if (file.exists() && jout != null)
2050 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2051 jout.putNextEntry(new JarEntry(jarEntryName));
2054 // dis = new DataInputStream(new FileInputStream(file));
2055 // byte[] data = new byte[(int) file.length()];
2056 // dis.readFully(data);
2057 // writeJarEntry(jout, jarEntryName, data);
2059 } catch (Exception ex)
2061 ex.printStackTrace();
2066 * Copies input to output, in 4K buffers; handles any data (text or binary)
2070 * @throws IOException
2072 protected void copyAll(InputStream in, OutputStream out)
2075 byte[] buffer = new byte[4096];
2077 while ((bytesRead = in.read(buffer)) != -1)
2079 out.write(buffer, 0, bytesRead);
2084 * Save the state of a structure viewer
2089 * the archive XML element under which to save the state
2092 * @param matchedFile
2096 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2097 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2098 String matchedFile, StructureViewerBase viewFrame)
2100 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2103 * Look for any bindings for this viewer to the PDB file of interest
2104 * (including part matches excluding chain id)
2106 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2108 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2109 final String pdbId = pdbentry.getId();
2110 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2111 && entry.getId().toLowerCase(Locale.ROOT)
2112 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2115 * not interested in a binding to a different PDB entry here
2119 if (matchedFile == null)
2121 matchedFile = pdbentry.getFile();
2123 else if (!matchedFile.equals(pdbentry.getFile()))
2126 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2127 + pdbentry.getFile());
2131 // can get at it if the ID
2132 // match is ambiguous (e.g.
2135 for (int smap = 0; smap < viewFrame.getBinding()
2136 .getSequence()[peid].length; smap++)
2138 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2139 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2141 StructureState state = new StructureState();
2142 state.setVisible(true);
2143 state.setXpos(viewFrame.getX());
2144 state.setYpos(viewFrame.getY());
2145 state.setWidth(viewFrame.getWidth());
2146 state.setHeight(viewFrame.getHeight());
2147 final String viewId = viewFrame.getViewId();
2148 state.setViewId(viewId);
2149 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2150 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2151 state.setColourByJmol(viewFrame.isColouredByViewer());
2152 state.setType(viewFrame.getViewerType().toString());
2153 // pdb.addStructureState(state);
2154 pdb.getStructureState().add(state);
2162 * Populates the AnnotationColourScheme xml for save. This captures the
2163 * settings of the options in the 'Colour by Annotation' dialog.
2166 * @param userColours
2170 private AnnotationColourScheme constructAnnotationColours(
2171 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2174 AnnotationColourScheme ac = new AnnotationColourScheme();
2175 ac.setAboveThreshold(acg.getAboveThreshold());
2176 ac.setThreshold(acg.getAnnotationThreshold());
2177 // 2.10.2 save annotationId (unique) not annotation label
2178 ac.setAnnotation(acg.getAnnotation().annotationId);
2179 if (acg.getBaseColour() instanceof UserColourScheme)
2182 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2187 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2190 ac.setMaxColour(acg.getMaxColour().getRGB());
2191 ac.setMinColour(acg.getMinColour().getRGB());
2192 ac.setPerSequence(acg.isSeqAssociated());
2193 ac.setPredefinedColours(acg.isPredefinedColours());
2197 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2198 IdentityHashMap<SequenceGroup, String> groupRefs,
2199 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2200 SequenceSet vamsasSet)
2203 for (int i = 0; i < aa.length; i++)
2205 Annotation an = new Annotation();
2207 AlignmentAnnotation annotation = aa[i];
2208 if (annotation.annotationId != null)
2210 annotationIds.put(annotation.annotationId, annotation);
2213 an.setId(annotation.annotationId);
2215 an.setVisible(annotation.visible);
2217 an.setDescription(annotation.description);
2219 if (annotation.sequenceRef != null)
2221 // 2.9 JAL-1781 xref on sequence id rather than name
2222 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2224 if (annotation.groupRef != null)
2226 String groupIdr = groupRefs.get(annotation.groupRef);
2227 if (groupIdr == null)
2229 // make a locally unique String
2230 groupRefs.put(annotation.groupRef,
2231 groupIdr = ("" + System.currentTimeMillis()
2232 + annotation.groupRef.getName()
2233 + groupRefs.size()));
2235 an.setGroupRef(groupIdr.toString());
2238 // store all visualization attributes for annotation
2239 an.setGraphHeight(annotation.graphHeight);
2240 an.setCentreColLabels(annotation.centreColLabels);
2241 an.setScaleColLabels(annotation.scaleColLabel);
2242 an.setShowAllColLabels(annotation.showAllColLabels);
2243 an.setBelowAlignment(annotation.belowAlignment);
2245 if (annotation.graph > 0)
2248 an.setGraphType(annotation.graph);
2249 an.setGraphGroup(annotation.graphGroup);
2250 if (annotation.getThreshold() != null)
2252 ThresholdLine line = new ThresholdLine();
2253 line.setLabel(annotation.getThreshold().label);
2254 line.setValue(annotation.getThreshold().value);
2255 line.setColour(annotation.getThreshold().colour.getRGB());
2256 an.setThresholdLine(line);
2264 an.setLabel(annotation.label);
2266 if (annotation == av.getAlignmentQualityAnnot()
2267 || annotation == av.getAlignmentConservationAnnotation()
2268 || annotation == av.getAlignmentConsensusAnnotation()
2269 || annotation.autoCalculated)
2271 // new way of indicating autocalculated annotation -
2272 an.setAutoCalculated(annotation.autoCalculated);
2274 if (annotation.hasScore())
2276 an.setScore(annotation.getScore());
2279 if (annotation.getCalcId() != null)
2281 calcIdSet.add(annotation.getCalcId());
2282 an.setCalcId(annotation.getCalcId());
2284 if (annotation.hasProperties())
2286 for (String pr : annotation.getProperties())
2288 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2290 prop.setValue(annotation.getProperty(pr));
2291 // an.addProperty(prop);
2292 an.getProperty().add(prop);
2296 AnnotationElement ae;
2297 if (annotation.annotations != null)
2299 an.setScoreOnly(false);
2300 for (int a = 0; a < annotation.annotations.length; a++)
2302 if ((annotation == null) || (annotation.annotations[a] == null))
2307 ae = new AnnotationElement();
2308 if (annotation.annotations[a].description != null)
2310 ae.setDescription(annotation.annotations[a].description);
2312 if (annotation.annotations[a].displayCharacter != null)
2314 ae.setDisplayCharacter(
2315 annotation.annotations[a].displayCharacter);
2318 if (!Float.isNaN(annotation.annotations[a].value))
2320 ae.setValue(annotation.annotations[a].value);
2324 if (annotation.annotations[a].secondaryStructure > ' ')
2326 ae.setSecondaryStructure(
2327 annotation.annotations[a].secondaryStructure + "");
2330 if (annotation.annotations[a].colour != null
2331 && annotation.annotations[a].colour != java.awt.Color.black)
2333 ae.setColour(annotation.annotations[a].colour.getRGB());
2336 // an.addAnnotationElement(ae);
2337 an.getAnnotationElement().add(ae);
2338 if (annotation.autoCalculated)
2340 // only write one non-null entry into the annotation row -
2341 // sufficient to get the visualization attributes necessary to
2349 an.setScoreOnly(true);
2351 if (!storeDS || (storeDS && !annotation.autoCalculated))
2353 // skip autocalculated annotation - these are only provided for
2355 // vamsasSet.addAnnotation(an);
2356 vamsasSet.getAnnotation().add(an);
2362 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2364 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2365 if (settings != null)
2367 CalcIdParam vCalcIdParam = new CalcIdParam();
2368 vCalcIdParam.setCalcId(calcId);
2369 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2370 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2371 // generic URI allowing a third party to resolve another instance of the
2372 // service used for this calculation
2373 for (String url : settings.getServiceURLs())
2375 // vCalcIdParam.addServiceURL(urls);
2376 vCalcIdParam.getServiceURL().add(url);
2378 vCalcIdParam.setVersion("1.0");
2379 if (settings.getPreset() != null)
2381 WsParamSetI setting = settings.getPreset();
2382 vCalcIdParam.setName(setting.getName());
2383 vCalcIdParam.setDescription(setting.getDescription());
2387 vCalcIdParam.setName("");
2388 vCalcIdParam.setDescription("Last used parameters");
2390 // need to be able to recover 1) settings 2) user-defined presets or
2391 // recreate settings from preset 3) predefined settings provided by
2392 // service - or settings that can be transferred (or discarded)
2393 vCalcIdParam.setParameters(
2394 settings.getWsParamFile().replace("\n", "|\\n|"));
2395 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2396 // todo - decide if updateImmediately is needed for any projects.
2398 return vCalcIdParam;
2403 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2406 if (calcIdParam.getVersion().equals("1.0"))
2408 final String[] calcIds = calcIdParam.getServiceURL()
2409 .toArray(new String[0]);
2410 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2411 .getPreferredServiceFor(calcIds);
2412 if (service != null)
2414 WsParamSetI parmSet = null;
2417 parmSet = service.getParamStore().parseServiceParameterFile(
2418 calcIdParam.getName(), calcIdParam.getDescription(),
2420 calcIdParam.getParameters().replace("|\\n|", "\n"));
2421 } catch (IOException x)
2423 Console.warn("Couldn't parse parameter data for "
2424 + calcIdParam.getCalcId(), x);
2427 List<ArgumentI> argList = null;
2428 if (calcIdParam.getName().length() > 0)
2430 parmSet = service.getParamStore()
2431 .getPreset(calcIdParam.getName());
2432 if (parmSet != null)
2434 // TODO : check we have a good match with settings in AACon -
2435 // otherwise we'll need to create a new preset
2440 argList = parmSet.getArguments();
2443 AAConSettings settings = new AAConSettings(
2444 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2445 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2446 calcIdParam.isNeedsUpdate());
2452 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2456 throw new Error(MessageManager.formatMessage(
2457 "error.unsupported_version_calcIdparam", new Object[]
2458 { calcIdParam.toString() }));
2462 * External mapping between jalview objects and objects yielding a valid and
2463 * unique object ID string. This is null for normal Jalview project IO, but
2464 * non-null when a jalview project is being read or written as part of a
2467 IdentityHashMap jv2vobj = null;
2470 * Construct a unique ID for jvobj using either existing bindings or if none
2471 * exist, the result of the hashcode call for the object.
2474 * jalview data object
2475 * @return unique ID for referring to jvobj
2477 private String makeHashCode(Object jvobj, String altCode)
2479 if (jv2vobj != null)
2481 Object id = jv2vobj.get(jvobj);
2484 return id.toString();
2486 // check string ID mappings
2487 if (jvids2vobj != null && jvobj instanceof String)
2489 id = jvids2vobj.get(jvobj);
2493 return id.toString();
2495 // give up and warn that something has gone wrong
2497 "Cannot find ID for object in external mapping : " + jvobj);
2503 * return local jalview object mapped to ID, if it exists
2507 * @return null or object bound to idcode
2509 private Object retrieveExistingObj(String idcode)
2511 if (idcode != null && vobj2jv != null)
2513 return vobj2jv.get(idcode);
2519 * binding from ID strings from external mapping table to jalview data model
2522 private Hashtable vobj2jv;
2524 private Sequence createVamsasSequence(String id, SequenceI jds)
2526 return createVamsasSequence(true, id, jds, null);
2529 private Sequence createVamsasSequence(boolean recurse, String id,
2530 SequenceI jds, SequenceI parentseq)
2532 Sequence vamsasSeq = new Sequence();
2533 vamsasSeq.setId(id);
2534 vamsasSeq.setName(jds.getName());
2535 vamsasSeq.setSequence(jds.getSequenceAsString());
2536 vamsasSeq.setDescription(jds.getDescription());
2537 List<DBRefEntry> dbrefs = null;
2538 if (jds.getDatasetSequence() != null)
2540 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2544 // seqId==dsseqid so we can tell which sequences really are
2545 // dataset sequences only
2546 vamsasSeq.setDsseqid(id);
2547 dbrefs = jds.getDBRefs();
2548 if (parentseq == null)
2555 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2559 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2561 DBRef dbref = new DBRef();
2562 DBRefEntry ref = dbrefs.get(d);
2563 dbref.setSource(ref.getSource());
2564 dbref.setVersion(ref.getVersion());
2565 dbref.setAccessionId(ref.getAccessionId());
2566 dbref.setCanonical(ref.isCanonical());
2567 if (ref instanceof GeneLocus)
2569 dbref.setLocus(true);
2573 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2575 dbref.setMapping(mp);
2577 vamsasSeq.getDBRef().add(dbref);
2583 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2584 SequenceI parentseq, SequenceI jds, boolean recurse)
2587 if (jmp.getMap() != null)
2591 jalview.util.MapList mlst = jmp.getMap();
2592 List<int[]> r = mlst.getFromRanges();
2593 for (int[] range : r)
2595 MapListFrom mfrom = new MapListFrom();
2596 mfrom.setStart(range[0]);
2597 mfrom.setEnd(range[1]);
2598 // mp.addMapListFrom(mfrom);
2599 mp.getMapListFrom().add(mfrom);
2601 r = mlst.getToRanges();
2602 for (int[] range : r)
2604 MapListTo mto = new MapListTo();
2605 mto.setStart(range[0]);
2606 mto.setEnd(range[1]);
2607 // mp.addMapListTo(mto);
2608 mp.getMapListTo().add(mto);
2610 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2611 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2612 if (jmp.getTo() != null)
2614 // MappingChoice mpc = new MappingChoice();
2616 // check/create ID for the sequence referenced by getTo()
2619 SequenceI ps = null;
2620 if (parentseq != jmp.getTo()
2621 && parentseq.getDatasetSequence() != jmp.getTo())
2623 // chaining dbref rather than a handshaking one
2624 jmpid = seqHash(ps = jmp.getTo());
2628 jmpid = seqHash(ps = parentseq);
2630 // mpc.setDseqFor(jmpid);
2631 mp.setDseqFor(jmpid);
2632 if (!seqRefIds.containsKey(jmpid))
2634 Console.debug("creatign new DseqFor ID");
2635 seqRefIds.put(jmpid, ps);
2639 Console.debug("reusing DseqFor ID");
2642 // mp.setMappingChoice(mpc);
2648 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2649 List<UserColourScheme> userColours, JalviewModel jm)
2652 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2653 boolean newucs = false;
2654 if (!userColours.contains(ucs))
2656 userColours.add(ucs);
2659 id = "ucs" + userColours.indexOf(ucs);
2662 // actually create the scheme's entry in the XML model
2663 java.awt.Color[] colours = ucs.getColours();
2664 UserColours uc = new UserColours();
2665 // UserColourScheme jbucs = new UserColourScheme();
2666 JalviewUserColours jbucs = new JalviewUserColours();
2668 for (int i = 0; i < colours.length; i++)
2670 Colour col = new Colour();
2671 col.setName(ResidueProperties.aa[i]);
2672 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2673 // jbucs.addColour(col);
2674 jbucs.getColour().add(col);
2676 if (ucs.getLowerCaseColours() != null)
2678 colours = ucs.getLowerCaseColours();
2679 for (int i = 0; i < colours.length; i++)
2681 Colour col = new Colour();
2682 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2683 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2684 // jbucs.addColour(col);
2685 jbucs.getColour().add(col);
2690 uc.setUserColourScheme(jbucs);
2691 // jm.addUserColours(uc);
2692 jm.getUserColours().add(uc);
2698 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2701 List<UserColours> uc = jm.getUserColours();
2702 UserColours colours = null;
2704 for (int i = 0; i < uc.length; i++)
2706 if (uc[i].getId().equals(id))
2713 for (UserColours c : uc)
2715 if (c.getId().equals(id))
2722 java.awt.Color[] newColours = new java.awt.Color[24];
2724 for (int i = 0; i < 24; i++)
2726 newColours[i] = new java.awt.Color(Integer.parseInt(
2727 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2728 colours.getUserColourScheme().getColour().get(i).getRGB(),
2732 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2735 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2737 newColours = new java.awt.Color[23];
2738 for (int i = 0; i < 23; i++)
2740 newColours[i] = new java.awt.Color(
2741 Integer.parseInt(colours.getUserColourScheme().getColour()
2742 .get(i + 24).getRGB(), 16));
2744 ucs.setLowerCaseColours(newColours);
2751 * contains last error message (if any) encountered by XML loader.
2753 String errorMessage = null;
2756 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2757 * exceptions are raised during project XML parsing
2759 public boolean attemptversion1parse = false;
2762 * Load a jalview project archive from a jar file
2765 * - HTTP URL or filename
2767 public AlignFrame loadJalviewAlign(final Object file)
2770 jalview.gui.AlignFrame af = null;
2774 // create list to store references for any new Jmol viewers created
2775 newStructureViewers = new Vector<>();
2776 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2777 // Workaround is to make sure caller implements the JarInputStreamProvider
2779 // so we can re-open the jar input stream for each entry.
2781 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2782 af = loadJalviewAlign(jprovider);
2785 af.setMenusForViewport();
2787 } catch (MalformedURLException e)
2789 errorMessage = "Invalid URL format for '" + file + "'";
2795 SwingUtilities.invokeAndWait(new Runnable()
2800 setLoadingFinishedForNewStructureViewers();
2803 } catch (Exception x)
2805 System.err.println("Error loading alignment: " + x.getMessage());
2811 @SuppressWarnings("unused")
2812 private jarInputStreamProvider createjarInputStreamProvider(
2813 final Object ofile) throws MalformedURLException
2816 // BH 2018 allow for bytes already attached to File object
2819 String file = (ofile instanceof File
2820 ? ((File) ofile).getCanonicalPath()
2821 : ofile.toString());
2822 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2825 errorMessage = null;
2826 uniqueSetSuffix = null;
2828 viewportsAdded.clear();
2829 frefedSequence = null;
2831 if (HttpUtils.startsWithHttpOrHttps(file))
2833 url = new URL(file);
2835 final URL _url = url;
2836 return new jarInputStreamProvider()
2840 public JarInputStream getJarInputStream() throws IOException
2844 // System.out.println("Jalview2XML: opening byte jarInputStream for
2845 // bytes.length=" + bytes.length);
2846 return new JarInputStream(new ByteArrayInputStream(bytes));
2850 // System.out.println("Jalview2XML: opening url jarInputStream for "
2852 return new JarInputStream(_url.openStream());
2856 // System.out.println("Jalview2XML: opening file jarInputStream for
2858 return new JarInputStream(new FileInputStream(file));
2863 public String getFilename()
2868 } catch (IOException e)
2870 e.printStackTrace();
2876 * Recover jalview session from a jalview project archive. Caller may
2877 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2878 * themselves. Any null fields will be initialised with default values,
2879 * non-null fields are left alone.
2884 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2886 errorMessage = null;
2887 if (uniqueSetSuffix == null)
2889 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2891 if (seqRefIds == null)
2895 AlignFrame af = null, _af = null;
2896 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2897 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2898 final String file = jprovider.getFilename();
2901 JarInputStream jin = null;
2902 JarEntry jarentry = null;
2907 jin = jprovider.getJarInputStream();
2908 for (int i = 0; i < entryCount; i++)
2910 jarentry = jin.getNextJarEntry();
2913 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2915 JAXBContext jc = JAXBContext
2916 .newInstance("jalview.xml.binding.jalview");
2917 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2918 .createXMLStreamReader(jin);
2919 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2920 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2921 JalviewModel.class);
2922 JalviewModel object = jbe.getValue();
2924 if (true) // !skipViewport(object))
2926 _af = loadFromObject(object, file, true, jprovider);
2927 if (_af != null && object.getViewport().size() > 0)
2928 // getJalviewModelSequence().getViewportCount() > 0)
2932 // store a reference to the first view
2935 if (_af.getViewport().isGatherViewsHere())
2937 // if this is a gathered view, keep its reference since
2938 // after gathering views, only this frame will remain
2940 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2943 // Save dataset to register mappings once all resolved
2944 importedDatasets.put(
2945 af.getViewport().getAlignment().getDataset(),
2946 af.getViewport().getAlignment().getDataset());
2951 else if (jarentry != null)
2953 // Some other file here.
2956 } while (jarentry != null);
2958 resolveFrefedSequences();
2959 } catch (IOException ex)
2961 ex.printStackTrace();
2962 errorMessage = "Couldn't locate Jalview XML file : " + file;
2964 "Exception whilst loading jalview XML file : " + ex + "\n");
2965 } catch (Exception ex)
2967 System.err.println("Parsing as Jalview Version 2 file failed.");
2968 ex.printStackTrace(System.err);
2969 if (attemptversion1parse)
2971 // used to attempt to parse as V1 castor-generated xml
2973 if (Desktop.instance != null)
2975 Desktop.instance.stopLoading();
2979 System.out.println("Successfully loaded archive file");
2982 ex.printStackTrace();
2985 "Exception whilst loading jalview XML file : " + ex + "\n");
2986 } catch (OutOfMemoryError e)
2988 // Don't use the OOM Window here
2989 errorMessage = "Out of memory loading jalview XML file";
2990 System.err.println("Out of memory whilst loading jalview XML file");
2991 e.printStackTrace();
2995 * Regather multiple views (with the same sequence set id) to the frame (if
2996 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2997 * views instead of separate frames. Note this doesn't restore a state where
2998 * some expanded views in turn have tabbed views - the last "first tab" read
2999 * in will play the role of gatherer for all.
3001 for (AlignFrame fr : gatherToThisFrame.values())
3003 Desktop.instance.gatherViews(fr);
3006 restoreSplitFrames();
3007 for (AlignmentI ds : importedDatasets.keySet())
3009 if (ds.getCodonFrames() != null)
3011 StructureSelectionManager
3012 .getStructureSelectionManager(Desktop.instance)
3013 .registerMappings(ds.getCodonFrames());
3016 if (errorMessage != null)
3021 if (Desktop.instance != null)
3023 Desktop.instance.stopLoading();
3030 * Try to reconstruct and display SplitFrame windows, where each contains
3031 * complementary dna and protein alignments. Done by pairing up AlignFrame
3032 * objects (created earlier) which have complementary viewport ids associated.
3034 protected void restoreSplitFrames()
3036 List<SplitFrame> gatherTo = new ArrayList<>();
3037 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3038 Map<String, AlignFrame> dna = new HashMap<>();
3041 * Identify the DNA alignments
3043 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3046 AlignFrame af = candidate.getValue();
3047 if (af.getViewport().getAlignment().isNucleotide())
3049 dna.put(candidate.getKey().getId(), af);
3054 * Try to match up the protein complements
3056 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3059 AlignFrame af = candidate.getValue();
3060 if (!af.getViewport().getAlignment().isNucleotide())
3062 String complementId = candidate.getKey().getComplementId();
3063 // only non-null complements should be in the Map
3064 if (complementId != null && dna.containsKey(complementId))
3066 final AlignFrame dnaFrame = dna.get(complementId);
3067 SplitFrame sf = createSplitFrame(dnaFrame, af);
3068 addedToSplitFrames.add(dnaFrame);
3069 addedToSplitFrames.add(af);
3070 dnaFrame.setMenusForViewport();
3071 af.setMenusForViewport();
3072 if (af.getViewport().isGatherViewsHere())
3081 * Open any that we failed to pair up (which shouldn't happen!) as
3082 * standalone AlignFrame's.
3084 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3087 AlignFrame af = candidate.getValue();
3088 if (!addedToSplitFrames.contains(af))
3090 Viewport view = candidate.getKey();
3091 Desktop.addInternalFrame(af, view.getTitle(),
3092 safeInt(view.getWidth()), safeInt(view.getHeight()));
3093 af.setMenusForViewport();
3094 System.err.println("Failed to restore view " + view.getTitle()
3095 + " to split frame");
3100 * Gather back into tabbed views as flagged.
3102 for (SplitFrame sf : gatherTo)
3104 Desktop.instance.gatherViews(sf);
3107 splitFrameCandidates.clear();
3111 * Construct and display one SplitFrame holding DNA and protein alignments.
3114 * @param proteinFrame
3117 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3118 AlignFrame proteinFrame)
3120 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3121 String title = MessageManager.getString("label.linked_view_title");
3122 int width = (int) dnaFrame.getBounds().getWidth();
3123 int height = (int) (dnaFrame.getBounds().getHeight()
3124 + proteinFrame.getBounds().getHeight() + 50);
3127 * SplitFrame location is saved to both enclosed frames
3129 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3130 Desktop.addInternalFrame(splitFrame, title, width, height);
3133 * And compute cDNA consensus (couldn't do earlier with consensus as
3134 * mappings were not yet present)
3136 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3142 * check errorMessage for a valid error message and raise an error box in the
3143 * GUI or write the current errorMessage to stderr and then clear the error
3146 protected void reportErrors()
3148 reportErrors(false);
3151 protected void reportErrors(final boolean saving)
3153 if (errorMessage != null)
3155 final String finalErrorMessage = errorMessage;
3158 javax.swing.SwingUtilities.invokeLater(new Runnable()
3163 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3165 "Error " + (saving ? "saving" : "loading")
3167 JvOptionPane.WARNING_MESSAGE);
3173 System.err.println("Problem loading Jalview file: " + errorMessage);
3176 errorMessage = null;
3179 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3182 * when set, local views will be updated from view stored in JalviewXML
3183 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3184 * sync if this is set to true.
3186 private final boolean updateLocalViews = false;
3189 * Returns the path to a temporary file holding the PDB file for the given PDB
3190 * id. The first time of asking, searches for a file of that name in the
3191 * Jalview project jar, and copies it to a new temporary file. Any repeat
3192 * requests just return the path to the file previously created.
3198 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3201 if (alreadyLoadedPDB.containsKey(pdbId))
3203 return alreadyLoadedPDB.get(pdbId).toString();
3206 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3208 if (tempFile != null)
3210 alreadyLoadedPDB.put(pdbId, tempFile);
3216 * Copies the jar entry of given name to a new temporary file and returns the
3217 * path to the file, or null if the entry is not found.
3220 * @param jarEntryName
3222 * a prefix for the temporary file name, must be at least three
3224 * @param suffixModel
3225 * null or original file - so new file can be given the same suffix
3229 protected String copyJarEntry(jarInputStreamProvider jprovider,
3230 String jarEntryName, String prefix, String suffixModel)
3232 String suffix = ".tmp";
3233 if (suffixModel == null)
3235 suffixModel = jarEntryName;
3237 int sfpos = suffixModel.lastIndexOf(".");
3238 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3240 suffix = "." + suffixModel.substring(sfpos + 1);
3243 try (JarInputStream jin = jprovider.getJarInputStream())
3245 JarEntry entry = null;
3248 entry = jin.getNextJarEntry();
3249 } while (entry != null && !entry.getName().equals(jarEntryName));
3253 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3254 File outFile = File.createTempFile(prefix, suffix);
3255 outFile.deleteOnExit();
3256 try (OutputStream os = new FileOutputStream(outFile))
3260 String t = outFile.getAbsolutePath();
3266 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3268 } catch (Exception ex)
3270 ex.printStackTrace();
3276 private class JvAnnotRow
3278 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3285 * persisted version of annotation row from which to take vis properties
3287 public jalview.datamodel.AlignmentAnnotation template;
3290 * original position of the annotation row in the alignment
3296 * Load alignment frame from jalview XML DOM object
3298 * @param jalviewModel
3301 * filename source string
3302 * @param loadTreesAndStructures
3303 * when false only create Viewport
3305 * data source provider
3306 * @return alignment frame created from view stored in DOM
3308 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3309 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3311 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3313 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3315 // JalviewModelSequence jms = object.getJalviewModelSequence();
3317 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3319 Viewport view = (jalviewModel.getViewport().size() > 0)
3320 ? jalviewModel.getViewport().get(0)
3323 // ////////////////////////////////
3324 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3327 // If we just load in the same jar file again, the sequenceSetId
3328 // will be the same, and we end up with multiple references
3329 // to the same sequenceSet. We must modify this id on load
3330 // so that each load of the file gives a unique id
3333 * used to resolve correct alignment dataset for alignments with multiple
3336 String uniqueSeqSetId = null;
3337 String viewId = null;
3340 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3341 viewId = (view.getId() == null ? null
3342 : view.getId() + uniqueSetSuffix);
3345 // ////////////////////////////////
3348 List<SequenceI> hiddenSeqs = null;
3350 List<SequenceI> tmpseqs = new ArrayList<>();
3352 boolean multipleView = false;
3353 SequenceI referenceseqForView = null;
3354 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3355 List<JSeq> jseqs = jalviewModel.getJSeq();
3356 int vi = 0; // counter in vamsasSeq array
3357 for (int i = 0; i < jseqs.size(); i++)
3359 JSeq jseq = jseqs.get(i);
3360 String seqId = jseq.getId();
3362 SequenceI tmpSeq = seqRefIds.get(seqId);
3365 if (!incompleteSeqs.containsKey(seqId))
3367 // may not need this check, but keep it for at least 2.9,1 release
3368 if (tmpSeq.getStart() != jseq.getStart()
3369 || tmpSeq.getEnd() != jseq.getEnd())
3371 System.err.println(String.format(
3372 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3373 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3374 jseq.getStart(), jseq.getEnd()));
3379 incompleteSeqs.remove(seqId);
3381 if (vamsasSeqs.size() > vi
3382 && vamsasSeqs.get(vi).getId().equals(seqId))
3384 // most likely we are reading a dataset XML document so
3385 // update from vamsasSeq section of XML for this sequence
3386 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3387 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3388 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3393 // reading multiple views, so vamsasSeq set is a subset of JSeq
3394 multipleView = true;
3396 tmpSeq.setStart(jseq.getStart());
3397 tmpSeq.setEnd(jseq.getEnd());
3398 tmpseqs.add(tmpSeq);
3402 Sequence vamsasSeq = vamsasSeqs.get(vi);
3403 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3404 vamsasSeq.getSequence());
3405 tmpSeq.setDescription(vamsasSeq.getDescription());
3406 tmpSeq.setStart(jseq.getStart());
3407 tmpSeq.setEnd(jseq.getEnd());
3408 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3409 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3410 tmpseqs.add(tmpSeq);
3414 if (safeBoolean(jseq.isViewreference()))
3416 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3419 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3421 if (hiddenSeqs == null)
3423 hiddenSeqs = new ArrayList<>();
3426 hiddenSeqs.add(tmpSeq);
3431 // Create the alignment object from the sequence set
3432 // ///////////////////////////////
3433 SequenceI[] orderedSeqs = tmpseqs
3434 .toArray(new SequenceI[tmpseqs.size()]);
3436 AlignmentI al = null;
3437 // so we must create or recover the dataset alignment before going further
3438 // ///////////////////////////////
3439 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3441 // older jalview projects do not have a dataset - so creat alignment and
3443 al = new Alignment(orderedSeqs);
3444 al.setDataset(null);
3448 boolean isdsal = jalviewModel.getViewport().isEmpty();
3451 // we are importing a dataset record, so
3452 // recover reference to an alignment already materialsed as dataset
3453 al = getDatasetFor(vamsasSet.getDatasetId());
3457 // materialse the alignment
3458 al = new Alignment(orderedSeqs);
3462 addDatasetRef(vamsasSet.getDatasetId(), al);
3465 // finally, verify all data in vamsasSet is actually present in al
3466 // passing on flag indicating if it is actually a stored dataset
3467 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3470 if (referenceseqForView != null)
3472 al.setSeqrep(referenceseqForView);
3474 // / Add the alignment properties
3475 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3477 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3479 al.setProperty(ssp.getKey(), ssp.getValue());
3482 // ///////////////////////////////
3484 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3487 // load sequence features, database references and any associated PDB
3488 // structures for the alignment
3490 // prior to 2.10, this part would only be executed the first time a
3491 // sequence was encountered, but not afterwards.
3492 // now, for 2.10 projects, this is also done if the xml doc includes
3493 // dataset sequences not actually present in any particular view.
3495 for (int i = 0; i < vamsasSeqs.size(); i++)
3497 JSeq jseq = jseqs.get(i);
3498 if (jseq.getFeatures().size() > 0)
3500 List<Feature> features = jseq.getFeatures();
3501 for (int f = 0; f < features.size(); f++)
3503 Feature feat = features.get(f);
3504 SequenceFeature sf = new SequenceFeature(feat.getType(),
3505 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3506 safeFloat(feat.getScore()), feat.getFeatureGroup());
3507 sf.setStatus(feat.getStatus());
3510 * load any feature attributes - include map-valued attributes
3512 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3513 for (int od = 0; od < feat.getOtherData().size(); od++)
3515 OtherData keyValue = feat.getOtherData().get(od);
3516 String attributeName = keyValue.getKey();
3517 String attributeValue = keyValue.getValue();
3518 if (attributeName.startsWith("LINK"))
3520 sf.addLink(attributeValue);
3524 String subAttribute = keyValue.getKey2();
3525 if (subAttribute == null)
3527 // simple string-valued attribute
3528 sf.setValue(attributeName, attributeValue);
3532 // attribute 'key' has sub-attribute 'key2'
3533 if (!mapAttributes.containsKey(attributeName))
3535 mapAttributes.put(attributeName, new HashMap<>());
3537 mapAttributes.get(attributeName).put(subAttribute,
3542 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3545 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3548 // adds feature to datasequence's feature set (since Jalview 2.10)
3549 al.getSequenceAt(i).addSequenceFeature(sf);
3552 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3554 // adds dbrefs to datasequence's set (since Jalview 2.10)
3556 al.getSequenceAt(i).getDatasetSequence() == null
3557 ? al.getSequenceAt(i)
3558 : al.getSequenceAt(i).getDatasetSequence(),
3561 if (jseq.getPdbids().size() > 0)
3563 List<Pdbids> ids = jseq.getPdbids();
3564 for (int p = 0; p < ids.size(); p++)
3566 Pdbids pdbid = ids.get(p);
3567 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3568 entry.setId(pdbid.getId());
3569 if (pdbid.getType() != null)
3571 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3573 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3577 entry.setType(PDBEntry.Type.FILE);
3580 // jprovider is null when executing 'New View'
3581 if (pdbid.getFile() != null && jprovider != null)
3583 if (!pdbloaded.containsKey(pdbid.getFile()))
3585 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3590 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3594 if (pdbid.getPdbentryItem() != null)
3596 for (PdbentryItem item : pdbid.getPdbentryItem())
3598 for (Property pr : item.getProperty())
3600 entry.setProperty(pr.getName(), pr.getValue());
3605 for (Property prop : pdbid.getProperty())
3607 entry.setProperty(prop.getName(), prop.getValue());
3609 StructureSelectionManager
3610 .getStructureSelectionManager(Desktop.instance)
3611 .registerPDBEntry(entry);
3612 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3613 if (al.getSequenceAt(i).getDatasetSequence() != null)
3615 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3619 al.getSequenceAt(i).addPDBId(entry);
3624 } // end !multipleview
3626 // ///////////////////////////////
3627 // LOAD SEQUENCE MAPPINGS
3629 if (vamsasSet.getAlcodonFrame().size() > 0)
3631 // TODO Potentially this should only be done once for all views of an
3633 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3634 for (int i = 0; i < alc.size(); i++)
3636 AlignedCodonFrame cf = new AlignedCodonFrame();
3637 if (alc.get(i).getAlcodMap().size() > 0)
3639 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3640 for (int m = 0; m < maps.size(); m++)
3642 AlcodMap map = maps.get(m);
3643 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3645 jalview.datamodel.Mapping mapping = null;
3646 // attach to dna sequence reference.
3647 if (map.getMapping() != null)
3649 mapping = addMapping(map.getMapping());
3650 if (dnaseq != null && mapping.getTo() != null)
3652 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3658 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3662 al.addCodonFrame(cf);
3667 // ////////////////////////////////
3669 List<JvAnnotRow> autoAlan = new ArrayList<>();
3672 * store any annotations which forward reference a group's ID
3674 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3676 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3678 List<Annotation> an = vamsasSet.getAnnotation();
3680 for (int i = 0; i < an.size(); i++)
3682 Annotation annotation = an.get(i);
3685 * test if annotation is automatically calculated for this view only
3687 boolean autoForView = false;
3688 if (annotation.getLabel().equals("Quality")
3689 || annotation.getLabel().equals("Conservation")
3690 || annotation.getLabel().equals("Consensus"))
3692 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3694 // JAXB has no has() test; schema defaults value to false
3695 // if (!annotation.hasAutoCalculated())
3697 // annotation.setAutoCalculated(true);
3700 if (autoForView || annotation.isAutoCalculated())
3702 // remove ID - we don't recover annotation from other views for
3703 // view-specific annotation
3704 annotation.setId(null);
3707 // set visibility for other annotation in this view
3708 String annotationId = annotation.getId();
3709 if (annotationId != null && annotationIds.containsKey(annotationId))
3711 AlignmentAnnotation jda = annotationIds.get(annotationId);
3712 // in principle Visible should always be true for annotation displayed
3713 // in multiple views
3714 if (annotation.isVisible() != null)
3716 jda.visible = annotation.isVisible();
3719 al.addAnnotation(jda);
3723 // Construct new annotation from model.
3724 List<AnnotationElement> ae = annotation.getAnnotationElement();
3725 jalview.datamodel.Annotation[] anot = null;
3726 java.awt.Color firstColour = null;
3728 if (!annotation.isScoreOnly())
3730 anot = new jalview.datamodel.Annotation[al.getWidth()];
3731 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3733 AnnotationElement annElement = ae.get(aa);
3734 anpos = annElement.getPosition();
3736 if (anpos >= anot.length)
3741 float value = safeFloat(annElement.getValue());
3742 anot[anpos] = new jalview.datamodel.Annotation(
3743 annElement.getDisplayCharacter(),
3744 annElement.getDescription(),
3745 (annElement.getSecondaryStructure() == null
3746 || annElement.getSecondaryStructure()
3750 .getSecondaryStructure()
3753 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3754 if (firstColour == null)
3756 firstColour = anot[anpos].colour;
3760 jalview.datamodel.AlignmentAnnotation jaa = null;
3762 if (annotation.isGraph())
3764 float llim = 0, hlim = 0;
3765 // if (autoForView || an[i].isAutoCalculated()) {
3768 jaa = new jalview.datamodel.AlignmentAnnotation(
3769 annotation.getLabel(), annotation.getDescription(), anot,
3770 llim, hlim, safeInt(annotation.getGraphType()));
3772 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3773 jaa._linecolour = firstColour;
3774 if (annotation.getThresholdLine() != null)
3776 jaa.setThreshold(new jalview.datamodel.GraphLine(
3777 safeFloat(annotation.getThresholdLine().getValue()),
3778 annotation.getThresholdLine().getLabel(),
3779 new java.awt.Color(safeInt(
3780 annotation.getThresholdLine().getColour()))));
3782 if (autoForView || annotation.isAutoCalculated())
3784 // Hardwire the symbol display line to ensure that labels for
3785 // histograms are displayed
3791 jaa = new jalview.datamodel.AlignmentAnnotation(
3792 annotation.getLabel(), annotation.getDescription(), anot);
3793 jaa._linecolour = firstColour;
3795 // register new annotation
3796 if (annotation.getId() != null)
3798 annotationIds.put(annotation.getId(), jaa);
3799 jaa.annotationId = annotation.getId();
3801 // recover sequence association
3802 String sequenceRef = annotation.getSequenceRef();
3803 if (sequenceRef != null)
3805 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3806 SequenceI sequence = seqRefIds.get(sequenceRef);
3807 if (sequence == null)
3809 // in pre-2.9 projects sequence ref is to sequence name
3810 sequence = al.findName(sequenceRef);
3812 if (sequence != null)
3814 jaa.createSequenceMapping(sequence, 1, true);
3815 sequence.addAlignmentAnnotation(jaa);
3818 // and make a note of any group association
3819 if (annotation.getGroupRef() != null
3820 && annotation.getGroupRef().length() > 0)
3822 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3823 .get(annotation.getGroupRef());
3826 aal = new ArrayList<>();
3827 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3832 if (annotation.getScore() != null)
3834 jaa.setScore(annotation.getScore().doubleValue());
3836 if (annotation.isVisible() != null)
3838 jaa.visible = annotation.isVisible().booleanValue();
3841 if (annotation.isCentreColLabels() != null)
3843 jaa.centreColLabels = annotation.isCentreColLabels()
3847 if (annotation.isScaleColLabels() != null)
3849 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3851 if (annotation.isAutoCalculated())
3853 // newer files have an 'autoCalculated' flag and store calculation
3854 // state in viewport properties
3855 jaa.autoCalculated = true; // means annotation will be marked for
3856 // update at end of load.
3858 if (annotation.getGraphHeight() != null)
3860 jaa.graphHeight = annotation.getGraphHeight().intValue();
3862 jaa.belowAlignment = annotation.isBelowAlignment();
3863 jaa.setCalcId(annotation.getCalcId());
3864 if (annotation.getProperty().size() > 0)
3866 for (Annotation.Property prop : annotation.getProperty())
3868 jaa.setProperty(prop.getName(), prop.getValue());
3871 if (jaa.autoCalculated)
3873 autoAlan.add(new JvAnnotRow(i, jaa));
3876 // if (!autoForView)
3878 // add autocalculated group annotation and any user created annotation
3880 al.addAnnotation(jaa);
3884 // ///////////////////////
3886 // Create alignment markup and styles for this view
3887 if (jalviewModel.getJGroup().size() > 0)
3889 List<JGroup> groups = jalviewModel.getJGroup();
3890 boolean addAnnotSchemeGroup = false;
3891 for (int i = 0; i < groups.size(); i++)
3893 JGroup jGroup = groups.get(i);
3894 ColourSchemeI cs = null;
3895 if (jGroup.getColour() != null)
3897 if (jGroup.getColour().startsWith("ucs"))
3899 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3901 else if (jGroup.getColour().equals("AnnotationColourGradient")
3902 && jGroup.getAnnotationColours() != null)
3904 addAnnotSchemeGroup = true;
3908 cs = ColourSchemeProperty.getColourScheme(null, al,
3909 jGroup.getColour());
3912 int pidThreshold = safeInt(jGroup.getPidThreshold());
3914 Vector<SequenceI> seqs = new Vector<>();
3916 for (int s = 0; s < jGroup.getSeq().size(); s++)
3918 String seqId = jGroup.getSeq().get(s);
3919 SequenceI ts = seqRefIds.get(seqId);
3923 seqs.addElement(ts);
3927 if (seqs.size() < 1)
3932 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3933 safeBoolean(jGroup.isDisplayBoxes()),
3934 safeBoolean(jGroup.isDisplayText()),
3935 safeBoolean(jGroup.isColourText()),
3936 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3937 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3938 sg.getGroupColourScheme()
3939 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3940 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3942 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3943 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3944 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3945 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3946 // attributes with a default in the schema are never null
3947 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3948 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3949 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3950 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3951 if (jGroup.getConsThreshold() != null
3952 && jGroup.getConsThreshold().intValue() != 0)
3954 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3957 c.verdict(false, 25);
3958 sg.cs.setConservation(c);
3961 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3963 // re-instate unique group/annotation row reference
3964 List<AlignmentAnnotation> jaal = groupAnnotRefs
3965 .get(jGroup.getId());
3968 for (AlignmentAnnotation jaa : jaal)
3971 if (jaa.autoCalculated)
3973 // match up and try to set group autocalc alignment row for this
3975 if (jaa.label.startsWith("Consensus for "))
3977 sg.setConsensus(jaa);
3979 // match up and try to set group autocalc alignment row for this
3981 if (jaa.label.startsWith("Conservation for "))
3983 sg.setConservationRow(jaa);
3990 if (addAnnotSchemeGroup)
3992 // reconstruct the annotation colourscheme
3994 constructAnnotationColour(jGroup.getAnnotationColours(),
3995 null, al, jalviewModel, false));
4001 // only dataset in this model, so just return.
4004 // ///////////////////////////////
4007 AlignFrame af = null;
4008 AlignViewport av = null;
4009 // now check to see if we really need to create a new viewport.
4010 if (multipleView && viewportsAdded.size() == 0)
4012 // We recovered an alignment for which a viewport already exists.
4013 // TODO: fix up any settings necessary for overlaying stored state onto
4014 // state recovered from another document. (may not be necessary).
4015 // we may need a binding from a viewport in memory to one recovered from
4017 // and then recover its containing af to allow the settings to be applied.
4018 // TODO: fix for vamsas demo
4020 "About to recover a viewport for existing alignment: Sequence set ID is "
4022 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4023 if (seqsetobj != null)
4025 if (seqsetobj instanceof String)
4027 uniqueSeqSetId = (String) seqsetobj;
4029 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4035 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4041 * indicate that annotation colours are applied across all groups (pre
4042 * Jalview 2.8.1 behaviour)
4044 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4045 jalviewModel.getVersion());
4047 AlignmentPanel ap = null;
4048 boolean isnewview = true;
4051 // Check to see if this alignment already has a view id == viewId
4052 jalview.gui.AlignmentPanel views[] = Desktop
4053 .getAlignmentPanels(uniqueSeqSetId);
4054 if (views != null && views.length > 0)
4056 for (int v = 0; v < views.length; v++)
4058 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4060 // recover the existing alignpanel, alignframe, viewport
4061 af = views[v].alignFrame;
4064 // TODO: could even skip resetting view settings if we don't want to
4065 // change the local settings from other jalview processes
4074 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4075 uniqueSeqSetId, viewId, autoAlan);
4076 av = af.getViewport();
4081 * Load any trees, PDB structures and viewers
4083 * Not done if flag is false (when this method is used for New View)
4085 if (loadTreesAndStructures)
4087 loadTrees(jalviewModel, view, af, av, ap);
4088 loadExternalTrees(jprovider, jalviewModel, av);
4089 loadPCAViewers(jalviewModel, ap);
4090 loadPDBStructures(jprovider, jseqs, af, ap);
4091 loadRnaViewers(jprovider, jseqs, ap);
4093 // and finally return.
4097 private void loadExternalTrees(jarInputStreamProvider jprovider,
4098 JalviewModel jms, AlignViewport av)
4100 // TODO: allow more than one archeopteryx session per project
4101 String treeFile = copyJarEntry(jprovider, "aptx-test", "aptx", null);
4102 if (treeFile != null)
4106 AptxInit.createInstancesFromFile(treeFile, av);
4107 } catch (IOException e)
4109 // TODO Auto-generated catch block
4110 e.printStackTrace();
4119 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4120 * panel is restored from separate jar entries, two (gapped and trimmed) per
4121 * sequence and secondary structure.
4123 * Currently each viewer shows just one sequence and structure (gapped and
4124 * trimmed), however this method is designed to support multiple sequences or
4125 * structures in viewers if wanted in future.
4131 private void loadRnaViewers(jarInputStreamProvider jprovider,
4132 List<JSeq> jseqs, AlignmentPanel ap)
4135 * scan the sequences for references to viewers; create each one the first
4136 * time it is referenced, add Rna models to existing viewers
4138 for (JSeq jseq : jseqs)
4140 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4142 RnaViewer viewer = jseq.getRnaViewer().get(i);
4143 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4146 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4148 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4149 SequenceI seq = seqRefIds.get(jseq.getId());
4150 AlignmentAnnotation ann = this.annotationIds
4151 .get(ss.getAnnotationId());
4154 * add the structure to the Varna display (with session state copied
4155 * from the jar to a temporary file)
4157 boolean gapped = safeBoolean(ss.isGapped());
4158 String rnaTitle = ss.getTitle();
4159 String sessionState = ss.getViewerState();
4160 String tempStateFile = copyJarEntry(jprovider, sessionState,
4162 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4163 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4165 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4171 * Locate and return an already instantiated matching AppVarna, or create one
4175 * @param viewIdSuffix
4179 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4180 String viewIdSuffix, AlignmentPanel ap)
4183 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4184 * if load is repeated
4186 String postLoadId = viewer.getViewId() + viewIdSuffix;
4187 for (JInternalFrame frame : getAllFrames())
4189 if (frame instanceof AppVarna)
4191 AppVarna varna = (AppVarna) frame;
4192 if (postLoadId.equals(varna.getViewId()))
4194 // this viewer is already instantiated
4195 // could in future here add ap as another 'parent' of the
4196 // AppVarna window; currently just 1-to-many
4203 * viewer not found - make it
4205 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4206 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4207 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4208 safeInt(viewer.getDividerLocation()));
4209 AppVarna varna = new AppVarna(model, ap);
4215 * Load any saved trees
4223 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4224 AlignViewport av, AlignmentPanel ap)
4226 // TODO result of automated refactoring - are all these parameters needed?
4229 for (int t = 0; t < jm.getTree().size(); t++)
4232 Tree tree = jm.getTree().get(t);
4234 TreeFrameI externalViewer = AptxInit.createInstanceFromNhx(
4235 tree.getTitle(), tree.getNewick(),
4238 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4241 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4242 tree.getTitle(), safeInt(tree.getWidth()),
4243 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4244 safeInt(tree.getYpos()));
4245 if (tree.getId() != null)
4247 // perhaps bind the tree id to something ?
4252 // update local tree attributes ?
4253 // TODO: should check if tp has been manipulated by user - if so its
4254 // settings shouldn't be modified
4255 tp.setTitle(tree.getTitle());
4256 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4257 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4258 safeInt(tree.getHeight())));
4259 tp.setViewport(av); // af.viewport;
4260 // TODO: verify 'associate with all views' works still
4261 tp.getTreeCanvas().setViewport(av); // af.viewport;
4262 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4264 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4268 "There was a problem recovering stored Newick tree: \n"
4269 + tree.getNewick());
4273 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4274 tp.fitToWindow_actionPerformed(null);
4276 if (tree.getFontName() != null)
4279 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4280 safeInt(tree.getFontSize())));
4285 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4286 safeInt(view.getFontSize())));
4289 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4290 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4291 tp.showDistances(safeBoolean(tree.isShowDistances()));
4293 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4295 if (safeBoolean(tree.isCurrentTree()))
4297 af.getViewport().setCurrentTree(tp.getTree());
4301 } catch (Exception ex)
4303 ex.printStackTrace();
4308 * Load and link any saved structure viewers.
4315 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4316 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4319 * Run through all PDB ids on the alignment, and collect mappings between
4320 * distinct view ids and all sequences referring to that view.
4322 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4324 for (int i = 0; i < jseqs.size(); i++)
4326 JSeq jseq = jseqs.get(i);
4327 if (jseq.getPdbids().size() > 0)
4329 List<Pdbids> ids = jseq.getPdbids();
4330 for (int p = 0; p < ids.size(); p++)
4332 Pdbids pdbid = ids.get(p);
4333 final int structureStateCount = pdbid.getStructureState().size();
4334 for (int s = 0; s < structureStateCount; s++)
4336 // check to see if we haven't already created this structure view
4337 final StructureState structureState = pdbid.getStructureState()
4339 String sviewid = (structureState.getViewId() == null) ? null
4340 : structureState.getViewId() + uniqueSetSuffix;
4341 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4342 // Originally : pdbid.getFile()
4343 // : TODO: verify external PDB file recovery still works in normal
4344 // jalview project load
4346 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4347 jpdb.setId(pdbid.getId());
4349 int x = safeInt(structureState.getXpos());
4350 int y = safeInt(structureState.getYpos());
4351 int width = safeInt(structureState.getWidth());
4352 int height = safeInt(structureState.getHeight());
4354 // Probably don't need to do this anymore...
4355 // Desktop.desktop.getComponentAt(x, y);
4356 // TODO: NOW: check that this recovers the PDB file correctly.
4357 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4359 jalview.datamodel.SequenceI seq = seqRefIds
4360 .get(jseq.getId() + "");
4361 if (sviewid == null)
4363 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4366 if (!structureViewers.containsKey(sviewid))
4368 String viewerType = structureState.getType();
4369 if (viewerType == null) // pre Jalview 2.9
4371 viewerType = ViewerType.JMOL.toString();
4373 structureViewers.put(sviewid,
4374 new StructureViewerModel(x, y, width, height, false,
4375 false, true, structureState.getViewId(),
4377 // Legacy pre-2.7 conversion JAL-823 :
4378 // do not assume any view has to be linked for colour by
4382 // assemble String[] { pdb files }, String[] { id for each
4383 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4384 // seqs_file 2}, boolean[] {
4385 // linkAlignPanel,superposeWithAlignpanel}} from hash
4386 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4387 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4388 || structureState.isAlignwithAlignPanel());
4391 * Default colour by linked panel to false if not specified (e.g.
4392 * for pre-2.7 projects)
4394 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4395 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4396 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4399 * Default colour by viewer to true if not specified (e.g. for
4402 boolean colourByViewer = jmoldat.isColourByViewer();
4403 colourByViewer &= structureState.isColourByJmol();
4404 jmoldat.setColourByViewer(colourByViewer);
4406 if (jmoldat.getStateData().length() < structureState.getValue()
4407 /*Content()*/.length())
4409 jmoldat.setStateData(structureState.getValue());// Content());
4411 if (pdbid.getFile() != null)
4413 File mapkey = new File(pdbid.getFile());
4414 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4415 if (seqstrmaps == null)
4417 jmoldat.getFileData().put(mapkey,
4418 seqstrmaps = jmoldat.new StructureData(pdbFile,
4421 if (!seqstrmaps.getSeqList().contains(seq))
4423 seqstrmaps.getSeqList().add(seq);
4429 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");
4430 Console.warn(errorMessage);
4436 // Instantiate the associated structure views
4437 for (Entry<String, StructureViewerModel> entry : structureViewers
4442 createOrLinkStructureViewer(entry, af, ap, jprovider);
4443 } catch (Exception e)
4446 "Error loading structure viewer: " + e.getMessage());
4447 // failed - try the next one
4459 protected void createOrLinkStructureViewer(
4460 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4461 AlignmentPanel ap, jarInputStreamProvider jprovider)
4463 final StructureViewerModel stateData = viewerData.getValue();
4466 * Search for any viewer windows already open from other alignment views
4467 * that exactly match the stored structure state
4469 StructureViewerBase comp = findMatchingViewer(viewerData);
4473 linkStructureViewer(ap, comp, stateData);
4477 String type = stateData.getType();
4480 ViewerType viewerType = ViewerType.valueOf(type);
4481 createStructureViewer(viewerType, viewerData, af, jprovider);
4482 } catch (IllegalArgumentException | NullPointerException e)
4484 // TODO JAL-3619 show error dialog / offer an alternative viewer
4485 Console.error("Invalid structure viewer type: " + type);
4490 * Generates a name for the entry in the project jar file to hold state
4491 * information for a structure viewer
4496 protected String getViewerJarEntryName(String viewId)
4498 return VIEWER_PREFIX + viewId;
4502 * Returns any open frame that matches given structure viewer data. The match
4503 * is based on the unique viewId, or (for older project versions) the frame's
4509 protected StructureViewerBase findMatchingViewer(
4510 Entry<String, StructureViewerModel> viewerData)
4512 final String sviewid = viewerData.getKey();
4513 final StructureViewerModel svattrib = viewerData.getValue();
4514 StructureViewerBase comp = null;
4515 JInternalFrame[] frames = getAllFrames();
4516 for (JInternalFrame frame : frames)
4518 if (frame instanceof StructureViewerBase)
4521 * Post jalview 2.4 schema includes structure view id
4523 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4526 comp = (StructureViewerBase) frame;
4527 break; // break added in 2.9
4530 * Otherwise test for matching position and size of viewer frame
4532 else if (frame.getX() == svattrib.getX()
4533 && frame.getY() == svattrib.getY()
4534 && frame.getHeight() == svattrib.getHeight()
4535 && frame.getWidth() == svattrib.getWidth())
4537 comp = (StructureViewerBase) frame;
4538 // no break in faint hope of an exact match on viewId
4546 * Link an AlignmentPanel to an existing structure viewer.
4551 * @param useinViewerSuperpos
4552 * @param usetoColourbyseq
4553 * @param viewerColouring
4555 protected void linkStructureViewer(AlignmentPanel ap,
4556 StructureViewerBase viewer, StructureViewerModel stateData)
4558 // NOTE: if the jalview project is part of a shared session then
4559 // view synchronization should/could be done here.
4561 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4562 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4563 final boolean viewerColouring = stateData.isColourByViewer();
4564 Map<File, StructureData> oldFiles = stateData.getFileData();
4567 * Add mapping for sequences in this view to an already open viewer
4569 final AAStructureBindingModel binding = viewer.getBinding();
4570 for (File id : oldFiles.keySet())
4572 // add this and any other pdb files that should be present in the
4574 StructureData filedat = oldFiles.get(id);
4575 String pdbFile = filedat.getFilePath();
4576 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4577 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4579 binding.addSequenceForStructFile(pdbFile, seq);
4581 // and add the AlignmentPanel's reference to the view panel
4582 viewer.addAlignmentPanel(ap);
4583 if (useinViewerSuperpos)
4585 viewer.useAlignmentPanelForSuperposition(ap);
4589 viewer.excludeAlignmentPanelForSuperposition(ap);
4591 if (usetoColourbyseq)
4593 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4597 viewer.excludeAlignmentPanelForColourbyseq(ap);
4602 * Get all frames within the Desktop.
4606 protected JInternalFrame[] getAllFrames()
4608 JInternalFrame[] frames = null;
4609 // TODO is this necessary - is it safe - risk of hanging?
4614 frames = Desktop.desktop.getAllFrames();
4615 } catch (ArrayIndexOutOfBoundsException e)
4617 // occasional No such child exceptions are thrown here...
4621 } catch (InterruptedException f)
4625 } while (frames == null);
4630 * Answers true if 'version' is equal to or later than 'supported', where each
4631 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4632 * changes. Development and test values for 'version' are leniently treated
4636 * - minimum version we are comparing against
4638 * - version of data being processsed
4641 public static boolean isVersionStringLaterThan(String supported,
4644 if (supported == null || version == null
4645 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4646 || version.equalsIgnoreCase("Test")
4647 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4649 System.err.println("Assuming project file with "
4650 + (version == null ? "null" : version)
4651 + " is compatible with Jalview version " + supported);
4656 return StringUtils.compareVersions(version, supported, "b") >= 0;
4660 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4662 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4664 if (newStructureViewers != null)
4666 sview.getBinding().setFinishedLoadingFromArchive(false);
4667 newStructureViewers.add(sview);
4671 protected void setLoadingFinishedForNewStructureViewers()
4673 if (newStructureViewers != null)
4675 for (JalviewStructureDisplayI sview : newStructureViewers)
4677 sview.getBinding().setFinishedLoadingFromArchive(true);
4679 newStructureViewers.clear();
4680 newStructureViewers = null;
4684 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4685 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4686 Viewport view, String uniqueSeqSetId, String viewId,
4687 List<JvAnnotRow> autoAlan)
4689 AlignFrame af = null;
4690 af = new AlignFrame(al, safeInt(view.getWidth()),
4691 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4695 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4696 // System.out.println("Jalview2XML AF " + e);
4697 // super.processKeyEvent(e);
4704 af.setFileName(file, FileFormat.Jalview);
4706 final AlignViewport viewport = af.getViewport();
4707 for (int i = 0; i < JSEQ.size(); i++)
4709 int colour = safeInt(JSEQ.get(i).getColour());
4710 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4716 viewport.setColourByReferenceSeq(true);
4717 viewport.setDisplayReferenceSeq(true);
4720 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4722 if (view.getSequenceSetId() != null)
4724 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4726 viewport.setSequenceSetId(uniqueSeqSetId);
4729 // propagate shared settings to this new view
4730 viewport.setHistoryList(av.getHistoryList());
4731 viewport.setRedoList(av.getRedoList());
4735 viewportsAdded.put(uniqueSeqSetId, viewport);
4737 // TODO: check if this method can be called repeatedly without
4738 // side-effects if alignpanel already registered.
4739 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4741 // apply Hidden regions to view.
4742 if (hiddenSeqs != null)
4744 for (int s = 0; s < JSEQ.size(); s++)
4746 SequenceGroup hidden = new SequenceGroup();
4747 boolean isRepresentative = false;
4748 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4750 isRepresentative = true;
4751 SequenceI sequenceToHide = al
4752 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4753 hidden.addSequence(sequenceToHide, false);
4754 // remove from hiddenSeqs list so we don't try to hide it twice
4755 hiddenSeqs.remove(sequenceToHide);
4757 if (isRepresentative)
4759 SequenceI representativeSequence = al.getSequenceAt(s);
4760 hidden.addSequence(representativeSequence, false);
4761 viewport.hideRepSequences(representativeSequence, hidden);
4765 SequenceI[] hseqs = hiddenSeqs
4766 .toArray(new SequenceI[hiddenSeqs.size()]);
4767 viewport.hideSequence(hseqs);
4770 // recover view properties and display parameters
4772 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4773 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4774 final int pidThreshold = safeInt(view.getPidThreshold());
4775 viewport.setThreshold(pidThreshold);
4777 viewport.setColourText(safeBoolean(view.isShowColourText()));
4779 viewport.setConservationSelected(
4780 safeBoolean(view.isConservationSelected()));
4781 viewport.setIncrement(safeInt(view.getConsThreshold()));
4782 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4783 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4784 viewport.setFont(new Font(view.getFontName(),
4785 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4787 ViewStyleI vs = viewport.getViewStyle();
4788 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4789 viewport.setViewStyle(vs);
4790 // TODO: allow custom charWidth/Heights to be restored by updating them
4791 // after setting font - which means set above to false
4792 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4793 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4794 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4796 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4798 viewport.setShowText(safeBoolean(view.isShowText()));
4800 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4801 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4802 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4803 viewport.setShowUnconserved(view.isShowUnconserved());
4804 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4806 if (view.getViewName() != null)
4808 viewport.setViewName(view.getViewName());
4809 af.setInitialTabVisible();
4811 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4812 safeInt(view.getWidth()), safeInt(view.getHeight()));
4813 // startSeq set in af.alignPanel.updateLayout below
4814 af.alignPanel.updateLayout();
4815 ColourSchemeI cs = null;
4816 // apply colourschemes
4817 if (view.getBgColour() != null)
4819 if (view.getBgColour().startsWith("ucs"))
4821 cs = getUserColourScheme(jm, view.getBgColour());
4823 else if (view.getBgColour().startsWith("Annotation"))
4825 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4826 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4833 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4834 view.getBgColour());
4839 * turn off 'alignment colour applies to all groups'
4840 * while restoring global colour scheme
4842 viewport.setColourAppliesToAllGroups(false);
4843 viewport.setGlobalColourScheme(cs);
4844 viewport.getResidueShading().setThreshold(pidThreshold,
4845 view.isIgnoreGapsinConsensus());
4846 viewport.getResidueShading()
4847 .setConsensus(viewport.getSequenceConsensusHash());
4848 if (safeBoolean(view.isConservationSelected()) && cs != null)
4850 viewport.getResidueShading()
4851 .setConservationInc(safeInt(view.getConsThreshold()));
4853 af.changeColour(cs);
4854 viewport.setColourAppliesToAllGroups(true);
4856 viewport.setShowSequenceFeatures(
4857 safeBoolean(view.isShowSequenceFeatures()));
4859 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4860 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4861 viewport.setFollowHighlight(view.isFollowHighlight());
4862 viewport.followSelection = view.isFollowSelection();
4863 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4864 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4865 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4866 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4867 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4868 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4869 viewport.setShowGroupConservation(view.isShowGroupConservation());
4870 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4871 viewport.setShowComplementFeaturesOnTop(
4872 view.isShowComplementFeaturesOnTop());
4874 // recover feature settings
4875 if (jm.getFeatureSettings() != null)
4877 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4878 .getFeatureRenderer();
4879 FeaturesDisplayed fdi;
4880 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4881 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
4883 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4884 Map<String, Float> featureOrder = new Hashtable<>();
4886 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
4889 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4890 String featureType = setting.getType();
4893 * restore feature filters (if any)
4895 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4897 if (filters != null)
4899 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
4901 if (!filter.isEmpty())
4903 fr.setFeatureFilter(featureType, filter);
4908 * restore feature colour scheme
4910 Color maxColour = new Color(setting.getColour());
4911 if (setting.getMincolour() != null)
4914 * minColour is always set unless a simple colour
4915 * (including for colour by label though it doesn't use it)
4917 Color minColour = new Color(setting.getMincolour().intValue());
4918 Color noValueColour = minColour;
4919 NoValueColour noColour = setting.getNoValueColour();
4920 if (noColour == NoValueColour.NONE)
4922 noValueColour = null;
4924 else if (noColour == NoValueColour.MAX)
4926 noValueColour = maxColour;
4928 float min = safeFloat(safeFloat(setting.getMin()));
4929 float max = setting.getMax() == null ? 1f
4930 : setting.getMax().floatValue();
4931 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4932 maxColour, noValueColour, min, max);
4933 if (setting.getAttributeName().size() > 0)
4935 gc.setAttributeName(setting.getAttributeName().toArray(
4936 new String[setting.getAttributeName().size()]));
4938 if (setting.getThreshold() != null)
4940 gc.setThreshold(setting.getThreshold().floatValue());
4941 int threshstate = safeInt(setting.getThreshstate());
4942 // -1 = None, 0 = Below, 1 = Above threshold
4943 if (threshstate == 0)
4945 gc.setBelowThreshold(true);
4947 else if (threshstate == 1)
4949 gc.setAboveThreshold(true);
4952 gc.setAutoScaled(true); // default
4953 if (setting.isAutoScale() != null)
4955 gc.setAutoScaled(setting.isAutoScale());
4957 if (setting.isColourByLabel() != null)
4959 gc.setColourByLabel(setting.isColourByLabel());
4961 // and put in the feature colour table.
4962 featureColours.put(featureType, gc);
4966 featureColours.put(featureType, new FeatureColour(maxColour));
4968 renderOrder[fs] = featureType;
4969 if (setting.getOrder() != null)
4971 featureOrder.put(featureType, setting.getOrder().floatValue());
4975 featureOrder.put(featureType, Float.valueOf(
4976 fs / jm.getFeatureSettings().getSetting().size()));
4978 if (safeBoolean(setting.isDisplay()))
4980 fdi.setVisible(featureType);
4983 Map<String, Boolean> fgtable = new Hashtable<>();
4984 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4986 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4987 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4989 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4990 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4991 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4992 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4993 fgtable, featureColours, 1.0f, featureOrder);
4994 fr.transferSettings(frs);
4997 if (view.getHiddenColumns().size() > 0)
4999 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5001 final HiddenColumns hc = view.getHiddenColumns().get(c);
5002 viewport.hideColumns(safeInt(hc.getStart()),
5003 safeInt(hc.getEnd()) /* +1 */);
5006 if (view.getCalcIdParam() != null)
5008 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5010 if (calcIdParam != null)
5012 if (recoverCalcIdParam(calcIdParam, viewport))
5017 Console.warn("Couldn't recover parameters for "
5018 + calcIdParam.getCalcId());
5023 af.setMenusFromViewport(viewport);
5024 af.setTitle(view.getTitle());
5025 // TODO: we don't need to do this if the viewport is aready visible.
5027 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5028 * has a 'cdna/protein complement' view, in which case save it in order to
5029 * populate a SplitFrame once all views have been read in.
5031 String complementaryViewId = view.getComplementId();
5032 if (complementaryViewId == null)
5034 Desktop.addInternalFrame(af, view.getTitle(),
5035 safeInt(view.getWidth()), safeInt(view.getHeight()));
5036 // recompute any autoannotation
5037 af.alignPanel.updateAnnotation(false, true);
5038 reorderAutoannotation(af, al, autoAlan);
5039 af.alignPanel.alignmentChanged();
5043 splitFrameCandidates.put(view, af);
5049 * Reads saved data to restore Colour by Annotation settings
5051 * @param viewAnnColour
5055 * @param checkGroupAnnColour
5058 private ColourSchemeI constructAnnotationColour(
5059 AnnotationColourScheme viewAnnColour, AlignFrame af,
5060 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5062 boolean propagateAnnColour = false;
5063 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5065 if (checkGroupAnnColour && al.getGroups() != null
5066 && al.getGroups().size() > 0)
5068 // pre 2.8.1 behaviour
5069 // check to see if we should transfer annotation colours
5070 propagateAnnColour = true;
5071 for (SequenceGroup sg : al.getGroups())
5073 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5075 propagateAnnColour = false;
5081 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5083 String annotationId = viewAnnColour.getAnnotation();
5084 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5087 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5089 if (matchedAnnotation == null
5090 && annAlignment.getAlignmentAnnotation() != null)
5092 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5095 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5097 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5102 if (matchedAnnotation == null)
5104 System.err.println("Failed to match annotation colour scheme for "
5108 if (matchedAnnotation.getThreshold() == null)
5110 matchedAnnotation.setThreshold(
5111 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5112 "Threshold", Color.black));
5115 AnnotationColourGradient cs = null;
5116 if (viewAnnColour.getColourScheme().equals("None"))
5118 cs = new AnnotationColourGradient(matchedAnnotation,
5119 new Color(safeInt(viewAnnColour.getMinColour())),
5120 new Color(safeInt(viewAnnColour.getMaxColour())),
5121 safeInt(viewAnnColour.getAboveThreshold()));
5123 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5125 cs = new AnnotationColourGradient(matchedAnnotation,
5126 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5127 safeInt(viewAnnColour.getAboveThreshold()));
5131 cs = new AnnotationColourGradient(matchedAnnotation,
5132 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5133 viewAnnColour.getColourScheme()),
5134 safeInt(viewAnnColour.getAboveThreshold()));
5137 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5138 boolean useOriginalColours = safeBoolean(
5139 viewAnnColour.isPredefinedColours());
5140 cs.setSeqAssociated(perSequenceOnly);
5141 cs.setPredefinedColours(useOriginalColours);
5143 if (propagateAnnColour && al.getGroups() != null)
5145 // Also use these settings for all the groups
5146 for (int g = 0; g < al.getGroups().size(); g++)
5148 SequenceGroup sg = al.getGroups().get(g);
5149 if (sg.getGroupColourScheme() == null)
5154 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5155 matchedAnnotation, sg.getColourScheme(),
5156 safeInt(viewAnnColour.getAboveThreshold()));
5157 sg.setColourScheme(groupScheme);
5158 groupScheme.setSeqAssociated(perSequenceOnly);
5159 groupScheme.setPredefinedColours(useOriginalColours);
5165 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5166 List<JvAnnotRow> autoAlan)
5168 // copy over visualization settings for autocalculated annotation in the
5170 if (al.getAlignmentAnnotation() != null)
5173 * Kludge for magic autoannotation names (see JAL-811)
5175 String[] magicNames = new String[] { "Consensus", "Quality",
5177 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5178 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5179 for (String nm : magicNames)
5181 visan.put(nm, nullAnnot);
5183 for (JvAnnotRow auan : autoAlan)
5185 visan.put(auan.template.label
5186 + (auan.template.getCalcId() == null ? ""
5187 : "\t" + auan.template.getCalcId()),
5190 int hSize = al.getAlignmentAnnotation().length;
5191 List<JvAnnotRow> reorder = new ArrayList<>();
5192 // work through any autoCalculated annotation already on the view
5193 // removing it if it should be placed in a different location on the
5194 // annotation panel.
5195 List<String> remains = new ArrayList<>(visan.keySet());
5196 for (int h = 0; h < hSize; h++)
5198 jalview.datamodel.AlignmentAnnotation jalan = al
5199 .getAlignmentAnnotation()[h];
5200 if (jalan.autoCalculated)
5203 JvAnnotRow valan = visan.get(k = jalan.label);
5204 if (jalan.getCalcId() != null)
5206 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5211 // delete the auto calculated row from the alignment
5212 al.deleteAnnotation(jalan, false);
5216 if (valan != nullAnnot)
5218 if (jalan != valan.template)
5220 // newly created autoannotation row instance
5221 // so keep a reference to the visible annotation row
5222 // and copy over all relevant attributes
5223 if (valan.template.graphHeight >= 0)
5226 jalan.graphHeight = valan.template.graphHeight;
5228 jalan.visible = valan.template.visible;
5230 reorder.add(new JvAnnotRow(valan.order, jalan));
5235 // Add any (possibly stale) autocalculated rows that were not appended to
5236 // the view during construction
5237 for (String other : remains)
5239 JvAnnotRow othera = visan.get(other);
5240 if (othera != nullAnnot && othera.template.getCalcId() != null
5241 && othera.template.getCalcId().length() > 0)
5243 reorder.add(othera);
5246 // now put the automatic annotation in its correct place
5247 int s = 0, srt[] = new int[reorder.size()];
5248 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5249 for (JvAnnotRow jvar : reorder)
5252 srt[s++] = jvar.order;
5255 jalview.util.QuickSort.sort(srt, rws);
5256 // and re-insert the annotation at its correct position
5257 for (JvAnnotRow jvar : rws)
5259 al.addAnnotation(jvar.template, jvar.order);
5261 af.alignPanel.adjustAnnotationHeight();
5265 Hashtable skipList = null;
5268 * TODO remove this method
5271 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5272 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5273 * throw new Error("Implementation Error. No skipList defined for this
5274 * Jalview2XML instance."); } return (AlignFrame)
5275 * skipList.get(view.getSequenceSetId()); }
5279 * Check if the Jalview view contained in object should be skipped or not.
5282 * @return true if view's sequenceSetId is a key in skipList
5284 private boolean skipViewport(JalviewModel object)
5286 if (skipList == null)
5290 String id = object.getViewport().get(0).getSequenceSetId();
5291 if (skipList.containsKey(id))
5293 Console.debug("Skipping seuqence set id " + id);
5299 public void addToSkipList(AlignFrame af)
5301 if (skipList == null)
5303 skipList = new Hashtable();
5305 skipList.put(af.getViewport().getSequenceSetId(), af);
5308 public void clearSkipList()
5310 if (skipList != null)
5317 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5318 boolean ignoreUnrefed, String uniqueSeqSetId)
5320 jalview.datamodel.AlignmentI ds = getDatasetFor(
5321 vamsasSet.getDatasetId());
5322 AlignmentI xtant_ds = ds;
5323 if (xtant_ds == null)
5325 // good chance we are about to create a new dataset, but check if we've
5326 // seen some of the dataset sequence IDs before.
5327 // TODO: skip this check if we are working with project generated by
5328 // version 2.11 or later
5329 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5330 if (xtant_ds != null)
5333 addDatasetRef(vamsasSet.getDatasetId(), ds);
5336 Vector<SequenceI> dseqs = null;
5339 // recovering an alignment View
5340 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5341 if (seqSetDS != null)
5343 if (ds != null && ds != seqSetDS)
5346 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5347 + " - CDS/Protein crossreference data may be lost");
5348 if (xtant_ds != null)
5350 // This can only happen if the unique sequence set ID was bound to a
5351 // dataset that did not contain any of the sequences in the view
5352 // currently being restored.
5354 "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.");
5358 addDatasetRef(vamsasSet.getDatasetId(), ds);
5363 // try even harder to restore dataset
5364 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5365 // create a list of new dataset sequences
5366 dseqs = new Vector<>();
5368 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5370 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5371 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5373 // create a new dataset
5376 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5377 dseqs.copyInto(dsseqs);
5378 ds = new jalview.datamodel.Alignment(dsseqs);
5379 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5380 + " for alignment " + System.identityHashCode(al));
5381 addDatasetRef(vamsasSet.getDatasetId(), ds);
5383 // set the dataset for the newly imported alignment.
5384 if (al.getDataset() == null && !ignoreUnrefed)
5387 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5388 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5390 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5394 * XML dataset sequence ID to materialised dataset reference
5396 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5399 * @return the first materialised dataset reference containing a dataset
5400 * sequence referenced in the given view
5402 * - sequences from the view
5404 AlignmentI checkIfHasDataset(List<Sequence> list)
5406 for (Sequence restoredSeq : list)
5408 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5409 if (datasetFor != null)
5418 * Register ds as the containing dataset for the dataset sequences referenced
5419 * by sequences in list
5422 * - sequences in a view
5425 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5427 for (Sequence restoredSeq : list)
5429 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5430 if (prevDS != null && prevDS != ds)
5432 Console.warn("Dataset sequence appears in many datasets: "
5433 + restoredSeq.getDsseqid());
5434 // TODO: try to merge!
5442 * sequence definition to create/merge dataset sequence for
5446 * vector to add new dataset sequence to
5447 * @param ignoreUnrefed
5448 * - when true, don't create new sequences from vamsasSeq if it's id
5449 * doesn't already have an asssociated Jalview sequence.
5451 * - used to reorder the sequence in the alignment according to the
5452 * vamsasSeq array ordering, to preserve ordering of dataset
5454 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5455 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5458 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5460 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5461 boolean reorder = false;
5462 SequenceI dsq = null;
5463 if (sq != null && sq.getDatasetSequence() != null)
5465 dsq = sq.getDatasetSequence();
5471 if (sq == null && ignoreUnrefed)
5475 String sqid = vamsasSeq.getDsseqid();
5478 // need to create or add a new dataset sequence reference to this sequence
5481 dsq = seqRefIds.get(sqid);
5486 // make a new dataset sequence
5487 dsq = sq.createDatasetSequence();
5490 // make up a new dataset reference for this sequence
5491 sqid = seqHash(dsq);
5493 dsq.setVamsasId(uniqueSetSuffix + sqid);
5494 seqRefIds.put(sqid, dsq);
5499 dseqs.addElement(dsq);
5504 ds.addSequence(dsq);
5510 { // make this dataset sequence sq's dataset sequence
5511 sq.setDatasetSequence(dsq);
5512 // and update the current dataset alignment
5517 if (!dseqs.contains(dsq))
5524 if (ds.findIndex(dsq) < 0)
5526 ds.addSequence(dsq);
5533 // TODO: refactor this as a merge dataset sequence function
5534 // now check that sq (the dataset sequence) sequence really is the union of
5535 // all references to it
5536 // boolean pre = sq.getStart() < dsq.getStart();
5537 // boolean post = sq.getEnd() > dsq.getEnd();
5541 // StringBuffer sb = new StringBuffer();
5542 String newres = jalview.analysis.AlignSeq.extractGaps(
5543 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5544 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5545 && newres.length() > dsq.getLength())
5547 // Update with the longer sequence.
5551 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5552 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5553 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5554 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5556 dsq.setSequence(newres);
5558 // TODO: merges will never happen if we 'know' we have the real dataset
5559 // sequence - this should be detected when id==dssid
5561 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5562 // + (pre ? "prepended" : "") + " "
5563 // + (post ? "appended" : ""));
5568 // sequence refs are identical. We may need to update the existing dataset
5569 // alignment with this one, though.
5570 if (ds != null && dseqs == null)
5572 int opos = ds.findIndex(dsq);
5573 SequenceI tseq = null;
5574 if (opos != -1 && vseqpos != opos)
5576 // remove from old position
5577 ds.deleteSequence(dsq);
5579 if (vseqpos < ds.getHeight())
5581 if (vseqpos != opos)
5583 // save sequence at destination position
5584 tseq = ds.getSequenceAt(vseqpos);
5585 ds.replaceSequenceAt(vseqpos, dsq);
5586 ds.addSequence(tseq);
5591 ds.addSequence(dsq);
5598 * TODO use AlignmentI here and in related methods - needs
5599 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5601 Hashtable<String, AlignmentI> datasetIds = null;
5603 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5605 private AlignmentI getDatasetFor(String datasetId)
5607 if (datasetIds == null)
5609 datasetIds = new Hashtable<>();
5612 if (datasetIds.containsKey(datasetId))
5614 return datasetIds.get(datasetId);
5619 private void addDatasetRef(String datasetId, AlignmentI dataset)
5621 if (datasetIds == null)
5623 datasetIds = new Hashtable<>();
5625 datasetIds.put(datasetId, dataset);
5629 * make a new dataset ID for this jalview dataset alignment
5634 private String getDatasetIdRef(AlignmentI dataset)
5636 if (dataset.getDataset() != null)
5639 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5641 String datasetId = makeHashCode(dataset, null);
5642 if (datasetId == null)
5644 // make a new datasetId and record it
5645 if (dataset2Ids == null)
5647 dataset2Ids = new IdentityHashMap<>();
5651 datasetId = dataset2Ids.get(dataset);
5653 if (datasetId == null)
5655 datasetId = "ds" + dataset2Ids.size() + 1;
5656 dataset2Ids.put(dataset, datasetId);
5663 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5664 * constructed as a special subclass GeneLocus.
5666 * @param datasetSequence
5669 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5671 for (int d = 0; d < sequence.getDBRef().size(); d++)
5673 DBRef dr = sequence.getDBRef().get(d);
5677 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5678 dr.getAccessionId());
5682 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5683 dr.getAccessionId());
5685 if (dr.getMapping() != null)
5687 entry.setMap(addMapping(dr.getMapping()));
5689 entry.setCanonical(dr.isCanonical());
5690 datasetSequence.addDBRef(entry);
5694 private jalview.datamodel.Mapping addMapping(Mapping m)
5696 SequenceI dsto = null;
5697 // Mapping m = dr.getMapping();
5698 int fr[] = new int[m.getMapListFrom().size() * 2];
5699 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5700 for (int _i = 0; from.hasNext(); _i += 2)
5702 MapListFrom mf = from.next();
5703 fr[_i] = mf.getStart();
5704 fr[_i + 1] = mf.getEnd();
5706 int fto[] = new int[m.getMapListTo().size() * 2];
5707 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5708 for (int _i = 0; to.hasNext(); _i += 2)
5710 MapListTo mf = to.next();
5711 fto[_i] = mf.getStart();
5712 fto[_i + 1] = mf.getEnd();
5714 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5715 fto, m.getMapFromUnit().intValue(),
5716 m.getMapToUnit().intValue());
5719 * (optional) choice of dseqFor or Sequence
5721 if (m.getDseqFor() != null)
5723 String dsfor = m.getDseqFor();
5724 if (seqRefIds.containsKey(dsfor))
5729 jmap.setTo(seqRefIds.get(dsfor));
5733 frefedSequence.add(newMappingRef(dsfor, jmap));
5736 else if (m.getSequence() != null)
5739 * local sequence definition
5741 Sequence ms = m.getSequence();
5742 SequenceI djs = null;
5743 String sqid = ms.getDsseqid();
5744 if (sqid != null && sqid.length() > 0)
5747 * recover dataset sequence
5749 djs = seqRefIds.get(sqid);
5754 "Warning - making up dataset sequence id for DbRef sequence map reference");
5755 sqid = ((Object) ms).toString(); // make up a new hascode for
5756 // undefined dataset sequence hash
5757 // (unlikely to happen)
5763 * make a new dataset sequence and add it to refIds hash
5765 djs = new jalview.datamodel.Sequence(ms.getName(),
5767 djs.setStart(jmap.getMap().getToLowest());
5768 djs.setEnd(jmap.getMap().getToHighest());
5769 djs.setVamsasId(uniqueSetSuffix + sqid);
5771 incompleteSeqs.put(sqid, djs);
5772 seqRefIds.put(sqid, djs);
5775 Console.debug("about to recurse on addDBRefs.");
5784 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5785 * view as XML (but not to file), and then reloading it
5790 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5793 JalviewModel jm = saveState(ap, null, null, null);
5796 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5797 ap.getAlignment().getDataset());
5799 uniqueSetSuffix = "";
5800 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5801 jm.getViewport().get(0).setId(null);
5802 // we don't overwrite the view we just copied
5804 if (this.frefedSequence == null)
5806 frefedSequence = new Vector<>();
5809 viewportsAdded.clear();
5811 AlignFrame af = loadFromObject(jm, null, false, null);
5812 af.getAlignPanels().clear();
5813 af.closeMenuItem_actionPerformed(true);
5816 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5817 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5818 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5819 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5820 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5823 return af.alignPanel;
5826 private Hashtable jvids2vobj;
5829 * set the object to ID mapping tables used to write/recover objects and XML
5830 * ID strings for the jalview project. If external tables are provided then
5831 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5832 * object goes out of scope. - also populates the datasetIds hashtable with
5833 * alignment objects containing dataset sequences
5836 * Map from ID strings to jalview datamodel
5838 * Map from jalview datamodel to ID strings
5842 public void setObjectMappingTables(Hashtable vobj2jv,
5843 IdentityHashMap jv2vobj)
5845 this.jv2vobj = jv2vobj;
5846 this.vobj2jv = vobj2jv;
5847 Iterator ds = jv2vobj.keySet().iterator();
5849 while (ds.hasNext())
5851 Object jvobj = ds.next();
5852 id = jv2vobj.get(jvobj).toString();
5853 if (jvobj instanceof jalview.datamodel.Alignment)
5855 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5857 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5860 else if (jvobj instanceof jalview.datamodel.Sequence)
5862 // register sequence object so the XML parser can recover it.
5863 if (seqRefIds == null)
5865 seqRefIds = new HashMap<>();
5867 if (seqsToIds == null)
5869 seqsToIds = new IdentityHashMap<>();
5871 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5872 seqsToIds.put((SequenceI) jvobj, id);
5874 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5877 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5878 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5879 if (jvann.annotationId == null)
5881 jvann.annotationId = anid;
5883 if (!jvann.annotationId.equals(anid))
5885 // TODO verify that this is the correct behaviour
5886 Console.warn("Overriding Annotation ID for " + anid
5887 + " from different id : " + jvann.annotationId);
5888 jvann.annotationId = anid;
5891 else if (jvobj instanceof String)
5893 if (jvids2vobj == null)
5895 jvids2vobj = new Hashtable();
5896 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5901 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5907 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5908 * objects created from the project archive. If string is null (default for
5909 * construction) then suffix will be set automatically.
5913 public void setUniqueSetSuffix(String string)
5915 uniqueSetSuffix = string;
5920 * uses skipList2 as the skipList for skipping views on sequence sets
5921 * associated with keys in the skipList
5925 public void setSkipList(Hashtable skipList2)
5927 skipList = skipList2;
5931 * Reads the jar entry of given name and returns its contents, or null if the
5932 * entry is not found.
5935 * @param jarEntryName
5938 protected String readJarEntry(jarInputStreamProvider jprovider,
5939 String jarEntryName)
5941 String result = null;
5942 BufferedReader in = null;
5947 * Reopen the jar input stream and traverse its entries to find a matching
5950 JarInputStream jin = jprovider.getJarInputStream();
5951 JarEntry entry = null;
5954 entry = jin.getNextJarEntry();
5955 } while (entry != null && !entry.getName().equals(jarEntryName));
5959 StringBuilder out = new StringBuilder(256);
5960 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5963 while ((data = in.readLine()) != null)
5967 result = out.toString();
5972 "Couldn't find entry in Jalview Jar for " + jarEntryName);
5974 } catch (Exception ex)
5976 ex.printStackTrace();
5984 } catch (IOException e)
5995 * Returns an incrementing counter (0, 1, 2...)
5999 private synchronized int nextCounter()
6005 * Loads any saved PCA viewers
6010 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6014 List<PcaViewer> pcaviewers = model.getPcaViewer();
6015 for (PcaViewer viewer : pcaviewers)
6017 String modelName = viewer.getScoreModelName();
6018 SimilarityParamsI params = new SimilarityParams(
6019 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6020 viewer.isIncludeGaps(),
6021 viewer.isDenominateByShortestLength());
6024 * create the panel (without computing the PCA)
6026 PCAPanel panel = new PCAPanel(ap, modelName, params);
6028 panel.setTitle(viewer.getTitle());
6029 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6030 viewer.getWidth(), viewer.getHeight()));
6032 boolean showLabels = viewer.isShowLabels();
6033 panel.setShowLabels(showLabels);
6034 panel.getRotatableCanvas().setShowLabels(showLabels);
6035 panel.getRotatableCanvas()
6036 .setBgColour(new Color(viewer.getBgColour()));
6037 panel.getRotatableCanvas()
6038 .setApplyToAllViews(viewer.isLinkToAllViews());
6041 * load PCA output data
6043 ScoreModelI scoreModel = ScoreModels.getInstance()
6044 .getScoreModel(modelName, ap);
6045 PCA pca = new PCA(null, scoreModel, params);
6046 PcaDataType pcaData = viewer.getPcaData();
6048 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6049 pca.setPairwiseScores(pairwise);
6051 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6052 pca.setTridiagonal(triDiag);
6054 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6055 pca.setEigenmatrix(result);
6057 panel.getPcaModel().setPCA(pca);
6060 * we haven't saved the input data! (JAL-2647 to do)
6062 panel.setInputData(null);
6065 * add the sequence points for the PCA display
6067 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6068 for (SequencePoint sp : viewer.getSequencePoint())
6070 String seqId = sp.getSequenceRef();
6071 SequenceI seq = seqRefIds.get(seqId);
6074 throw new IllegalStateException(
6075 "Unmatched seqref for PCA: " + seqId);
6077 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6078 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6080 seqPoints.add(seqPoint);
6082 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6085 * set min-max ranges and scale after setPoints (which recomputes them)
6087 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6088 SeqPointMin spMin = viewer.getSeqPointMin();
6089 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6091 SeqPointMax spMax = viewer.getSeqPointMax();
6092 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6094 panel.getRotatableCanvas().setSeqMinMax(min, max);
6096 // todo: hold points list in PCAModel only
6097 panel.getPcaModel().setSequencePoints(seqPoints);
6099 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6100 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6101 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6103 // is this duplication needed?
6104 panel.setTop(seqPoints.size() - 1);
6105 panel.getPcaModel().setTop(seqPoints.size() - 1);
6108 * add the axes' end points for the display
6110 for (int i = 0; i < 3; i++)
6112 Axis axis = viewer.getAxis().get(i);
6113 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6114 axis.getXPos(), axis.getYPos(), axis.getZPos());
6117 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6118 "label.calc_title", "PCA", modelName), 475, 450);
6120 } catch (Exception ex)
6122 Console.error("Error loading PCA: " + ex.toString());
6127 * Creates a new structure viewer window
6134 protected void createStructureViewer(ViewerType viewerType,
6135 final Entry<String, StructureViewerModel> viewerData,
6136 AlignFrame af, jarInputStreamProvider jprovider)
6138 final StructureViewerModel viewerModel = viewerData.getValue();
6139 String sessionFilePath = null;
6141 if (viewerType == ViewerType.JMOL)
6143 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6147 String viewerJarEntryName = getViewerJarEntryName(
6148 viewerModel.getViewId());
6149 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6150 "viewerSession", ".tmp");
6152 final String sessionPath = sessionFilePath;
6153 final String sviewid = viewerData.getKey();
6156 SwingUtilities.invokeAndWait(new Runnable()
6161 JalviewStructureDisplayI sview = null;
6164 sview = StructureViewer.createView(viewerType, af.alignPanel,
6165 viewerModel, sessionPath, sviewid);
6166 addNewStructureViewer(sview);
6167 } catch (OutOfMemoryError ex)
6169 new OOMWarning("Restoring structure view for " + viewerType,
6170 (OutOfMemoryError) ex.getCause());
6171 if (sview != null && sview.isVisible())
6173 sview.closeViewer(false);
6174 sview.setVisible(false);
6180 } catch (InvocationTargetException | InterruptedException ex)
6182 Console.warn("Unexpected error when opening " + viewerType
6183 + " structure viewer", ex);
6188 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6189 * the path of the file. "load file" commands are rewritten to change the
6190 * original PDB file names to those created as the Jalview project is loaded.
6196 private String rewriteJmolSession(StructureViewerModel svattrib,
6197 jarInputStreamProvider jprovider)
6199 String state = svattrib.getStateData(); // Jalview < 2.9
6200 if (state == null || state.isEmpty()) // Jalview >= 2.9
6202 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6203 state = readJarEntry(jprovider, jarEntryName);
6205 // TODO or simpler? for each key in oldFiles,
6206 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6207 // (allowing for different path escapings)
6208 StringBuilder rewritten = new StringBuilder(state.length());
6209 int cp = 0, ncp, ecp;
6210 Map<File, StructureData> oldFiles = svattrib.getFileData();
6211 while ((ncp = state.indexOf("load ", cp)) > -1)
6215 // look for next filename in load statement
6216 rewritten.append(state.substring(cp,
6217 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6218 String oldfilenam = state.substring(ncp,
6219 ecp = state.indexOf("\"", ncp));
6220 // recover the new mapping data for this old filename
6221 // have to normalize filename - since Jmol and jalview do
6222 // filename translation differently.
6223 StructureData filedat = oldFiles.get(new File(oldfilenam));
6224 if (filedat == null)
6226 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6227 filedat = oldFiles.get(new File(reformatedOldFilename));
6229 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6230 rewritten.append("\"");
6231 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6232 // look for next file statement.
6233 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6237 // just append rest of state
6238 rewritten.append(state.substring(cp));
6242 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6243 rewritten = new StringBuilder(state);
6244 rewritten.append("; load append ");
6245 for (File id : oldFiles.keySet())
6247 // add pdb files that should be present in the viewer
6248 StructureData filedat = oldFiles.get(id);
6249 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6251 rewritten.append(";");
6254 if (rewritten.length() == 0)
6258 final String history = "history = ";
6259 int historyIndex = rewritten.indexOf(history);
6260 if (historyIndex > -1)
6263 * change "history = [true|false];" to "history = [1|0];"
6265 historyIndex += history.length();
6266 String val = rewritten.substring(historyIndex, historyIndex + 5);
6267 if (val.startsWith("true"))
6269 rewritten.replace(historyIndex, historyIndex + 4, "1");
6271 else if (val.startsWith("false"))
6273 rewritten.replace(historyIndex, historyIndex + 5, "0");
6279 File tmp = File.createTempFile("viewerSession", ".tmp");
6280 try (OutputStream os = new FileOutputStream(tmp))
6282 InputStream is = new ByteArrayInputStream(
6283 rewritten.toString().getBytes());
6285 return tmp.getAbsolutePath();
6287 } catch (IOException e)
6289 Console.error("Error restoring Jmol session: " + e.toString());
6295 * Populates an XML model of the feature colour scheme for one feature type
6297 * @param featureType
6301 public static Colour marshalColour(String featureType,
6302 FeatureColourI fcol)
6304 Colour col = new Colour();
6305 if (fcol.isSimpleColour())
6307 col.setRGB(Format.getHexString(fcol.getColour()));
6311 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6312 col.setMin(fcol.getMin());
6313 col.setMax(fcol.getMax());
6314 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6315 col.setAutoScale(fcol.isAutoScaled());
6316 col.setThreshold(fcol.getThreshold());
6317 col.setColourByLabel(fcol.isColourByLabel());
6318 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6319 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6320 : ThresholdType.NONE));
6321 if (fcol.isColourByAttribute())
6323 final String[] attName = fcol.getAttributeName();
6324 col.getAttributeName().add(attName[0]);
6325 if (attName.length > 1)
6327 col.getAttributeName().add(attName[1]);
6330 Color noColour = fcol.getNoColour();
6331 if (noColour == null)
6333 col.setNoValueColour(NoValueColour.NONE);
6335 else if (noColour == fcol.getMaxColour())
6337 col.setNoValueColour(NoValueColour.MAX);
6341 col.setNoValueColour(NoValueColour.MIN);
6344 col.setName(featureType);
6349 * Populates an XML model of the feature filter(s) for one feature type
6351 * @param firstMatcher
6352 * the first (or only) match condition)
6354 * remaining match conditions (if any)
6356 * if true, conditions are and-ed, else or-ed
6358 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6359 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6362 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6364 if (filters.hasNext())
6369 CompoundMatcher compound = new CompoundMatcher();
6370 compound.setAnd(and);
6371 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6372 firstMatcher, Collections.emptyIterator(), and);
6373 // compound.addMatcherSet(matcher1);
6374 compound.getMatcherSet().add(matcher1);
6375 FeatureMatcherI nextMatcher = filters.next();
6376 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6377 nextMatcher, filters, and);
6378 // compound.addMatcherSet(matcher2);
6379 compound.getMatcherSet().add(matcher2);
6380 result.setCompoundMatcher(compound);
6385 * single condition matcher
6387 // MatchCondition matcherModel = new MatchCondition();
6388 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6389 matcherModel.setCondition(
6390 firstMatcher.getMatcher().getCondition().getStableName());
6391 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6392 if (firstMatcher.isByAttribute())
6394 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6395 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6396 String[] attName = firstMatcher.getAttribute();
6397 matcherModel.getAttributeName().add(attName[0]); // attribute
6398 if (attName.length > 1)
6400 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6403 else if (firstMatcher.isByLabel())
6405 matcherModel.setBy(FilterBy.BY_LABEL);
6407 else if (firstMatcher.isByScore())
6409 matcherModel.setBy(FilterBy.BY_SCORE);
6411 result.setMatchCondition(matcherModel);
6418 * Loads one XML model of a feature filter to a Jalview object
6420 * @param featureType
6421 * @param matcherSetModel
6424 public static FeatureMatcherSetI parseFilter(String featureType,
6425 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6427 FeatureMatcherSetI result = new FeatureMatcherSet();
6430 parseFilterConditions(result, matcherSetModel, true);
6431 } catch (IllegalStateException e)
6433 // mixing AND and OR conditions perhaps
6435 String.format("Error reading filter conditions for '%s': %s",
6436 featureType, e.getMessage()));
6437 // return as much as was parsed up to the error
6444 * Adds feature match conditions to matcherSet as unmarshalled from XML
6445 * (possibly recursively for compound conditions)
6448 * @param matcherSetModel
6450 * if true, multiple conditions are AND-ed, else they are OR-ed
6451 * @throws IllegalStateException
6452 * if AND and OR conditions are mixed
6454 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6455 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6458 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6459 .getMatchCondition();
6465 FilterBy filterBy = mc.getBy();
6466 Condition cond = Condition.fromString(mc.getCondition());
6467 String pattern = mc.getValue();
6468 FeatureMatcherI matchCondition = null;
6469 if (filterBy == FilterBy.BY_LABEL)
6471 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6473 else if (filterBy == FilterBy.BY_SCORE)
6475 matchCondition = FeatureMatcher.byScore(cond, pattern);
6478 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6480 final List<String> attributeName = mc.getAttributeName();
6481 String[] attNames = attributeName
6482 .toArray(new String[attributeName.size()]);
6483 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6488 * note this throws IllegalStateException if AND-ing to a
6489 * previously OR-ed compound condition, or vice versa
6493 matcherSet.and(matchCondition);
6497 matcherSet.or(matchCondition);
6503 * compound condition
6505 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6506 .getCompoundMatcher().getMatcherSet();
6507 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6508 if (matchers.size() == 2)
6510 parseFilterConditions(matcherSet, matchers.get(0), anded);
6511 parseFilterConditions(matcherSet, matchers.get(1), anded);
6515 System.err.println("Malformed compound filter condition");
6521 * Loads one XML model of a feature colour to a Jalview object
6523 * @param colourModel
6526 public static FeatureColourI parseColour(Colour colourModel)
6528 FeatureColourI colour = null;
6530 if (colourModel.getMax() != null)
6532 Color mincol = null;
6533 Color maxcol = null;
6534 Color noValueColour = null;
6538 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6539 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6540 } catch (Exception e)
6542 Console.warn("Couldn't parse out graduated feature color.", e);
6545 NoValueColour noCol = colourModel.getNoValueColour();
6546 if (noCol == NoValueColour.MIN)
6548 noValueColour = mincol;
6550 else if (noCol == NoValueColour.MAX)
6552 noValueColour = maxcol;
6555 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6556 safeFloat(colourModel.getMin()),
6557 safeFloat(colourModel.getMax()));
6558 final List<String> attributeName = colourModel.getAttributeName();
6559 String[] attributes = attributeName
6560 .toArray(new String[attributeName.size()]);
6561 if (attributes != null && attributes.length > 0)
6563 colour.setAttributeName(attributes);
6565 if (colourModel.isAutoScale() != null)
6567 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6569 if (colourModel.isColourByLabel() != null)
6571 colour.setColourByLabel(
6572 colourModel.isColourByLabel().booleanValue());
6574 if (colourModel.getThreshold() != null)
6576 colour.setThreshold(colourModel.getThreshold().floatValue());
6578 ThresholdType ttyp = colourModel.getThreshType();
6579 if (ttyp == ThresholdType.ABOVE)
6581 colour.setAboveThreshold(true);
6583 else if (ttyp == ThresholdType.BELOW)
6585 colour.setBelowThreshold(true);
6590 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6591 colour = new FeatureColour(color);