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;
28 import java.awt.Dimension;
30 import java.awt.Rectangle;
31 import java.io.BufferedReader;
32 import java.io.ByteArrayInputStream;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.OutputStream;
40 import java.io.OutputStreamWriter;
41 import java.io.PrintWriter;
42 import java.lang.reflect.InvocationTargetException;
43 import java.math.BigInteger;
44 import java.net.MalformedURLException;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.Collections;
49 import java.util.Enumeration;
50 import java.util.GregorianCalendar;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Hashtable;
54 import java.util.IdentityHashMap;
55 import java.util.Iterator;
56 import java.util.LinkedHashMap;
57 import java.util.List;
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.datamodel.AlignedCodonFrame;
88 import jalview.datamodel.Alignment;
89 import jalview.datamodel.AlignmentAnnotation;
90 import jalview.datamodel.AlignmentI;
91 import jalview.datamodel.DBRefEntry;
92 import jalview.datamodel.GeneLocus;
93 import jalview.datamodel.GraphLine;
94 import jalview.datamodel.PDBEntry;
95 import jalview.datamodel.Point;
96 import jalview.datamodel.RnaViewerModel;
97 import jalview.datamodel.SequenceFeature;
98 import jalview.datamodel.SequenceGroup;
99 import jalview.datamodel.SequenceI;
100 import jalview.datamodel.StructureViewerModel;
101 import jalview.datamodel.StructureViewerModel.StructureData;
102 import jalview.datamodel.features.FeatureMatcher;
103 import jalview.datamodel.features.FeatureMatcherI;
104 import jalview.datamodel.features.FeatureMatcherSet;
105 import jalview.datamodel.features.FeatureMatcherSetI;
106 import jalview.ext.varna.RnaModel;
107 import jalview.gui.AlignFrame;
108 import jalview.gui.AlignViewport;
109 import jalview.gui.AlignmentPanel;
110 import jalview.gui.AppVarna;
111 import jalview.gui.Desktop;
112 import jalview.gui.JvOptionPane;
113 import jalview.gui.OOMWarning;
114 import jalview.gui.OverviewPanel;
115 import jalview.gui.PCAPanel;
116 import jalview.gui.PaintRefresher;
117 import jalview.gui.SplitFrame;
118 import jalview.gui.StructureViewer;
119 import jalview.gui.StructureViewer.ViewerType;
120 import jalview.gui.StructureViewerBase;
121 import jalview.gui.TreePanel;
122 import jalview.io.BackupFiles;
123 import jalview.io.DataSourceType;
124 import jalview.io.FileFormat;
125 import jalview.io.NewickFile;
126 import jalview.math.Matrix;
127 import jalview.math.MatrixI;
128 import jalview.renderer.ResidueShaderI;
129 import jalview.schemes.AnnotationColourGradient;
130 import jalview.schemes.ColourSchemeI;
131 import jalview.schemes.ColourSchemeProperty;
132 import jalview.schemes.FeatureColour;
133 import jalview.schemes.ResidueProperties;
134 import jalview.schemes.UserColourScheme;
135 import jalview.structure.StructureSelectionManager;
136 import jalview.structures.models.AAStructureBindingModel;
137 import jalview.util.Format;
138 import jalview.util.MessageManager;
139 import jalview.util.Platform;
140 import jalview.util.StringUtils;
141 import jalview.util.jarInputStreamProvider;
142 import jalview.util.matcher.Condition;
143 import jalview.viewmodel.AlignmentViewport;
144 import jalview.viewmodel.PCAModel;
145 import jalview.viewmodel.ViewportRanges;
146 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
147 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
148 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
149 import jalview.ws.jws2.Jws2Discoverer;
150 import jalview.ws.jws2.dm.AAConSettings;
151 import jalview.ws.jws2.jabaws2.Jws2Instance;
152 import jalview.ws.params.ArgumentI;
153 import jalview.ws.params.AutoCalcSetting;
154 import jalview.ws.params.WsParamSetI;
155 import jalview.xml.binding.jalview.AlcodonFrame;
156 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
157 import jalview.xml.binding.jalview.Annotation;
158 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
159 import jalview.xml.binding.jalview.AnnotationColourScheme;
160 import jalview.xml.binding.jalview.AnnotationElement;
161 import jalview.xml.binding.jalview.DoubleMatrix;
162 import jalview.xml.binding.jalview.DoubleVector;
163 import jalview.xml.binding.jalview.Feature;
164 import jalview.xml.binding.jalview.Feature.OtherData;
165 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
166 import jalview.xml.binding.jalview.FilterBy;
167 import jalview.xml.binding.jalview.JalviewModel;
168 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
169 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
170 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
171 import jalview.xml.binding.jalview.JalviewModel.JGroup;
172 import jalview.xml.binding.jalview.JalviewModel.JSeq;
173 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
176 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
177 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
178 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
181 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
182 import jalview.xml.binding.jalview.JalviewModel.Tree;
183 import jalview.xml.binding.jalview.JalviewModel.UserColours;
184 import jalview.xml.binding.jalview.JalviewModel.Viewport;
185 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
187 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
188 import jalview.xml.binding.jalview.JalviewUserColours;
189 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
190 import jalview.xml.binding.jalview.MapListType.MapListFrom;
191 import jalview.xml.binding.jalview.MapListType.MapListTo;
192 import jalview.xml.binding.jalview.Mapping;
193 import jalview.xml.binding.jalview.NoValueColour;
194 import jalview.xml.binding.jalview.ObjectFactory;
195 import jalview.xml.binding.jalview.PcaDataType;
196 import jalview.xml.binding.jalview.Pdbentry.Property;
197 import jalview.xml.binding.jalview.Sequence;
198 import jalview.xml.binding.jalview.Sequence.DBRef;
199 import jalview.xml.binding.jalview.SequenceSet;
200 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
201 import jalview.xml.binding.jalview.ThresholdType;
202 import jalview.xml.binding.jalview.VAMSAS;
205 * Write out the current jalview desktop state as a Jalview XML stream.
207 * Note: the vamsas objects referred to here are primitive versions of the
208 * VAMSAS project schema elements - they are not the same and most likely never
212 * @version $Revision: 1.134 $
214 public class Jalview2XML
217 // BH 2018 we add the .jvp binary extension to J2S so that
218 // it will declare that binary when we do the file save from the browser
222 Platform.addJ2SBinaryType(".jvp?");
225 private static final String VIEWER_PREFIX = "viewer_";
227 private static final String RNA_PREFIX = "rna_";
229 private static final String UTF_8 = "UTF-8";
232 * prefix for recovering datasets for alignments with multiple views where
233 * non-existent dataset IDs were written for some views
235 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
237 // use this with nextCounter() to make unique names for entities
238 private int counter = 0;
241 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
242 * of sequence objects are created.
244 IdentityHashMap<SequenceI, String> seqsToIds = null;
247 * jalview XML Sequence ID to jalview sequence object reference (both dataset
248 * and alignment sequences. Populated as XML reps of sequence objects are
251 Map<String, SequenceI> seqRefIds = null;
253 Map<String, SequenceI> incompleteSeqs = null;
255 List<SeqFref> frefedSequence = null;
257 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
260 * Map of reconstructed AlignFrame objects that appear to have come from
261 * SplitFrame objects (have a dna/protein complement view).
263 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
266 * Map from displayed rna structure models to their saved session state jar
269 private Map<RnaModel, String> rnaSessions = new HashMap<>();
272 * A helper method for safely using the value of an optional attribute that
273 * may be null if not present in the XML. Answers the boolean value, or false
279 public static boolean safeBoolean(Boolean b)
281 return b == null ? false : b.booleanValue();
285 * A helper method for safely using the value of an optional attribute that
286 * may be null if not present in the XML. Answers the integer value, or zero
292 public static int safeInt(Integer i)
294 return i == null ? 0 : i.intValue();
298 * A helper method for safely using the value of an optional attribute that
299 * may be null if not present in the XML. Answers the float value, or zero if
305 public static float safeFloat(Float f)
307 return f == null ? 0f : f.floatValue();
311 * create/return unique hash string for sq
314 * @return new or existing unique string for sq
316 String seqHash(SequenceI sq)
318 if (seqsToIds == null)
322 if (seqsToIds.containsKey(sq))
324 return seqsToIds.get(sq);
328 // create sequential key
329 String key = "sq" + (seqsToIds.size() + 1);
330 key = makeHashCode(sq, key); // check we don't have an external reference
332 seqsToIds.put(sq, key);
339 if (seqsToIds == null)
341 seqsToIds = new IdentityHashMap<>();
343 if (seqRefIds == null)
345 seqRefIds = new HashMap<>();
347 if (incompleteSeqs == null)
349 incompleteSeqs = new HashMap<>();
351 if (frefedSequence == null)
353 frefedSequence = new ArrayList<>();
361 public Jalview2XML(boolean raiseGUI)
363 this.raiseGUI = raiseGUI;
367 * base class for resolving forward references to sequences by their ID
372 abstract class SeqFref
378 public SeqFref(String _sref, String type)
384 public String getSref()
389 public SequenceI getSrefSeq()
391 return seqRefIds.get(sref);
394 public boolean isResolvable()
396 return seqRefIds.get(sref) != null;
399 public SequenceI getSrefDatasetSeq()
401 SequenceI sq = seqRefIds.get(sref);
404 while (sq.getDatasetSequence() != null)
406 sq = sq.getDatasetSequence();
413 * @return true if the forward reference was fully resolved
415 abstract boolean resolve();
418 public String toString()
420 return type + " reference to " + sref;
425 * create forward reference for a mapping
431 public SeqFref newMappingRef(final String sref,
432 final jalview.datamodel.Mapping _jmap)
434 SeqFref fref = new SeqFref(sref, "Mapping")
436 public jalview.datamodel.Mapping jmap = _jmap;
441 SequenceI seq = getSrefDatasetSeq();
453 public SeqFref newAlcodMapRef(final String sref,
454 final AlignedCodonFrame _cf,
455 final jalview.datamodel.Mapping _jmap)
458 SeqFref fref = new SeqFref(sref, "Codon Frame")
460 AlignedCodonFrame cf = _cf;
462 public jalview.datamodel.Mapping mp = _jmap;
465 public boolean isResolvable()
467 return super.isResolvable() && mp.getTo() != null;
473 SequenceI seq = getSrefDatasetSeq();
478 cf.addMap(seq, mp.getTo(), mp.getMap());
485 public void resolveFrefedSequences()
487 Iterator<SeqFref> nextFref = frefedSequence.iterator();
488 int toresolve = frefedSequence.size();
489 int unresolved = 0, failedtoresolve = 0;
490 while (nextFref.hasNext())
492 SeqFref ref = nextFref.next();
493 if (ref.isResolvable())
505 } catch (Exception x)
508 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
521 System.err.println("Jalview Project Import: There were " + unresolved
522 + " forward references left unresolved on the stack.");
524 if (failedtoresolve > 0)
526 System.err.println("SERIOUS! " + failedtoresolve
527 + " resolvable forward references failed to resolve.");
529 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
532 "Jalview Project Import: There are " + incompleteSeqs.size()
533 + " sequences which may have incomplete metadata.");
534 if (incompleteSeqs.size() < 10)
536 for (SequenceI s : incompleteSeqs.values())
538 System.err.println(s.toString());
544 "Too many to report. Skipping output of incomplete sequences.");
550 * This maintains a map of viewports, the key being the seqSetId. Important to
551 * set historyItem and redoList for multiple views
553 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
555 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
557 String uniqueSetSuffix = "";
560 * List of pdbfiles added to Jar
562 List<String> pdbfiles = null;
564 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
565 public void saveState(File statefile)
567 FileOutputStream fos = null;
572 fos = new FileOutputStream(statefile);
574 JarOutputStream jout = new JarOutputStream(fos);
578 } catch (Exception e)
580 Cache.log.error("Couln't write Jalview state to " + statefile, e);
581 // TODO: inform user of the problem - they need to know if their data was
583 if (errorMessage == null)
585 errorMessage = "Did't write Jalview Archive to output file '"
586 + statefile + "' - See console error log for details";
590 errorMessage += "(Didn't write Jalview Archive to output file '"
601 } catch (IOException e)
611 * Writes a jalview project archive to the given Jar output stream.
615 public void saveState(JarOutputStream jout)
617 AlignFrame[] frames = Desktop.getAlignFrames();
623 saveAllFrames(Arrays.asList(frames), jout);
627 * core method for storing state for a set of AlignFrames.
630 * - frames involving all data to be exported (including containing
633 * - project output stream
635 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
637 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
640 * ensure cached data is clear before starting
642 // todo tidy up seqRefIds, seqsToIds initialisation / reset
644 splitFrameCandidates.clear();
649 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
650 // //////////////////////////////////////////////////
652 List<String> shortNames = new ArrayList<>();
653 List<String> viewIds = new ArrayList<>();
656 for (int i = frames.size() - 1; i > -1; i--)
658 AlignFrame af = frames.get(i);
660 if (skipList != null && skipList
661 .containsKey(af.getViewport().getSequenceSetId()))
666 String shortName = makeFilename(af, shortNames);
668 int apSize = af.getAlignPanels().size();
670 for (int ap = 0; ap < apSize; ap++)
672 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
674 String fileName = apSize == 1 ? shortName : ap + shortName;
675 if (!fileName.endsWith(".xml"))
677 fileName = fileName + ".xml";
680 saveState(apanel, fileName, jout, viewIds);
682 String dssid = getDatasetIdRef(
683 af.getViewport().getAlignment().getDataset());
684 if (!dsses.containsKey(dssid))
686 dsses.put(dssid, af);
691 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
697 } catch (Exception foo)
701 } catch (Exception ex)
703 // TODO: inform user of the problem - they need to know if their data was
705 if (errorMessage == null)
707 errorMessage = "Couldn't write Jalview Archive - see error output for details";
709 ex.printStackTrace();
714 * Generates a distinct file name, based on the title of the AlignFrame, by
715 * appending _n for increasing n until an unused name is generated. The new
716 * name (without its extension) is added to the list.
720 * @return the generated name, with .xml extension
722 protected String makeFilename(AlignFrame af, List<String> namesUsed)
724 String shortName = af.getTitle();
726 if (shortName.indexOf(File.separatorChar) > -1)
728 shortName = shortName
729 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
734 while (namesUsed.contains(shortName))
736 if (shortName.endsWith("_" + (count - 1)))
738 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
741 shortName = shortName.concat("_" + count);
745 namesUsed.add(shortName);
747 if (!shortName.endsWith(".xml"))
749 shortName = shortName + ".xml";
754 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
755 public boolean saveAlignment(AlignFrame af, String jarFile,
760 // create backupfiles object and get new temp filename destination
761 boolean doBackup = BackupFiles.getEnabled();
762 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
763 FileOutputStream fos = new FileOutputStream(doBackup ?
764 backupfiles.getTempFilePath() : jarFile);
766 JarOutputStream jout = new JarOutputStream(fos);
767 List<AlignFrame> frames = new ArrayList<>();
769 // resolve splitframes
770 if (af.getViewport().getCodingComplement() != null)
772 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
778 saveAllFrames(frames, jout);
782 } catch (Exception foo)
786 boolean success = true;
790 backupfiles.setWriteSuccess(success);
791 success = backupfiles.rollBackupsAndRenameTempFile();
795 } catch (Exception ex)
797 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
798 ex.printStackTrace();
803 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
804 String fileName, JarOutputStream jout)
807 for (String dssids : dsses.keySet())
809 AlignFrame _af = dsses.get(dssids);
810 String jfileName = fileName + " Dataset for " + _af.getTitle();
811 if (!jfileName.endsWith(".xml"))
813 jfileName = jfileName + ".xml";
815 saveState(_af.alignPanel, jfileName, true, jout, null);
820 * create a JalviewModel from an alignment view and marshall it to a
824 * panel to create jalview model for
826 * name of alignment panel written to output stream
833 public JalviewModel saveState(AlignmentPanel ap, String fileName,
834 JarOutputStream jout, List<String> viewIds)
836 return saveState(ap, fileName, false, jout, viewIds);
840 * create a JalviewModel from an alignment view and marshall it to a
844 * panel to create jalview model for
846 * name of alignment panel written to output stream
848 * when true, only write the dataset for the alignment, not the data
849 * associated with the view.
855 public JalviewModel saveState(AlignmentPanel ap, String fileName,
856 boolean storeDS, JarOutputStream jout, List<String> viewIds)
860 viewIds = new ArrayList<>();
865 List<UserColourScheme> userColours = new ArrayList<>();
867 AlignViewport av = ap.av;
868 ViewportRanges vpRanges = av.getRanges();
870 final ObjectFactory objectFactory = new ObjectFactory();
871 JalviewModel object = objectFactory.createJalviewModel();
872 object.setVamsasModel(new VAMSAS());
874 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
877 GregorianCalendar c = new GregorianCalendar();
878 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
879 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
880 object.setCreationDate(now);
881 } catch (DatatypeConfigurationException e)
883 System.err.println("error writing date: " + e.toString());
886 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
889 * rjal is full height alignment, jal is actual alignment with full metadata
890 * but excludes hidden sequences.
892 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
894 if (av.hasHiddenRows())
896 rjal = jal.getHiddenSequences().getFullAlignment();
899 SequenceSet vamsasSet = new SequenceSet();
901 // JalviewModelSequence jms = new JalviewModelSequence();
903 vamsasSet.setGapChar(jal.getGapCharacter() + "");
905 if (jal.getDataset() != null)
907 // dataset id is the dataset's hashcode
908 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
911 // switch jal and the dataset
912 jal = jal.getDataset();
916 if (jal.getProperties() != null)
918 Enumeration en = jal.getProperties().keys();
919 while (en.hasMoreElements())
921 String key = en.nextElement().toString();
922 SequenceSetProperties ssp = new SequenceSetProperties();
924 ssp.setValue(jal.getProperties().get(key).toString());
925 // vamsasSet.addSequenceSetProperties(ssp);
926 vamsasSet.getSequenceSetProperties().add(ssp);
931 Set<String> calcIdSet = new HashSet<>();
932 // record the set of vamsas sequence XML POJO we create.
933 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
935 for (final SequenceI jds : rjal.getSequences())
937 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
938 : jds.getDatasetSequence();
939 String id = seqHash(jds);
940 if (vamsasSetIds.get(id) == null)
942 if (seqRefIds.get(id) != null && !storeDS)
944 // This happens for two reasons: 1. multiple views are being
946 // 2. the hashCode has collided with another sequence's code. This
948 // HAPPEN! (PF00072.15.stk does this)
949 // JBPNote: Uncomment to debug writing out of files that do not read
950 // back in due to ArrayOutOfBoundExceptions.
951 // System.err.println("vamsasSeq backref: "+id+"");
952 // System.err.println(jds.getName()+"
953 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
954 // System.err.println("Hashcode: "+seqHash(jds));
955 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
956 // System.err.println(rsq.getName()+"
957 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
958 // System.err.println("Hashcode: "+seqHash(rsq));
962 vamsasSeq = createVamsasSequence(id, jds);
963 // vamsasSet.addSequence(vamsasSeq);
964 vamsasSet.getSequence().add(vamsasSeq);
965 vamsasSetIds.put(id, vamsasSeq);
966 seqRefIds.put(id, jds);
970 jseq.setStart(jds.getStart());
971 jseq.setEnd(jds.getEnd());
972 jseq.setColour(av.getSequenceColour(jds).getRGB());
974 jseq.setId(id); // jseq id should be a string not a number
977 // Store any sequences this sequence represents
978 if (av.hasHiddenRows())
980 // use rjal, contains the full height alignment
982 av.getAlignment().getHiddenSequences().isHidden(jds));
984 if (av.isHiddenRepSequence(jds))
986 jalview.datamodel.SequenceI[] reps = av
987 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
989 for (int h = 0; h < reps.length; h++)
993 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
994 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
999 // mark sequence as reference - if it is the reference for this view
1000 if (jal.hasSeqrep())
1002 jseq.setViewreference(jds == jal.getSeqrep());
1006 // TODO: omit sequence features from each alignment view's XML dump if we
1007 // are storing dataset
1008 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1009 for (SequenceFeature sf : sfs)
1011 // Features features = new Features();
1012 Feature features = new Feature();
1014 features.setBegin(sf.getBegin());
1015 features.setEnd(sf.getEnd());
1016 features.setDescription(sf.getDescription());
1017 features.setType(sf.getType());
1018 features.setFeatureGroup(sf.getFeatureGroup());
1019 features.setScore(sf.getScore());
1020 if (sf.links != null)
1022 for (int l = 0; l < sf.links.size(); l++)
1024 OtherData keyValue = new OtherData();
1025 keyValue.setKey("LINK_" + l);
1026 keyValue.setValue(sf.links.elementAt(l).toString());
1027 // features.addOtherData(keyValue);
1028 features.getOtherData().add(keyValue);
1031 if (sf.otherDetails != null)
1034 * save feature attributes, which may be simple strings or
1035 * map valued (have sub-attributes)
1037 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1039 String key = entry.getKey();
1040 Object value = entry.getValue();
1041 if (value instanceof Map<?, ?>)
1043 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1046 OtherData otherData = new OtherData();
1047 otherData.setKey(key);
1048 otherData.setKey2(subAttribute.getKey());
1049 otherData.setValue(subAttribute.getValue().toString());
1050 // features.addOtherData(otherData);
1051 features.getOtherData().add(otherData);
1056 OtherData otherData = new OtherData();
1057 otherData.setKey(key);
1058 otherData.setValue(value.toString());
1059 // features.addOtherData(otherData);
1060 features.getOtherData().add(otherData);
1065 // jseq.addFeatures(features);
1066 jseq.getFeatures().add(features);
1069 if (jdatasq.getAllPDBEntries() != null)
1071 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1072 while (en.hasMoreElements())
1074 Pdbids pdb = new Pdbids();
1075 jalview.datamodel.PDBEntry entry = en.nextElement();
1077 String pdbId = entry.getId();
1079 pdb.setType(entry.getType());
1082 * Store any structure views associated with this sequence. This
1083 * section copes with duplicate entries in the project, so a dataset
1084 * only view *should* be coped with sensibly.
1086 // This must have been loaded, is it still visible?
1087 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1088 String matchedFile = null;
1089 for (int f = frames.length - 1; f > -1; f--)
1091 if (frames[f] instanceof StructureViewerBase)
1093 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1094 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1095 matchedFile, viewFrame);
1097 * Only store each structure viewer's state once in the project
1098 * jar. First time through only (storeDS==false)
1100 String viewId = viewFrame.getViewId();
1101 String viewerType = viewFrame.getViewerType().toString();
1102 if (!storeDS && !viewIds.contains(viewId))
1104 viewIds.add(viewId);
1105 File viewerState = viewFrame.saveSession();
1106 if (viewerState != null)
1108 copyFileToJar(jout, viewerState.getPath(),
1109 getViewerJarEntryName(viewId), viewerType);
1113 Cache.log.error("Failed to save viewer state for "
1121 if (matchedFile != null || entry.getFile() != null)
1123 if (entry.getFile() != null)
1126 matchedFile = entry.getFile();
1128 pdb.setFile(matchedFile); // entry.getFile());
1129 if (pdbfiles == null)
1131 pdbfiles = new ArrayList<>();
1134 if (!pdbfiles.contains(pdbId))
1136 pdbfiles.add(pdbId);
1137 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1141 Enumeration<String> props = entry.getProperties();
1142 if (props.hasMoreElements())
1144 // PdbentryItem item = new PdbentryItem();
1145 while (props.hasMoreElements())
1147 Property prop = new Property();
1148 String key = props.nextElement();
1150 prop.setValue(entry.getProperty(key).toString());
1151 // item.addProperty(prop);
1152 pdb.getProperty().add(prop);
1154 // pdb.addPdbentryItem(item);
1157 // jseq.addPdbids(pdb);
1158 jseq.getPdbids().add(pdb);
1162 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1164 // jms.addJSeq(jseq);
1165 object.getJSeq().add(jseq);
1168 if (!storeDS && av.hasHiddenRows())
1170 jal = av.getAlignment();
1174 if (storeDS && jal.getCodonFrames() != null)
1176 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1177 for (AlignedCodonFrame acf : jac)
1179 AlcodonFrame alc = new AlcodonFrame();
1180 if (acf.getProtMappings() != null
1181 && acf.getProtMappings().length > 0)
1183 boolean hasMap = false;
1184 SequenceI[] dnas = acf.getdnaSeqs();
1185 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1186 for (int m = 0; m < pmaps.length; m++)
1188 AlcodMap alcmap = new AlcodMap();
1189 alcmap.setDnasq(seqHash(dnas[m]));
1191 createVamsasMapping(pmaps[m], dnas[m], null, false));
1192 // alc.addAlcodMap(alcmap);
1193 alc.getAlcodMap().add(alcmap);
1198 // vamsasSet.addAlcodonFrame(alc);
1199 vamsasSet.getAlcodonFrame().add(alc);
1202 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1204 // AlcodonFrame alc = new AlcodonFrame();
1205 // vamsasSet.addAlcodonFrame(alc);
1206 // for (int p = 0; p < acf.aaWidth; p++)
1208 // Alcodon cmap = new Alcodon();
1209 // if (acf.codons[p] != null)
1211 // // Null codons indicate a gapped column in the translated peptide
1213 // cmap.setPos1(acf.codons[p][0]);
1214 // cmap.setPos2(acf.codons[p][1]);
1215 // cmap.setPos3(acf.codons[p][2]);
1217 // alc.addAlcodon(cmap);
1219 // if (acf.getProtMappings() != null
1220 // && acf.getProtMappings().length > 0)
1222 // SequenceI[] dnas = acf.getdnaSeqs();
1223 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1224 // for (int m = 0; m < pmaps.length; m++)
1226 // AlcodMap alcmap = new AlcodMap();
1227 // alcmap.setDnasq(seqHash(dnas[m]));
1228 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1230 // alc.addAlcodMap(alcmap);
1237 // /////////////////////////////////
1238 if (!storeDS && av.getCurrentTree() != null)
1240 // FIND ANY ASSOCIATED TREES
1241 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1242 if (Desktop.desktop != null)
1244 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1246 for (int t = 0; t < frames.length; t++)
1248 if (frames[t] instanceof TreePanel)
1250 TreePanel tp = (TreePanel) frames[t];
1252 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1254 JalviewModel.Tree tree = new JalviewModel.Tree();
1255 tree.setTitle(tp.getTitle());
1256 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1257 tree.setNewick(tp.getTree().print());
1258 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1260 tree.setFitToWindow(tp.fitToWindow.getState());
1261 tree.setFontName(tp.getTreeFont().getName());
1262 tree.setFontSize(tp.getTreeFont().getSize());
1263 tree.setFontStyle(tp.getTreeFont().getStyle());
1264 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1266 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1267 tree.setShowDistances(tp.distanceMenu.getState());
1269 tree.setHeight(tp.getHeight());
1270 tree.setWidth(tp.getWidth());
1271 tree.setXpos(tp.getX());
1272 tree.setYpos(tp.getY());
1273 tree.setId(makeHashCode(tp, null));
1274 tree.setLinkToAllViews(
1275 tp.getTreeCanvas().isApplyToAllViews());
1277 // jms.addTree(tree);
1278 object.getTree().add(tree);
1288 if (!storeDS && Desktop.desktop != null)
1290 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1292 if (frame instanceof PCAPanel)
1294 PCAPanel panel = (PCAPanel) frame;
1295 if (panel.getAlignViewport().getAlignment() == jal)
1297 savePCA(panel, object);
1305 * store forward refs from an annotationRow to any groups
1307 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1310 for (SequenceI sq : jal.getSequences())
1312 // Store annotation on dataset sequences only
1313 AlignmentAnnotation[] aa = sq.getAnnotation();
1314 if (aa != null && aa.length > 0)
1316 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1323 if (jal.getAlignmentAnnotation() != null)
1325 // Store the annotation shown on the alignment.
1326 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1327 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1332 if (jal.getGroups() != null)
1334 JGroup[] groups = new JGroup[jal.getGroups().size()];
1336 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1338 JGroup jGroup = new JGroup();
1339 groups[++i] = jGroup;
1341 jGroup.setStart(sg.getStartRes());
1342 jGroup.setEnd(sg.getEndRes());
1343 jGroup.setName(sg.getName());
1344 if (groupRefs.containsKey(sg))
1346 // group has references so set its ID field
1347 jGroup.setId(groupRefs.get(sg));
1349 ColourSchemeI colourScheme = sg.getColourScheme();
1350 if (colourScheme != null)
1352 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1353 if (groupColourScheme.conservationApplied())
1355 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1357 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1360 setUserColourScheme(colourScheme, userColours,
1365 jGroup.setColour(colourScheme.getSchemeName());
1368 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1370 jGroup.setColour("AnnotationColourGradient");
1371 jGroup.setAnnotationColours(constructAnnotationColours(
1372 (jalview.schemes.AnnotationColourGradient) colourScheme,
1373 userColours, object));
1375 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1378 setUserColourScheme(colourScheme, userColours, object));
1382 jGroup.setColour(colourScheme.getSchemeName());
1385 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1388 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1389 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1390 jGroup.setDisplayText(sg.getDisplayText());
1391 jGroup.setColourText(sg.getColourText());
1392 jGroup.setTextCol1(sg.textColour.getRGB());
1393 jGroup.setTextCol2(sg.textColour2.getRGB());
1394 jGroup.setTextColThreshold(sg.thresholdTextColour);
1395 jGroup.setShowUnconserved(sg.getShowNonconserved());
1396 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1397 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1398 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1399 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1400 for (SequenceI seq : sg.getSequences())
1402 // jGroup.addSeq(seqHash(seq));
1403 jGroup.getSeq().add(seqHash(seq));
1407 //jms.setJGroup(groups);
1409 for (JGroup grp : groups)
1411 object.getJGroup().add(grp);
1416 // /////////SAVE VIEWPORT
1417 Viewport view = new Viewport();
1418 view.setTitle(ap.alignFrame.getTitle());
1419 view.setSequenceSetId(
1420 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1421 view.setId(av.getViewId());
1422 if (av.getCodingComplement() != null)
1424 view.setComplementId(av.getCodingComplement().getViewId());
1426 view.setViewName(av.getViewName());
1427 view.setGatheredViews(av.isGatherViewsHere());
1429 Rectangle size = ap.av.getExplodedGeometry();
1430 Rectangle position = size;
1433 size = ap.alignFrame.getBounds();
1434 if (av.getCodingComplement() != null)
1436 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1444 view.setXpos(position.x);
1445 view.setYpos(position.y);
1447 view.setWidth(size.width);
1448 view.setHeight(size.height);
1450 view.setStartRes(vpRanges.getStartRes());
1451 view.setStartSeq(vpRanges.getStartSeq());
1453 OverviewPanel ov = ap.getOverviewPanel();
1456 Overview overview = new Overview();
1457 Rectangle bounds = ov.getBounds();
1458 overview.setXpos(bounds.x);
1459 overview.setYpos(bounds.y);
1460 overview.setWidth(bounds.width);
1461 overview.setHeight(bounds.height);
1462 overview.setShowHidden(ov.isShowHiddenRegions());
1463 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1464 overview.setResidueColour(ov.getCanvas().getResidueColour().getRGB());
1465 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1466 String title = ((JInternalFrame) SwingUtilities
1467 .getAncestorOfClass(JInternalFrame.class, ov)).getTitle();
1468 overview.setTitle(title);
1469 view.setOverview(overview);
1471 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1473 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1474 userColours, object));
1477 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1479 AnnotationColourScheme ac = constructAnnotationColours(
1480 (jalview.schemes.AnnotationColourGradient) av
1481 .getGlobalColourScheme(),
1482 userColours, object);
1484 view.setAnnotationColours(ac);
1485 view.setBgColour("AnnotationColourGradient");
1489 view.setBgColour(ColourSchemeProperty
1490 .getColourName(av.getGlobalColourScheme()));
1493 ResidueShaderI vcs = av.getResidueShading();
1494 ColourSchemeI cs = av.getGlobalColourScheme();
1498 if (vcs.conservationApplied())
1500 view.setConsThreshold(vcs.getConservationInc());
1501 if (cs instanceof jalview.schemes.UserColourScheme)
1503 view.setBgColour(setUserColourScheme(cs, userColours, object));
1506 view.setPidThreshold(vcs.getThreshold());
1509 view.setConservationSelected(av.getConservationSelected());
1510 view.setPidSelected(av.getAbovePIDThreshold());
1511 final Font font = av.getFont();
1512 view.setFontName(font.getName());
1513 view.setFontSize(font.getSize());
1514 view.setFontStyle(font.getStyle());
1515 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1516 view.setRenderGaps(av.isRenderGaps());
1517 view.setShowAnnotation(av.isShowAnnotation());
1518 view.setShowBoxes(av.getShowBoxes());
1519 view.setShowColourText(av.getColourText());
1520 view.setShowFullId(av.getShowJVSuffix());
1521 view.setRightAlignIds(av.isRightAlignIds());
1522 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1523 view.setShowText(av.getShowText());
1524 view.setShowUnconserved(av.getShowUnconserved());
1525 view.setWrapAlignment(av.getWrapAlignment());
1526 view.setTextCol1(av.getTextColour().getRGB());
1527 view.setTextCol2(av.getTextColour2().getRGB());
1528 view.setTextColThreshold(av.getThresholdTextColour());
1529 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1530 view.setShowSequenceLogo(av.isShowSequenceLogo());
1531 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1532 view.setShowGroupConsensus(av.isShowGroupConsensus());
1533 view.setShowGroupConservation(av.isShowGroupConservation());
1534 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1535 view.setShowDbRefTooltip(av.isShowDBRefs());
1536 view.setFollowHighlight(av.isFollowHighlight());
1537 view.setFollowSelection(av.followSelection);
1538 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1539 view.setShowComplementFeatures(av.isShowComplementFeatures());
1540 view.setShowComplementFeaturesOnTop(
1541 av.isShowComplementFeaturesOnTop());
1542 if (av.getFeaturesDisplayed() != null)
1544 FeatureSettings fs = new FeatureSettings();
1546 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1547 .getFeatureRenderer();
1548 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1550 Vector<String> settingsAdded = new Vector<>();
1551 if (renderOrder != null)
1553 for (String featureType : renderOrder)
1555 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1556 setting.setType(featureType);
1559 * save any filter for the feature type
1561 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1562 if (filter != null) {
1563 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1564 FeatureMatcherI firstFilter = filters.next();
1565 setting.setMatcherSet(Jalview2XML.marshalFilter(
1566 firstFilter, filters, filter.isAnded()));
1570 * save colour scheme for the feature type
1572 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1573 if (!fcol.isSimpleColour())
1575 setting.setColour(fcol.getMaxColour().getRGB());
1576 setting.setMincolour(fcol.getMinColour().getRGB());
1577 setting.setMin(fcol.getMin());
1578 setting.setMax(fcol.getMax());
1579 setting.setColourByLabel(fcol.isColourByLabel());
1580 if (fcol.isColourByAttribute())
1582 String[] attName = fcol.getAttributeName();
1583 setting.getAttributeName().add(attName[0]);
1584 if (attName.length > 1)
1586 setting.getAttributeName().add(attName[1]);
1589 setting.setAutoScale(fcol.isAutoScaled());
1590 setting.setThreshold(fcol.getThreshold());
1591 Color noColour = fcol.getNoColour();
1592 if (noColour == null)
1594 setting.setNoValueColour(NoValueColour.NONE);
1596 else if (noColour.equals(fcol.getMaxColour()))
1598 setting.setNoValueColour(NoValueColour.MAX);
1602 setting.setNoValueColour(NoValueColour.MIN);
1604 // -1 = No threshold, 0 = Below, 1 = Above
1605 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1606 : (fcol.isBelowThreshold() ? 0 : -1));
1610 setting.setColour(fcol.getColour().getRGB());
1614 av.getFeaturesDisplayed().isVisible(featureType));
1616 .getOrder(featureType);
1619 setting.setOrder(rorder);
1621 /// fs.addSetting(setting);
1622 fs.getSetting().add(setting);
1623 settingsAdded.addElement(featureType);
1627 // is groups actually supposed to be a map here ?
1628 Iterator<String> en = fr.getFeatureGroups().iterator();
1629 Vector<String> groupsAdded = new Vector<>();
1630 while (en.hasNext())
1632 String grp = en.next();
1633 if (groupsAdded.contains(grp))
1637 Group g = new Group();
1639 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1642 fs.getGroup().add(g);
1643 groupsAdded.addElement(grp);
1645 // jms.setFeatureSettings(fs);
1646 object.setFeatureSettings(fs);
1649 if (av.hasHiddenColumns())
1651 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1652 .getHiddenColumns();
1655 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1659 Iterator<int[]> hiddenRegions = hidden.iterator();
1660 while (hiddenRegions.hasNext())
1662 int[] region = hiddenRegions.next();
1663 HiddenColumns hc = new HiddenColumns();
1664 hc.setStart(region[0]);
1665 hc.setEnd(region[1]);
1666 // view.addHiddenColumns(hc);
1667 view.getHiddenColumns().add(hc);
1671 if (calcIdSet.size() > 0)
1673 for (String calcId : calcIdSet)
1675 if (calcId.trim().length() > 0)
1677 CalcIdParam cidp = createCalcIdParam(calcId, av);
1678 // Some calcIds have no parameters.
1681 // view.addCalcIdParam(cidp);
1682 view.getCalcIdParam().add(cidp);
1688 // jms.addViewport(view);
1689 object.getViewport().add(view);
1691 // object.setJalviewModelSequence(jms);
1692 // object.getVamsasModel().addSequenceSet(vamsasSet);
1693 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1695 if (jout != null && fileName != null)
1697 // We may not want to write the object to disk,
1698 // eg we can copy the alignViewport to a new view object
1699 // using save and then load
1702 fileName = fileName.replace('\\', '/');
1703 System.out.println("Writing jar entry " + fileName);
1704 JarEntry entry = new JarEntry(fileName);
1705 jout.putNextEntry(entry);
1706 PrintWriter pout = new PrintWriter(
1707 new OutputStreamWriter(jout, UTF_8));
1708 JAXBContext jaxbContext = JAXBContext
1709 .newInstance(JalviewModel.class);
1710 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1712 // output pretty printed
1713 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1714 jaxbMarshaller.marshal(
1715 new ObjectFactory().createJalviewModel(object), pout);
1717 // jaxbMarshaller.marshal(object, pout);
1718 // marshaller.marshal(object);
1721 } catch (Exception ex)
1723 // TODO: raise error in GUI if marshalling failed.
1724 System.err.println("Error writing Jalview project");
1725 ex.printStackTrace();
1732 * Writes PCA viewer attributes and computed values to an XML model object and
1733 * adds it to the JalviewModel. Any exceptions are reported by logging.
1735 protected void savePCA(PCAPanel panel, JalviewModel object)
1739 PcaViewer viewer = new PcaViewer();
1740 viewer.setHeight(panel.getHeight());
1741 viewer.setWidth(panel.getWidth());
1742 viewer.setXpos(panel.getX());
1743 viewer.setYpos(panel.getY());
1744 viewer.setTitle(panel.getTitle());
1745 PCAModel pcaModel = panel.getPcaModel();
1746 viewer.setScoreModelName(pcaModel.getScoreModelName());
1747 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1748 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1749 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1751 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1752 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1753 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1754 SeqPointMin spmin = new SeqPointMin();
1755 spmin.setXPos(spMin[0]);
1756 spmin.setYPos(spMin[1]);
1757 spmin.setZPos(spMin[2]);
1758 viewer.setSeqPointMin(spmin);
1759 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1760 SeqPointMax spmax = new SeqPointMax();
1761 spmax.setXPos(spMax[0]);
1762 spmax.setYPos(spMax[1]);
1763 spmax.setZPos(spMax[2]);
1764 viewer.setSeqPointMax(spmax);
1765 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1766 viewer.setLinkToAllViews(
1767 panel.getRotatableCanvas().isApplyToAllViews());
1768 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1769 viewer.setIncludeGaps(sp.includeGaps());
1770 viewer.setMatchGaps(sp.matchGaps());
1771 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1772 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1775 * sequence points on display
1777 for (jalview.datamodel.SequencePoint spt : pcaModel
1778 .getSequencePoints())
1780 SequencePoint point = new SequencePoint();
1781 point.setSequenceRef(seqHash(spt.getSequence()));
1782 point.setXPos(spt.coord.x);
1783 point.setYPos(spt.coord.y);
1784 point.setZPos(spt.coord.z);
1785 viewer.getSequencePoint().add(point);
1789 * (end points of) axes on display
1791 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1794 Axis axis = new Axis();
1798 viewer.getAxis().add(axis);
1802 * raw PCA data (note we are not restoring PCA inputs here -
1803 * alignment view, score model, similarity parameters)
1805 PcaDataType data = new PcaDataType();
1806 viewer.setPcaData(data);
1807 PCA pca = pcaModel.getPcaData();
1809 DoubleMatrix pm = new DoubleMatrix();
1810 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1811 data.setPairwiseMatrix(pm);
1813 DoubleMatrix tm = new DoubleMatrix();
1814 saveDoubleMatrix(pca.getTridiagonal(), tm);
1815 data.setTridiagonalMatrix(tm);
1817 DoubleMatrix eigenMatrix = new DoubleMatrix();
1818 data.setEigenMatrix(eigenMatrix);
1819 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1821 object.getPcaViewer().add(viewer);
1822 } catch (Throwable t)
1824 Cache.log.error("Error saving PCA: " + t.getMessage());
1829 * Stores values from a matrix into an XML element, including (if present) the
1834 * @see #loadDoubleMatrix(DoubleMatrix)
1836 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1838 xmlMatrix.setRows(m.height());
1839 xmlMatrix.setColumns(m.width());
1840 for (int i = 0; i < m.height(); i++)
1842 DoubleVector row = new DoubleVector();
1843 for (int j = 0; j < m.width(); j++)
1845 row.getV().add(m.getValue(i, j));
1847 xmlMatrix.getRow().add(row);
1849 if (m.getD() != null)
1851 DoubleVector dVector = new DoubleVector();
1852 for (double d : m.getD())
1854 dVector.getV().add(d);
1856 xmlMatrix.setD(dVector);
1858 if (m.getE() != null)
1860 DoubleVector eVector = new DoubleVector();
1861 for (double e : m.getE())
1863 eVector.getV().add(e);
1865 xmlMatrix.setE(eVector);
1870 * Loads XML matrix data into a new Matrix object, including the D and/or E
1871 * vectors (if present)
1875 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1877 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1879 int rows = mData.getRows();
1880 double[][] vals = new double[rows][];
1882 for (int i = 0; i < rows; i++)
1884 List<Double> dVector = mData.getRow().get(i).getV();
1885 vals[i] = new double[dVector.size()];
1887 for (Double d : dVector)
1893 MatrixI m = new Matrix(vals);
1895 if (mData.getD() != null)
1897 List<Double> dVector = mData.getD().getV();
1898 double[] vec = new double[dVector.size()];
1900 for (Double d : dVector)
1906 if (mData.getE() != null)
1908 List<Double> dVector = mData.getE().getV();
1909 double[] vec = new double[dVector.size()];
1911 for (Double d : dVector)
1922 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1923 * for each viewer, with
1925 * <li>viewer geometry (position, size, split pane divider location)</li>
1926 * <li>index of the selected structure in the viewer (currently shows gapped
1928 * <li>the id of the annotation holding RNA secondary structure</li>
1929 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1931 * Varna viewer state is also written out (in native Varna XML) to separate
1932 * project jar entries. A separate entry is written for each RNA structure
1933 * displayed, with the naming convention
1935 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1943 * @param storeDataset
1945 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1946 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1947 boolean storeDataset)
1949 if (Desktop.desktop == null)
1953 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1954 for (int f = frames.length - 1; f > -1; f--)
1956 if (frames[f] instanceof AppVarna)
1958 AppVarna varna = (AppVarna) frames[f];
1960 * link the sequence to every viewer that is showing it and is linked to
1961 * its alignment panel
1963 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1965 String viewId = varna.getViewId();
1966 RnaViewer rna = new RnaViewer();
1967 rna.setViewId(viewId);
1968 rna.setTitle(varna.getTitle());
1969 rna.setXpos(varna.getX());
1970 rna.setYpos(varna.getY());
1971 rna.setWidth(varna.getWidth());
1972 rna.setHeight(varna.getHeight());
1973 rna.setDividerLocation(varna.getDividerLocation());
1974 rna.setSelectedRna(varna.getSelectedIndex());
1975 // jseq.addRnaViewer(rna);
1976 jseq.getRnaViewer().add(rna);
1979 * Store each Varna panel's state once in the project per sequence.
1980 * First time through only (storeDataset==false)
1982 // boolean storeSessions = false;
1983 // String sequenceViewId = viewId + seqsToIds.get(jds);
1984 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1986 // viewIds.add(sequenceViewId);
1987 // storeSessions = true;
1989 for (RnaModel model : varna.getModels())
1991 if (model.seq == jds)
1994 * VARNA saves each view (sequence or alignment secondary
1995 * structure, gapped or trimmed) as a separate XML file
1997 String jarEntryName = rnaSessions.get(model);
1998 if (jarEntryName == null)
2001 String varnaStateFile = varna.getStateInfo(model.rna);
2002 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2003 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2004 rnaSessions.put(model, jarEntryName);
2006 SecondaryStructure ss = new SecondaryStructure();
2007 String annotationId = varna.getAnnotation(jds).annotationId;
2008 ss.setAnnotationId(annotationId);
2009 ss.setViewerState(jarEntryName);
2010 ss.setGapped(model.gapped);
2011 ss.setTitle(model.title);
2012 // rna.addSecondaryStructure(ss);
2013 rna.getSecondaryStructure().add(ss);
2022 * Copy the contents of a file to a new entry added to the output jar
2026 * @param jarEntryName
2028 * additional identifying info to log to the console
2030 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2031 String jarEntryName, String msg)
2033 try (InputStream is = new FileInputStream(infilePath))
2035 File file = new File(infilePath);
2036 if (file.exists() && jout != null)
2039 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2040 jout.putNextEntry(new JarEntry(jarEntryName));
2043 // dis = new DataInputStream(new FileInputStream(file));
2044 // byte[] data = new byte[(int) file.length()];
2045 // dis.readFully(data);
2046 // writeJarEntry(jout, jarEntryName, data);
2048 } catch (Exception ex)
2050 ex.printStackTrace();
2055 * Copies input to output, in 4K buffers; handles any data (text or binary)
2059 * @throws IOException
2061 protected void copyAll(InputStream in, OutputStream out)
2064 byte[] buffer = new byte[4096];
2066 while ((bytesRead = in.read(buffer)) != -1)
2068 out.write(buffer, 0, bytesRead);
2073 * Save the state of a structure viewer
2078 * the archive XML element under which to save the state
2081 * @param matchedFile
2085 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2086 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2087 String matchedFile, StructureViewerBase viewFrame)
2089 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2092 * Look for any bindings for this viewer to the PDB file of interest
2093 * (including part matches excluding chain id)
2095 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2097 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2098 final String pdbId = pdbentry.getId();
2099 if (!pdbId.equals(entry.getId())
2100 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2101 .startsWith(pdbId.toLowerCase())))
2104 * not interested in a binding to a different PDB entry here
2108 if (matchedFile == null)
2110 matchedFile = pdbentry.getFile();
2112 else if (!matchedFile.equals(pdbentry.getFile()))
2115 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2116 + pdbentry.getFile());
2120 // can get at it if the ID
2121 // match is ambiguous (e.g.
2124 for (int smap = 0; smap < viewFrame.getBinding()
2125 .getSequence()[peid].length; smap++)
2127 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2128 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2130 StructureState state = new StructureState();
2131 state.setVisible(true);
2132 state.setXpos(viewFrame.getX());
2133 state.setYpos(viewFrame.getY());
2134 state.setWidth(viewFrame.getWidth());
2135 state.setHeight(viewFrame.getHeight());
2136 final String viewId = viewFrame.getViewId();
2137 state.setViewId(viewId);
2138 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2139 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2140 state.setColourByJmol(viewFrame.isColouredByViewer());
2141 state.setType(viewFrame.getViewerType().toString());
2142 // pdb.addStructureState(state);
2143 pdb.getStructureState().add(state);
2151 * Populates the AnnotationColourScheme xml for save. This captures the
2152 * settings of the options in the 'Colour by Annotation' dialog.
2155 * @param userColours
2159 private AnnotationColourScheme constructAnnotationColours(
2160 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2163 AnnotationColourScheme ac = new AnnotationColourScheme();
2164 ac.setAboveThreshold(acg.getAboveThreshold());
2165 ac.setThreshold(acg.getAnnotationThreshold());
2166 // 2.10.2 save annotationId (unique) not annotation label
2167 ac.setAnnotation(acg.getAnnotation().annotationId);
2168 if (acg.getBaseColour() instanceof UserColourScheme)
2171 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2176 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2179 ac.setMaxColour(acg.getMaxColour().getRGB());
2180 ac.setMinColour(acg.getMinColour().getRGB());
2181 ac.setPerSequence(acg.isSeqAssociated());
2182 ac.setPredefinedColours(acg.isPredefinedColours());
2186 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2187 IdentityHashMap<SequenceGroup, String> groupRefs,
2188 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2189 SequenceSet vamsasSet)
2192 for (int i = 0; i < aa.length; i++)
2194 Annotation an = new Annotation();
2196 AlignmentAnnotation annotation = aa[i];
2197 if (annotation.annotationId != null)
2199 annotationIds.put(annotation.annotationId, annotation);
2202 an.setId(annotation.annotationId);
2204 an.setVisible(annotation.visible);
2206 an.setDescription(annotation.description);
2208 if (annotation.sequenceRef != null)
2210 // 2.9 JAL-1781 xref on sequence id rather than name
2211 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2213 if (annotation.groupRef != null)
2215 String groupIdr = groupRefs.get(annotation.groupRef);
2216 if (groupIdr == null)
2218 // make a locally unique String
2219 groupRefs.put(annotation.groupRef,
2220 groupIdr = ("" + System.currentTimeMillis()
2221 + annotation.groupRef.getName()
2222 + groupRefs.size()));
2224 an.setGroupRef(groupIdr.toString());
2227 // store all visualization attributes for annotation
2228 an.setGraphHeight(annotation.graphHeight);
2229 an.setCentreColLabels(annotation.centreColLabels);
2230 an.setScaleColLabels(annotation.scaleColLabel);
2231 an.setShowAllColLabels(annotation.showAllColLabels);
2232 an.setBelowAlignment(annotation.belowAlignment);
2234 if (annotation.graph > 0)
2237 an.setGraphType(annotation.graph);
2238 an.setGraphGroup(annotation.graphGroup);
2239 if (annotation.getThreshold() != null)
2241 ThresholdLine line = new ThresholdLine();
2242 line.setLabel(annotation.getThreshold().label);
2243 line.setValue(annotation.getThreshold().value);
2244 line.setColour(annotation.getThreshold().colour.getRGB());
2245 an.setThresholdLine(line);
2253 an.setLabel(annotation.label);
2255 if (annotation == av.getAlignmentQualityAnnot()
2256 || annotation == av.getAlignmentConservationAnnotation()
2257 || annotation == av.getAlignmentConsensusAnnotation()
2258 || annotation.autoCalculated)
2260 // new way of indicating autocalculated annotation -
2261 an.setAutoCalculated(annotation.autoCalculated);
2263 if (annotation.hasScore())
2265 an.setScore(annotation.getScore());
2268 if (annotation.getCalcId() != null)
2270 calcIdSet.add(annotation.getCalcId());
2271 an.setCalcId(annotation.getCalcId());
2273 if (annotation.hasProperties())
2275 for (String pr : annotation.getProperties())
2277 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2279 prop.setValue(annotation.getProperty(pr));
2280 // an.addProperty(prop);
2281 an.getProperty().add(prop);
2285 AnnotationElement ae;
2286 if (annotation.annotations != null)
2288 an.setScoreOnly(false);
2289 for (int a = 0; a < annotation.annotations.length; a++)
2291 if ((annotation == null) || (annotation.annotations[a] == null))
2296 ae = new AnnotationElement();
2297 if (annotation.annotations[a].description != null)
2299 ae.setDescription(annotation.annotations[a].description);
2301 if (annotation.annotations[a].displayCharacter != null)
2303 ae.setDisplayCharacter(
2304 annotation.annotations[a].displayCharacter);
2307 if (!Float.isNaN(annotation.annotations[a].value))
2309 ae.setValue(annotation.annotations[a].value);
2313 if (annotation.annotations[a].secondaryStructure > ' ')
2315 ae.setSecondaryStructure(
2316 annotation.annotations[a].secondaryStructure + "");
2319 if (annotation.annotations[a].colour != null
2320 && annotation.annotations[a].colour != java.awt.Color.black)
2322 ae.setColour(annotation.annotations[a].colour.getRGB());
2325 // an.addAnnotationElement(ae);
2326 an.getAnnotationElement().add(ae);
2327 if (annotation.autoCalculated)
2329 // only write one non-null entry into the annotation row -
2330 // sufficient to get the visualization attributes necessary to
2338 an.setScoreOnly(true);
2340 if (!storeDS || (storeDS && !annotation.autoCalculated))
2342 // skip autocalculated annotation - these are only provided for
2344 // vamsasSet.addAnnotation(an);
2345 vamsasSet.getAnnotation().add(an);
2351 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2353 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2354 if (settings != null)
2356 CalcIdParam vCalcIdParam = new CalcIdParam();
2357 vCalcIdParam.setCalcId(calcId);
2358 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2359 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2360 // generic URI allowing a third party to resolve another instance of the
2361 // service used for this calculation
2362 for (String url : settings.getServiceURLs())
2364 // vCalcIdParam.addServiceURL(urls);
2365 vCalcIdParam.getServiceURL().add(url);
2367 vCalcIdParam.setVersion("1.0");
2368 if (settings.getPreset() != null)
2370 WsParamSetI setting = settings.getPreset();
2371 vCalcIdParam.setName(setting.getName());
2372 vCalcIdParam.setDescription(setting.getDescription());
2376 vCalcIdParam.setName("");
2377 vCalcIdParam.setDescription("Last used parameters");
2379 // need to be able to recover 1) settings 2) user-defined presets or
2380 // recreate settings from preset 3) predefined settings provided by
2381 // service - or settings that can be transferred (or discarded)
2382 vCalcIdParam.setParameters(
2383 settings.getWsParamFile().replace("\n", "|\\n|"));
2384 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2385 // todo - decide if updateImmediately is needed for any projects.
2387 return vCalcIdParam;
2392 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2395 if (calcIdParam.getVersion().equals("1.0"))
2397 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2398 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2399 .getPreferredServiceFor(calcIds);
2400 if (service != null)
2402 WsParamSetI parmSet = null;
2405 parmSet = service.getParamStore().parseServiceParameterFile(
2406 calcIdParam.getName(), calcIdParam.getDescription(),
2408 calcIdParam.getParameters().replace("|\\n|", "\n"));
2409 } catch (IOException x)
2411 warn("Couldn't parse parameter data for "
2412 + calcIdParam.getCalcId(), x);
2415 List<ArgumentI> argList = null;
2416 if (calcIdParam.getName().length() > 0)
2418 parmSet = service.getParamStore()
2419 .getPreset(calcIdParam.getName());
2420 if (parmSet != null)
2422 // TODO : check we have a good match with settings in AACon -
2423 // otherwise we'll need to create a new preset
2428 argList = parmSet.getArguments();
2431 AAConSettings settings = new AAConSettings(
2432 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2433 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2434 calcIdParam.isNeedsUpdate());
2439 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2443 throw new Error(MessageManager.formatMessage(
2444 "error.unsupported_version_calcIdparam", new Object[]
2445 { calcIdParam.toString() }));
2449 * External mapping between jalview objects and objects yielding a valid and
2450 * unique object ID string. This is null for normal Jalview project IO, but
2451 * non-null when a jalview project is being read or written as part of a
2454 IdentityHashMap jv2vobj = null;
2457 * Construct a unique ID for jvobj using either existing bindings or if none
2458 * exist, the result of the hashcode call for the object.
2461 * jalview data object
2462 * @return unique ID for referring to jvobj
2464 private String makeHashCode(Object jvobj, String altCode)
2466 if (jv2vobj != null)
2468 Object id = jv2vobj.get(jvobj);
2471 return id.toString();
2473 // check string ID mappings
2474 if (jvids2vobj != null && jvobj instanceof String)
2476 id = jvids2vobj.get(jvobj);
2480 return id.toString();
2482 // give up and warn that something has gone wrong
2483 warn("Cannot find ID for object in external mapping : " + jvobj);
2489 * return local jalview object mapped to ID, if it exists
2493 * @return null or object bound to idcode
2495 private Object retrieveExistingObj(String idcode)
2497 if (idcode != null && vobj2jv != null)
2499 return vobj2jv.get(idcode);
2505 * binding from ID strings from external mapping table to jalview data model
2508 private Hashtable vobj2jv;
2510 private Sequence createVamsasSequence(String id, SequenceI jds)
2512 return createVamsasSequence(true, id, jds, null);
2515 private Sequence createVamsasSequence(boolean recurse, String id,
2516 SequenceI jds, SequenceI parentseq)
2518 Sequence vamsasSeq = new Sequence();
2519 vamsasSeq.setId(id);
2520 vamsasSeq.setName(jds.getName());
2521 vamsasSeq.setSequence(jds.getSequenceAsString());
2522 vamsasSeq.setDescription(jds.getDescription());
2523 List<DBRefEntry> dbrefs = null;
2524 if (jds.getDatasetSequence() != null)
2526 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2530 // seqId==dsseqid so we can tell which sequences really are
2531 // dataset sequences only
2532 vamsasSeq.setDsseqid(id);
2533 dbrefs = jds.getDBRefs();
2534 if (parentseq == null)
2541 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2545 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2547 DBRef dbref = new DBRef();
2548 DBRefEntry ref = dbrefs.get(d);
2549 dbref.setSource(ref.getSource());
2550 dbref.setVersion(ref.getVersion());
2551 dbref.setAccessionId(ref.getAccessionId());
2552 if (ref instanceof GeneLocus)
2554 dbref.setLocus(true);
2558 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2560 dbref.setMapping(mp);
2562 vamsasSeq.getDBRef().add(dbref);
2568 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2569 SequenceI parentseq, SequenceI jds, boolean recurse)
2572 if (jmp.getMap() != null)
2576 jalview.util.MapList mlst = jmp.getMap();
2577 List<int[]> r = mlst.getFromRanges();
2578 for (int[] range : r)
2580 MapListFrom mfrom = new MapListFrom();
2581 mfrom.setStart(range[0]);
2582 mfrom.setEnd(range[1]);
2583 // mp.addMapListFrom(mfrom);
2584 mp.getMapListFrom().add(mfrom);
2586 r = mlst.getToRanges();
2587 for (int[] range : r)
2589 MapListTo mto = new MapListTo();
2590 mto.setStart(range[0]);
2591 mto.setEnd(range[1]);
2592 // mp.addMapListTo(mto);
2593 mp.getMapListTo().add(mto);
2595 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2596 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2597 if (jmp.getTo() != null)
2599 // MappingChoice mpc = new MappingChoice();
2601 // check/create ID for the sequence referenced by getTo()
2604 SequenceI ps = null;
2605 if (parentseq != jmp.getTo()
2606 && parentseq.getDatasetSequence() != jmp.getTo())
2608 // chaining dbref rather than a handshaking one
2609 jmpid = seqHash(ps = jmp.getTo());
2613 jmpid = seqHash(ps = parentseq);
2615 // mpc.setDseqFor(jmpid);
2616 mp.setDseqFor(jmpid);
2617 if (!seqRefIds.containsKey(jmpid))
2619 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2620 seqRefIds.put(jmpid, ps);
2624 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2627 // mp.setMappingChoice(mpc);
2633 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2634 List<UserColourScheme> userColours, JalviewModel jm)
2637 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2638 boolean newucs = false;
2639 if (!userColours.contains(ucs))
2641 userColours.add(ucs);
2644 id = "ucs" + userColours.indexOf(ucs);
2647 // actually create the scheme's entry in the XML model
2648 java.awt.Color[] colours = ucs.getColours();
2649 UserColours uc = new UserColours();
2650 // UserColourScheme jbucs = new UserColourScheme();
2651 JalviewUserColours jbucs = new JalviewUserColours();
2653 for (int i = 0; i < colours.length; i++)
2655 Colour col = new Colour();
2656 col.setName(ResidueProperties.aa[i]);
2657 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2658 // jbucs.addColour(col);
2659 jbucs.getColour().add(col);
2661 if (ucs.getLowerCaseColours() != null)
2663 colours = ucs.getLowerCaseColours();
2664 for (int i = 0; i < colours.length; i++)
2666 Colour col = new Colour();
2667 col.setName(ResidueProperties.aa[i].toLowerCase());
2668 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2669 // jbucs.addColour(col);
2670 jbucs.getColour().add(col);
2675 uc.setUserColourScheme(jbucs);
2676 // jm.addUserColours(uc);
2677 jm.getUserColours().add(uc);
2683 jalview.schemes.UserColourScheme getUserColourScheme(
2684 JalviewModel jm, String id)
2686 List<UserColours> uc = jm.getUserColours();
2687 UserColours colours = null;
2689 for (int i = 0; i < uc.length; i++)
2691 if (uc[i].getId().equals(id))
2698 for (UserColours c : uc)
2700 if (c.getId().equals(id))
2707 java.awt.Color[] newColours = new java.awt.Color[24];
2709 for (int i = 0; i < 24; i++)
2711 newColours[i] = new java.awt.Color(Integer.parseInt(
2712 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2713 colours.getUserColourScheme().getColour().get(i).getRGB(),
2717 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2720 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2722 newColours = new java.awt.Color[23];
2723 for (int i = 0; i < 23; i++)
2725 newColours[i] = new java.awt.Color(Integer.parseInt(
2726 colours.getUserColourScheme().getColour().get(i + 24)
2730 ucs.setLowerCaseColours(newColours);
2737 * contains last error message (if any) encountered by XML loader.
2739 String errorMessage = null;
2742 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2743 * exceptions are raised during project XML parsing
2745 public boolean attemptversion1parse = false;
2748 * Load a jalview project archive from a jar file
2751 * - HTTP URL or filename
2753 public AlignFrame loadJalviewAlign(final Object file)
2756 jalview.gui.AlignFrame af = null;
2760 // create list to store references for any new Jmol viewers created
2761 newStructureViewers = new Vector<>();
2762 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2763 // Workaround is to make sure caller implements the JarInputStreamProvider
2765 // so we can re-open the jar input stream for each entry.
2767 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2768 af = loadJalviewAlign(jprovider);
2771 af.setMenusForViewport();
2773 } catch (MalformedURLException e)
2775 errorMessage = "Invalid URL format for '" + file + "'";
2781 SwingUtilities.invokeAndWait(new Runnable()
2786 setLoadingFinishedForNewStructureViewers();
2789 } catch (Exception x)
2791 System.err.println("Error loading alignment: " + x.getMessage());
2797 @SuppressWarnings("unused")
2798 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2800 // BH 2018 allow for bytes already attached to File object
2802 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2803 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2806 errorMessage = null;
2807 uniqueSetSuffix = null;
2809 viewportsAdded.clear();
2810 frefedSequence = null;
2812 if (file.startsWith("http://")) {
2813 url = new URL(file);
2815 final URL _url = url;
2816 return new jarInputStreamProvider() {
2819 public JarInputStream getJarInputStream() throws IOException {
2820 if (bytes != null) {
2821 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2822 return new JarInputStream(new ByteArrayInputStream(bytes));
2825 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2826 return new JarInputStream(_url.openStream());
2828 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2829 return new JarInputStream(new FileInputStream(file));
2834 public String getFilename() {
2838 } catch (IOException e) {
2839 e.printStackTrace();
2845 * Recover jalview session from a jalview project archive. Caller may
2846 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2847 * themselves. Any null fields will be initialised with default values,
2848 * non-null fields are left alone.
2853 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2855 errorMessage = null;
2856 if (uniqueSetSuffix == null)
2858 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2860 if (seqRefIds == null)
2864 AlignFrame af = null, _af = null;
2865 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2866 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2867 final String file = jprovider.getFilename();
2870 JarInputStream jin = null;
2871 JarEntry jarentry = null;
2876 jin = jprovider.getJarInputStream();
2877 for (int i = 0; i < entryCount; i++)
2879 jarentry = jin.getNextJarEntry();
2882 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2884 JAXBContext jc = JAXBContext
2885 .newInstance("jalview.xml.binding.jalview");
2886 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2887 .createXMLStreamReader(jin);
2888 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2889 JAXBElement<JalviewModel> jbe = um
2890 .unmarshal(streamReader, JalviewModel.class);
2891 JalviewModel object = jbe.getValue();
2893 if (true) // !skipViewport(object))
2895 _af = loadFromObject(object, file, true, jprovider);
2896 if (_af != null && object.getViewport().size() > 0)
2897 // getJalviewModelSequence().getViewportCount() > 0)
2901 // store a reference to the first view
2904 if (_af.getViewport().isGatherViewsHere())
2906 // if this is a gathered view, keep its reference since
2907 // after gathering views, only this frame will remain
2909 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2912 // Save dataset to register mappings once all resolved
2913 importedDatasets.put(
2914 af.getViewport().getAlignment().getDataset(),
2915 af.getViewport().getAlignment().getDataset());
2920 else if (jarentry != null)
2922 // Some other file here.
2925 } while (jarentry != null);
2926 resolveFrefedSequences();
2927 } catch (IOException ex)
2929 ex.printStackTrace();
2930 errorMessage = "Couldn't locate Jalview XML file : " + file;
2932 "Exception whilst loading jalview XML file : " + ex + "\n");
2933 } catch (Exception ex)
2935 System.err.println("Parsing as Jalview Version 2 file failed.");
2936 ex.printStackTrace(System.err);
2937 if (attemptversion1parse)
2939 // used to attempt to parse as V1 castor-generated xml
2941 if (Desktop.instance != null)
2943 Desktop.instance.stopLoading();
2947 System.out.println("Successfully loaded archive file");
2950 ex.printStackTrace();
2953 "Exception whilst loading jalview XML file : " + ex + "\n");
2954 } catch (OutOfMemoryError e)
2956 // Don't use the OOM Window here
2957 errorMessage = "Out of memory loading jalview XML file";
2958 System.err.println("Out of memory whilst loading jalview XML file");
2959 e.printStackTrace();
2963 * Regather multiple views (with the same sequence set id) to the frame (if
2964 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2965 * views instead of separate frames. Note this doesn't restore a state where
2966 * some expanded views in turn have tabbed views - the last "first tab" read
2967 * in will play the role of gatherer for all.
2969 for (AlignFrame fr : gatherToThisFrame.values())
2971 Desktop.instance.gatherViews(fr);
2974 restoreSplitFrames();
2975 for (AlignmentI ds : importedDatasets.keySet())
2977 if (ds.getCodonFrames() != null)
2979 StructureSelectionManager
2980 .getStructureSelectionManager(Desktop.instance)
2981 .registerMappings(ds.getCodonFrames());
2984 if (errorMessage != null)
2989 if (Desktop.instance != null)
2991 Desktop.instance.stopLoading();
2998 * Try to reconstruct and display SplitFrame windows, where each contains
2999 * complementary dna and protein alignments. Done by pairing up AlignFrame
3000 * objects (created earlier) which have complementary viewport ids associated.
3002 protected void restoreSplitFrames()
3004 List<SplitFrame> gatherTo = new ArrayList<>();
3005 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3006 Map<String, AlignFrame> dna = new HashMap<>();
3009 * Identify the DNA alignments
3011 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3014 AlignFrame af = candidate.getValue();
3015 if (af.getViewport().getAlignment().isNucleotide())
3017 dna.put(candidate.getKey().getId(), af);
3022 * Try to match up the protein complements
3024 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3027 AlignFrame af = candidate.getValue();
3028 if (!af.getViewport().getAlignment().isNucleotide())
3030 String complementId = candidate.getKey().getComplementId();
3031 // only non-null complements should be in the Map
3032 if (complementId != null && dna.containsKey(complementId))
3034 final AlignFrame dnaFrame = dna.get(complementId);
3035 SplitFrame sf = createSplitFrame(dnaFrame, af);
3036 addedToSplitFrames.add(dnaFrame);
3037 addedToSplitFrames.add(af);
3038 dnaFrame.setMenusForViewport();
3039 af.setMenusForViewport();
3040 if (af.getViewport().isGatherViewsHere())
3049 * Open any that we failed to pair up (which shouldn't happen!) as
3050 * standalone AlignFrame's.
3052 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3055 AlignFrame af = candidate.getValue();
3056 if (!addedToSplitFrames.contains(af))
3058 Viewport view = candidate.getKey();
3059 Desktop.addInternalFrame(af, view.getTitle(),
3060 safeInt(view.getWidth()), safeInt(view.getHeight()));
3061 af.setMenusForViewport();
3062 System.err.println("Failed to restore view " + view.getTitle()
3063 + " to split frame");
3068 * Gather back into tabbed views as flagged.
3070 for (SplitFrame sf : gatherTo)
3072 Desktop.instance.gatherViews(sf);
3075 splitFrameCandidates.clear();
3079 * Construct and display one SplitFrame holding DNA and protein alignments.
3082 * @param proteinFrame
3085 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3086 AlignFrame proteinFrame)
3088 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3089 String title = MessageManager.getString("label.linked_view_title");
3090 int width = (int) dnaFrame.getBounds().getWidth();
3091 int height = (int) (dnaFrame.getBounds().getHeight()
3092 + proteinFrame.getBounds().getHeight() + 50);
3095 * SplitFrame location is saved to both enclosed frames
3097 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3098 Desktop.addInternalFrame(splitFrame, title, width, height);
3101 * And compute cDNA consensus (couldn't do earlier with consensus as
3102 * mappings were not yet present)
3104 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3110 * check errorMessage for a valid error message and raise an error box in the
3111 * GUI or write the current errorMessage to stderr and then clear the error
3114 protected void reportErrors()
3116 reportErrors(false);
3119 protected void reportErrors(final boolean saving)
3121 if (errorMessage != null)
3123 final String finalErrorMessage = errorMessage;
3126 javax.swing.SwingUtilities.invokeLater(new Runnable()
3131 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3133 "Error " + (saving ? "saving" : "loading")
3135 JvOptionPane.WARNING_MESSAGE);
3141 System.err.println("Problem loading Jalview file: " + errorMessage);
3144 errorMessage = null;
3147 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3150 * when set, local views will be updated from view stored in JalviewXML
3151 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3152 * sync if this is set to true.
3154 private final boolean updateLocalViews = false;
3157 * Returns the path to a temporary file holding the PDB file for the given PDB
3158 * id. The first time of asking, searches for a file of that name in the
3159 * Jalview project jar, and copies it to a new temporary file. Any repeat
3160 * requests just return the path to the file previously created.
3166 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3169 if (alreadyLoadedPDB.containsKey(pdbId))
3171 return alreadyLoadedPDB.get(pdbId).toString();
3174 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3176 if (tempFile != null)
3178 alreadyLoadedPDB.put(pdbId, tempFile);
3184 * Copies the jar entry of given name to a new temporary file and returns the
3185 * path to the file, or null if the entry is not found.
3188 * @param jarEntryName
3190 * a prefix for the temporary file name, must be at least three
3192 * @param suffixModel
3193 * null or original file - so new file can be given the same suffix
3197 protected String copyJarEntry(jarInputStreamProvider jprovider,
3198 String jarEntryName, String prefix, String suffixModel)
3200 String suffix = ".tmp";
3201 if (suffixModel == null)
3203 suffixModel = jarEntryName;
3205 int sfpos = suffixModel.lastIndexOf(".");
3206 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3208 suffix = "." + suffixModel.substring(sfpos + 1);
3211 try (JarInputStream jin = jprovider.getJarInputStream())
3213 JarEntry entry = null;
3216 entry = jin.getNextJarEntry();
3217 } while (entry != null && !entry.getName().equals(jarEntryName));
3221 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3222 File outFile = File.createTempFile(prefix, suffix);
3223 outFile.deleteOnExit();
3224 try (OutputStream os = new FileOutputStream(outFile))
3228 String t = outFile.getAbsolutePath();
3233 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3235 } catch (Exception ex)
3237 ex.printStackTrace();
3243 private class JvAnnotRow
3245 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3252 * persisted version of annotation row from which to take vis properties
3254 public jalview.datamodel.AlignmentAnnotation template;
3257 * original position of the annotation row in the alignment
3263 * Load alignment frame from jalview XML DOM object
3265 * @param jalviewModel
3268 * filename source string
3269 * @param loadTreesAndStructures
3270 * when false only create Viewport
3272 * data source provider
3273 * @return alignment frame created from view stored in DOM
3275 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3276 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3278 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3279 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3281 // JalviewModelSequence jms = object.getJalviewModelSequence();
3283 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3285 Viewport view = (jalviewModel.getViewport().size() > 0)
3286 ? jalviewModel.getViewport().get(0)
3289 // ////////////////////////////////
3290 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3293 // If we just load in the same jar file again, the sequenceSetId
3294 // will be the same, and we end up with multiple references
3295 // to the same sequenceSet. We must modify this id on load
3296 // so that each load of the file gives a unique id
3299 * used to resolve correct alignment dataset for alignments with multiple
3302 String uniqueSeqSetId = null;
3303 String viewId = null;
3306 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3307 viewId = (view.getId() == null ? null
3308 : view.getId() + uniqueSetSuffix);
3311 // ////////////////////////////////
3314 List<SequenceI> hiddenSeqs = null;
3316 List<SequenceI> tmpseqs = new ArrayList<>();
3318 boolean multipleView = false;
3319 SequenceI referenceseqForView = null;
3320 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3321 List<JSeq> jseqs = jalviewModel.getJSeq();
3322 int vi = 0; // counter in vamsasSeq array
3323 for (int i = 0; i < jseqs.size(); i++)
3325 JSeq jseq = jseqs.get(i);
3326 String seqId = jseq.getId();
3328 SequenceI tmpSeq = seqRefIds.get(seqId);
3331 if (!incompleteSeqs.containsKey(seqId))
3333 // may not need this check, but keep it for at least 2.9,1 release
3334 if (tmpSeq.getStart() != jseq.getStart()
3335 || tmpSeq.getEnd() != jseq.getEnd())
3338 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3339 tmpSeq.getName(), tmpSeq.getStart(),
3340 tmpSeq.getEnd(), jseq.getStart(),
3346 incompleteSeqs.remove(seqId);
3348 if (vamsasSeqs.size() > vi
3349 && vamsasSeqs.get(vi).getId().equals(seqId))
3351 // most likely we are reading a dataset XML document so
3352 // update from vamsasSeq section of XML for this sequence
3353 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3354 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3355 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3360 // reading multiple views, so vamsasSeq set is a subset of JSeq
3361 multipleView = true;
3363 tmpSeq.setStart(jseq.getStart());
3364 tmpSeq.setEnd(jseq.getEnd());
3365 tmpseqs.add(tmpSeq);
3369 Sequence vamsasSeq = vamsasSeqs.get(vi);
3370 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3371 vamsasSeq.getSequence());
3372 tmpSeq.setDescription(vamsasSeq.getDescription());
3373 tmpSeq.setStart(jseq.getStart());
3374 tmpSeq.setEnd(jseq.getEnd());
3375 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3376 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3377 tmpseqs.add(tmpSeq);
3381 if (safeBoolean(jseq.isViewreference()))
3383 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3386 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3388 if (hiddenSeqs == null)
3390 hiddenSeqs = new ArrayList<>();
3393 hiddenSeqs.add(tmpSeq);
3398 // Create the alignment object from the sequence set
3399 // ///////////////////////////////
3400 SequenceI[] orderedSeqs = tmpseqs
3401 .toArray(new SequenceI[tmpseqs.size()]);
3403 AlignmentI al = null;
3404 // so we must create or recover the dataset alignment before going further
3405 // ///////////////////////////////
3406 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3408 // older jalview projects do not have a dataset - so creat alignment and
3410 al = new Alignment(orderedSeqs);
3411 al.setDataset(null);
3415 boolean isdsal = jalviewModel.getViewport().isEmpty();
3418 // we are importing a dataset record, so
3419 // recover reference to an alignment already materialsed as dataset
3420 al = getDatasetFor(vamsasSet.getDatasetId());
3424 // materialse the alignment
3425 al = new Alignment(orderedSeqs);
3429 addDatasetRef(vamsasSet.getDatasetId(), al);
3432 // finally, verify all data in vamsasSet is actually present in al
3433 // passing on flag indicating if it is actually a stored dataset
3434 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3437 if (referenceseqForView != null)
3439 al.setSeqrep(referenceseqForView);
3441 // / Add the alignment properties
3442 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3444 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3446 al.setProperty(ssp.getKey(), ssp.getValue());
3449 // ///////////////////////////////
3451 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3454 // load sequence features, database references and any associated PDB
3455 // structures for the alignment
3457 // prior to 2.10, this part would only be executed the first time a
3458 // sequence was encountered, but not afterwards.
3459 // now, for 2.10 projects, this is also done if the xml doc includes
3460 // dataset sequences not actually present in any particular view.
3462 for (int i = 0; i < vamsasSeqs.size(); i++)
3464 JSeq jseq = jseqs.get(i);
3465 if (jseq.getFeatures().size() > 0)
3467 List<Feature> features = jseq.getFeatures();
3468 for (int f = 0; f < features.size(); f++)
3470 Feature feat = features.get(f);
3471 SequenceFeature sf = new SequenceFeature(feat.getType(),
3472 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3473 safeFloat(feat.getScore()), feat.getFeatureGroup());
3474 sf.setStatus(feat.getStatus());
3477 * load any feature attributes - include map-valued attributes
3479 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3480 for (int od = 0; od < feat.getOtherData().size(); od++)
3482 OtherData keyValue = feat.getOtherData().get(od);
3483 String attributeName = keyValue.getKey();
3484 String attributeValue = keyValue.getValue();
3485 if (attributeName.startsWith("LINK"))
3487 sf.addLink(attributeValue);
3491 String subAttribute = keyValue.getKey2();
3492 if (subAttribute == null)
3494 // simple string-valued attribute
3495 sf.setValue(attributeName, attributeValue);
3499 // attribute 'key' has sub-attribute 'key2'
3500 if (!mapAttributes.containsKey(attributeName))
3502 mapAttributes.put(attributeName, new HashMap<>());
3504 mapAttributes.get(attributeName).put(subAttribute,
3509 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3512 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3515 // adds feature to datasequence's feature set (since Jalview 2.10)
3516 al.getSequenceAt(i).addSequenceFeature(sf);
3519 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3521 // adds dbrefs to datasequence's set (since Jalview 2.10)
3523 al.getSequenceAt(i).getDatasetSequence() == null
3524 ? al.getSequenceAt(i)
3525 : al.getSequenceAt(i).getDatasetSequence(),
3528 if (jseq.getPdbids().size() > 0)
3530 List<Pdbids> ids = jseq.getPdbids();
3531 for (int p = 0; p < ids.size(); p++)
3533 Pdbids pdbid = ids.get(p);
3534 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3535 entry.setId(pdbid.getId());
3536 if (pdbid.getType() != null)
3538 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3540 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3544 entry.setType(PDBEntry.Type.FILE);
3547 // jprovider is null when executing 'New View'
3548 if (pdbid.getFile() != null && jprovider != null)
3550 if (!pdbloaded.containsKey(pdbid.getFile()))
3552 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3557 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3561 if (pdbid.getPdbentryItem() != null)
3563 for (PdbentryItem item : pdbid.getPdbentryItem())
3565 for (Property pr : item.getProperty())
3567 entry.setProperty(pr.getName(), pr.getValue());
3572 for (Property prop : pdbid.getProperty())
3574 entry.setProperty(prop.getName(), prop.getValue());
3576 StructureSelectionManager
3577 .getStructureSelectionManager(Desktop.instance)
3578 .registerPDBEntry(entry);
3579 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3580 if (al.getSequenceAt(i).getDatasetSequence() != null)
3582 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3586 al.getSequenceAt(i).addPDBId(entry);
3591 } // end !multipleview
3593 // ///////////////////////////////
3594 // LOAD SEQUENCE MAPPINGS
3596 if (vamsasSet.getAlcodonFrame().size() > 0)
3598 // TODO Potentially this should only be done once for all views of an
3600 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3601 for (int i = 0; i < alc.size(); i++)
3603 AlignedCodonFrame cf = new AlignedCodonFrame();
3604 if (alc.get(i).getAlcodMap().size() > 0)
3606 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3607 for (int m = 0; m < maps.size(); m++)
3609 AlcodMap map = maps.get(m);
3610 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3612 jalview.datamodel.Mapping mapping = null;
3613 // attach to dna sequence reference.
3614 if (map.getMapping() != null)
3616 mapping = addMapping(map.getMapping());
3617 if (dnaseq != null && mapping.getTo() != null)
3619 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3625 newAlcodMapRef(map.getDnasq(), cf, mapping));
3629 al.addCodonFrame(cf);
3634 // ////////////////////////////////
3636 List<JvAnnotRow> autoAlan = new ArrayList<>();
3639 * store any annotations which forward reference a group's ID
3641 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3643 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3645 List<Annotation> an = vamsasSet.getAnnotation();
3647 for (int i = 0; i < an.size(); i++)
3649 Annotation annotation = an.get(i);
3652 * test if annotation is automatically calculated for this view only
3654 boolean autoForView = false;
3655 if (annotation.getLabel().equals("Quality")
3656 || annotation.getLabel().equals("Conservation")
3657 || annotation.getLabel().equals("Consensus"))
3659 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3661 // JAXB has no has() test; schema defaults value to false
3662 // if (!annotation.hasAutoCalculated())
3664 // annotation.setAutoCalculated(true);
3667 if (autoForView || annotation.isAutoCalculated())
3669 // remove ID - we don't recover annotation from other views for
3670 // view-specific annotation
3671 annotation.setId(null);
3674 // set visibility for other annotation in this view
3675 String annotationId = annotation.getId();
3676 if (annotationId != null && annotationIds.containsKey(annotationId))
3678 AlignmentAnnotation jda = annotationIds.get(annotationId);
3679 // in principle Visible should always be true for annotation displayed
3680 // in multiple views
3681 if (annotation.isVisible() != null)
3683 jda.visible = annotation.isVisible();
3686 al.addAnnotation(jda);
3690 // Construct new annotation from model.
3691 List<AnnotationElement> ae = annotation.getAnnotationElement();
3692 jalview.datamodel.Annotation[] anot = null;
3693 java.awt.Color firstColour = null;
3695 if (!annotation.isScoreOnly())
3697 anot = new jalview.datamodel.Annotation[al.getWidth()];
3698 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3700 AnnotationElement annElement = ae.get(aa);
3701 anpos = annElement.getPosition();
3703 if (anpos >= anot.length)
3708 float value = safeFloat(annElement.getValue());
3709 anot[anpos] = new jalview.datamodel.Annotation(
3710 annElement.getDisplayCharacter(),
3711 annElement.getDescription(),
3712 (annElement.getSecondaryStructure() == null
3713 || annElement.getSecondaryStructure()
3717 .getSecondaryStructure()
3720 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3721 if (firstColour == null)
3723 firstColour = anot[anpos].colour;
3727 jalview.datamodel.AlignmentAnnotation jaa = null;
3729 if (annotation.isGraph())
3731 float llim = 0, hlim = 0;
3732 // if (autoForView || an[i].isAutoCalculated()) {
3735 jaa = new jalview.datamodel.AlignmentAnnotation(
3736 annotation.getLabel(), annotation.getDescription(), anot,
3737 llim, hlim, safeInt(annotation.getGraphType()));
3739 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3740 jaa._linecolour = firstColour;
3741 if (annotation.getThresholdLine() != null)
3743 jaa.setThreshold(new jalview.datamodel.GraphLine(
3744 safeFloat(annotation.getThresholdLine().getValue()),
3745 annotation.getThresholdLine().getLabel(),
3746 new java.awt.Color(safeInt(
3747 annotation.getThresholdLine().getColour()))));
3749 if (autoForView || annotation.isAutoCalculated())
3751 // Hardwire the symbol display line to ensure that labels for
3752 // histograms are displayed
3758 jaa = new jalview.datamodel.AlignmentAnnotation(
3759 annotation.getLabel(), annotation.getDescription(), anot);
3760 jaa._linecolour = firstColour;
3762 // register new annotation
3763 if (annotation.getId() != null)
3765 annotationIds.put(annotation.getId(), jaa);
3766 jaa.annotationId = annotation.getId();
3768 // recover sequence association
3769 String sequenceRef = annotation.getSequenceRef();
3770 if (sequenceRef != null)
3772 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3773 SequenceI sequence = seqRefIds.get(sequenceRef);
3774 if (sequence == null)
3776 // in pre-2.9 projects sequence ref is to sequence name
3777 sequence = al.findName(sequenceRef);
3779 if (sequence != null)
3781 jaa.createSequenceMapping(sequence, 1, true);
3782 sequence.addAlignmentAnnotation(jaa);
3785 // and make a note of any group association
3786 if (annotation.getGroupRef() != null
3787 && annotation.getGroupRef().length() > 0)
3789 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3790 .get(annotation.getGroupRef());
3793 aal = new ArrayList<>();
3794 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3799 if (annotation.getScore() != null)
3801 jaa.setScore(annotation.getScore().doubleValue());
3803 if (annotation.isVisible() != null)
3805 jaa.visible = annotation.isVisible().booleanValue();
3808 if (annotation.isCentreColLabels() != null)
3810 jaa.centreColLabels = annotation.isCentreColLabels()
3814 if (annotation.isScaleColLabels() != null)
3816 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3818 if (annotation.isAutoCalculated())
3820 // newer files have an 'autoCalculated' flag and store calculation
3821 // state in viewport properties
3822 jaa.autoCalculated = true; // means annotation will be marked for
3823 // update at end of load.
3825 if (annotation.getGraphHeight() != null)
3827 jaa.graphHeight = annotation.getGraphHeight().intValue();
3829 jaa.belowAlignment = annotation.isBelowAlignment();
3830 jaa.setCalcId(annotation.getCalcId());
3831 if (annotation.getProperty().size() > 0)
3833 for (Annotation.Property prop : annotation
3836 jaa.setProperty(prop.getName(), prop.getValue());
3839 if (jaa.autoCalculated)
3841 autoAlan.add(new JvAnnotRow(i, jaa));
3844 // if (!autoForView)
3846 // add autocalculated group annotation and any user created annotation
3848 al.addAnnotation(jaa);
3852 // ///////////////////////
3854 // Create alignment markup and styles for this view
3855 if (jalviewModel.getJGroup().size() > 0)
3857 List<JGroup> groups = jalviewModel.getJGroup();
3858 boolean addAnnotSchemeGroup = false;
3859 for (int i = 0; i < groups.size(); i++)
3861 JGroup jGroup = groups.get(i);
3862 ColourSchemeI cs = null;
3863 if (jGroup.getColour() != null)
3865 if (jGroup.getColour().startsWith("ucs"))
3867 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3869 else if (jGroup.getColour().equals("AnnotationColourGradient")
3870 && jGroup.getAnnotationColours() != null)
3872 addAnnotSchemeGroup = true;
3876 cs = ColourSchemeProperty.getColourScheme(null, al,
3877 jGroup.getColour());
3880 int pidThreshold = safeInt(jGroup.getPidThreshold());
3882 Vector<SequenceI> seqs = new Vector<>();
3884 for (int s = 0; s < jGroup.getSeq().size(); s++)
3886 String seqId = jGroup.getSeq().get(s);
3887 SequenceI ts = seqRefIds.get(seqId);
3891 seqs.addElement(ts);
3895 if (seqs.size() < 1)
3900 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3901 safeBoolean(jGroup.isDisplayBoxes()),
3902 safeBoolean(jGroup.isDisplayText()),
3903 safeBoolean(jGroup.isColourText()),
3904 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3905 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3906 sg.getGroupColourScheme()
3907 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3908 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3910 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3911 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3912 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3913 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3914 // attributes with a default in the schema are never null
3915 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3916 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3917 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3918 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3919 if (jGroup.getConsThreshold() != null
3920 && jGroup.getConsThreshold().intValue() != 0)
3922 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3925 c.verdict(false, 25);
3926 sg.cs.setConservation(c);
3929 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3931 // re-instate unique group/annotation row reference
3932 List<AlignmentAnnotation> jaal = groupAnnotRefs
3933 .get(jGroup.getId());
3936 for (AlignmentAnnotation jaa : jaal)
3939 if (jaa.autoCalculated)
3941 // match up and try to set group autocalc alignment row for this
3943 if (jaa.label.startsWith("Consensus for "))
3945 sg.setConsensus(jaa);
3947 // match up and try to set group autocalc alignment row for this
3949 if (jaa.label.startsWith("Conservation for "))
3951 sg.setConservationRow(jaa);
3958 if (addAnnotSchemeGroup)
3960 // reconstruct the annotation colourscheme
3961 sg.setColourScheme(constructAnnotationColour(
3962 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3968 // only dataset in this model, so just return.
3971 // ///////////////////////////////
3974 AlignFrame af = null;
3975 AlignViewport av = null;
3976 // now check to see if we really need to create a new viewport.
3977 if (multipleView && viewportsAdded.size() == 0)
3979 // We recovered an alignment for which a viewport already exists.
3980 // TODO: fix up any settings necessary for overlaying stored state onto
3981 // state recovered from another document. (may not be necessary).
3982 // we may need a binding from a viewport in memory to one recovered from
3984 // and then recover its containing af to allow the settings to be applied.
3985 // TODO: fix for vamsas demo
3987 "About to recover a viewport for existing alignment: Sequence set ID is "
3989 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3990 if (seqsetobj != null)
3992 if (seqsetobj instanceof String)
3994 uniqueSeqSetId = (String) seqsetobj;
3996 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4002 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4008 * indicate that annotation colours are applied across all groups (pre
4009 * Jalview 2.8.1 behaviour)
4011 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4012 jalviewModel.getVersion());
4014 AlignmentPanel ap = null;
4015 boolean isnewview = true;
4018 // Check to see if this alignment already has a view id == viewId
4019 jalview.gui.AlignmentPanel views[] = Desktop
4020 .getAlignmentPanels(uniqueSeqSetId);
4021 if (views != null && views.length > 0)
4023 for (int v = 0; v < views.length; v++)
4025 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4027 // recover the existing alignpanel, alignframe, viewport
4028 af = views[v].alignFrame;
4031 // TODO: could even skip resetting view settings if we don't want to
4032 // change the local settings from other jalview processes
4041 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4042 uniqueSeqSetId, viewId, autoAlan);
4043 av = af.getViewport();
4048 * Load any trees, PDB structures and viewers, Overview
4050 * Not done if flag is false (when this method is used for New View)
4052 if (loadTreesAndStructures)
4054 loadTrees(jalviewModel, view, af, av, ap);
4055 loadPCAViewers(jalviewModel, ap);
4056 loadPDBStructures(jprovider, jseqs, af, ap);
4057 loadRnaViewers(jprovider, jseqs, ap);
4058 loadOverview(view, af);
4060 // and finally return.
4065 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4066 * and geometry as saved
4071 protected void loadOverview(Viewport view, AlignFrame af)
4073 Overview overview = view.getOverview();
4074 if (overview != null)
4076 OverviewPanel overviewPanel = af
4077 .openOverviewPanel(overview.isShowHidden());
4078 overviewPanel.setBounds(overview.getXpos(), overview.getYpos(),
4079 overview.getWidth(), overview.getHeight());
4080 overviewPanel.setPreferredSize(
4081 new Dimension(overview.getWidth(), overview.getHeight()));
4082 Color gap = new Color(overview.getGapColour());
4083 Color residue = new Color(overview.getResidueColour());
4084 Color hidden = new Color(overview.getHiddenColour());
4085 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4086 ((JInternalFrame) SwingUtilities
4087 .getAncestorOfClass(JInternalFrame.class, overviewPanel))
4088 .setTitle(overview.getTitle());
4093 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4094 * panel is restored from separate jar entries, two (gapped and trimmed) per
4095 * sequence and secondary structure.
4097 * Currently each viewer shows just one sequence and structure (gapped and
4098 * trimmed), however this method is designed to support multiple sequences or
4099 * structures in viewers if wanted in future.
4105 private void loadRnaViewers(jarInputStreamProvider jprovider,
4106 List<JSeq> jseqs, AlignmentPanel ap)
4109 * scan the sequences for references to viewers; create each one the first
4110 * time it is referenced, add Rna models to existing viewers
4112 for (JSeq jseq : jseqs)
4114 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4116 RnaViewer viewer = jseq.getRnaViewer().get(i);
4117 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4120 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4122 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4123 SequenceI seq = seqRefIds.get(jseq.getId());
4124 AlignmentAnnotation ann = this.annotationIds
4125 .get(ss.getAnnotationId());
4128 * add the structure to the Varna display (with session state copied
4129 * from the jar to a temporary file)
4131 boolean gapped = safeBoolean(ss.isGapped());
4132 String rnaTitle = ss.getTitle();
4133 String sessionState = ss.getViewerState();
4134 String tempStateFile = copyJarEntry(jprovider, sessionState,
4136 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4137 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4139 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4145 * Locate and return an already instantiated matching AppVarna, or create one
4149 * @param viewIdSuffix
4153 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4154 String viewIdSuffix, AlignmentPanel ap)
4157 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4158 * if load is repeated
4160 String postLoadId = viewer.getViewId() + viewIdSuffix;
4161 for (JInternalFrame frame : getAllFrames())
4163 if (frame instanceof AppVarna)
4165 AppVarna varna = (AppVarna) frame;
4166 if (postLoadId.equals(varna.getViewId()))
4168 // this viewer is already instantiated
4169 // could in future here add ap as another 'parent' of the
4170 // AppVarna window; currently just 1-to-many
4177 * viewer not found - make it
4179 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4180 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4181 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4182 safeInt(viewer.getDividerLocation()));
4183 AppVarna varna = new AppVarna(model, ap);
4189 * Load any saved trees
4197 protected void loadTrees(JalviewModel jm, Viewport view,
4198 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4200 // TODO result of automated refactoring - are all these parameters needed?
4203 for (int t = 0; t < jm.getTree().size(); t++)
4206 Tree tree = jm.getTree().get(t);
4208 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4211 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4212 tree.getTitle(), safeInt(tree.getWidth()),
4213 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4214 safeInt(tree.getYpos()));
4215 if (tree.getId() != null)
4217 // perhaps bind the tree id to something ?
4222 // update local tree attributes ?
4223 // TODO: should check if tp has been manipulated by user - if so its
4224 // settings shouldn't be modified
4225 tp.setTitle(tree.getTitle());
4226 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4227 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4228 safeInt(tree.getHeight())));
4229 tp.setViewport(av); // af.viewport;
4230 // TODO: verify 'associate with all views' works still
4231 tp.getTreeCanvas().setViewport(av); // af.viewport;
4232 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4234 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4237 warn("There was a problem recovering stored Newick tree: \n"
4238 + tree.getNewick());
4242 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4243 tp.fitToWindow_actionPerformed(null);
4245 if (tree.getFontName() != null)
4248 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4249 safeInt(tree.getFontSize())));
4254 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4255 safeInt(view.getFontSize())));
4258 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4259 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4260 tp.showDistances(safeBoolean(tree.isShowDistances()));
4262 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4264 if (safeBoolean(tree.isCurrentTree()))
4266 af.getViewport().setCurrentTree(tp.getTree());
4270 } catch (Exception ex)
4272 ex.printStackTrace();
4277 * Load and link any saved structure viewers.
4284 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4285 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4288 * Run through all PDB ids on the alignment, and collect mappings between
4289 * distinct view ids and all sequences referring to that view.
4291 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4293 for (int i = 0; i < jseqs.size(); i++)
4295 JSeq jseq = jseqs.get(i);
4296 if (jseq.getPdbids().size() > 0)
4298 List<Pdbids> ids = jseq.getPdbids();
4299 for (int p = 0; p < ids.size(); p++)
4301 Pdbids pdbid = ids.get(p);
4302 final int structureStateCount = pdbid.getStructureState().size();
4303 for (int s = 0; s < structureStateCount; s++)
4305 // check to see if we haven't already created this structure view
4306 final StructureState structureState = pdbid
4307 .getStructureState().get(s);
4308 String sviewid = (structureState.getViewId() == null) ? null
4309 : structureState.getViewId() + uniqueSetSuffix;
4310 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4311 // Originally : pdbid.getFile()
4312 // : TODO: verify external PDB file recovery still works in normal
4313 // jalview project load
4315 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4316 jpdb.setId(pdbid.getId());
4318 int x = safeInt(structureState.getXpos());
4319 int y = safeInt(structureState.getYpos());
4320 int width = safeInt(structureState.getWidth());
4321 int height = safeInt(structureState.getHeight());
4323 // Probably don't need to do this anymore...
4324 // Desktop.desktop.getComponentAt(x, y);
4325 // TODO: NOW: check that this recovers the PDB file correctly.
4326 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4328 jalview.datamodel.SequenceI seq = seqRefIds
4329 .get(jseq.getId() + "");
4330 if (sviewid == null)
4332 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4335 if (!structureViewers.containsKey(sviewid))
4337 String viewerType = structureState.getType();
4338 if (viewerType == null) // pre Jalview 2.9
4340 viewerType = ViewerType.JMOL.toString();
4342 structureViewers.put(sviewid,
4343 new StructureViewerModel(x, y, width, height, false,
4344 false, true, structureState.getViewId(),
4346 // Legacy pre-2.7 conversion JAL-823 :
4347 // do not assume any view has to be linked for colour by
4351 // assemble String[] { pdb files }, String[] { id for each
4352 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4353 // seqs_file 2}, boolean[] {
4354 // linkAlignPanel,superposeWithAlignpanel}} from hash
4355 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4356 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4357 || structureState.isAlignwithAlignPanel());
4360 * Default colour by linked panel to false if not specified (e.g.
4361 * for pre-2.7 projects)
4363 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4364 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4365 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4368 * Default colour by viewer to true if not specified (e.g. for
4371 boolean colourByViewer = jmoldat.isColourByViewer();
4372 colourByViewer &= structureState.isColourByJmol();
4373 jmoldat.setColourByViewer(colourByViewer);
4375 if (jmoldat.getStateData().length() < structureState
4376 .getValue()/*Content()*/.length())
4378 jmoldat.setStateData(structureState.getValue());// Content());
4380 if (pdbid.getFile() != null)
4382 File mapkey = new File(pdbid.getFile());
4383 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4384 if (seqstrmaps == null)
4386 jmoldat.getFileData().put(mapkey,
4387 seqstrmaps = jmoldat.new StructureData(pdbFile,
4390 if (!seqstrmaps.getSeqList().contains(seq))
4392 seqstrmaps.getSeqList().add(seq);
4398 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");
4405 // Instantiate the associated structure views
4406 for (Entry<String, StructureViewerModel> entry : structureViewers
4411 createOrLinkStructureViewer(entry, af, ap, jprovider);
4412 } catch (Exception e)
4415 "Error loading structure viewer: " + e.getMessage());
4416 // failed - try the next one
4428 protected void createOrLinkStructureViewer(
4429 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4430 AlignmentPanel ap, jarInputStreamProvider jprovider)
4432 final StructureViewerModel stateData = viewerData.getValue();
4435 * Search for any viewer windows already open from other alignment views
4436 * that exactly match the stored structure state
4438 StructureViewerBase comp = findMatchingViewer(viewerData);
4442 linkStructureViewer(ap, comp, stateData);
4446 String type = stateData.getType();
4449 ViewerType viewerType = ViewerType.valueOf(type);
4450 createStructureViewer(viewerType, viewerData, af, jprovider);
4451 } catch (IllegalArgumentException | NullPointerException e)
4453 // TODO JAL-3619 show error dialog / offer an alternative viewer
4455 "Invalid structure viewer type: " + type);
4460 * Generates a name for the entry in the project jar file to hold state
4461 * information for a structure viewer
4466 protected String getViewerJarEntryName(String viewId)
4468 return VIEWER_PREFIX + viewId;
4472 * Returns any open frame that matches given structure viewer data. The match
4473 * is based on the unique viewId, or (for older project versions) the frame's
4479 protected StructureViewerBase findMatchingViewer(
4480 Entry<String, StructureViewerModel> viewerData)
4482 final String sviewid = viewerData.getKey();
4483 final StructureViewerModel svattrib = viewerData.getValue();
4484 StructureViewerBase comp = null;
4485 JInternalFrame[] frames = getAllFrames();
4486 for (JInternalFrame frame : frames)
4488 if (frame instanceof StructureViewerBase)
4491 * Post jalview 2.4 schema includes structure view id
4493 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4496 comp = (StructureViewerBase) frame;
4497 break; // break added in 2.9
4500 * Otherwise test for matching position and size of viewer frame
4502 else if (frame.getX() == svattrib.getX()
4503 && frame.getY() == svattrib.getY()
4504 && frame.getHeight() == svattrib.getHeight()
4505 && frame.getWidth() == svattrib.getWidth())
4507 comp = (StructureViewerBase) frame;
4508 // no break in faint hope of an exact match on viewId
4516 * Link an AlignmentPanel to an existing structure viewer.
4521 * @param useinViewerSuperpos
4522 * @param usetoColourbyseq
4523 * @param viewerColouring
4525 protected void linkStructureViewer(AlignmentPanel ap,
4526 StructureViewerBase viewer, StructureViewerModel stateData)
4528 // NOTE: if the jalview project is part of a shared session then
4529 // view synchronization should/could be done here.
4531 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4532 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4533 final boolean viewerColouring = stateData.isColourByViewer();
4534 Map<File, StructureData> oldFiles = stateData.getFileData();
4537 * Add mapping for sequences in this view to an already open viewer
4539 final AAStructureBindingModel binding = viewer.getBinding();
4540 for (File id : oldFiles.keySet())
4542 // add this and any other pdb files that should be present in the
4544 StructureData filedat = oldFiles.get(id);
4545 String pdbFile = filedat.getFilePath();
4546 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4547 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4549 binding.addSequenceForStructFile(pdbFile, seq);
4551 // and add the AlignmentPanel's reference to the view panel
4552 viewer.addAlignmentPanel(ap);
4553 if (useinViewerSuperpos)
4555 viewer.useAlignmentPanelForSuperposition(ap);
4559 viewer.excludeAlignmentPanelForSuperposition(ap);
4561 if (usetoColourbyseq)
4563 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4567 viewer.excludeAlignmentPanelForColourbyseq(ap);
4572 * Get all frames within the Desktop.
4576 protected JInternalFrame[] getAllFrames()
4578 JInternalFrame[] frames = null;
4579 // TODO is this necessary - is it safe - risk of hanging?
4584 frames = Desktop.desktop.getAllFrames();
4585 } catch (ArrayIndexOutOfBoundsException e)
4587 // occasional No such child exceptions are thrown here...
4591 } catch (InterruptedException f)
4595 } while (frames == null);
4600 * Answers true if 'version' is equal to or later than 'supported', where each
4601 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4602 * changes. Development and test values for 'version' are leniently treated
4606 * - minimum version we are comparing against
4608 * - version of data being processsed
4611 public static boolean isVersionStringLaterThan(String supported,
4614 if (supported == null || version == null
4615 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4616 || version.equalsIgnoreCase("Test")
4617 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4619 System.err.println("Assuming project file with "
4620 + (version == null ? "null" : version)
4621 + " is compatible with Jalview version " + supported);
4626 return StringUtils.compareVersions(version, supported, "b") >= 0;
4630 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4632 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4634 if (newStructureViewers != null)
4636 sview.getBinding().setFinishedLoadingFromArchive(false);
4637 newStructureViewers.add(sview);
4641 protected void setLoadingFinishedForNewStructureViewers()
4643 if (newStructureViewers != null)
4645 for (JalviewStructureDisplayI sview : newStructureViewers)
4647 sview.getBinding().setFinishedLoadingFromArchive(true);
4649 newStructureViewers.clear();
4650 newStructureViewers = null;
4654 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4655 List<SequenceI> hiddenSeqs, AlignmentI al,
4656 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4657 String viewId, List<JvAnnotRow> autoAlan)
4659 AlignFrame af = null;
4660 af = new AlignFrame(al, safeInt(view.getWidth()),
4661 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4665 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4666 // System.out.println("Jalview2XML AF " + e);
4667 // super.processKeyEvent(e);
4674 af.setFileName(file, FileFormat.Jalview);
4676 final AlignViewport viewport = af.getViewport();
4677 for (int i = 0; i < JSEQ.size(); i++)
4679 int colour = safeInt(JSEQ.get(i).getColour());
4680 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4686 viewport.setColourByReferenceSeq(true);
4687 viewport.setDisplayReferenceSeq(true);
4690 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4692 if (view.getSequenceSetId() != null)
4694 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4696 viewport.setSequenceSetId(uniqueSeqSetId);
4699 // propagate shared settings to this new view
4700 viewport.setHistoryList(av.getHistoryList());
4701 viewport.setRedoList(av.getRedoList());
4705 viewportsAdded.put(uniqueSeqSetId, viewport);
4707 // TODO: check if this method can be called repeatedly without
4708 // side-effects if alignpanel already registered.
4709 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4711 // apply Hidden regions to view.
4712 if (hiddenSeqs != null)
4714 for (int s = 0; s < JSEQ.size(); s++)
4716 SequenceGroup hidden = new SequenceGroup();
4717 boolean isRepresentative = false;
4718 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4720 isRepresentative = true;
4721 SequenceI sequenceToHide = al
4722 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4723 hidden.addSequence(sequenceToHide, false);
4724 // remove from hiddenSeqs list so we don't try to hide it twice
4725 hiddenSeqs.remove(sequenceToHide);
4727 if (isRepresentative)
4729 SequenceI representativeSequence = al.getSequenceAt(s);
4730 hidden.addSequence(representativeSequence, false);
4731 viewport.hideRepSequences(representativeSequence, hidden);
4735 SequenceI[] hseqs = hiddenSeqs
4736 .toArray(new SequenceI[hiddenSeqs.size()]);
4737 viewport.hideSequence(hseqs);
4740 // recover view properties and display parameters
4742 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4743 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4744 final int pidThreshold = safeInt(view.getPidThreshold());
4745 viewport.setThreshold(pidThreshold);
4747 viewport.setColourText(safeBoolean(view.isShowColourText()));
4750 .setConservationSelected(
4751 safeBoolean(view.isConservationSelected()));
4752 viewport.setIncrement(safeInt(view.getConsThreshold()));
4753 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4754 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4755 viewport.setFont(new Font(view.getFontName(),
4756 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4758 ViewStyleI vs = viewport.getViewStyle();
4759 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4760 viewport.setViewStyle(vs);
4761 // TODO: allow custom charWidth/Heights to be restored by updating them
4762 // after setting font - which means set above to false
4763 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4764 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4765 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4767 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4769 viewport.setShowText(safeBoolean(view.isShowText()));
4771 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4772 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4773 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4774 viewport.setShowUnconserved(view.isShowUnconserved());
4775 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4777 if (view.getViewName() != null)
4779 viewport.setViewName(view.getViewName());
4780 af.setInitialTabVisible();
4782 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4783 safeInt(view.getWidth()), safeInt(view.getHeight()));
4784 // startSeq set in af.alignPanel.updateLayout below
4785 af.alignPanel.updateLayout();
4786 ColourSchemeI cs = null;
4787 // apply colourschemes
4788 if (view.getBgColour() != null)
4790 if (view.getBgColour().startsWith("ucs"))
4792 cs = getUserColourScheme(jm, view.getBgColour());
4794 else if (view.getBgColour().startsWith("Annotation"))
4796 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4797 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4804 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4805 view.getBgColour());
4810 * turn off 'alignment colour applies to all groups'
4811 * while restoring global colour scheme
4813 viewport.setColourAppliesToAllGroups(false);
4814 viewport.setGlobalColourScheme(cs);
4815 viewport.getResidueShading().setThreshold(pidThreshold,
4816 view.isIgnoreGapsinConsensus());
4817 viewport.getResidueShading()
4818 .setConsensus(viewport.getSequenceConsensusHash());
4819 if (safeBoolean(view.isConservationSelected()) && cs != null)
4821 viewport.getResidueShading()
4822 .setConservationInc(safeInt(view.getConsThreshold()));
4824 af.changeColour(cs);
4825 viewport.setColourAppliesToAllGroups(true);
4828 .setShowSequenceFeatures(
4829 safeBoolean(view.isShowSequenceFeatures()));
4831 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4832 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4833 viewport.setFollowHighlight(view.isFollowHighlight());
4834 viewport.followSelection = view.isFollowSelection();
4835 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4836 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4837 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4838 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4839 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4840 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4841 viewport.setShowGroupConservation(view.isShowGroupConservation());
4842 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4843 viewport.setShowComplementFeaturesOnTop(
4844 view.isShowComplementFeaturesOnTop());
4846 // recover feature settings
4847 if (jm.getFeatureSettings() != null)
4849 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4850 .getFeatureRenderer();
4851 FeaturesDisplayed fdi;
4852 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4853 String[] renderOrder = new String[jm.getFeatureSettings()
4854 .getSetting().size()];
4855 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4856 Map<String, Float> featureOrder = new Hashtable<>();
4858 for (int fs = 0; fs < jm.getFeatureSettings()
4859 .getSetting().size(); fs++)
4861 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4862 String featureType = setting.getType();
4865 * restore feature filters (if any)
4867 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4869 if (filters != null)
4871 FeatureMatcherSetI filter = Jalview2XML
4872 .parseFilter(featureType, filters);
4873 if (!filter.isEmpty())
4875 fr.setFeatureFilter(featureType, filter);
4880 * restore feature colour scheme
4882 Color maxColour = new Color(setting.getColour());
4883 if (setting.getMincolour() != null)
4886 * minColour is always set unless a simple colour
4887 * (including for colour by label though it doesn't use it)
4889 Color minColour = new Color(setting.getMincolour().intValue());
4890 Color noValueColour = minColour;
4891 NoValueColour noColour = setting.getNoValueColour();
4892 if (noColour == NoValueColour.NONE)
4894 noValueColour = null;
4896 else if (noColour == NoValueColour.MAX)
4898 noValueColour = maxColour;
4900 float min = safeFloat(safeFloat(setting.getMin()));
4901 float max = setting.getMax() == null ? 1f
4902 : setting.getMax().floatValue();
4903 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4905 noValueColour, min, max);
4906 if (setting.getAttributeName().size() > 0)
4908 gc.setAttributeName(setting.getAttributeName().toArray(
4909 new String[setting.getAttributeName().size()]));
4911 if (setting.getThreshold() != null)
4913 gc.setThreshold(setting.getThreshold().floatValue());
4914 int threshstate = safeInt(setting.getThreshstate());
4915 // -1 = None, 0 = Below, 1 = Above threshold
4916 if (threshstate == 0)
4918 gc.setBelowThreshold(true);
4920 else if (threshstate == 1)
4922 gc.setAboveThreshold(true);
4925 gc.setAutoScaled(true); // default
4926 if (setting.isAutoScale() != null)
4928 gc.setAutoScaled(setting.isAutoScale());
4930 if (setting.isColourByLabel() != null)
4932 gc.setColourByLabel(setting.isColourByLabel());
4934 // and put in the feature colour table.
4935 featureColours.put(featureType, gc);
4939 featureColours.put(featureType,
4940 new FeatureColour(maxColour));
4942 renderOrder[fs] = featureType;
4943 if (setting.getOrder() != null)
4945 featureOrder.put(featureType, setting.getOrder().floatValue());
4949 featureOrder.put(featureType, Float.valueOf(
4950 fs / jm.getFeatureSettings().getSetting().size()));
4952 if (safeBoolean(setting.isDisplay()))
4954 fdi.setVisible(featureType);
4957 Map<String, Boolean> fgtable = new Hashtable<>();
4958 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4960 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4961 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4963 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4964 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4965 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4966 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4967 fgtable, featureColours, 1.0f, featureOrder);
4968 fr.transferSettings(frs);
4971 if (view.getHiddenColumns().size() > 0)
4973 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4975 final HiddenColumns hc = view.getHiddenColumns().get(c);
4976 viewport.hideColumns(safeInt(hc.getStart()),
4977 safeInt(hc.getEnd()) /* +1 */);
4980 if (view.getCalcIdParam() != null)
4982 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4984 if (calcIdParam != null)
4986 if (recoverCalcIdParam(calcIdParam, viewport))
4991 warn("Couldn't recover parameters for "
4992 + calcIdParam.getCalcId());
4997 af.setMenusFromViewport(viewport);
4998 af.setTitle(view.getTitle());
4999 // TODO: we don't need to do this if the viewport is aready visible.
5001 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5002 * has a 'cdna/protein complement' view, in which case save it in order to
5003 * populate a SplitFrame once all views have been read in.
5005 String complementaryViewId = view.getComplementId();
5006 if (complementaryViewId == null)
5008 Desktop.addInternalFrame(af, view.getTitle(),
5009 safeInt(view.getWidth()), safeInt(view.getHeight()));
5010 // recompute any autoannotation
5011 af.alignPanel.updateAnnotation(false, true);
5012 reorderAutoannotation(af, al, autoAlan);
5013 af.alignPanel.alignmentChanged();
5017 splitFrameCandidates.put(view, af);
5024 * Reads saved data to restore Colour by Annotation settings
5026 * @param viewAnnColour
5030 * @param checkGroupAnnColour
5033 private ColourSchemeI constructAnnotationColour(
5034 AnnotationColourScheme viewAnnColour, AlignFrame af,
5035 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5037 boolean propagateAnnColour = false;
5038 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5040 if (checkGroupAnnColour && al.getGroups() != null
5041 && al.getGroups().size() > 0)
5043 // pre 2.8.1 behaviour
5044 // check to see if we should transfer annotation colours
5045 propagateAnnColour = true;
5046 for (SequenceGroup sg : al.getGroups())
5048 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5050 propagateAnnColour = false;
5056 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5058 String annotationId = viewAnnColour.getAnnotation();
5059 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5062 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5064 if (matchedAnnotation == null
5065 && annAlignment.getAlignmentAnnotation() != null)
5067 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5070 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5072 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5077 if (matchedAnnotation == null)
5079 System.err.println("Failed to match annotation colour scheme for "
5083 if (matchedAnnotation.getThreshold() == null)
5085 matchedAnnotation.setThreshold(
5086 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5087 "Threshold", Color.black));
5090 AnnotationColourGradient cs = null;
5091 if (viewAnnColour.getColourScheme().equals("None"))
5093 cs = new AnnotationColourGradient(matchedAnnotation,
5094 new Color(safeInt(viewAnnColour.getMinColour())),
5095 new Color(safeInt(viewAnnColour.getMaxColour())),
5096 safeInt(viewAnnColour.getAboveThreshold()));
5098 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5100 cs = new AnnotationColourGradient(matchedAnnotation,
5101 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5102 safeInt(viewAnnColour.getAboveThreshold()));
5106 cs = new AnnotationColourGradient(matchedAnnotation,
5107 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5108 viewAnnColour.getColourScheme()),
5109 safeInt(viewAnnColour.getAboveThreshold()));
5112 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5113 boolean useOriginalColours = safeBoolean(
5114 viewAnnColour.isPredefinedColours());
5115 cs.setSeqAssociated(perSequenceOnly);
5116 cs.setPredefinedColours(useOriginalColours);
5118 if (propagateAnnColour && al.getGroups() != null)
5120 // Also use these settings for all the groups
5121 for (int g = 0; g < al.getGroups().size(); g++)
5123 SequenceGroup sg = al.getGroups().get(g);
5124 if (sg.getGroupColourScheme() == null)
5129 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5130 matchedAnnotation, sg.getColourScheme(),
5131 safeInt(viewAnnColour.getAboveThreshold()));
5132 sg.setColourScheme(groupScheme);
5133 groupScheme.setSeqAssociated(perSequenceOnly);
5134 groupScheme.setPredefinedColours(useOriginalColours);
5140 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5141 List<JvAnnotRow> autoAlan)
5143 // copy over visualization settings for autocalculated annotation in the
5145 if (al.getAlignmentAnnotation() != null)
5148 * Kludge for magic autoannotation names (see JAL-811)
5150 String[] magicNames = new String[] { "Consensus", "Quality",
5152 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5153 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5154 for (String nm : magicNames)
5156 visan.put(nm, nullAnnot);
5158 for (JvAnnotRow auan : autoAlan)
5160 visan.put(auan.template.label
5161 + (auan.template.getCalcId() == null ? ""
5162 : "\t" + auan.template.getCalcId()),
5165 int hSize = al.getAlignmentAnnotation().length;
5166 List<JvAnnotRow> reorder = new ArrayList<>();
5167 // work through any autoCalculated annotation already on the view
5168 // removing it if it should be placed in a different location on the
5169 // annotation panel.
5170 List<String> remains = new ArrayList<>(visan.keySet());
5171 for (int h = 0; h < hSize; h++)
5173 jalview.datamodel.AlignmentAnnotation jalan = al
5174 .getAlignmentAnnotation()[h];
5175 if (jalan.autoCalculated)
5178 JvAnnotRow valan = visan.get(k = jalan.label);
5179 if (jalan.getCalcId() != null)
5181 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5186 // delete the auto calculated row from the alignment
5187 al.deleteAnnotation(jalan, false);
5191 if (valan != nullAnnot)
5193 if (jalan != valan.template)
5195 // newly created autoannotation row instance
5196 // so keep a reference to the visible annotation row
5197 // and copy over all relevant attributes
5198 if (valan.template.graphHeight >= 0)
5201 jalan.graphHeight = valan.template.graphHeight;
5203 jalan.visible = valan.template.visible;
5205 reorder.add(new JvAnnotRow(valan.order, jalan));
5210 // Add any (possibly stale) autocalculated rows that were not appended to
5211 // the view during construction
5212 for (String other : remains)
5214 JvAnnotRow othera = visan.get(other);
5215 if (othera != nullAnnot && othera.template.getCalcId() != null
5216 && othera.template.getCalcId().length() > 0)
5218 reorder.add(othera);
5221 // now put the automatic annotation in its correct place
5222 int s = 0, srt[] = new int[reorder.size()];
5223 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5224 for (JvAnnotRow jvar : reorder)
5227 srt[s++] = jvar.order;
5230 jalview.util.QuickSort.sort(srt, rws);
5231 // and re-insert the annotation at its correct position
5232 for (JvAnnotRow jvar : rws)
5234 al.addAnnotation(jvar.template, jvar.order);
5236 af.alignPanel.adjustAnnotationHeight();
5240 Hashtable skipList = null;
5243 * TODO remove this method
5246 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5247 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5248 * throw new Error("Implementation Error. No skipList defined for this
5249 * Jalview2XML instance."); } return (AlignFrame)
5250 * skipList.get(view.getSequenceSetId()); }
5254 * Check if the Jalview view contained in object should be skipped or not.
5257 * @return true if view's sequenceSetId is a key in skipList
5259 private boolean skipViewport(JalviewModel object)
5261 if (skipList == null)
5265 String id = object.getViewport().get(0).getSequenceSetId();
5266 if (skipList.containsKey(id))
5268 if (Cache.log != null && Cache.log.isDebugEnabled())
5270 Cache.log.debug("Skipping seuqence set id " + id);
5277 public void addToSkipList(AlignFrame af)
5279 if (skipList == null)
5281 skipList = new Hashtable();
5283 skipList.put(af.getViewport().getSequenceSetId(), af);
5286 public void clearSkipList()
5288 if (skipList != null)
5295 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5296 boolean ignoreUnrefed, String uniqueSeqSetId)
5298 jalview.datamodel.AlignmentI ds = getDatasetFor(
5299 vamsasSet.getDatasetId());
5300 AlignmentI xtant_ds = ds;
5301 if (xtant_ds == null)
5303 // good chance we are about to create a new dataset, but check if we've
5304 // seen some of the dataset sequence IDs before.
5305 // TODO: skip this check if we are working with project generated by
5306 // version 2.11 or later
5307 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5308 if (xtant_ds != null)
5311 addDatasetRef(vamsasSet.getDatasetId(), ds);
5314 Vector<SequenceI> dseqs = null;
5317 // recovering an alignment View
5318 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5319 if (seqSetDS != null)
5321 if (ds != null && ds != seqSetDS)
5323 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5324 + " - CDS/Protein crossreference data may be lost");
5325 if (xtant_ds != null)
5327 // This can only happen if the unique sequence set ID was bound to a
5328 // dataset that did not contain any of the sequences in the view
5329 // currently being restored.
5330 warn("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.");
5334 addDatasetRef(vamsasSet.getDatasetId(), ds);
5339 // try even harder to restore dataset
5340 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5341 // create a list of new dataset sequences
5342 dseqs = new Vector<>();
5344 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5346 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5347 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5349 // create a new dataset
5352 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5353 dseqs.copyInto(dsseqs);
5354 ds = new jalview.datamodel.Alignment(dsseqs);
5355 debug("Created new dataset " + vamsasSet.getDatasetId()
5356 + " for alignment " + System.identityHashCode(al));
5357 addDatasetRef(vamsasSet.getDatasetId(), ds);
5359 // set the dataset for the newly imported alignment.
5360 if (al.getDataset() == null && !ignoreUnrefed)
5363 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5364 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5366 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5370 * XML dataset sequence ID to materialised dataset reference
5372 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5375 * @return the first materialised dataset reference containing a dataset
5376 * sequence referenced in the given view
5378 * - sequences from the view
5380 AlignmentI checkIfHasDataset(List<Sequence> list)
5382 for (Sequence restoredSeq : list)
5384 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5385 if (datasetFor != null)
5394 * Register ds as the containing dataset for the dataset sequences referenced
5395 * by sequences in list
5398 * - sequences in a view
5401 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5403 for (Sequence restoredSeq : list)
5405 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5406 if (prevDS != null && prevDS != ds)
5408 warn("Dataset sequence appears in many datasets: "
5409 + restoredSeq.getDsseqid());
5410 // TODO: try to merge!
5417 * sequence definition to create/merge dataset sequence for
5421 * vector to add new dataset sequence to
5422 * @param ignoreUnrefed
5423 * - when true, don't create new sequences from vamsasSeq if it's id
5424 * doesn't already have an asssociated Jalview sequence.
5426 * - used to reorder the sequence in the alignment according to the
5427 * vamsasSeq array ordering, to preserve ordering of dataset
5429 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5430 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5433 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5435 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5436 boolean reorder = false;
5437 SequenceI dsq = null;
5438 if (sq != null && sq.getDatasetSequence() != null)
5440 dsq = sq.getDatasetSequence();
5446 if (sq == null && ignoreUnrefed)
5450 String sqid = vamsasSeq.getDsseqid();
5453 // need to create or add a new dataset sequence reference to this sequence
5456 dsq = seqRefIds.get(sqid);
5461 // make a new dataset sequence
5462 dsq = sq.createDatasetSequence();
5465 // make up a new dataset reference for this sequence
5466 sqid = seqHash(dsq);
5468 dsq.setVamsasId(uniqueSetSuffix + sqid);
5469 seqRefIds.put(sqid, dsq);
5474 dseqs.addElement(dsq);
5479 ds.addSequence(dsq);
5485 { // make this dataset sequence sq's dataset sequence
5486 sq.setDatasetSequence(dsq);
5487 // and update the current dataset alignment
5492 if (!dseqs.contains(dsq))
5499 if (ds.findIndex(dsq) < 0)
5501 ds.addSequence(dsq);
5508 // TODO: refactor this as a merge dataset sequence function
5509 // now check that sq (the dataset sequence) sequence really is the union of
5510 // all references to it
5511 // boolean pre = sq.getStart() < dsq.getStart();
5512 // boolean post = sq.getEnd() > dsq.getEnd();
5516 // StringBuffer sb = new StringBuffer();
5517 String newres = jalview.analysis.AlignSeq.extractGaps(
5518 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5519 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5520 && newres.length() > dsq.getLength())
5522 // Update with the longer sequence.
5526 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5527 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5528 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5529 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5531 dsq.setSequence(newres);
5533 // TODO: merges will never happen if we 'know' we have the real dataset
5534 // sequence - this should be detected when id==dssid
5536 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5537 // + (pre ? "prepended" : "") + " "
5538 // + (post ? "appended" : ""));
5543 // sequence refs are identical. We may need to update the existing dataset
5544 // alignment with this one, though.
5545 if (ds != null && dseqs == null)
5547 int opos = ds.findIndex(dsq);
5548 SequenceI tseq = null;
5549 if (opos != -1 && vseqpos != opos)
5551 // remove from old position
5552 ds.deleteSequence(dsq);
5554 if (vseqpos < ds.getHeight())
5556 if (vseqpos != opos)
5558 // save sequence at destination position
5559 tseq = ds.getSequenceAt(vseqpos);
5560 ds.replaceSequenceAt(vseqpos, dsq);
5561 ds.addSequence(tseq);
5566 ds.addSequence(dsq);
5573 * TODO use AlignmentI here and in related methods - needs
5574 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5576 Hashtable<String, AlignmentI> datasetIds = null;
5578 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5580 private AlignmentI getDatasetFor(String datasetId)
5582 if (datasetIds == null)
5584 datasetIds = new Hashtable<>();
5587 if (datasetIds.containsKey(datasetId))
5589 return datasetIds.get(datasetId);
5594 private void addDatasetRef(String datasetId, AlignmentI dataset)
5596 if (datasetIds == null)
5598 datasetIds = new Hashtable<>();
5600 datasetIds.put(datasetId, dataset);
5604 * make a new dataset ID for this jalview dataset alignment
5609 private String getDatasetIdRef(AlignmentI dataset)
5611 if (dataset.getDataset() != null)
5613 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5615 String datasetId = makeHashCode(dataset, null);
5616 if (datasetId == null)
5618 // make a new datasetId and record it
5619 if (dataset2Ids == null)
5621 dataset2Ids = new IdentityHashMap<>();
5625 datasetId = dataset2Ids.get(dataset);
5627 if (datasetId == null)
5629 datasetId = "ds" + dataset2Ids.size() + 1;
5630 dataset2Ids.put(dataset, datasetId);
5637 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5638 * constructed as a special subclass GeneLocus.
5640 * @param datasetSequence
5643 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5645 for (int d = 0; d < sequence.getDBRef().size(); d++)
5647 DBRef dr = sequence.getDBRef().get(d);
5651 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5652 dr.getAccessionId());
5656 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5657 dr.getAccessionId());
5659 if (dr.getMapping() != null)
5661 entry.setMap(addMapping(dr.getMapping()));
5663 datasetSequence.addDBRef(entry);
5667 private jalview.datamodel.Mapping addMapping(Mapping m)
5669 SequenceI dsto = null;
5670 // Mapping m = dr.getMapping();
5671 int fr[] = new int[m.getMapListFrom().size() * 2];
5672 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5673 for (int _i = 0; from.hasNext(); _i += 2)
5675 MapListFrom mf = from.next();
5676 fr[_i] = mf.getStart();
5677 fr[_i + 1] = mf.getEnd();
5679 int fto[] = new int[m.getMapListTo().size() * 2];
5680 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5681 for (int _i = 0; to.hasNext(); _i += 2)
5683 MapListTo mf = to.next();
5684 fto[_i] = mf.getStart();
5685 fto[_i + 1] = mf.getEnd();
5687 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5688 fto, m.getMapFromUnit().intValue(),
5689 m.getMapToUnit().intValue());
5692 * (optional) choice of dseqFor or Sequence
5694 if (m.getDseqFor() != null)
5696 String dsfor = m.getDseqFor();
5697 if (seqRefIds.containsKey(dsfor))
5702 jmap.setTo(seqRefIds.get(dsfor));
5706 frefedSequence.add(newMappingRef(dsfor, jmap));
5709 else if (m.getSequence() != null)
5712 * local sequence definition
5714 Sequence ms = m.getSequence();
5715 SequenceI djs = null;
5716 String sqid = ms.getDsseqid();
5717 if (sqid != null && sqid.length() > 0)
5720 * recover dataset sequence
5722 djs = seqRefIds.get(sqid);
5727 "Warning - making up dataset sequence id for DbRef sequence map reference");
5728 sqid = ((Object) ms).toString(); // make up a new hascode for
5729 // undefined dataset sequence hash
5730 // (unlikely to happen)
5736 * make a new dataset sequence and add it to refIds hash
5738 djs = new jalview.datamodel.Sequence(ms.getName(),
5740 djs.setStart(jmap.getMap().getToLowest());
5741 djs.setEnd(jmap.getMap().getToHighest());
5742 djs.setVamsasId(uniqueSetSuffix + sqid);
5744 incompleteSeqs.put(sqid, djs);
5745 seqRefIds.put(sqid, djs);
5748 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5757 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5758 * view as XML (but not to file), and then reloading it
5763 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5766 JalviewModel jm = saveState(ap, null, null, null);
5769 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5770 ap.getAlignment().getDataset());
5772 uniqueSetSuffix = "";
5773 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5774 jm.getViewport().get(0).setId(null);
5775 // we don't overwrite the view we just copied
5777 if (this.frefedSequence == null)
5779 frefedSequence = new Vector<>();
5782 viewportsAdded.clear();
5784 AlignFrame af = loadFromObject(jm, null, false, null);
5785 af.getAlignPanels().clear();
5786 af.closeMenuItem_actionPerformed(true);
5789 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5790 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5791 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5792 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5793 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5796 return af.alignPanel;
5799 private Hashtable jvids2vobj;
5801 private void warn(String msg)
5806 private void warn(String msg, Exception e)
5808 if (Cache.log != null)
5812 Cache.log.warn(msg, e);
5816 Cache.log.warn(msg);
5821 System.err.println("Warning: " + msg);
5824 e.printStackTrace();
5829 private void debug(String string)
5831 debug(string, null);
5834 private void debug(String msg, Exception e)
5836 if (Cache.log != null)
5840 Cache.log.debug(msg, e);
5844 Cache.log.debug(msg);
5849 System.err.println("Warning: " + msg);
5852 e.printStackTrace();
5858 * set the object to ID mapping tables used to write/recover objects and XML
5859 * ID strings for the jalview project. If external tables are provided then
5860 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5861 * object goes out of scope. - also populates the datasetIds hashtable with
5862 * alignment objects containing dataset sequences
5865 * Map from ID strings to jalview datamodel
5867 * Map from jalview datamodel to ID strings
5871 public void setObjectMappingTables(Hashtable vobj2jv,
5872 IdentityHashMap jv2vobj)
5874 this.jv2vobj = jv2vobj;
5875 this.vobj2jv = vobj2jv;
5876 Iterator ds = jv2vobj.keySet().iterator();
5878 while (ds.hasNext())
5880 Object jvobj = ds.next();
5881 id = jv2vobj.get(jvobj).toString();
5882 if (jvobj instanceof jalview.datamodel.Alignment)
5884 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5886 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5889 else if (jvobj instanceof jalview.datamodel.Sequence)
5891 // register sequence object so the XML parser can recover it.
5892 if (seqRefIds == null)
5894 seqRefIds = new HashMap<>();
5896 if (seqsToIds == null)
5898 seqsToIds = new IdentityHashMap<>();
5900 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5901 seqsToIds.put((SequenceI) jvobj, id);
5903 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5906 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5907 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5908 if (jvann.annotationId == null)
5910 jvann.annotationId = anid;
5912 if (!jvann.annotationId.equals(anid))
5914 // TODO verify that this is the correct behaviour
5915 this.warn("Overriding Annotation ID for " + anid
5916 + " from different id : " + jvann.annotationId);
5917 jvann.annotationId = anid;
5920 else if (jvobj instanceof String)
5922 if (jvids2vobj == null)
5924 jvids2vobj = new Hashtable();
5925 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5930 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5936 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5937 * objects created from the project archive. If string is null (default for
5938 * construction) then suffix will be set automatically.
5942 public void setUniqueSetSuffix(String string)
5944 uniqueSetSuffix = string;
5949 * uses skipList2 as the skipList for skipping views on sequence sets
5950 * associated with keys in the skipList
5954 public void setSkipList(Hashtable skipList2)
5956 skipList = skipList2;
5960 * Reads the jar entry of given name and returns its contents, or null if the
5961 * entry is not found.
5964 * @param jarEntryName
5967 protected String readJarEntry(jarInputStreamProvider jprovider,
5968 String jarEntryName)
5970 String result = null;
5971 BufferedReader in = null;
5976 * Reopen the jar input stream and traverse its entries to find a matching
5979 JarInputStream jin = jprovider.getJarInputStream();
5980 JarEntry entry = null;
5983 entry = jin.getNextJarEntry();
5984 } while (entry != null && !entry.getName().equals(jarEntryName));
5988 StringBuilder out = new StringBuilder(256);
5989 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5992 while ((data = in.readLine()) != null)
5996 result = out.toString();
6000 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6002 } catch (Exception ex)
6004 ex.printStackTrace();
6012 } catch (IOException e)
6023 * Returns an incrementing counter (0, 1, 2...)
6027 private synchronized int nextCounter()
6033 * Loads any saved PCA viewers
6038 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6042 List<PcaViewer> pcaviewers = model.getPcaViewer();
6043 for (PcaViewer viewer : pcaviewers)
6045 String modelName = viewer.getScoreModelName();
6046 SimilarityParamsI params = new SimilarityParams(
6047 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6048 viewer.isIncludeGaps(),
6049 viewer.isDenominateByShortestLength());
6052 * create the panel (without computing the PCA)
6054 PCAPanel panel = new PCAPanel(ap, modelName, params);
6056 panel.setTitle(viewer.getTitle());
6057 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6058 viewer.getWidth(), viewer.getHeight()));
6060 boolean showLabels = viewer.isShowLabels();
6061 panel.setShowLabels(showLabels);
6062 panel.getRotatableCanvas().setShowLabels(showLabels);
6063 panel.getRotatableCanvas()
6064 .setBgColour(new Color(viewer.getBgColour()));
6065 panel.getRotatableCanvas()
6066 .setApplyToAllViews(viewer.isLinkToAllViews());
6069 * load PCA output data
6071 ScoreModelI scoreModel = ScoreModels.getInstance()
6072 .getScoreModel(modelName, ap);
6073 PCA pca = new PCA(null, scoreModel, params);
6074 PcaDataType pcaData = viewer.getPcaData();
6076 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6077 pca.setPairwiseScores(pairwise);
6079 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6080 pca.setTridiagonal(triDiag);
6082 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6083 pca.setEigenmatrix(result);
6085 panel.getPcaModel().setPCA(pca);
6088 * we haven't saved the input data! (JAL-2647 to do)
6090 panel.setInputData(null);
6093 * add the sequence points for the PCA display
6095 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6096 for (SequencePoint sp : viewer.getSequencePoint())
6098 String seqId = sp.getSequenceRef();
6099 SequenceI seq = seqRefIds.get(seqId);
6102 throw new IllegalStateException(
6103 "Unmatched seqref for PCA: " + seqId);
6105 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6106 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6108 seqPoints.add(seqPoint);
6110 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6113 * set min-max ranges and scale after setPoints (which recomputes them)
6115 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6116 SeqPointMin spMin = viewer.getSeqPointMin();
6117 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6119 SeqPointMax spMax = viewer.getSeqPointMax();
6120 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6122 panel.getRotatableCanvas().setSeqMinMax(min, max);
6124 // todo: hold points list in PCAModel only
6125 panel.getPcaModel().setSequencePoints(seqPoints);
6127 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6128 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6129 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6131 // is this duplication needed?
6132 panel.setTop(seqPoints.size() - 1);
6133 panel.getPcaModel().setTop(seqPoints.size() - 1);
6136 * add the axes' end points for the display
6138 for (int i = 0; i < 3; i++)
6140 Axis axis = viewer.getAxis().get(i);
6141 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6142 axis.getXPos(), axis.getYPos(), axis.getZPos());
6145 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6146 "label.calc_title", "PCA", modelName), 475, 450);
6148 } catch (Exception ex)
6150 Cache.log.error("Error loading PCA: " + ex.toString());
6155 * Creates a new structure viewer window
6162 protected void createStructureViewer(
6163 ViewerType viewerType, final Entry<String, StructureViewerModel> viewerData,
6164 AlignFrame af, jarInputStreamProvider jprovider)
6166 final StructureViewerModel viewerModel = viewerData.getValue();
6167 String sessionFilePath = null;
6169 if (viewerType == ViewerType.JMOL)
6171 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6175 String viewerJarEntryName = getViewerJarEntryName(
6176 viewerModel.getViewId());
6177 sessionFilePath = copyJarEntry(jprovider,
6179 "viewerSession", ".tmp");
6181 final String sessionPath = sessionFilePath;
6182 final String sviewid = viewerData.getKey();
6185 SwingUtilities.invokeAndWait(new Runnable()
6190 JalviewStructureDisplayI sview = null;
6193 sview = StructureViewer.createView(viewerType, af.alignPanel,
6194 viewerModel, sessionPath, sviewid);
6195 addNewStructureViewer(sview);
6196 } catch (OutOfMemoryError ex)
6198 new OOMWarning("Restoring structure view for "
6200 (OutOfMemoryError) ex.getCause());
6201 if (sview != null && sview.isVisible())
6203 sview.closeViewer(false);
6204 sview.setVisible(false);
6210 } catch (InvocationTargetException | InterruptedException ex)
6212 warn("Unexpected error when opening " + viewerType
6213 + " structure viewer", ex);
6218 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6219 * the path of the file. "load file" commands are rewritten to change the
6220 * original PDB file names to those created as the Jalview project is loaded.
6226 private String rewriteJmolSession(StructureViewerModel svattrib,
6227 jarInputStreamProvider jprovider)
6229 String state = svattrib.getStateData(); // Jalview < 2.9
6230 if (state == null || state.isEmpty()) // Jalview >= 2.9
6232 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6233 state = readJarEntry(jprovider, jarEntryName);
6235 // TODO or simpler? for each key in oldFiles,
6236 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6237 // (allowing for different path escapings)
6238 StringBuilder rewritten = new StringBuilder(state.length());
6239 int cp = 0, ncp, ecp;
6240 Map<File, StructureData> oldFiles = svattrib.getFileData();
6241 while ((ncp = state.indexOf("load ", cp)) > -1)
6245 // look for next filename in load statement
6246 rewritten.append(state.substring(cp,
6247 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6248 String oldfilenam = state.substring(ncp,
6249 ecp = state.indexOf("\"", ncp));
6250 // recover the new mapping data for this old filename
6251 // have to normalize filename - since Jmol and jalview do
6252 // filename translation differently.
6253 StructureData filedat = oldFiles.get(new File(oldfilenam));
6254 if (filedat == null)
6256 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6257 filedat = oldFiles.get(new File(reformatedOldFilename));
6260 .append(Platform.escapeBackslashes(filedat.getFilePath()));
6261 rewritten.append("\"");
6262 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6263 // look for next file statement.
6264 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6268 // just append rest of state
6269 rewritten.append(state.substring(cp));
6273 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6274 rewritten = new StringBuilder(state);
6275 rewritten.append("; load append ");
6276 for (File id : oldFiles.keySet())
6278 // add pdb files that should be present in the viewer
6279 StructureData filedat = oldFiles.get(id);
6280 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6282 rewritten.append(";");
6285 if (rewritten.length() == 0)
6289 final String history = "history = ";
6290 int historyIndex = rewritten.indexOf(history);
6291 if (historyIndex > -1)
6294 * change "history = [true|false];" to "history = [1|0];"
6296 historyIndex += history.length();
6297 String val = rewritten.substring(historyIndex, historyIndex + 5);
6298 if (val.startsWith("true"))
6300 rewritten.replace(historyIndex, historyIndex + 4, "1");
6302 else if (val.startsWith("false"))
6304 rewritten.replace(historyIndex, historyIndex + 5, "0");
6310 File tmp = File.createTempFile("viewerSession", ".tmp");
6311 try (OutputStream os = new FileOutputStream(tmp))
6313 InputStream is = new ByteArrayInputStream(
6314 rewritten.toString().getBytes());
6316 return tmp.getAbsolutePath();
6318 } catch (IOException e)
6320 Cache.log.error("Error restoring Jmol session: " + e.toString());
6326 * Populates an XML model of the feature colour scheme for one feature type
6328 * @param featureType
6332 public static Colour marshalColour(
6333 String featureType, FeatureColourI fcol)
6335 Colour col = new Colour();
6336 if (fcol.isSimpleColour())
6338 col.setRGB(Format.getHexString(fcol.getColour()));
6342 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6343 col.setMin(fcol.getMin());
6344 col.setMax(fcol.getMax());
6345 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6346 col.setAutoScale(fcol.isAutoScaled());
6347 col.setThreshold(fcol.getThreshold());
6348 col.setColourByLabel(fcol.isColourByLabel());
6349 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6350 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6351 : ThresholdType.NONE));
6352 if (fcol.isColourByAttribute())
6354 final String[] attName = fcol.getAttributeName();
6355 col.getAttributeName().add(attName[0]);
6356 if (attName.length > 1)
6358 col.getAttributeName().add(attName[1]);
6361 Color noColour = fcol.getNoColour();
6362 if (noColour == null)
6364 col.setNoValueColour(NoValueColour.NONE);
6366 else if (noColour == fcol.getMaxColour())
6368 col.setNoValueColour(NoValueColour.MAX);
6372 col.setNoValueColour(NoValueColour.MIN);
6375 col.setName(featureType);
6380 * Populates an XML model of the feature filter(s) for one feature type
6382 * @param firstMatcher
6383 * the first (or only) match condition)
6385 * remaining match conditions (if any)
6387 * if true, conditions are and-ed, else or-ed
6389 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6390 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6393 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6395 if (filters.hasNext())
6400 CompoundMatcher compound = new CompoundMatcher();
6401 compound.setAnd(and);
6402 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6403 firstMatcher, Collections.emptyIterator(), and);
6404 // compound.addMatcherSet(matcher1);
6405 compound.getMatcherSet().add(matcher1);
6406 FeatureMatcherI nextMatcher = filters.next();
6407 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6408 nextMatcher, filters, and);
6409 // compound.addMatcherSet(matcher2);
6410 compound.getMatcherSet().add(matcher2);
6411 result.setCompoundMatcher(compound);
6416 * single condition matcher
6418 // MatchCondition matcherModel = new MatchCondition();
6419 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6420 matcherModel.setCondition(
6421 firstMatcher.getMatcher().getCondition().getStableName());
6422 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6423 if (firstMatcher.isByAttribute())
6425 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6426 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6427 String[] attName = firstMatcher.getAttribute();
6428 matcherModel.getAttributeName().add(attName[0]); // attribute
6429 if (attName.length > 1)
6431 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6434 else if (firstMatcher.isByLabel())
6436 matcherModel.setBy(FilterBy.BY_LABEL);
6438 else if (firstMatcher.isByScore())
6440 matcherModel.setBy(FilterBy.BY_SCORE);
6442 result.setMatchCondition(matcherModel);
6449 * Loads one XML model of a feature filter to a Jalview object
6451 * @param featureType
6452 * @param matcherSetModel
6455 public static FeatureMatcherSetI parseFilter(
6457 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6459 FeatureMatcherSetI result = new FeatureMatcherSet();
6462 parseFilterConditions(result, matcherSetModel, true);
6463 } catch (IllegalStateException e)
6465 // mixing AND and OR conditions perhaps
6467 String.format("Error reading filter conditions for '%s': %s",
6468 featureType, e.getMessage()));
6469 // return as much as was parsed up to the error
6476 * Adds feature match conditions to matcherSet as unmarshalled from XML
6477 * (possibly recursively for compound conditions)
6480 * @param matcherSetModel
6482 * if true, multiple conditions are AND-ed, else they are OR-ed
6483 * @throws IllegalStateException
6484 * if AND and OR conditions are mixed
6486 protected static void parseFilterConditions(
6487 FeatureMatcherSetI matcherSet,
6488 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6491 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6492 .getMatchCondition();
6498 FilterBy filterBy = mc.getBy();
6499 Condition cond = Condition.fromString(mc.getCondition());
6500 String pattern = mc.getValue();
6501 FeatureMatcherI matchCondition = null;
6502 if (filterBy == FilterBy.BY_LABEL)
6504 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6506 else if (filterBy == FilterBy.BY_SCORE)
6508 matchCondition = FeatureMatcher.byScore(cond, pattern);
6511 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6513 final List<String> attributeName = mc.getAttributeName();
6514 String[] attNames = attributeName
6515 .toArray(new String[attributeName.size()]);
6516 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6521 * note this throws IllegalStateException if AND-ing to a
6522 * previously OR-ed compound condition, or vice versa
6526 matcherSet.and(matchCondition);
6530 matcherSet.or(matchCondition);
6536 * compound condition
6538 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6539 .getCompoundMatcher().getMatcherSet();
6540 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6541 if (matchers.size() == 2)
6543 parseFilterConditions(matcherSet, matchers.get(0), anded);
6544 parseFilterConditions(matcherSet, matchers.get(1), anded);
6548 System.err.println("Malformed compound filter condition");
6554 * Loads one XML model of a feature colour to a Jalview object
6556 * @param colourModel
6559 public static FeatureColourI parseColour(Colour colourModel)
6561 FeatureColourI colour = null;
6563 if (colourModel.getMax() != null)
6565 Color mincol = null;
6566 Color maxcol = null;
6567 Color noValueColour = null;
6571 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6572 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6573 } catch (Exception e)
6575 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6578 NoValueColour noCol = colourModel.getNoValueColour();
6579 if (noCol == NoValueColour.MIN)
6581 noValueColour = mincol;
6583 else if (noCol == NoValueColour.MAX)
6585 noValueColour = maxcol;
6588 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6589 safeFloat(colourModel.getMin()),
6590 safeFloat(colourModel.getMax()));
6591 final List<String> attributeName = colourModel.getAttributeName();
6592 String[] attributes = attributeName
6593 .toArray(new String[attributeName.size()]);
6594 if (attributes != null && attributes.length > 0)
6596 colour.setAttributeName(attributes);
6598 if (colourModel.isAutoScale() != null)
6600 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6602 if (colourModel.isColourByLabel() != null)
6604 colour.setColourByLabel(
6605 colourModel.isColourByLabel().booleanValue());
6607 if (colourModel.getThreshold() != null)
6609 colour.setThreshold(colourModel.getThreshold().floatValue());
6611 ThresholdType ttyp = colourModel.getThreshType();
6612 if (ttyp == ThresholdType.ABOVE)
6614 colour.setAboveThreshold(true);
6616 else if (ttyp == ThresholdType.BELOW)
6618 colour.setBelowThreshold(true);
6623 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6624 colour = new FeatureColour(color);