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 view.setOverview(overview);
1468 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1470 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1471 userColours, object));
1474 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1476 AnnotationColourScheme ac = constructAnnotationColours(
1477 (jalview.schemes.AnnotationColourGradient) av
1478 .getGlobalColourScheme(),
1479 userColours, object);
1481 view.setAnnotationColours(ac);
1482 view.setBgColour("AnnotationColourGradient");
1486 view.setBgColour(ColourSchemeProperty
1487 .getColourName(av.getGlobalColourScheme()));
1490 ResidueShaderI vcs = av.getResidueShading();
1491 ColourSchemeI cs = av.getGlobalColourScheme();
1495 if (vcs.conservationApplied())
1497 view.setConsThreshold(vcs.getConservationInc());
1498 if (cs instanceof jalview.schemes.UserColourScheme)
1500 view.setBgColour(setUserColourScheme(cs, userColours, object));
1503 view.setPidThreshold(vcs.getThreshold());
1506 view.setConservationSelected(av.getConservationSelected());
1507 view.setPidSelected(av.getAbovePIDThreshold());
1508 final Font font = av.getFont();
1509 view.setFontName(font.getName());
1510 view.setFontSize(font.getSize());
1511 view.setFontStyle(font.getStyle());
1512 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1513 view.setRenderGaps(av.isRenderGaps());
1514 view.setShowAnnotation(av.isShowAnnotation());
1515 view.setShowBoxes(av.getShowBoxes());
1516 view.setShowColourText(av.getColourText());
1517 view.setShowFullId(av.getShowJVSuffix());
1518 view.setRightAlignIds(av.isRightAlignIds());
1519 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1520 view.setShowText(av.getShowText());
1521 view.setShowUnconserved(av.getShowUnconserved());
1522 view.setWrapAlignment(av.getWrapAlignment());
1523 view.setTextCol1(av.getTextColour().getRGB());
1524 view.setTextCol2(av.getTextColour2().getRGB());
1525 view.setTextColThreshold(av.getThresholdTextColour());
1526 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1527 view.setShowSequenceLogo(av.isShowSequenceLogo());
1528 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1529 view.setShowGroupConsensus(av.isShowGroupConsensus());
1530 view.setShowGroupConservation(av.isShowGroupConservation());
1531 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1532 view.setShowDbRefTooltip(av.isShowDBRefs());
1533 view.setFollowHighlight(av.isFollowHighlight());
1534 view.setFollowSelection(av.followSelection);
1535 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1536 view.setShowComplementFeatures(av.isShowComplementFeatures());
1537 view.setShowComplementFeaturesOnTop(
1538 av.isShowComplementFeaturesOnTop());
1539 if (av.getFeaturesDisplayed() != null)
1541 FeatureSettings fs = new FeatureSettings();
1543 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1544 .getFeatureRenderer();
1545 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1547 Vector<String> settingsAdded = new Vector<>();
1548 if (renderOrder != null)
1550 for (String featureType : renderOrder)
1552 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1553 setting.setType(featureType);
1556 * save any filter for the feature type
1558 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1559 if (filter != null) {
1560 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1561 FeatureMatcherI firstFilter = filters.next();
1562 setting.setMatcherSet(Jalview2XML.marshalFilter(
1563 firstFilter, filters, filter.isAnded()));
1567 * save colour scheme for the feature type
1569 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1570 if (!fcol.isSimpleColour())
1572 setting.setColour(fcol.getMaxColour().getRGB());
1573 setting.setMincolour(fcol.getMinColour().getRGB());
1574 setting.setMin(fcol.getMin());
1575 setting.setMax(fcol.getMax());
1576 setting.setColourByLabel(fcol.isColourByLabel());
1577 if (fcol.isColourByAttribute())
1579 String[] attName = fcol.getAttributeName();
1580 setting.getAttributeName().add(attName[0]);
1581 if (attName.length > 1)
1583 setting.getAttributeName().add(attName[1]);
1586 setting.setAutoScale(fcol.isAutoScaled());
1587 setting.setThreshold(fcol.getThreshold());
1588 Color noColour = fcol.getNoColour();
1589 if (noColour == null)
1591 setting.setNoValueColour(NoValueColour.NONE);
1593 else if (noColour.equals(fcol.getMaxColour()))
1595 setting.setNoValueColour(NoValueColour.MAX);
1599 setting.setNoValueColour(NoValueColour.MIN);
1601 // -1 = No threshold, 0 = Below, 1 = Above
1602 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1603 : (fcol.isBelowThreshold() ? 0 : -1));
1607 setting.setColour(fcol.getColour().getRGB());
1611 av.getFeaturesDisplayed().isVisible(featureType));
1613 .getOrder(featureType);
1616 setting.setOrder(rorder);
1618 /// fs.addSetting(setting);
1619 fs.getSetting().add(setting);
1620 settingsAdded.addElement(featureType);
1624 // is groups actually supposed to be a map here ?
1625 Iterator<String> en = fr.getFeatureGroups().iterator();
1626 Vector<String> groupsAdded = new Vector<>();
1627 while (en.hasNext())
1629 String grp = en.next();
1630 if (groupsAdded.contains(grp))
1634 Group g = new Group();
1636 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1639 fs.getGroup().add(g);
1640 groupsAdded.addElement(grp);
1642 // jms.setFeatureSettings(fs);
1643 object.setFeatureSettings(fs);
1646 if (av.hasHiddenColumns())
1648 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1649 .getHiddenColumns();
1652 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1656 Iterator<int[]> hiddenRegions = hidden.iterator();
1657 while (hiddenRegions.hasNext())
1659 int[] region = hiddenRegions.next();
1660 HiddenColumns hc = new HiddenColumns();
1661 hc.setStart(region[0]);
1662 hc.setEnd(region[1]);
1663 // view.addHiddenColumns(hc);
1664 view.getHiddenColumns().add(hc);
1668 if (calcIdSet.size() > 0)
1670 for (String calcId : calcIdSet)
1672 if (calcId.trim().length() > 0)
1674 CalcIdParam cidp = createCalcIdParam(calcId, av);
1675 // Some calcIds have no parameters.
1678 // view.addCalcIdParam(cidp);
1679 view.getCalcIdParam().add(cidp);
1685 // jms.addViewport(view);
1686 object.getViewport().add(view);
1688 // object.setJalviewModelSequence(jms);
1689 // object.getVamsasModel().addSequenceSet(vamsasSet);
1690 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1692 if (jout != null && fileName != null)
1694 // We may not want to write the object to disk,
1695 // eg we can copy the alignViewport to a new view object
1696 // using save and then load
1699 fileName = fileName.replace('\\', '/');
1700 System.out.println("Writing jar entry " + fileName);
1701 JarEntry entry = new JarEntry(fileName);
1702 jout.putNextEntry(entry);
1703 PrintWriter pout = new PrintWriter(
1704 new OutputStreamWriter(jout, UTF_8));
1705 JAXBContext jaxbContext = JAXBContext
1706 .newInstance(JalviewModel.class);
1707 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1709 // output pretty printed
1710 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1711 jaxbMarshaller.marshal(
1712 new ObjectFactory().createJalviewModel(object), pout);
1714 // jaxbMarshaller.marshal(object, pout);
1715 // marshaller.marshal(object);
1718 } catch (Exception ex)
1720 // TODO: raise error in GUI if marshalling failed.
1721 System.err.println("Error writing Jalview project");
1722 ex.printStackTrace();
1729 * Writes PCA viewer attributes and computed values to an XML model object and
1730 * adds it to the JalviewModel. Any exceptions are reported by logging.
1732 protected void savePCA(PCAPanel panel, JalviewModel object)
1736 PcaViewer viewer = new PcaViewer();
1737 viewer.setHeight(panel.getHeight());
1738 viewer.setWidth(panel.getWidth());
1739 viewer.setXpos(panel.getX());
1740 viewer.setYpos(panel.getY());
1741 viewer.setTitle(panel.getTitle());
1742 PCAModel pcaModel = panel.getPcaModel();
1743 viewer.setScoreModelName(pcaModel.getScoreModelName());
1744 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1745 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1746 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1748 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1749 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1750 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1751 SeqPointMin spmin = new SeqPointMin();
1752 spmin.setXPos(spMin[0]);
1753 spmin.setYPos(spMin[1]);
1754 spmin.setZPos(spMin[2]);
1755 viewer.setSeqPointMin(spmin);
1756 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1757 SeqPointMax spmax = new SeqPointMax();
1758 spmax.setXPos(spMax[0]);
1759 spmax.setYPos(spMax[1]);
1760 spmax.setZPos(spMax[2]);
1761 viewer.setSeqPointMax(spmax);
1762 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1763 viewer.setLinkToAllViews(
1764 panel.getRotatableCanvas().isApplyToAllViews());
1765 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1766 viewer.setIncludeGaps(sp.includeGaps());
1767 viewer.setMatchGaps(sp.matchGaps());
1768 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1769 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1772 * sequence points on display
1774 for (jalview.datamodel.SequencePoint spt : pcaModel
1775 .getSequencePoints())
1777 SequencePoint point = new SequencePoint();
1778 point.setSequenceRef(seqHash(spt.getSequence()));
1779 point.setXPos(spt.coord.x);
1780 point.setYPos(spt.coord.y);
1781 point.setZPos(spt.coord.z);
1782 viewer.getSequencePoint().add(point);
1786 * (end points of) axes on display
1788 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1791 Axis axis = new Axis();
1795 viewer.getAxis().add(axis);
1799 * raw PCA data (note we are not restoring PCA inputs here -
1800 * alignment view, score model, similarity parameters)
1802 PcaDataType data = new PcaDataType();
1803 viewer.setPcaData(data);
1804 PCA pca = pcaModel.getPcaData();
1806 DoubleMatrix pm = new DoubleMatrix();
1807 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1808 data.setPairwiseMatrix(pm);
1810 DoubleMatrix tm = new DoubleMatrix();
1811 saveDoubleMatrix(pca.getTridiagonal(), tm);
1812 data.setTridiagonalMatrix(tm);
1814 DoubleMatrix eigenMatrix = new DoubleMatrix();
1815 data.setEigenMatrix(eigenMatrix);
1816 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1818 object.getPcaViewer().add(viewer);
1819 } catch (Throwable t)
1821 Cache.log.error("Error saving PCA: " + t.getMessage());
1826 * Stores values from a matrix into an XML element, including (if present) the
1831 * @see #loadDoubleMatrix(DoubleMatrix)
1833 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1835 xmlMatrix.setRows(m.height());
1836 xmlMatrix.setColumns(m.width());
1837 for (int i = 0; i < m.height(); i++)
1839 DoubleVector row = new DoubleVector();
1840 for (int j = 0; j < m.width(); j++)
1842 row.getV().add(m.getValue(i, j));
1844 xmlMatrix.getRow().add(row);
1846 if (m.getD() != null)
1848 DoubleVector dVector = new DoubleVector();
1849 for (double d : m.getD())
1851 dVector.getV().add(d);
1853 xmlMatrix.setD(dVector);
1855 if (m.getE() != null)
1857 DoubleVector eVector = new DoubleVector();
1858 for (double e : m.getE())
1860 eVector.getV().add(e);
1862 xmlMatrix.setE(eVector);
1867 * Loads XML matrix data into a new Matrix object, including the D and/or E
1868 * vectors (if present)
1872 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1874 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1876 int rows = mData.getRows();
1877 double[][] vals = new double[rows][];
1879 for (int i = 0; i < rows; i++)
1881 List<Double> dVector = mData.getRow().get(i).getV();
1882 vals[i] = new double[dVector.size()];
1884 for (Double d : dVector)
1890 MatrixI m = new Matrix(vals);
1892 if (mData.getD() != null)
1894 List<Double> dVector = mData.getD().getV();
1895 double[] vec = new double[dVector.size()];
1897 for (Double d : dVector)
1903 if (mData.getE() != null)
1905 List<Double> dVector = mData.getE().getV();
1906 double[] vec = new double[dVector.size()];
1908 for (Double d : dVector)
1919 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1920 * for each viewer, with
1922 * <li>viewer geometry (position, size, split pane divider location)</li>
1923 * <li>index of the selected structure in the viewer (currently shows gapped
1925 * <li>the id of the annotation holding RNA secondary structure</li>
1926 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1928 * Varna viewer state is also written out (in native Varna XML) to separate
1929 * project jar entries. A separate entry is written for each RNA structure
1930 * displayed, with the naming convention
1932 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1940 * @param storeDataset
1942 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1943 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1944 boolean storeDataset)
1946 if (Desktop.desktop == null)
1950 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1951 for (int f = frames.length - 1; f > -1; f--)
1953 if (frames[f] instanceof AppVarna)
1955 AppVarna varna = (AppVarna) frames[f];
1957 * link the sequence to every viewer that is showing it and is linked to
1958 * its alignment panel
1960 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1962 String viewId = varna.getViewId();
1963 RnaViewer rna = new RnaViewer();
1964 rna.setViewId(viewId);
1965 rna.setTitle(varna.getTitle());
1966 rna.setXpos(varna.getX());
1967 rna.setYpos(varna.getY());
1968 rna.setWidth(varna.getWidth());
1969 rna.setHeight(varna.getHeight());
1970 rna.setDividerLocation(varna.getDividerLocation());
1971 rna.setSelectedRna(varna.getSelectedIndex());
1972 // jseq.addRnaViewer(rna);
1973 jseq.getRnaViewer().add(rna);
1976 * Store each Varna panel's state once in the project per sequence.
1977 * First time through only (storeDataset==false)
1979 // boolean storeSessions = false;
1980 // String sequenceViewId = viewId + seqsToIds.get(jds);
1981 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1983 // viewIds.add(sequenceViewId);
1984 // storeSessions = true;
1986 for (RnaModel model : varna.getModels())
1988 if (model.seq == jds)
1991 * VARNA saves each view (sequence or alignment secondary
1992 * structure, gapped or trimmed) as a separate XML file
1994 String jarEntryName = rnaSessions.get(model);
1995 if (jarEntryName == null)
1998 String varnaStateFile = varna.getStateInfo(model.rna);
1999 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2000 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2001 rnaSessions.put(model, jarEntryName);
2003 SecondaryStructure ss = new SecondaryStructure();
2004 String annotationId = varna.getAnnotation(jds).annotationId;
2005 ss.setAnnotationId(annotationId);
2006 ss.setViewerState(jarEntryName);
2007 ss.setGapped(model.gapped);
2008 ss.setTitle(model.title);
2009 // rna.addSecondaryStructure(ss);
2010 rna.getSecondaryStructure().add(ss);
2019 * Copy the contents of a file to a new entry added to the output jar
2023 * @param jarEntryName
2025 * additional identifying info to log to the console
2027 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2028 String jarEntryName, String msg)
2030 try (InputStream is = new FileInputStream(infilePath))
2032 File file = new File(infilePath);
2033 if (file.exists() && jout != null)
2036 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2037 jout.putNextEntry(new JarEntry(jarEntryName));
2040 // dis = new DataInputStream(new FileInputStream(file));
2041 // byte[] data = new byte[(int) file.length()];
2042 // dis.readFully(data);
2043 // writeJarEntry(jout, jarEntryName, data);
2045 } catch (Exception ex)
2047 ex.printStackTrace();
2052 * Copies input to output, in 4K buffers; handles any data (text or binary)
2056 * @throws IOException
2058 protected void copyAll(InputStream in, OutputStream out)
2061 byte[] buffer = new byte[4096];
2063 while ((bytesRead = in.read(buffer)) != -1)
2065 out.write(buffer, 0, bytesRead);
2070 * Save the state of a structure viewer
2075 * the archive XML element under which to save the state
2078 * @param matchedFile
2082 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2083 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2084 String matchedFile, StructureViewerBase viewFrame)
2086 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2089 * Look for any bindings for this viewer to the PDB file of interest
2090 * (including part matches excluding chain id)
2092 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2094 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2095 final String pdbId = pdbentry.getId();
2096 if (!pdbId.equals(entry.getId())
2097 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2098 .startsWith(pdbId.toLowerCase())))
2101 * not interested in a binding to a different PDB entry here
2105 if (matchedFile == null)
2107 matchedFile = pdbentry.getFile();
2109 else if (!matchedFile.equals(pdbentry.getFile()))
2112 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2113 + pdbentry.getFile());
2117 // can get at it if the ID
2118 // match is ambiguous (e.g.
2121 for (int smap = 0; smap < viewFrame.getBinding()
2122 .getSequence()[peid].length; smap++)
2124 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2125 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2127 StructureState state = new StructureState();
2128 state.setVisible(true);
2129 state.setXpos(viewFrame.getX());
2130 state.setYpos(viewFrame.getY());
2131 state.setWidth(viewFrame.getWidth());
2132 state.setHeight(viewFrame.getHeight());
2133 final String viewId = viewFrame.getViewId();
2134 state.setViewId(viewId);
2135 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2136 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2137 state.setColourByJmol(viewFrame.isColouredByViewer());
2138 state.setType(viewFrame.getViewerType().toString());
2139 // pdb.addStructureState(state);
2140 pdb.getStructureState().add(state);
2148 * Populates the AnnotationColourScheme xml for save. This captures the
2149 * settings of the options in the 'Colour by Annotation' dialog.
2152 * @param userColours
2156 private AnnotationColourScheme constructAnnotationColours(
2157 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2160 AnnotationColourScheme ac = new AnnotationColourScheme();
2161 ac.setAboveThreshold(acg.getAboveThreshold());
2162 ac.setThreshold(acg.getAnnotationThreshold());
2163 // 2.10.2 save annotationId (unique) not annotation label
2164 ac.setAnnotation(acg.getAnnotation().annotationId);
2165 if (acg.getBaseColour() instanceof UserColourScheme)
2168 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2173 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2176 ac.setMaxColour(acg.getMaxColour().getRGB());
2177 ac.setMinColour(acg.getMinColour().getRGB());
2178 ac.setPerSequence(acg.isSeqAssociated());
2179 ac.setPredefinedColours(acg.isPredefinedColours());
2183 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2184 IdentityHashMap<SequenceGroup, String> groupRefs,
2185 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2186 SequenceSet vamsasSet)
2189 for (int i = 0; i < aa.length; i++)
2191 Annotation an = new Annotation();
2193 AlignmentAnnotation annotation = aa[i];
2194 if (annotation.annotationId != null)
2196 annotationIds.put(annotation.annotationId, annotation);
2199 an.setId(annotation.annotationId);
2201 an.setVisible(annotation.visible);
2203 an.setDescription(annotation.description);
2205 if (annotation.sequenceRef != null)
2207 // 2.9 JAL-1781 xref on sequence id rather than name
2208 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2210 if (annotation.groupRef != null)
2212 String groupIdr = groupRefs.get(annotation.groupRef);
2213 if (groupIdr == null)
2215 // make a locally unique String
2216 groupRefs.put(annotation.groupRef,
2217 groupIdr = ("" + System.currentTimeMillis()
2218 + annotation.groupRef.getName()
2219 + groupRefs.size()));
2221 an.setGroupRef(groupIdr.toString());
2224 // store all visualization attributes for annotation
2225 an.setGraphHeight(annotation.graphHeight);
2226 an.setCentreColLabels(annotation.centreColLabels);
2227 an.setScaleColLabels(annotation.scaleColLabel);
2228 an.setShowAllColLabels(annotation.showAllColLabels);
2229 an.setBelowAlignment(annotation.belowAlignment);
2231 if (annotation.graph > 0)
2234 an.setGraphType(annotation.graph);
2235 an.setGraphGroup(annotation.graphGroup);
2236 if (annotation.getThreshold() != null)
2238 ThresholdLine line = new ThresholdLine();
2239 line.setLabel(annotation.getThreshold().label);
2240 line.setValue(annotation.getThreshold().value);
2241 line.setColour(annotation.getThreshold().colour.getRGB());
2242 an.setThresholdLine(line);
2250 an.setLabel(annotation.label);
2252 if (annotation == av.getAlignmentQualityAnnot()
2253 || annotation == av.getAlignmentConservationAnnotation()
2254 || annotation == av.getAlignmentConsensusAnnotation()
2255 || annotation.autoCalculated)
2257 // new way of indicating autocalculated annotation -
2258 an.setAutoCalculated(annotation.autoCalculated);
2260 if (annotation.hasScore())
2262 an.setScore(annotation.getScore());
2265 if (annotation.getCalcId() != null)
2267 calcIdSet.add(annotation.getCalcId());
2268 an.setCalcId(annotation.getCalcId());
2270 if (annotation.hasProperties())
2272 for (String pr : annotation.getProperties())
2274 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2276 prop.setValue(annotation.getProperty(pr));
2277 // an.addProperty(prop);
2278 an.getProperty().add(prop);
2282 AnnotationElement ae;
2283 if (annotation.annotations != null)
2285 an.setScoreOnly(false);
2286 for (int a = 0; a < annotation.annotations.length; a++)
2288 if ((annotation == null) || (annotation.annotations[a] == null))
2293 ae = new AnnotationElement();
2294 if (annotation.annotations[a].description != null)
2296 ae.setDescription(annotation.annotations[a].description);
2298 if (annotation.annotations[a].displayCharacter != null)
2300 ae.setDisplayCharacter(
2301 annotation.annotations[a].displayCharacter);
2304 if (!Float.isNaN(annotation.annotations[a].value))
2306 ae.setValue(annotation.annotations[a].value);
2310 if (annotation.annotations[a].secondaryStructure > ' ')
2312 ae.setSecondaryStructure(
2313 annotation.annotations[a].secondaryStructure + "");
2316 if (annotation.annotations[a].colour != null
2317 && annotation.annotations[a].colour != java.awt.Color.black)
2319 ae.setColour(annotation.annotations[a].colour.getRGB());
2322 // an.addAnnotationElement(ae);
2323 an.getAnnotationElement().add(ae);
2324 if (annotation.autoCalculated)
2326 // only write one non-null entry into the annotation row -
2327 // sufficient to get the visualization attributes necessary to
2335 an.setScoreOnly(true);
2337 if (!storeDS || (storeDS && !annotation.autoCalculated))
2339 // skip autocalculated annotation - these are only provided for
2341 // vamsasSet.addAnnotation(an);
2342 vamsasSet.getAnnotation().add(an);
2348 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2350 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2351 if (settings != null)
2353 CalcIdParam vCalcIdParam = new CalcIdParam();
2354 vCalcIdParam.setCalcId(calcId);
2355 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2356 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2357 // generic URI allowing a third party to resolve another instance of the
2358 // service used for this calculation
2359 for (String url : settings.getServiceURLs())
2361 // vCalcIdParam.addServiceURL(urls);
2362 vCalcIdParam.getServiceURL().add(url);
2364 vCalcIdParam.setVersion("1.0");
2365 if (settings.getPreset() != null)
2367 WsParamSetI setting = settings.getPreset();
2368 vCalcIdParam.setName(setting.getName());
2369 vCalcIdParam.setDescription(setting.getDescription());
2373 vCalcIdParam.setName("");
2374 vCalcIdParam.setDescription("Last used parameters");
2376 // need to be able to recover 1) settings 2) user-defined presets or
2377 // recreate settings from preset 3) predefined settings provided by
2378 // service - or settings that can be transferred (or discarded)
2379 vCalcIdParam.setParameters(
2380 settings.getWsParamFile().replace("\n", "|\\n|"));
2381 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2382 // todo - decide if updateImmediately is needed for any projects.
2384 return vCalcIdParam;
2389 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2392 if (calcIdParam.getVersion().equals("1.0"))
2394 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2395 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2396 .getPreferredServiceFor(calcIds);
2397 if (service != null)
2399 WsParamSetI parmSet = null;
2402 parmSet = service.getParamStore().parseServiceParameterFile(
2403 calcIdParam.getName(), calcIdParam.getDescription(),
2405 calcIdParam.getParameters().replace("|\\n|", "\n"));
2406 } catch (IOException x)
2408 warn("Couldn't parse parameter data for "
2409 + calcIdParam.getCalcId(), x);
2412 List<ArgumentI> argList = null;
2413 if (calcIdParam.getName().length() > 0)
2415 parmSet = service.getParamStore()
2416 .getPreset(calcIdParam.getName());
2417 if (parmSet != null)
2419 // TODO : check we have a good match with settings in AACon -
2420 // otherwise we'll need to create a new preset
2425 argList = parmSet.getArguments();
2428 AAConSettings settings = new AAConSettings(
2429 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2430 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2431 calcIdParam.isNeedsUpdate());
2436 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2440 throw new Error(MessageManager.formatMessage(
2441 "error.unsupported_version_calcIdparam", new Object[]
2442 { calcIdParam.toString() }));
2446 * External mapping between jalview objects and objects yielding a valid and
2447 * unique object ID string. This is null for normal Jalview project IO, but
2448 * non-null when a jalview project is being read or written as part of a
2451 IdentityHashMap jv2vobj = null;
2454 * Construct a unique ID for jvobj using either existing bindings or if none
2455 * exist, the result of the hashcode call for the object.
2458 * jalview data object
2459 * @return unique ID for referring to jvobj
2461 private String makeHashCode(Object jvobj, String altCode)
2463 if (jv2vobj != null)
2465 Object id = jv2vobj.get(jvobj);
2468 return id.toString();
2470 // check string ID mappings
2471 if (jvids2vobj != null && jvobj instanceof String)
2473 id = jvids2vobj.get(jvobj);
2477 return id.toString();
2479 // give up and warn that something has gone wrong
2480 warn("Cannot find ID for object in external mapping : " + jvobj);
2486 * return local jalview object mapped to ID, if it exists
2490 * @return null or object bound to idcode
2492 private Object retrieveExistingObj(String idcode)
2494 if (idcode != null && vobj2jv != null)
2496 return vobj2jv.get(idcode);
2502 * binding from ID strings from external mapping table to jalview data model
2505 private Hashtable vobj2jv;
2507 private Sequence createVamsasSequence(String id, SequenceI jds)
2509 return createVamsasSequence(true, id, jds, null);
2512 private Sequence createVamsasSequence(boolean recurse, String id,
2513 SequenceI jds, SequenceI parentseq)
2515 Sequence vamsasSeq = new Sequence();
2516 vamsasSeq.setId(id);
2517 vamsasSeq.setName(jds.getName());
2518 vamsasSeq.setSequence(jds.getSequenceAsString());
2519 vamsasSeq.setDescription(jds.getDescription());
2520 List<DBRefEntry> dbrefs = null;
2521 if (jds.getDatasetSequence() != null)
2523 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2527 // seqId==dsseqid so we can tell which sequences really are
2528 // dataset sequences only
2529 vamsasSeq.setDsseqid(id);
2530 dbrefs = jds.getDBRefs();
2531 if (parentseq == null)
2538 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2542 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2544 DBRef dbref = new DBRef();
2545 DBRefEntry ref = dbrefs.get(d);
2546 dbref.setSource(ref.getSource());
2547 dbref.setVersion(ref.getVersion());
2548 dbref.setAccessionId(ref.getAccessionId());
2549 if (ref instanceof GeneLocus)
2551 dbref.setLocus(true);
2555 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2557 dbref.setMapping(mp);
2559 vamsasSeq.getDBRef().add(dbref);
2565 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2566 SequenceI parentseq, SequenceI jds, boolean recurse)
2569 if (jmp.getMap() != null)
2573 jalview.util.MapList mlst = jmp.getMap();
2574 List<int[]> r = mlst.getFromRanges();
2575 for (int[] range : r)
2577 MapListFrom mfrom = new MapListFrom();
2578 mfrom.setStart(range[0]);
2579 mfrom.setEnd(range[1]);
2580 // mp.addMapListFrom(mfrom);
2581 mp.getMapListFrom().add(mfrom);
2583 r = mlst.getToRanges();
2584 for (int[] range : r)
2586 MapListTo mto = new MapListTo();
2587 mto.setStart(range[0]);
2588 mto.setEnd(range[1]);
2589 // mp.addMapListTo(mto);
2590 mp.getMapListTo().add(mto);
2592 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2593 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2594 if (jmp.getTo() != null)
2596 // MappingChoice mpc = new MappingChoice();
2598 // check/create ID for the sequence referenced by getTo()
2601 SequenceI ps = null;
2602 if (parentseq != jmp.getTo()
2603 && parentseq.getDatasetSequence() != jmp.getTo())
2605 // chaining dbref rather than a handshaking one
2606 jmpid = seqHash(ps = jmp.getTo());
2610 jmpid = seqHash(ps = parentseq);
2612 // mpc.setDseqFor(jmpid);
2613 mp.setDseqFor(jmpid);
2614 if (!seqRefIds.containsKey(jmpid))
2616 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2617 seqRefIds.put(jmpid, ps);
2621 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2624 // mp.setMappingChoice(mpc);
2630 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2631 List<UserColourScheme> userColours, JalviewModel jm)
2634 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2635 boolean newucs = false;
2636 if (!userColours.contains(ucs))
2638 userColours.add(ucs);
2641 id = "ucs" + userColours.indexOf(ucs);
2644 // actually create the scheme's entry in the XML model
2645 java.awt.Color[] colours = ucs.getColours();
2646 UserColours uc = new UserColours();
2647 // UserColourScheme jbucs = new UserColourScheme();
2648 JalviewUserColours jbucs = new JalviewUserColours();
2650 for (int i = 0; i < colours.length; i++)
2652 Colour col = new Colour();
2653 col.setName(ResidueProperties.aa[i]);
2654 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2655 // jbucs.addColour(col);
2656 jbucs.getColour().add(col);
2658 if (ucs.getLowerCaseColours() != null)
2660 colours = ucs.getLowerCaseColours();
2661 for (int i = 0; i < colours.length; i++)
2663 Colour col = new Colour();
2664 col.setName(ResidueProperties.aa[i].toLowerCase());
2665 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2666 // jbucs.addColour(col);
2667 jbucs.getColour().add(col);
2672 uc.setUserColourScheme(jbucs);
2673 // jm.addUserColours(uc);
2674 jm.getUserColours().add(uc);
2680 jalview.schemes.UserColourScheme getUserColourScheme(
2681 JalviewModel jm, String id)
2683 List<UserColours> uc = jm.getUserColours();
2684 UserColours colours = null;
2686 for (int i = 0; i < uc.length; i++)
2688 if (uc[i].getId().equals(id))
2695 for (UserColours c : uc)
2697 if (c.getId().equals(id))
2704 java.awt.Color[] newColours = new java.awt.Color[24];
2706 for (int i = 0; i < 24; i++)
2708 newColours[i] = new java.awt.Color(Integer.parseInt(
2709 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2710 colours.getUserColourScheme().getColour().get(i).getRGB(),
2714 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2717 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2719 newColours = new java.awt.Color[23];
2720 for (int i = 0; i < 23; i++)
2722 newColours[i] = new java.awt.Color(Integer.parseInt(
2723 colours.getUserColourScheme().getColour().get(i + 24)
2727 ucs.setLowerCaseColours(newColours);
2734 * contains last error message (if any) encountered by XML loader.
2736 String errorMessage = null;
2739 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2740 * exceptions are raised during project XML parsing
2742 public boolean attemptversion1parse = false;
2745 * Load a jalview project archive from a jar file
2748 * - HTTP URL or filename
2750 public AlignFrame loadJalviewAlign(final Object file)
2753 jalview.gui.AlignFrame af = null;
2757 // create list to store references for any new Jmol viewers created
2758 newStructureViewers = new Vector<>();
2759 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2760 // Workaround is to make sure caller implements the JarInputStreamProvider
2762 // so we can re-open the jar input stream for each entry.
2764 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2765 af = loadJalviewAlign(jprovider);
2768 af.setMenusForViewport();
2770 } catch (MalformedURLException e)
2772 errorMessage = "Invalid URL format for '" + file + "'";
2778 SwingUtilities.invokeAndWait(new Runnable()
2783 setLoadingFinishedForNewStructureViewers();
2786 } catch (Exception x)
2788 System.err.println("Error loading alignment: " + x.getMessage());
2794 @SuppressWarnings("unused")
2795 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2797 // BH 2018 allow for bytes already attached to File object
2799 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2800 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2803 errorMessage = null;
2804 uniqueSetSuffix = null;
2806 viewportsAdded.clear();
2807 frefedSequence = null;
2809 if (file.startsWith("http://")) {
2810 url = new URL(file);
2812 final URL _url = url;
2813 return new jarInputStreamProvider() {
2816 public JarInputStream getJarInputStream() throws IOException {
2817 if (bytes != null) {
2818 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2819 return new JarInputStream(new ByteArrayInputStream(bytes));
2822 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2823 return new JarInputStream(_url.openStream());
2825 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2826 return new JarInputStream(new FileInputStream(file));
2831 public String getFilename() {
2835 } catch (IOException e) {
2836 e.printStackTrace();
2842 * Recover jalview session from a jalview project archive. Caller may
2843 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2844 * themselves. Any null fields will be initialised with default values,
2845 * non-null fields are left alone.
2850 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2852 errorMessage = null;
2853 if (uniqueSetSuffix == null)
2855 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2857 if (seqRefIds == null)
2861 AlignFrame af = null, _af = null;
2862 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2863 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2864 final String file = jprovider.getFilename();
2867 JarInputStream jin = null;
2868 JarEntry jarentry = null;
2873 jin = jprovider.getJarInputStream();
2874 for (int i = 0; i < entryCount; i++)
2876 jarentry = jin.getNextJarEntry();
2879 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2881 JAXBContext jc = JAXBContext
2882 .newInstance("jalview.xml.binding.jalview");
2883 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2884 .createXMLStreamReader(jin);
2885 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2886 JAXBElement<JalviewModel> jbe = um
2887 .unmarshal(streamReader, JalviewModel.class);
2888 JalviewModel object = jbe.getValue();
2890 if (true) // !skipViewport(object))
2892 _af = loadFromObject(object, file, true, jprovider);
2893 if (_af != null && object.getViewport().size() > 0)
2894 // getJalviewModelSequence().getViewportCount() > 0)
2898 // store a reference to the first view
2901 if (_af.getViewport().isGatherViewsHere())
2903 // if this is a gathered view, keep its reference since
2904 // after gathering views, only this frame will remain
2906 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2909 // Save dataset to register mappings once all resolved
2910 importedDatasets.put(
2911 af.getViewport().getAlignment().getDataset(),
2912 af.getViewport().getAlignment().getDataset());
2917 else if (jarentry != null)
2919 // Some other file here.
2922 } while (jarentry != null);
2923 resolveFrefedSequences();
2924 } catch (IOException ex)
2926 ex.printStackTrace();
2927 errorMessage = "Couldn't locate Jalview XML file : " + file;
2929 "Exception whilst loading jalview XML file : " + ex + "\n");
2930 } catch (Exception ex)
2932 System.err.println("Parsing as Jalview Version 2 file failed.");
2933 ex.printStackTrace(System.err);
2934 if (attemptversion1parse)
2936 // used to attempt to parse as V1 castor-generated xml
2938 if (Desktop.instance != null)
2940 Desktop.instance.stopLoading();
2944 System.out.println("Successfully loaded archive file");
2947 ex.printStackTrace();
2950 "Exception whilst loading jalview XML file : " + ex + "\n");
2951 } catch (OutOfMemoryError e)
2953 // Don't use the OOM Window here
2954 errorMessage = "Out of memory loading jalview XML file";
2955 System.err.println("Out of memory whilst loading jalview XML file");
2956 e.printStackTrace();
2960 * Regather multiple views (with the same sequence set id) to the frame (if
2961 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2962 * views instead of separate frames. Note this doesn't restore a state where
2963 * some expanded views in turn have tabbed views - the last "first tab" read
2964 * in will play the role of gatherer for all.
2966 for (AlignFrame fr : gatherToThisFrame.values())
2968 Desktop.instance.gatherViews(fr);
2971 restoreSplitFrames();
2972 for (AlignmentI ds : importedDatasets.keySet())
2974 if (ds.getCodonFrames() != null)
2976 StructureSelectionManager
2977 .getStructureSelectionManager(Desktop.instance)
2978 .registerMappings(ds.getCodonFrames());
2981 if (errorMessage != null)
2986 if (Desktop.instance != null)
2988 Desktop.instance.stopLoading();
2995 * Try to reconstruct and display SplitFrame windows, where each contains
2996 * complementary dna and protein alignments. Done by pairing up AlignFrame
2997 * objects (created earlier) which have complementary viewport ids associated.
2999 protected void restoreSplitFrames()
3001 List<SplitFrame> gatherTo = new ArrayList<>();
3002 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3003 Map<String, AlignFrame> dna = new HashMap<>();
3006 * Identify the DNA alignments
3008 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3011 AlignFrame af = candidate.getValue();
3012 if (af.getViewport().getAlignment().isNucleotide())
3014 dna.put(candidate.getKey().getId(), af);
3019 * Try to match up the protein complements
3021 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3024 AlignFrame af = candidate.getValue();
3025 if (!af.getViewport().getAlignment().isNucleotide())
3027 String complementId = candidate.getKey().getComplementId();
3028 // only non-null complements should be in the Map
3029 if (complementId != null && dna.containsKey(complementId))
3031 final AlignFrame dnaFrame = dna.get(complementId);
3032 SplitFrame sf = createSplitFrame(dnaFrame, af);
3033 addedToSplitFrames.add(dnaFrame);
3034 addedToSplitFrames.add(af);
3035 dnaFrame.setMenusForViewport();
3036 af.setMenusForViewport();
3037 if (af.getViewport().isGatherViewsHere())
3046 * Open any that we failed to pair up (which shouldn't happen!) as
3047 * standalone AlignFrame's.
3049 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3052 AlignFrame af = candidate.getValue();
3053 if (!addedToSplitFrames.contains(af))
3055 Viewport view = candidate.getKey();
3056 Desktop.addInternalFrame(af, view.getTitle(),
3057 safeInt(view.getWidth()), safeInt(view.getHeight()));
3058 af.setMenusForViewport();
3059 System.err.println("Failed to restore view " + view.getTitle()
3060 + " to split frame");
3065 * Gather back into tabbed views as flagged.
3067 for (SplitFrame sf : gatherTo)
3069 Desktop.instance.gatherViews(sf);
3072 splitFrameCandidates.clear();
3076 * Construct and display one SplitFrame holding DNA and protein alignments.
3079 * @param proteinFrame
3082 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3083 AlignFrame proteinFrame)
3085 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3086 String title = MessageManager.getString("label.linked_view_title");
3087 int width = (int) dnaFrame.getBounds().getWidth();
3088 int height = (int) (dnaFrame.getBounds().getHeight()
3089 + proteinFrame.getBounds().getHeight() + 50);
3092 * SplitFrame location is saved to both enclosed frames
3094 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3095 Desktop.addInternalFrame(splitFrame, title, width, height);
3098 * And compute cDNA consensus (couldn't do earlier with consensus as
3099 * mappings were not yet present)
3101 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3107 * check errorMessage for a valid error message and raise an error box in the
3108 * GUI or write the current errorMessage to stderr and then clear the error
3111 protected void reportErrors()
3113 reportErrors(false);
3116 protected void reportErrors(final boolean saving)
3118 if (errorMessage != null)
3120 final String finalErrorMessage = errorMessage;
3123 javax.swing.SwingUtilities.invokeLater(new Runnable()
3128 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3130 "Error " + (saving ? "saving" : "loading")
3132 JvOptionPane.WARNING_MESSAGE);
3138 System.err.println("Problem loading Jalview file: " + errorMessage);
3141 errorMessage = null;
3144 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3147 * when set, local views will be updated from view stored in JalviewXML
3148 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3149 * sync if this is set to true.
3151 private final boolean updateLocalViews = false;
3154 * Returns the path to a temporary file holding the PDB file for the given PDB
3155 * id. The first time of asking, searches for a file of that name in the
3156 * Jalview project jar, and copies it to a new temporary file. Any repeat
3157 * requests just return the path to the file previously created.
3163 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3166 if (alreadyLoadedPDB.containsKey(pdbId))
3168 return alreadyLoadedPDB.get(pdbId).toString();
3171 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3173 if (tempFile != null)
3175 alreadyLoadedPDB.put(pdbId, tempFile);
3181 * Copies the jar entry of given name to a new temporary file and returns the
3182 * path to the file, or null if the entry is not found.
3185 * @param jarEntryName
3187 * a prefix for the temporary file name, must be at least three
3189 * @param suffixModel
3190 * null or original file - so new file can be given the same suffix
3194 protected String copyJarEntry(jarInputStreamProvider jprovider,
3195 String jarEntryName, String prefix, String suffixModel)
3197 String suffix = ".tmp";
3198 if (suffixModel == null)
3200 suffixModel = jarEntryName;
3202 int sfpos = suffixModel.lastIndexOf(".");
3203 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3205 suffix = "." + suffixModel.substring(sfpos + 1);
3208 try (JarInputStream jin = jprovider.getJarInputStream())
3210 JarEntry entry = null;
3213 entry = jin.getNextJarEntry();
3214 } while (entry != null && !entry.getName().equals(jarEntryName));
3218 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3219 File outFile = File.createTempFile(prefix, suffix);
3220 outFile.deleteOnExit();
3221 try (OutputStream os = new FileOutputStream(outFile))
3225 String t = outFile.getAbsolutePath();
3230 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3232 } catch (Exception ex)
3234 ex.printStackTrace();
3240 private class JvAnnotRow
3242 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3249 * persisted version of annotation row from which to take vis properties
3251 public jalview.datamodel.AlignmentAnnotation template;
3254 * original position of the annotation row in the alignment
3260 * Load alignment frame from jalview XML DOM object
3262 * @param jalviewModel
3265 * filename source string
3266 * @param loadTreesAndStructures
3267 * when false only create Viewport
3269 * data source provider
3270 * @return alignment frame created from view stored in DOM
3272 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3273 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3275 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3276 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3278 // JalviewModelSequence jms = object.getJalviewModelSequence();
3280 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3282 Viewport view = (jalviewModel.getViewport().size() > 0)
3283 ? jalviewModel.getViewport().get(0)
3286 // ////////////////////////////////
3287 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3290 // If we just load in the same jar file again, the sequenceSetId
3291 // will be the same, and we end up with multiple references
3292 // to the same sequenceSet. We must modify this id on load
3293 // so that each load of the file gives a unique id
3296 * used to resolve correct alignment dataset for alignments with multiple
3299 String uniqueSeqSetId = null;
3300 String viewId = null;
3303 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3304 viewId = (view.getId() == null ? null
3305 : view.getId() + uniqueSetSuffix);
3308 // ////////////////////////////////
3311 List<SequenceI> hiddenSeqs = null;
3313 List<SequenceI> tmpseqs = new ArrayList<>();
3315 boolean multipleView = false;
3316 SequenceI referenceseqForView = null;
3317 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3318 List<JSeq> jseqs = jalviewModel.getJSeq();
3319 int vi = 0; // counter in vamsasSeq array
3320 for (int i = 0; i < jseqs.size(); i++)
3322 JSeq jseq = jseqs.get(i);
3323 String seqId = jseq.getId();
3325 SequenceI tmpSeq = seqRefIds.get(seqId);
3328 if (!incompleteSeqs.containsKey(seqId))
3330 // may not need this check, but keep it for at least 2.9,1 release
3331 if (tmpSeq.getStart() != jseq.getStart()
3332 || tmpSeq.getEnd() != jseq.getEnd())
3335 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3336 tmpSeq.getName(), tmpSeq.getStart(),
3337 tmpSeq.getEnd(), jseq.getStart(),
3343 incompleteSeqs.remove(seqId);
3345 if (vamsasSeqs.size() > vi
3346 && vamsasSeqs.get(vi).getId().equals(seqId))
3348 // most likely we are reading a dataset XML document so
3349 // update from vamsasSeq section of XML for this sequence
3350 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3351 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3352 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3357 // reading multiple views, so vamsasSeq set is a subset of JSeq
3358 multipleView = true;
3360 tmpSeq.setStart(jseq.getStart());
3361 tmpSeq.setEnd(jseq.getEnd());
3362 tmpseqs.add(tmpSeq);
3366 Sequence vamsasSeq = vamsasSeqs.get(vi);
3367 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3368 vamsasSeq.getSequence());
3369 tmpSeq.setDescription(vamsasSeq.getDescription());
3370 tmpSeq.setStart(jseq.getStart());
3371 tmpSeq.setEnd(jseq.getEnd());
3372 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3373 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3374 tmpseqs.add(tmpSeq);
3378 if (safeBoolean(jseq.isViewreference()))
3380 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3383 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3385 if (hiddenSeqs == null)
3387 hiddenSeqs = new ArrayList<>();
3390 hiddenSeqs.add(tmpSeq);
3395 // Create the alignment object from the sequence set
3396 // ///////////////////////////////
3397 SequenceI[] orderedSeqs = tmpseqs
3398 .toArray(new SequenceI[tmpseqs.size()]);
3400 AlignmentI al = null;
3401 // so we must create or recover the dataset alignment before going further
3402 // ///////////////////////////////
3403 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3405 // older jalview projects do not have a dataset - so creat alignment and
3407 al = new Alignment(orderedSeqs);
3408 al.setDataset(null);
3412 boolean isdsal = jalviewModel.getViewport().isEmpty();
3415 // we are importing a dataset record, so
3416 // recover reference to an alignment already materialsed as dataset
3417 al = getDatasetFor(vamsasSet.getDatasetId());
3421 // materialse the alignment
3422 al = new Alignment(orderedSeqs);
3426 addDatasetRef(vamsasSet.getDatasetId(), al);
3429 // finally, verify all data in vamsasSet is actually present in al
3430 // passing on flag indicating if it is actually a stored dataset
3431 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3434 if (referenceseqForView != null)
3436 al.setSeqrep(referenceseqForView);
3438 // / Add the alignment properties
3439 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3441 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3443 al.setProperty(ssp.getKey(), ssp.getValue());
3446 // ///////////////////////////////
3448 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3451 // load sequence features, database references and any associated PDB
3452 // structures for the alignment
3454 // prior to 2.10, this part would only be executed the first time a
3455 // sequence was encountered, but not afterwards.
3456 // now, for 2.10 projects, this is also done if the xml doc includes
3457 // dataset sequences not actually present in any particular view.
3459 for (int i = 0; i < vamsasSeqs.size(); i++)
3461 JSeq jseq = jseqs.get(i);
3462 if (jseq.getFeatures().size() > 0)
3464 List<Feature> features = jseq.getFeatures();
3465 for (int f = 0; f < features.size(); f++)
3467 Feature feat = features.get(f);
3468 SequenceFeature sf = new SequenceFeature(feat.getType(),
3469 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3470 safeFloat(feat.getScore()), feat.getFeatureGroup());
3471 sf.setStatus(feat.getStatus());
3474 * load any feature attributes - include map-valued attributes
3476 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3477 for (int od = 0; od < feat.getOtherData().size(); od++)
3479 OtherData keyValue = feat.getOtherData().get(od);
3480 String attributeName = keyValue.getKey();
3481 String attributeValue = keyValue.getValue();
3482 if (attributeName.startsWith("LINK"))
3484 sf.addLink(attributeValue);
3488 String subAttribute = keyValue.getKey2();
3489 if (subAttribute == null)
3491 // simple string-valued attribute
3492 sf.setValue(attributeName, attributeValue);
3496 // attribute 'key' has sub-attribute 'key2'
3497 if (!mapAttributes.containsKey(attributeName))
3499 mapAttributes.put(attributeName, new HashMap<>());
3501 mapAttributes.get(attributeName).put(subAttribute,
3506 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3509 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3512 // adds feature to datasequence's feature set (since Jalview 2.10)
3513 al.getSequenceAt(i).addSequenceFeature(sf);
3516 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3518 // adds dbrefs to datasequence's set (since Jalview 2.10)
3520 al.getSequenceAt(i).getDatasetSequence() == null
3521 ? al.getSequenceAt(i)
3522 : al.getSequenceAt(i).getDatasetSequence(),
3525 if (jseq.getPdbids().size() > 0)
3527 List<Pdbids> ids = jseq.getPdbids();
3528 for (int p = 0; p < ids.size(); p++)
3530 Pdbids pdbid = ids.get(p);
3531 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3532 entry.setId(pdbid.getId());
3533 if (pdbid.getType() != null)
3535 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3537 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3541 entry.setType(PDBEntry.Type.FILE);
3544 // jprovider is null when executing 'New View'
3545 if (pdbid.getFile() != null && jprovider != null)
3547 if (!pdbloaded.containsKey(pdbid.getFile()))
3549 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3554 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3558 if (pdbid.getPdbentryItem() != null)
3560 for (PdbentryItem item : pdbid.getPdbentryItem())
3562 for (Property pr : item.getProperty())
3564 entry.setProperty(pr.getName(), pr.getValue());
3569 for (Property prop : pdbid.getProperty())
3571 entry.setProperty(prop.getName(), prop.getValue());
3573 StructureSelectionManager
3574 .getStructureSelectionManager(Desktop.instance)
3575 .registerPDBEntry(entry);
3576 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3577 if (al.getSequenceAt(i).getDatasetSequence() != null)
3579 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3583 al.getSequenceAt(i).addPDBId(entry);
3588 } // end !multipleview
3590 // ///////////////////////////////
3591 // LOAD SEQUENCE MAPPINGS
3593 if (vamsasSet.getAlcodonFrame().size() > 0)
3595 // TODO Potentially this should only be done once for all views of an
3597 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3598 for (int i = 0; i < alc.size(); i++)
3600 AlignedCodonFrame cf = new AlignedCodonFrame();
3601 if (alc.get(i).getAlcodMap().size() > 0)
3603 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3604 for (int m = 0; m < maps.size(); m++)
3606 AlcodMap map = maps.get(m);
3607 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3609 jalview.datamodel.Mapping mapping = null;
3610 // attach to dna sequence reference.
3611 if (map.getMapping() != null)
3613 mapping = addMapping(map.getMapping());
3614 if (dnaseq != null && mapping.getTo() != null)
3616 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3622 newAlcodMapRef(map.getDnasq(), cf, mapping));
3626 al.addCodonFrame(cf);
3631 // ////////////////////////////////
3633 List<JvAnnotRow> autoAlan = new ArrayList<>();
3636 * store any annotations which forward reference a group's ID
3638 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3640 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3642 List<Annotation> an = vamsasSet.getAnnotation();
3644 for (int i = 0; i < an.size(); i++)
3646 Annotation annotation = an.get(i);
3649 * test if annotation is automatically calculated for this view only
3651 boolean autoForView = false;
3652 if (annotation.getLabel().equals("Quality")
3653 || annotation.getLabel().equals("Conservation")
3654 || annotation.getLabel().equals("Consensus"))
3656 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3658 // JAXB has no has() test; schema defaults value to false
3659 // if (!annotation.hasAutoCalculated())
3661 // annotation.setAutoCalculated(true);
3664 if (autoForView || annotation.isAutoCalculated())
3666 // remove ID - we don't recover annotation from other views for
3667 // view-specific annotation
3668 annotation.setId(null);
3671 // set visibility for other annotation in this view
3672 String annotationId = annotation.getId();
3673 if (annotationId != null && annotationIds.containsKey(annotationId))
3675 AlignmentAnnotation jda = annotationIds.get(annotationId);
3676 // in principle Visible should always be true for annotation displayed
3677 // in multiple views
3678 if (annotation.isVisible() != null)
3680 jda.visible = annotation.isVisible();
3683 al.addAnnotation(jda);
3687 // Construct new annotation from model.
3688 List<AnnotationElement> ae = annotation.getAnnotationElement();
3689 jalview.datamodel.Annotation[] anot = null;
3690 java.awt.Color firstColour = null;
3692 if (!annotation.isScoreOnly())
3694 anot = new jalview.datamodel.Annotation[al.getWidth()];
3695 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3697 AnnotationElement annElement = ae.get(aa);
3698 anpos = annElement.getPosition();
3700 if (anpos >= anot.length)
3705 float value = safeFloat(annElement.getValue());
3706 anot[anpos] = new jalview.datamodel.Annotation(
3707 annElement.getDisplayCharacter(),
3708 annElement.getDescription(),
3709 (annElement.getSecondaryStructure() == null
3710 || annElement.getSecondaryStructure()
3714 .getSecondaryStructure()
3717 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3718 if (firstColour == null)
3720 firstColour = anot[anpos].colour;
3724 jalview.datamodel.AlignmentAnnotation jaa = null;
3726 if (annotation.isGraph())
3728 float llim = 0, hlim = 0;
3729 // if (autoForView || an[i].isAutoCalculated()) {
3732 jaa = new jalview.datamodel.AlignmentAnnotation(
3733 annotation.getLabel(), annotation.getDescription(), anot,
3734 llim, hlim, safeInt(annotation.getGraphType()));
3736 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3737 jaa._linecolour = firstColour;
3738 if (annotation.getThresholdLine() != null)
3740 jaa.setThreshold(new jalview.datamodel.GraphLine(
3741 safeFloat(annotation.getThresholdLine().getValue()),
3742 annotation.getThresholdLine().getLabel(),
3743 new java.awt.Color(safeInt(
3744 annotation.getThresholdLine().getColour()))));
3746 if (autoForView || annotation.isAutoCalculated())
3748 // Hardwire the symbol display line to ensure that labels for
3749 // histograms are displayed
3755 jaa = new jalview.datamodel.AlignmentAnnotation(
3756 annotation.getLabel(), annotation.getDescription(), anot);
3757 jaa._linecolour = firstColour;
3759 // register new annotation
3760 if (annotation.getId() != null)
3762 annotationIds.put(annotation.getId(), jaa);
3763 jaa.annotationId = annotation.getId();
3765 // recover sequence association
3766 String sequenceRef = annotation.getSequenceRef();
3767 if (sequenceRef != null)
3769 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3770 SequenceI sequence = seqRefIds.get(sequenceRef);
3771 if (sequence == null)
3773 // in pre-2.9 projects sequence ref is to sequence name
3774 sequence = al.findName(sequenceRef);
3776 if (sequence != null)
3778 jaa.createSequenceMapping(sequence, 1, true);
3779 sequence.addAlignmentAnnotation(jaa);
3782 // and make a note of any group association
3783 if (annotation.getGroupRef() != null
3784 && annotation.getGroupRef().length() > 0)
3786 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3787 .get(annotation.getGroupRef());
3790 aal = new ArrayList<>();
3791 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3796 if (annotation.getScore() != null)
3798 jaa.setScore(annotation.getScore().doubleValue());
3800 if (annotation.isVisible() != null)
3802 jaa.visible = annotation.isVisible().booleanValue();
3805 if (annotation.isCentreColLabels() != null)
3807 jaa.centreColLabels = annotation.isCentreColLabels()
3811 if (annotation.isScaleColLabels() != null)
3813 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3815 if (annotation.isAutoCalculated())
3817 // newer files have an 'autoCalculated' flag and store calculation
3818 // state in viewport properties
3819 jaa.autoCalculated = true; // means annotation will be marked for
3820 // update at end of load.
3822 if (annotation.getGraphHeight() != null)
3824 jaa.graphHeight = annotation.getGraphHeight().intValue();
3826 jaa.belowAlignment = annotation.isBelowAlignment();
3827 jaa.setCalcId(annotation.getCalcId());
3828 if (annotation.getProperty().size() > 0)
3830 for (Annotation.Property prop : annotation
3833 jaa.setProperty(prop.getName(), prop.getValue());
3836 if (jaa.autoCalculated)
3838 autoAlan.add(new JvAnnotRow(i, jaa));
3841 // if (!autoForView)
3843 // add autocalculated group annotation and any user created annotation
3845 al.addAnnotation(jaa);
3849 // ///////////////////////
3851 // Create alignment markup and styles for this view
3852 if (jalviewModel.getJGroup().size() > 0)
3854 List<JGroup> groups = jalviewModel.getJGroup();
3855 boolean addAnnotSchemeGroup = false;
3856 for (int i = 0; i < groups.size(); i++)
3858 JGroup jGroup = groups.get(i);
3859 ColourSchemeI cs = null;
3860 if (jGroup.getColour() != null)
3862 if (jGroup.getColour().startsWith("ucs"))
3864 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3866 else if (jGroup.getColour().equals("AnnotationColourGradient")
3867 && jGroup.getAnnotationColours() != null)
3869 addAnnotSchemeGroup = true;
3873 cs = ColourSchemeProperty.getColourScheme(null, al,
3874 jGroup.getColour());
3877 int pidThreshold = safeInt(jGroup.getPidThreshold());
3879 Vector<SequenceI> seqs = new Vector<>();
3881 for (int s = 0; s < jGroup.getSeq().size(); s++)
3883 String seqId = jGroup.getSeq().get(s);
3884 SequenceI ts = seqRefIds.get(seqId);
3888 seqs.addElement(ts);
3892 if (seqs.size() < 1)
3897 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3898 safeBoolean(jGroup.isDisplayBoxes()),
3899 safeBoolean(jGroup.isDisplayText()),
3900 safeBoolean(jGroup.isColourText()),
3901 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3902 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3903 sg.getGroupColourScheme()
3904 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3905 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3907 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3908 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3909 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3910 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3911 // attributes with a default in the schema are never null
3912 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3913 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3914 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3915 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3916 if (jGroup.getConsThreshold() != null
3917 && jGroup.getConsThreshold().intValue() != 0)
3919 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3922 c.verdict(false, 25);
3923 sg.cs.setConservation(c);
3926 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3928 // re-instate unique group/annotation row reference
3929 List<AlignmentAnnotation> jaal = groupAnnotRefs
3930 .get(jGroup.getId());
3933 for (AlignmentAnnotation jaa : jaal)
3936 if (jaa.autoCalculated)
3938 // match up and try to set group autocalc alignment row for this
3940 if (jaa.label.startsWith("Consensus for "))
3942 sg.setConsensus(jaa);
3944 // match up and try to set group autocalc alignment row for this
3946 if (jaa.label.startsWith("Conservation for "))
3948 sg.setConservationRow(jaa);
3955 if (addAnnotSchemeGroup)
3957 // reconstruct the annotation colourscheme
3958 sg.setColourScheme(constructAnnotationColour(
3959 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3965 // only dataset in this model, so just return.
3968 // ///////////////////////////////
3971 AlignFrame af = null;
3972 AlignViewport av = null;
3973 // now check to see if we really need to create a new viewport.
3974 if (multipleView && viewportsAdded.size() == 0)
3976 // We recovered an alignment for which a viewport already exists.
3977 // TODO: fix up any settings necessary for overlaying stored state onto
3978 // state recovered from another document. (may not be necessary).
3979 // we may need a binding from a viewport in memory to one recovered from
3981 // and then recover its containing af to allow the settings to be applied.
3982 // TODO: fix for vamsas demo
3984 "About to recover a viewport for existing alignment: Sequence set ID is "
3986 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3987 if (seqsetobj != null)
3989 if (seqsetobj instanceof String)
3991 uniqueSeqSetId = (String) seqsetobj;
3993 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3999 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4005 * indicate that annotation colours are applied across all groups (pre
4006 * Jalview 2.8.1 behaviour)
4008 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4009 jalviewModel.getVersion());
4011 AlignmentPanel ap = null;
4012 boolean isnewview = true;
4015 // Check to see if this alignment already has a view id == viewId
4016 jalview.gui.AlignmentPanel views[] = Desktop
4017 .getAlignmentPanels(uniqueSeqSetId);
4018 if (views != null && views.length > 0)
4020 for (int v = 0; v < views.length; v++)
4022 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4024 // recover the existing alignpanel, alignframe, viewport
4025 af = views[v].alignFrame;
4028 // TODO: could even skip resetting view settings if we don't want to
4029 // change the local settings from other jalview processes
4038 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4039 uniqueSeqSetId, viewId, autoAlan);
4040 av = af.getViewport();
4045 * Load any trees, PDB structures and viewers
4047 * Not done if flag is false (when this method is used for New View)
4049 if (loadTreesAndStructures)
4051 loadTrees(jalviewModel, view, af, av, ap);
4052 loadPCAViewers(jalviewModel, ap);
4053 loadPDBStructures(jprovider, jseqs, af, ap);
4054 loadRnaViewers(jprovider, jseqs, ap);
4056 // and finally return.
4061 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4062 * panel is restored from separate jar entries, two (gapped and trimmed) per
4063 * sequence and secondary structure.
4065 * Currently each viewer shows just one sequence and structure (gapped and
4066 * trimmed), however this method is designed to support multiple sequences or
4067 * structures in viewers if wanted in future.
4073 private void loadRnaViewers(jarInputStreamProvider jprovider,
4074 List<JSeq> jseqs, AlignmentPanel ap)
4077 * scan the sequences for references to viewers; create each one the first
4078 * time it is referenced, add Rna models to existing viewers
4080 for (JSeq jseq : jseqs)
4082 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4084 RnaViewer viewer = jseq.getRnaViewer().get(i);
4085 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4088 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4090 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4091 SequenceI seq = seqRefIds.get(jseq.getId());
4092 AlignmentAnnotation ann = this.annotationIds
4093 .get(ss.getAnnotationId());
4096 * add the structure to the Varna display (with session state copied
4097 * from the jar to a temporary file)
4099 boolean gapped = safeBoolean(ss.isGapped());
4100 String rnaTitle = ss.getTitle();
4101 String sessionState = ss.getViewerState();
4102 String tempStateFile = copyJarEntry(jprovider, sessionState,
4104 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4105 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4107 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4113 * Locate and return an already instantiated matching AppVarna, or create one
4117 * @param viewIdSuffix
4121 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4122 String viewIdSuffix, AlignmentPanel ap)
4125 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4126 * if load is repeated
4128 String postLoadId = viewer.getViewId() + viewIdSuffix;
4129 for (JInternalFrame frame : getAllFrames())
4131 if (frame instanceof AppVarna)
4133 AppVarna varna = (AppVarna) frame;
4134 if (postLoadId.equals(varna.getViewId()))
4136 // this viewer is already instantiated
4137 // could in future here add ap as another 'parent' of the
4138 // AppVarna window; currently just 1-to-many
4145 * viewer not found - make it
4147 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4148 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4149 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4150 safeInt(viewer.getDividerLocation()));
4151 AppVarna varna = new AppVarna(model, ap);
4157 * Load any saved trees
4165 protected void loadTrees(JalviewModel jm, Viewport view,
4166 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4168 // TODO result of automated refactoring - are all these parameters needed?
4171 for (int t = 0; t < jm.getTree().size(); t++)
4174 Tree tree = jm.getTree().get(t);
4176 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4179 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4180 tree.getTitle(), safeInt(tree.getWidth()),
4181 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4182 safeInt(tree.getYpos()));
4183 if (tree.getId() != null)
4185 // perhaps bind the tree id to something ?
4190 // update local tree attributes ?
4191 // TODO: should check if tp has been manipulated by user - if so its
4192 // settings shouldn't be modified
4193 tp.setTitle(tree.getTitle());
4194 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4195 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4196 safeInt(tree.getHeight())));
4197 tp.setViewport(av); // af.viewport;
4198 // TODO: verify 'associate with all views' works still
4199 tp.getTreeCanvas().setViewport(av); // af.viewport;
4200 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4202 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4205 warn("There was a problem recovering stored Newick tree: \n"
4206 + tree.getNewick());
4210 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4211 tp.fitToWindow_actionPerformed(null);
4213 if (tree.getFontName() != null)
4216 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4217 safeInt(tree.getFontSize())));
4222 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4223 safeInt(view.getFontSize())));
4226 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4227 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4228 tp.showDistances(safeBoolean(tree.isShowDistances()));
4230 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4232 if (safeBoolean(tree.isCurrentTree()))
4234 af.getViewport().setCurrentTree(tp.getTree());
4238 } catch (Exception ex)
4240 ex.printStackTrace();
4245 * Load and link any saved structure viewers.
4252 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4253 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4256 * Run through all PDB ids on the alignment, and collect mappings between
4257 * distinct view ids and all sequences referring to that view.
4259 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4261 for (int i = 0; i < jseqs.size(); i++)
4263 JSeq jseq = jseqs.get(i);
4264 if (jseq.getPdbids().size() > 0)
4266 List<Pdbids> ids = jseq.getPdbids();
4267 for (int p = 0; p < ids.size(); p++)
4269 Pdbids pdbid = ids.get(p);
4270 final int structureStateCount = pdbid.getStructureState().size();
4271 for (int s = 0; s < structureStateCount; s++)
4273 // check to see if we haven't already created this structure view
4274 final StructureState structureState = pdbid
4275 .getStructureState().get(s);
4276 String sviewid = (structureState.getViewId() == null) ? null
4277 : structureState.getViewId() + uniqueSetSuffix;
4278 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4279 // Originally : pdbid.getFile()
4280 // : TODO: verify external PDB file recovery still works in normal
4281 // jalview project load
4283 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4284 jpdb.setId(pdbid.getId());
4286 int x = safeInt(structureState.getXpos());
4287 int y = safeInt(structureState.getYpos());
4288 int width = safeInt(structureState.getWidth());
4289 int height = safeInt(structureState.getHeight());
4291 // Probably don't need to do this anymore...
4292 // Desktop.desktop.getComponentAt(x, y);
4293 // TODO: NOW: check that this recovers the PDB file correctly.
4294 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4296 jalview.datamodel.SequenceI seq = seqRefIds
4297 .get(jseq.getId() + "");
4298 if (sviewid == null)
4300 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4303 if (!structureViewers.containsKey(sviewid))
4305 String viewerType = structureState.getType();
4306 if (viewerType == null) // pre Jalview 2.9
4308 viewerType = ViewerType.JMOL.toString();
4310 structureViewers.put(sviewid,
4311 new StructureViewerModel(x, y, width, height, false,
4312 false, true, structureState.getViewId(),
4314 // Legacy pre-2.7 conversion JAL-823 :
4315 // do not assume any view has to be linked for colour by
4319 // assemble String[] { pdb files }, String[] { id for each
4320 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4321 // seqs_file 2}, boolean[] {
4322 // linkAlignPanel,superposeWithAlignpanel}} from hash
4323 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4324 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4325 || structureState.isAlignwithAlignPanel());
4328 * Default colour by linked panel to false if not specified (e.g.
4329 * for pre-2.7 projects)
4331 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4332 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4333 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4336 * Default colour by viewer to true if not specified (e.g. for
4339 boolean colourByViewer = jmoldat.isColourByViewer();
4340 colourByViewer &= structureState.isColourByJmol();
4341 jmoldat.setColourByViewer(colourByViewer);
4343 if (jmoldat.getStateData().length() < structureState
4344 .getValue()/*Content()*/.length())
4346 jmoldat.setStateData(structureState.getValue());// Content());
4348 if (pdbid.getFile() != null)
4350 File mapkey = new File(pdbid.getFile());
4351 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4352 if (seqstrmaps == null)
4354 jmoldat.getFileData().put(mapkey,
4355 seqstrmaps = jmoldat.new StructureData(pdbFile,
4358 if (!seqstrmaps.getSeqList().contains(seq))
4360 seqstrmaps.getSeqList().add(seq);
4366 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");
4373 // Instantiate the associated structure views
4374 for (Entry<String, StructureViewerModel> entry : structureViewers
4379 createOrLinkStructureViewer(entry, af, ap, jprovider);
4380 } catch (Exception e)
4383 "Error loading structure viewer: " + e.getMessage());
4384 // failed - try the next one
4396 protected void createOrLinkStructureViewer(
4397 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4398 AlignmentPanel ap, jarInputStreamProvider jprovider)
4400 final StructureViewerModel stateData = viewerData.getValue();
4403 * Search for any viewer windows already open from other alignment views
4404 * that exactly match the stored structure state
4406 StructureViewerBase comp = findMatchingViewer(viewerData);
4410 linkStructureViewer(ap, comp, stateData);
4414 String type = stateData.getType();
4417 ViewerType viewerType = ViewerType.valueOf(type);
4418 createStructureViewer(viewerType, viewerData, af, jprovider);
4419 } catch (IllegalArgumentException | NullPointerException e)
4421 // TODO JAL-3619 show error dialog / offer an alternative viewer
4423 "Invalid structure viewer type: " + type);
4428 * Generates a name for the entry in the project jar file to hold state
4429 * information for a structure viewer
4434 protected String getViewerJarEntryName(String viewId)
4436 return VIEWER_PREFIX + viewId;
4440 * Returns any open frame that matches given structure viewer data. The match
4441 * is based on the unique viewId, or (for older project versions) the frame's
4447 protected StructureViewerBase findMatchingViewer(
4448 Entry<String, StructureViewerModel> viewerData)
4450 final String sviewid = viewerData.getKey();
4451 final StructureViewerModel svattrib = viewerData.getValue();
4452 StructureViewerBase comp = null;
4453 JInternalFrame[] frames = getAllFrames();
4454 for (JInternalFrame frame : frames)
4456 if (frame instanceof StructureViewerBase)
4459 * Post jalview 2.4 schema includes structure view id
4461 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4464 comp = (StructureViewerBase) frame;
4465 break; // break added in 2.9
4468 * Otherwise test for matching position and size of viewer frame
4470 else if (frame.getX() == svattrib.getX()
4471 && frame.getY() == svattrib.getY()
4472 && frame.getHeight() == svattrib.getHeight()
4473 && frame.getWidth() == svattrib.getWidth())
4475 comp = (StructureViewerBase) frame;
4476 // no break in faint hope of an exact match on viewId
4484 * Link an AlignmentPanel to an existing structure viewer.
4489 * @param useinViewerSuperpos
4490 * @param usetoColourbyseq
4491 * @param viewerColouring
4493 protected void linkStructureViewer(AlignmentPanel ap,
4494 StructureViewerBase viewer, StructureViewerModel stateData)
4496 // NOTE: if the jalview project is part of a shared session then
4497 // view synchronization should/could be done here.
4499 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4500 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4501 final boolean viewerColouring = stateData.isColourByViewer();
4502 Map<File, StructureData> oldFiles = stateData.getFileData();
4505 * Add mapping for sequences in this view to an already open viewer
4507 final AAStructureBindingModel binding = viewer.getBinding();
4508 for (File id : oldFiles.keySet())
4510 // add this and any other pdb files that should be present in the
4512 StructureData filedat = oldFiles.get(id);
4513 String pdbFile = filedat.getFilePath();
4514 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4515 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4517 binding.addSequenceForStructFile(pdbFile, seq);
4519 // and add the AlignmentPanel's reference to the view panel
4520 viewer.addAlignmentPanel(ap);
4521 if (useinViewerSuperpos)
4523 viewer.useAlignmentPanelForSuperposition(ap);
4527 viewer.excludeAlignmentPanelForSuperposition(ap);
4529 if (usetoColourbyseq)
4531 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4535 viewer.excludeAlignmentPanelForColourbyseq(ap);
4540 * Get all frames within the Desktop.
4544 protected JInternalFrame[] getAllFrames()
4546 JInternalFrame[] frames = null;
4547 // TODO is this necessary - is it safe - risk of hanging?
4552 frames = Desktop.desktop.getAllFrames();
4553 } catch (ArrayIndexOutOfBoundsException e)
4555 // occasional No such child exceptions are thrown here...
4559 } catch (InterruptedException f)
4563 } while (frames == null);
4568 * Answers true if 'version' is equal to or later than 'supported', where each
4569 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4570 * changes. Development and test values for 'version' are leniently treated
4574 * - minimum version we are comparing against
4576 * - version of data being processsed
4579 public static boolean isVersionStringLaterThan(String supported,
4582 if (supported == null || version == null
4583 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4584 || version.equalsIgnoreCase("Test")
4585 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4587 System.err.println("Assuming project file with "
4588 + (version == null ? "null" : version)
4589 + " is compatible with Jalview version " + supported);
4594 return StringUtils.compareVersions(version, supported, "b") >= 0;
4598 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4600 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4602 if (newStructureViewers != null)
4604 sview.getBinding().setFinishedLoadingFromArchive(false);
4605 newStructureViewers.add(sview);
4609 protected void setLoadingFinishedForNewStructureViewers()
4611 if (newStructureViewers != null)
4613 for (JalviewStructureDisplayI sview : newStructureViewers)
4615 sview.getBinding().setFinishedLoadingFromArchive(true);
4617 newStructureViewers.clear();
4618 newStructureViewers = null;
4622 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4623 List<SequenceI> hiddenSeqs, AlignmentI al,
4624 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4625 String viewId, List<JvAnnotRow> autoAlan)
4627 AlignFrame af = null;
4628 af = new AlignFrame(al, safeInt(view.getWidth()),
4629 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4633 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4634 // System.out.println("Jalview2XML AF " + e);
4635 // super.processKeyEvent(e);
4642 af.setFileName(file, FileFormat.Jalview);
4644 final AlignViewport viewport = af.getViewport();
4645 for (int i = 0; i < JSEQ.size(); i++)
4647 int colour = safeInt(JSEQ.get(i).getColour());
4648 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4654 viewport.setColourByReferenceSeq(true);
4655 viewport.setDisplayReferenceSeq(true);
4658 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4660 if (view.getSequenceSetId() != null)
4662 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4664 viewport.setSequenceSetId(uniqueSeqSetId);
4667 // propagate shared settings to this new view
4668 viewport.setHistoryList(av.getHistoryList());
4669 viewport.setRedoList(av.getRedoList());
4673 viewportsAdded.put(uniqueSeqSetId, viewport);
4675 // TODO: check if this method can be called repeatedly without
4676 // side-effects if alignpanel already registered.
4677 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4679 // apply Hidden regions to view.
4680 if (hiddenSeqs != null)
4682 for (int s = 0; s < JSEQ.size(); s++)
4684 SequenceGroup hidden = new SequenceGroup();
4685 boolean isRepresentative = false;
4686 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4688 isRepresentative = true;
4689 SequenceI sequenceToHide = al
4690 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4691 hidden.addSequence(sequenceToHide, false);
4692 // remove from hiddenSeqs list so we don't try to hide it twice
4693 hiddenSeqs.remove(sequenceToHide);
4695 if (isRepresentative)
4697 SequenceI representativeSequence = al.getSequenceAt(s);
4698 hidden.addSequence(representativeSequence, false);
4699 viewport.hideRepSequences(representativeSequence, hidden);
4703 SequenceI[] hseqs = hiddenSeqs
4704 .toArray(new SequenceI[hiddenSeqs.size()]);
4705 viewport.hideSequence(hseqs);
4708 // recover view properties and display parameters
4710 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4711 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4712 final int pidThreshold = safeInt(view.getPidThreshold());
4713 viewport.setThreshold(pidThreshold);
4715 viewport.setColourText(safeBoolean(view.isShowColourText()));
4718 .setConservationSelected(
4719 safeBoolean(view.isConservationSelected()));
4720 viewport.setIncrement(safeInt(view.getConsThreshold()));
4721 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4722 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4723 viewport.setFont(new Font(view.getFontName(),
4724 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4726 ViewStyleI vs = viewport.getViewStyle();
4727 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4728 viewport.setViewStyle(vs);
4729 // TODO: allow custom charWidth/Heights to be restored by updating them
4730 // after setting font - which means set above to false
4731 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4732 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4733 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4735 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4737 viewport.setShowText(safeBoolean(view.isShowText()));
4739 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4740 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4741 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4742 viewport.setShowUnconserved(view.isShowUnconserved());
4743 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4745 if (view.getViewName() != null)
4747 viewport.setViewName(view.getViewName());
4748 af.setInitialTabVisible();
4750 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4751 safeInt(view.getWidth()), safeInt(view.getHeight()));
4752 // startSeq set in af.alignPanel.updateLayout below
4753 af.alignPanel.updateLayout();
4754 ColourSchemeI cs = null;
4755 // apply colourschemes
4756 if (view.getBgColour() != null)
4758 if (view.getBgColour().startsWith("ucs"))
4760 cs = getUserColourScheme(jm, view.getBgColour());
4762 else if (view.getBgColour().startsWith("Annotation"))
4764 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4765 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4772 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4773 view.getBgColour());
4778 * turn off 'alignment colour applies to all groups'
4779 * while restoring global colour scheme
4781 viewport.setColourAppliesToAllGroups(false);
4782 viewport.setGlobalColourScheme(cs);
4783 viewport.getResidueShading().setThreshold(pidThreshold,
4784 view.isIgnoreGapsinConsensus());
4785 viewport.getResidueShading()
4786 .setConsensus(viewport.getSequenceConsensusHash());
4787 if (safeBoolean(view.isConservationSelected()) && cs != null)
4789 viewport.getResidueShading()
4790 .setConservationInc(safeInt(view.getConsThreshold()));
4792 af.changeColour(cs);
4793 viewport.setColourAppliesToAllGroups(true);
4796 .setShowSequenceFeatures(
4797 safeBoolean(view.isShowSequenceFeatures()));
4799 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4800 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4801 viewport.setFollowHighlight(view.isFollowHighlight());
4802 viewport.followSelection = view.isFollowSelection();
4803 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4804 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4805 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4806 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4807 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4808 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4809 viewport.setShowGroupConservation(view.isShowGroupConservation());
4810 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4811 viewport.setShowComplementFeaturesOnTop(
4812 view.isShowComplementFeaturesOnTop());
4814 // recover feature settings
4815 if (jm.getFeatureSettings() != null)
4817 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4818 .getFeatureRenderer();
4819 FeaturesDisplayed fdi;
4820 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4821 String[] renderOrder = new String[jm.getFeatureSettings()
4822 .getSetting().size()];
4823 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4824 Map<String, Float> featureOrder = new Hashtable<>();
4826 for (int fs = 0; fs < jm.getFeatureSettings()
4827 .getSetting().size(); fs++)
4829 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4830 String featureType = setting.getType();
4833 * restore feature filters (if any)
4835 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4837 if (filters != null)
4839 FeatureMatcherSetI filter = Jalview2XML
4840 .parseFilter(featureType, filters);
4841 if (!filter.isEmpty())
4843 fr.setFeatureFilter(featureType, filter);
4848 * restore feature colour scheme
4850 Color maxColour = new Color(setting.getColour());
4851 if (setting.getMincolour() != null)
4854 * minColour is always set unless a simple colour
4855 * (including for colour by label though it doesn't use it)
4857 Color minColour = new Color(setting.getMincolour().intValue());
4858 Color noValueColour = minColour;
4859 NoValueColour noColour = setting.getNoValueColour();
4860 if (noColour == NoValueColour.NONE)
4862 noValueColour = null;
4864 else if (noColour == NoValueColour.MAX)
4866 noValueColour = maxColour;
4868 float min = safeFloat(safeFloat(setting.getMin()));
4869 float max = setting.getMax() == null ? 1f
4870 : setting.getMax().floatValue();
4871 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4873 noValueColour, min, max);
4874 if (setting.getAttributeName().size() > 0)
4876 gc.setAttributeName(setting.getAttributeName().toArray(
4877 new String[setting.getAttributeName().size()]));
4879 if (setting.getThreshold() != null)
4881 gc.setThreshold(setting.getThreshold().floatValue());
4882 int threshstate = safeInt(setting.getThreshstate());
4883 // -1 = None, 0 = Below, 1 = Above threshold
4884 if (threshstate == 0)
4886 gc.setBelowThreshold(true);
4888 else if (threshstate == 1)
4890 gc.setAboveThreshold(true);
4893 gc.setAutoScaled(true); // default
4894 if (setting.isAutoScale() != null)
4896 gc.setAutoScaled(setting.isAutoScale());
4898 if (setting.isColourByLabel() != null)
4900 gc.setColourByLabel(setting.isColourByLabel());
4902 // and put in the feature colour table.
4903 featureColours.put(featureType, gc);
4907 featureColours.put(featureType,
4908 new FeatureColour(maxColour));
4910 renderOrder[fs] = featureType;
4911 if (setting.getOrder() != null)
4913 featureOrder.put(featureType, setting.getOrder().floatValue());
4917 featureOrder.put(featureType, Float.valueOf(
4918 fs / jm.getFeatureSettings().getSetting().size()));
4920 if (safeBoolean(setting.isDisplay()))
4922 fdi.setVisible(featureType);
4925 Map<String, Boolean> fgtable = new Hashtable<>();
4926 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4928 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4929 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4931 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4932 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4933 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4934 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4935 fgtable, featureColours, 1.0f, featureOrder);
4936 fr.transferSettings(frs);
4939 if (view.getHiddenColumns().size() > 0)
4941 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4943 final HiddenColumns hc = view.getHiddenColumns().get(c);
4944 viewport.hideColumns(safeInt(hc.getStart()),
4945 safeInt(hc.getEnd()) /* +1 */);
4948 if (view.getCalcIdParam() != null)
4950 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4952 if (calcIdParam != null)
4954 if (recoverCalcIdParam(calcIdParam, viewport))
4959 warn("Couldn't recover parameters for "
4960 + calcIdParam.getCalcId());
4965 af.setMenusFromViewport(viewport);
4966 af.setTitle(view.getTitle());
4967 // TODO: we don't need to do this if the viewport is aready visible.
4969 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4970 * has a 'cdna/protein complement' view, in which case save it in order to
4971 * populate a SplitFrame once all views have been read in.
4973 String complementaryViewId = view.getComplementId();
4974 if (complementaryViewId == null)
4976 Desktop.addInternalFrame(af, view.getTitle(),
4977 safeInt(view.getWidth()), safeInt(view.getHeight()));
4978 // recompute any autoannotation
4979 af.alignPanel.updateAnnotation(false, true);
4980 reorderAutoannotation(af, al, autoAlan);
4981 af.alignPanel.alignmentChanged();
4985 splitFrameCandidates.put(view, af);
4988 Overview overview = view.getOverview();
4989 if (overview != null)
4991 OverviewPanel overviewPanel = af.openOverviewPanel(overview.isShowHidden());
4992 overviewPanel.setBounds(overview.getXpos(), overview.getYpos(),
4993 overview.getWidth(), overview.getHeight());
4994 overviewPanel.setPreferredSize(new Dimension(
4995 overview.getWidth(), overview.getHeight()));
4996 Color gap = new Color(overview.getGapColour());
4997 Color residue = new Color(overview.getResidueColour());
4998 Color hidden = new Color(overview.getHiddenColour());
4999 overviewPanel.getCanvas().setColours(gap, residue, hidden);
5005 * Reads saved data to restore Colour by Annotation settings
5007 * @param viewAnnColour
5011 * @param checkGroupAnnColour
5014 private ColourSchemeI constructAnnotationColour(
5015 AnnotationColourScheme viewAnnColour, AlignFrame af,
5016 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5018 boolean propagateAnnColour = false;
5019 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5021 if (checkGroupAnnColour && al.getGroups() != null
5022 && al.getGroups().size() > 0)
5024 // pre 2.8.1 behaviour
5025 // check to see if we should transfer annotation colours
5026 propagateAnnColour = true;
5027 for (SequenceGroup sg : al.getGroups())
5029 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5031 propagateAnnColour = false;
5037 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5039 String annotationId = viewAnnColour.getAnnotation();
5040 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5043 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5045 if (matchedAnnotation == null
5046 && annAlignment.getAlignmentAnnotation() != null)
5048 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5051 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5053 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5058 if (matchedAnnotation == null)
5060 System.err.println("Failed to match annotation colour scheme for "
5064 if (matchedAnnotation.getThreshold() == null)
5066 matchedAnnotation.setThreshold(
5067 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5068 "Threshold", Color.black));
5071 AnnotationColourGradient cs = null;
5072 if (viewAnnColour.getColourScheme().equals("None"))
5074 cs = new AnnotationColourGradient(matchedAnnotation,
5075 new Color(safeInt(viewAnnColour.getMinColour())),
5076 new Color(safeInt(viewAnnColour.getMaxColour())),
5077 safeInt(viewAnnColour.getAboveThreshold()));
5079 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5081 cs = new AnnotationColourGradient(matchedAnnotation,
5082 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5083 safeInt(viewAnnColour.getAboveThreshold()));
5087 cs = new AnnotationColourGradient(matchedAnnotation,
5088 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5089 viewAnnColour.getColourScheme()),
5090 safeInt(viewAnnColour.getAboveThreshold()));
5093 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5094 boolean useOriginalColours = safeBoolean(
5095 viewAnnColour.isPredefinedColours());
5096 cs.setSeqAssociated(perSequenceOnly);
5097 cs.setPredefinedColours(useOriginalColours);
5099 if (propagateAnnColour && al.getGroups() != null)
5101 // Also use these settings for all the groups
5102 for (int g = 0; g < al.getGroups().size(); g++)
5104 SequenceGroup sg = al.getGroups().get(g);
5105 if (sg.getGroupColourScheme() == null)
5110 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5111 matchedAnnotation, sg.getColourScheme(),
5112 safeInt(viewAnnColour.getAboveThreshold()));
5113 sg.setColourScheme(groupScheme);
5114 groupScheme.setSeqAssociated(perSequenceOnly);
5115 groupScheme.setPredefinedColours(useOriginalColours);
5121 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5122 List<JvAnnotRow> autoAlan)
5124 // copy over visualization settings for autocalculated annotation in the
5126 if (al.getAlignmentAnnotation() != null)
5129 * Kludge for magic autoannotation names (see JAL-811)
5131 String[] magicNames = new String[] { "Consensus", "Quality",
5133 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5134 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5135 for (String nm : magicNames)
5137 visan.put(nm, nullAnnot);
5139 for (JvAnnotRow auan : autoAlan)
5141 visan.put(auan.template.label
5142 + (auan.template.getCalcId() == null ? ""
5143 : "\t" + auan.template.getCalcId()),
5146 int hSize = al.getAlignmentAnnotation().length;
5147 List<JvAnnotRow> reorder = new ArrayList<>();
5148 // work through any autoCalculated annotation already on the view
5149 // removing it if it should be placed in a different location on the
5150 // annotation panel.
5151 List<String> remains = new ArrayList<>(visan.keySet());
5152 for (int h = 0; h < hSize; h++)
5154 jalview.datamodel.AlignmentAnnotation jalan = al
5155 .getAlignmentAnnotation()[h];
5156 if (jalan.autoCalculated)
5159 JvAnnotRow valan = visan.get(k = jalan.label);
5160 if (jalan.getCalcId() != null)
5162 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5167 // delete the auto calculated row from the alignment
5168 al.deleteAnnotation(jalan, false);
5172 if (valan != nullAnnot)
5174 if (jalan != valan.template)
5176 // newly created autoannotation row instance
5177 // so keep a reference to the visible annotation row
5178 // and copy over all relevant attributes
5179 if (valan.template.graphHeight >= 0)
5182 jalan.graphHeight = valan.template.graphHeight;
5184 jalan.visible = valan.template.visible;
5186 reorder.add(new JvAnnotRow(valan.order, jalan));
5191 // Add any (possibly stale) autocalculated rows that were not appended to
5192 // the view during construction
5193 for (String other : remains)
5195 JvAnnotRow othera = visan.get(other);
5196 if (othera != nullAnnot && othera.template.getCalcId() != null
5197 && othera.template.getCalcId().length() > 0)
5199 reorder.add(othera);
5202 // now put the automatic annotation in its correct place
5203 int s = 0, srt[] = new int[reorder.size()];
5204 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5205 for (JvAnnotRow jvar : reorder)
5208 srt[s++] = jvar.order;
5211 jalview.util.QuickSort.sort(srt, rws);
5212 // and re-insert the annotation at its correct position
5213 for (JvAnnotRow jvar : rws)
5215 al.addAnnotation(jvar.template, jvar.order);
5217 af.alignPanel.adjustAnnotationHeight();
5221 Hashtable skipList = null;
5224 * TODO remove this method
5227 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5228 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5229 * throw new Error("Implementation Error. No skipList defined for this
5230 * Jalview2XML instance."); } return (AlignFrame)
5231 * skipList.get(view.getSequenceSetId()); }
5235 * Check if the Jalview view contained in object should be skipped or not.
5238 * @return true if view's sequenceSetId is a key in skipList
5240 private boolean skipViewport(JalviewModel object)
5242 if (skipList == null)
5246 String id = object.getViewport().get(0).getSequenceSetId();
5247 if (skipList.containsKey(id))
5249 if (Cache.log != null && Cache.log.isDebugEnabled())
5251 Cache.log.debug("Skipping seuqence set id " + id);
5258 public void addToSkipList(AlignFrame af)
5260 if (skipList == null)
5262 skipList = new Hashtable();
5264 skipList.put(af.getViewport().getSequenceSetId(), af);
5267 public void clearSkipList()
5269 if (skipList != null)
5276 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5277 boolean ignoreUnrefed, String uniqueSeqSetId)
5279 jalview.datamodel.AlignmentI ds = getDatasetFor(
5280 vamsasSet.getDatasetId());
5281 AlignmentI xtant_ds = ds;
5282 if (xtant_ds == null)
5284 // good chance we are about to create a new dataset, but check if we've
5285 // seen some of the dataset sequence IDs before.
5286 // TODO: skip this check if we are working with project generated by
5287 // version 2.11 or later
5288 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5289 if (xtant_ds != null)
5292 addDatasetRef(vamsasSet.getDatasetId(), ds);
5295 Vector<SequenceI> dseqs = null;
5298 // recovering an alignment View
5299 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5300 if (seqSetDS != null)
5302 if (ds != null && ds != seqSetDS)
5304 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5305 + " - CDS/Protein crossreference data may be lost");
5306 if (xtant_ds != null)
5308 // This can only happen if the unique sequence set ID was bound to a
5309 // dataset that did not contain any of the sequences in the view
5310 // currently being restored.
5311 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.");
5315 addDatasetRef(vamsasSet.getDatasetId(), ds);
5320 // try even harder to restore dataset
5321 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5322 // create a list of new dataset sequences
5323 dseqs = new Vector<>();
5325 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5327 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5328 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5330 // create a new dataset
5333 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5334 dseqs.copyInto(dsseqs);
5335 ds = new jalview.datamodel.Alignment(dsseqs);
5336 debug("Created new dataset " + vamsasSet.getDatasetId()
5337 + " for alignment " + System.identityHashCode(al));
5338 addDatasetRef(vamsasSet.getDatasetId(), ds);
5340 // set the dataset for the newly imported alignment.
5341 if (al.getDataset() == null && !ignoreUnrefed)
5344 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5345 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5347 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5351 * XML dataset sequence ID to materialised dataset reference
5353 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5356 * @return the first materialised dataset reference containing a dataset
5357 * sequence referenced in the given view
5359 * - sequences from the view
5361 AlignmentI checkIfHasDataset(List<Sequence> list)
5363 for (Sequence restoredSeq : list)
5365 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5366 if (datasetFor != null)
5375 * Register ds as the containing dataset for the dataset sequences referenced
5376 * by sequences in list
5379 * - sequences in a view
5382 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5384 for (Sequence restoredSeq : list)
5386 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5387 if (prevDS != null && prevDS != ds)
5389 warn("Dataset sequence appears in many datasets: "
5390 + restoredSeq.getDsseqid());
5391 // TODO: try to merge!
5398 * sequence definition to create/merge dataset sequence for
5402 * vector to add new dataset sequence to
5403 * @param ignoreUnrefed
5404 * - when true, don't create new sequences from vamsasSeq if it's id
5405 * doesn't already have an asssociated Jalview sequence.
5407 * - used to reorder the sequence in the alignment according to the
5408 * vamsasSeq array ordering, to preserve ordering of dataset
5410 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5411 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5414 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5416 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5417 boolean reorder = false;
5418 SequenceI dsq = null;
5419 if (sq != null && sq.getDatasetSequence() != null)
5421 dsq = sq.getDatasetSequence();
5427 if (sq == null && ignoreUnrefed)
5431 String sqid = vamsasSeq.getDsseqid();
5434 // need to create or add a new dataset sequence reference to this sequence
5437 dsq = seqRefIds.get(sqid);
5442 // make a new dataset sequence
5443 dsq = sq.createDatasetSequence();
5446 // make up a new dataset reference for this sequence
5447 sqid = seqHash(dsq);
5449 dsq.setVamsasId(uniqueSetSuffix + sqid);
5450 seqRefIds.put(sqid, dsq);
5455 dseqs.addElement(dsq);
5460 ds.addSequence(dsq);
5466 { // make this dataset sequence sq's dataset sequence
5467 sq.setDatasetSequence(dsq);
5468 // and update the current dataset alignment
5473 if (!dseqs.contains(dsq))
5480 if (ds.findIndex(dsq) < 0)
5482 ds.addSequence(dsq);
5489 // TODO: refactor this as a merge dataset sequence function
5490 // now check that sq (the dataset sequence) sequence really is the union of
5491 // all references to it
5492 // boolean pre = sq.getStart() < dsq.getStart();
5493 // boolean post = sq.getEnd() > dsq.getEnd();
5497 // StringBuffer sb = new StringBuffer();
5498 String newres = jalview.analysis.AlignSeq.extractGaps(
5499 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5500 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5501 && newres.length() > dsq.getLength())
5503 // Update with the longer sequence.
5507 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5508 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5509 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5510 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5512 dsq.setSequence(newres);
5514 // TODO: merges will never happen if we 'know' we have the real dataset
5515 // sequence - this should be detected when id==dssid
5517 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5518 // + (pre ? "prepended" : "") + " "
5519 // + (post ? "appended" : ""));
5524 // sequence refs are identical. We may need to update the existing dataset
5525 // alignment with this one, though.
5526 if (ds != null && dseqs == null)
5528 int opos = ds.findIndex(dsq);
5529 SequenceI tseq = null;
5530 if (opos != -1 && vseqpos != opos)
5532 // remove from old position
5533 ds.deleteSequence(dsq);
5535 if (vseqpos < ds.getHeight())
5537 if (vseqpos != opos)
5539 // save sequence at destination position
5540 tseq = ds.getSequenceAt(vseqpos);
5541 ds.replaceSequenceAt(vseqpos, dsq);
5542 ds.addSequence(tseq);
5547 ds.addSequence(dsq);
5554 * TODO use AlignmentI here and in related methods - needs
5555 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5557 Hashtable<String, AlignmentI> datasetIds = null;
5559 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5561 private AlignmentI getDatasetFor(String datasetId)
5563 if (datasetIds == null)
5565 datasetIds = new Hashtable<>();
5568 if (datasetIds.containsKey(datasetId))
5570 return datasetIds.get(datasetId);
5575 private void addDatasetRef(String datasetId, AlignmentI dataset)
5577 if (datasetIds == null)
5579 datasetIds = new Hashtable<>();
5581 datasetIds.put(datasetId, dataset);
5585 * make a new dataset ID for this jalview dataset alignment
5590 private String getDatasetIdRef(AlignmentI dataset)
5592 if (dataset.getDataset() != null)
5594 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5596 String datasetId = makeHashCode(dataset, null);
5597 if (datasetId == null)
5599 // make a new datasetId and record it
5600 if (dataset2Ids == null)
5602 dataset2Ids = new IdentityHashMap<>();
5606 datasetId = dataset2Ids.get(dataset);
5608 if (datasetId == null)
5610 datasetId = "ds" + dataset2Ids.size() + 1;
5611 dataset2Ids.put(dataset, datasetId);
5618 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5619 * constructed as a special subclass GeneLocus.
5621 * @param datasetSequence
5624 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5626 for (int d = 0; d < sequence.getDBRef().size(); d++)
5628 DBRef dr = sequence.getDBRef().get(d);
5632 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5633 dr.getAccessionId());
5637 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5638 dr.getAccessionId());
5640 if (dr.getMapping() != null)
5642 entry.setMap(addMapping(dr.getMapping()));
5644 datasetSequence.addDBRef(entry);
5648 private jalview.datamodel.Mapping addMapping(Mapping m)
5650 SequenceI dsto = null;
5651 // Mapping m = dr.getMapping();
5652 int fr[] = new int[m.getMapListFrom().size() * 2];
5653 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5654 for (int _i = 0; from.hasNext(); _i += 2)
5656 MapListFrom mf = from.next();
5657 fr[_i] = mf.getStart();
5658 fr[_i + 1] = mf.getEnd();
5660 int fto[] = new int[m.getMapListTo().size() * 2];
5661 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5662 for (int _i = 0; to.hasNext(); _i += 2)
5664 MapListTo mf = to.next();
5665 fto[_i] = mf.getStart();
5666 fto[_i + 1] = mf.getEnd();
5668 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5669 fto, m.getMapFromUnit().intValue(),
5670 m.getMapToUnit().intValue());
5673 * (optional) choice of dseqFor or Sequence
5675 if (m.getDseqFor() != null)
5677 String dsfor = m.getDseqFor();
5678 if (seqRefIds.containsKey(dsfor))
5683 jmap.setTo(seqRefIds.get(dsfor));
5687 frefedSequence.add(newMappingRef(dsfor, jmap));
5690 else if (m.getSequence() != null)
5693 * local sequence definition
5695 Sequence ms = m.getSequence();
5696 SequenceI djs = null;
5697 String sqid = ms.getDsseqid();
5698 if (sqid != null && sqid.length() > 0)
5701 * recover dataset sequence
5703 djs = seqRefIds.get(sqid);
5708 "Warning - making up dataset sequence id for DbRef sequence map reference");
5709 sqid = ((Object) ms).toString(); // make up a new hascode for
5710 // undefined dataset sequence hash
5711 // (unlikely to happen)
5717 * make a new dataset sequence and add it to refIds hash
5719 djs = new jalview.datamodel.Sequence(ms.getName(),
5721 djs.setStart(jmap.getMap().getToLowest());
5722 djs.setEnd(jmap.getMap().getToHighest());
5723 djs.setVamsasId(uniqueSetSuffix + sqid);
5725 incompleteSeqs.put(sqid, djs);
5726 seqRefIds.put(sqid, djs);
5729 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5738 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5739 * view as XML (but not to file), and then reloading it
5744 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5747 JalviewModel jm = saveState(ap, null, null, null);
5750 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5751 ap.getAlignment().getDataset());
5753 uniqueSetSuffix = "";
5754 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5755 jm.getViewport().get(0).setId(null);
5756 // we don't overwrite the view we just copied
5758 if (this.frefedSequence == null)
5760 frefedSequence = new Vector<>();
5763 viewportsAdded.clear();
5765 AlignFrame af = loadFromObject(jm, null, false, null);
5766 af.getAlignPanels().clear();
5767 af.closeMenuItem_actionPerformed(true);
5770 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5771 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5772 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5773 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5774 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5777 return af.alignPanel;
5780 private Hashtable jvids2vobj;
5782 private void warn(String msg)
5787 private void warn(String msg, Exception e)
5789 if (Cache.log != null)
5793 Cache.log.warn(msg, e);
5797 Cache.log.warn(msg);
5802 System.err.println("Warning: " + msg);
5805 e.printStackTrace();
5810 private void debug(String string)
5812 debug(string, null);
5815 private void debug(String msg, Exception e)
5817 if (Cache.log != null)
5821 Cache.log.debug(msg, e);
5825 Cache.log.debug(msg);
5830 System.err.println("Warning: " + msg);
5833 e.printStackTrace();
5839 * set the object to ID mapping tables used to write/recover objects and XML
5840 * ID strings for the jalview project. If external tables are provided then
5841 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5842 * object goes out of scope. - also populates the datasetIds hashtable with
5843 * alignment objects containing dataset sequences
5846 * Map from ID strings to jalview datamodel
5848 * Map from jalview datamodel to ID strings
5852 public void setObjectMappingTables(Hashtable vobj2jv,
5853 IdentityHashMap jv2vobj)
5855 this.jv2vobj = jv2vobj;
5856 this.vobj2jv = vobj2jv;
5857 Iterator ds = jv2vobj.keySet().iterator();
5859 while (ds.hasNext())
5861 Object jvobj = ds.next();
5862 id = jv2vobj.get(jvobj).toString();
5863 if (jvobj instanceof jalview.datamodel.Alignment)
5865 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5867 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5870 else if (jvobj instanceof jalview.datamodel.Sequence)
5872 // register sequence object so the XML parser can recover it.
5873 if (seqRefIds == null)
5875 seqRefIds = new HashMap<>();
5877 if (seqsToIds == null)
5879 seqsToIds = new IdentityHashMap<>();
5881 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5882 seqsToIds.put((SequenceI) jvobj, id);
5884 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5887 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5888 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5889 if (jvann.annotationId == null)
5891 jvann.annotationId = anid;
5893 if (!jvann.annotationId.equals(anid))
5895 // TODO verify that this is the correct behaviour
5896 this.warn("Overriding Annotation ID for " + anid
5897 + " from different id : " + jvann.annotationId);
5898 jvann.annotationId = anid;
5901 else if (jvobj instanceof String)
5903 if (jvids2vobj == null)
5905 jvids2vobj = new Hashtable();
5906 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5911 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5917 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5918 * objects created from the project archive. If string is null (default for
5919 * construction) then suffix will be set automatically.
5923 public void setUniqueSetSuffix(String string)
5925 uniqueSetSuffix = string;
5930 * uses skipList2 as the skipList for skipping views on sequence sets
5931 * associated with keys in the skipList
5935 public void setSkipList(Hashtable skipList2)
5937 skipList = skipList2;
5941 * Reads the jar entry of given name and returns its contents, or null if the
5942 * entry is not found.
5945 * @param jarEntryName
5948 protected String readJarEntry(jarInputStreamProvider jprovider,
5949 String jarEntryName)
5951 String result = null;
5952 BufferedReader in = null;
5957 * Reopen the jar input stream and traverse its entries to find a matching
5960 JarInputStream jin = jprovider.getJarInputStream();
5961 JarEntry entry = null;
5964 entry = jin.getNextJarEntry();
5965 } while (entry != null && !entry.getName().equals(jarEntryName));
5969 StringBuilder out = new StringBuilder(256);
5970 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5973 while ((data = in.readLine()) != null)
5977 result = out.toString();
5981 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5983 } catch (Exception ex)
5985 ex.printStackTrace();
5993 } catch (IOException e)
6004 * Returns an incrementing counter (0, 1, 2...)
6008 private synchronized int nextCounter()
6014 * Loads any saved PCA viewers
6019 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6023 List<PcaViewer> pcaviewers = model.getPcaViewer();
6024 for (PcaViewer viewer : pcaviewers)
6026 String modelName = viewer.getScoreModelName();
6027 SimilarityParamsI params = new SimilarityParams(
6028 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6029 viewer.isIncludeGaps(),
6030 viewer.isDenominateByShortestLength());
6033 * create the panel (without computing the PCA)
6035 PCAPanel panel = new PCAPanel(ap, modelName, params);
6037 panel.setTitle(viewer.getTitle());
6038 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6039 viewer.getWidth(), viewer.getHeight()));
6041 boolean showLabels = viewer.isShowLabels();
6042 panel.setShowLabels(showLabels);
6043 panel.getRotatableCanvas().setShowLabels(showLabels);
6044 panel.getRotatableCanvas()
6045 .setBgColour(new Color(viewer.getBgColour()));
6046 panel.getRotatableCanvas()
6047 .setApplyToAllViews(viewer.isLinkToAllViews());
6050 * load PCA output data
6052 ScoreModelI scoreModel = ScoreModels.getInstance()
6053 .getScoreModel(modelName, ap);
6054 PCA pca = new PCA(null, scoreModel, params);
6055 PcaDataType pcaData = viewer.getPcaData();
6057 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6058 pca.setPairwiseScores(pairwise);
6060 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6061 pca.setTridiagonal(triDiag);
6063 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6064 pca.setEigenmatrix(result);
6066 panel.getPcaModel().setPCA(pca);
6069 * we haven't saved the input data! (JAL-2647 to do)
6071 panel.setInputData(null);
6074 * add the sequence points for the PCA display
6076 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6077 for (SequencePoint sp : viewer.getSequencePoint())
6079 String seqId = sp.getSequenceRef();
6080 SequenceI seq = seqRefIds.get(seqId);
6083 throw new IllegalStateException(
6084 "Unmatched seqref for PCA: " + seqId);
6086 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6087 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6089 seqPoints.add(seqPoint);
6091 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6094 * set min-max ranges and scale after setPoints (which recomputes them)
6096 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6097 SeqPointMin spMin = viewer.getSeqPointMin();
6098 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6100 SeqPointMax spMax = viewer.getSeqPointMax();
6101 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6103 panel.getRotatableCanvas().setSeqMinMax(min, max);
6105 // todo: hold points list in PCAModel only
6106 panel.getPcaModel().setSequencePoints(seqPoints);
6108 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6109 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6110 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6112 // is this duplication needed?
6113 panel.setTop(seqPoints.size() - 1);
6114 panel.getPcaModel().setTop(seqPoints.size() - 1);
6117 * add the axes' end points for the display
6119 for (int i = 0; i < 3; i++)
6121 Axis axis = viewer.getAxis().get(i);
6122 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6123 axis.getXPos(), axis.getYPos(), axis.getZPos());
6126 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6127 "label.calc_title", "PCA", modelName), 475, 450);
6129 } catch (Exception ex)
6131 Cache.log.error("Error loading PCA: " + ex.toString());
6136 * Creates a new structure viewer window
6143 protected void createStructureViewer(
6144 ViewerType viewerType, final Entry<String, StructureViewerModel> viewerData,
6145 AlignFrame af, jarInputStreamProvider jprovider)
6147 final StructureViewerModel viewerModel = viewerData.getValue();
6148 String sessionFilePath = null;
6150 if (viewerType == ViewerType.JMOL)
6152 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6156 String viewerJarEntryName = getViewerJarEntryName(
6157 viewerModel.getViewId());
6158 sessionFilePath = copyJarEntry(jprovider,
6160 "viewerSession", ".tmp");
6162 final String sessionPath = sessionFilePath;
6163 final String sviewid = viewerData.getKey();
6166 SwingUtilities.invokeAndWait(new Runnable()
6171 JalviewStructureDisplayI sview = null;
6174 sview = StructureViewer.createView(viewerType, af.alignPanel,
6175 viewerModel, sessionPath, sviewid);
6176 addNewStructureViewer(sview);
6177 } catch (OutOfMemoryError ex)
6179 new OOMWarning("Restoring structure view for "
6181 (OutOfMemoryError) ex.getCause());
6182 if (sview != null && sview.isVisible())
6184 sview.closeViewer(false);
6185 sview.setVisible(false);
6191 } catch (InvocationTargetException | InterruptedException ex)
6193 warn("Unexpected error when opening " + viewerType
6194 + " structure viewer", ex);
6199 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6200 * the path of the file. "load file" commands are rewritten to change the
6201 * original PDB file names to those created as the Jalview project is loaded.
6207 private String rewriteJmolSession(StructureViewerModel svattrib,
6208 jarInputStreamProvider jprovider)
6210 String state = svattrib.getStateData(); // Jalview < 2.9
6211 if (state == null || state.isEmpty()) // Jalview >= 2.9
6213 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6214 state = readJarEntry(jprovider, jarEntryName);
6216 // TODO or simpler? for each key in oldFiles,
6217 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6218 // (allowing for different path escapings)
6219 StringBuilder rewritten = new StringBuilder(state.length());
6220 int cp = 0, ncp, ecp;
6221 Map<File, StructureData> oldFiles = svattrib.getFileData();
6222 while ((ncp = state.indexOf("load ", cp)) > -1)
6226 // look for next filename in load statement
6227 rewritten.append(state.substring(cp,
6228 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6229 String oldfilenam = state.substring(ncp,
6230 ecp = state.indexOf("\"", ncp));
6231 // recover the new mapping data for this old filename
6232 // have to normalize filename - since Jmol and jalview do
6233 // filename translation differently.
6234 StructureData filedat = oldFiles.get(new File(oldfilenam));
6235 if (filedat == null)
6237 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6238 filedat = oldFiles.get(new File(reformatedOldFilename));
6241 .append(Platform.escapeBackslashes(filedat.getFilePath()));
6242 rewritten.append("\"");
6243 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6244 // look for next file statement.
6245 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6249 // just append rest of state
6250 rewritten.append(state.substring(cp));
6254 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6255 rewritten = new StringBuilder(state);
6256 rewritten.append("; load append ");
6257 for (File id : oldFiles.keySet())
6259 // add pdb files that should be present in the viewer
6260 StructureData filedat = oldFiles.get(id);
6261 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6263 rewritten.append(";");
6266 if (rewritten.length() == 0)
6270 final String history = "history = ";
6271 int historyIndex = rewritten.indexOf(history);
6272 if (historyIndex > -1)
6275 * change "history = [true|false];" to "history = [1|0];"
6277 historyIndex += history.length();
6278 String val = rewritten.substring(historyIndex, historyIndex + 5);
6279 if (val.startsWith("true"))
6281 rewritten.replace(historyIndex, historyIndex + 4, "1");
6283 else if (val.startsWith("false"))
6285 rewritten.replace(historyIndex, historyIndex + 5, "0");
6291 File tmp = File.createTempFile("viewerSession", ".tmp");
6292 try (OutputStream os = new FileOutputStream(tmp))
6294 InputStream is = new ByteArrayInputStream(
6295 rewritten.toString().getBytes());
6297 return tmp.getAbsolutePath();
6299 } catch (IOException e)
6301 Cache.log.error("Error restoring Jmol session: " + e.toString());
6307 * Populates an XML model of the feature colour scheme for one feature type
6309 * @param featureType
6313 public static Colour marshalColour(
6314 String featureType, FeatureColourI fcol)
6316 Colour col = new Colour();
6317 if (fcol.isSimpleColour())
6319 col.setRGB(Format.getHexString(fcol.getColour()));
6323 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6324 col.setMin(fcol.getMin());
6325 col.setMax(fcol.getMax());
6326 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6327 col.setAutoScale(fcol.isAutoScaled());
6328 col.setThreshold(fcol.getThreshold());
6329 col.setColourByLabel(fcol.isColourByLabel());
6330 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6331 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6332 : ThresholdType.NONE));
6333 if (fcol.isColourByAttribute())
6335 final String[] attName = fcol.getAttributeName();
6336 col.getAttributeName().add(attName[0]);
6337 if (attName.length > 1)
6339 col.getAttributeName().add(attName[1]);
6342 Color noColour = fcol.getNoColour();
6343 if (noColour == null)
6345 col.setNoValueColour(NoValueColour.NONE);
6347 else if (noColour == fcol.getMaxColour())
6349 col.setNoValueColour(NoValueColour.MAX);
6353 col.setNoValueColour(NoValueColour.MIN);
6356 col.setName(featureType);
6361 * Populates an XML model of the feature filter(s) for one feature type
6363 * @param firstMatcher
6364 * the first (or only) match condition)
6366 * remaining match conditions (if any)
6368 * if true, conditions are and-ed, else or-ed
6370 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6371 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6374 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6376 if (filters.hasNext())
6381 CompoundMatcher compound = new CompoundMatcher();
6382 compound.setAnd(and);
6383 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6384 firstMatcher, Collections.emptyIterator(), and);
6385 // compound.addMatcherSet(matcher1);
6386 compound.getMatcherSet().add(matcher1);
6387 FeatureMatcherI nextMatcher = filters.next();
6388 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6389 nextMatcher, filters, and);
6390 // compound.addMatcherSet(matcher2);
6391 compound.getMatcherSet().add(matcher2);
6392 result.setCompoundMatcher(compound);
6397 * single condition matcher
6399 // MatchCondition matcherModel = new MatchCondition();
6400 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6401 matcherModel.setCondition(
6402 firstMatcher.getMatcher().getCondition().getStableName());
6403 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6404 if (firstMatcher.isByAttribute())
6406 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6407 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6408 String[] attName = firstMatcher.getAttribute();
6409 matcherModel.getAttributeName().add(attName[0]); // attribute
6410 if (attName.length > 1)
6412 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6415 else if (firstMatcher.isByLabel())
6417 matcherModel.setBy(FilterBy.BY_LABEL);
6419 else if (firstMatcher.isByScore())
6421 matcherModel.setBy(FilterBy.BY_SCORE);
6423 result.setMatchCondition(matcherModel);
6430 * Loads one XML model of a feature filter to a Jalview object
6432 * @param featureType
6433 * @param matcherSetModel
6436 public static FeatureMatcherSetI parseFilter(
6438 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6440 FeatureMatcherSetI result = new FeatureMatcherSet();
6443 parseFilterConditions(result, matcherSetModel, true);
6444 } catch (IllegalStateException e)
6446 // mixing AND and OR conditions perhaps
6448 String.format("Error reading filter conditions for '%s': %s",
6449 featureType, e.getMessage()));
6450 // return as much as was parsed up to the error
6457 * Adds feature match conditions to matcherSet as unmarshalled from XML
6458 * (possibly recursively for compound conditions)
6461 * @param matcherSetModel
6463 * if true, multiple conditions are AND-ed, else they are OR-ed
6464 * @throws IllegalStateException
6465 * if AND and OR conditions are mixed
6467 protected static void parseFilterConditions(
6468 FeatureMatcherSetI matcherSet,
6469 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6472 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6473 .getMatchCondition();
6479 FilterBy filterBy = mc.getBy();
6480 Condition cond = Condition.fromString(mc.getCondition());
6481 String pattern = mc.getValue();
6482 FeatureMatcherI matchCondition = null;
6483 if (filterBy == FilterBy.BY_LABEL)
6485 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6487 else if (filterBy == FilterBy.BY_SCORE)
6489 matchCondition = FeatureMatcher.byScore(cond, pattern);
6492 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6494 final List<String> attributeName = mc.getAttributeName();
6495 String[] attNames = attributeName
6496 .toArray(new String[attributeName.size()]);
6497 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6502 * note this throws IllegalStateException if AND-ing to a
6503 * previously OR-ed compound condition, or vice versa
6507 matcherSet.and(matchCondition);
6511 matcherSet.or(matchCondition);
6517 * compound condition
6519 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6520 .getCompoundMatcher().getMatcherSet();
6521 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6522 if (matchers.size() == 2)
6524 parseFilterConditions(matcherSet, matchers.get(0), anded);
6525 parseFilterConditions(matcherSet, matchers.get(1), anded);
6529 System.err.println("Malformed compound filter condition");
6535 * Loads one XML model of a feature colour to a Jalview object
6537 * @param colourModel
6540 public static FeatureColourI parseColour(Colour colourModel)
6542 FeatureColourI colour = null;
6544 if (colourModel.getMax() != null)
6546 Color mincol = null;
6547 Color maxcol = null;
6548 Color noValueColour = null;
6552 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6553 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6554 } catch (Exception e)
6556 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6559 NoValueColour noCol = colourModel.getNoValueColour();
6560 if (noCol == NoValueColour.MIN)
6562 noValueColour = mincol;
6564 else if (noCol == NoValueColour.MAX)
6566 noValueColour = maxcol;
6569 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6570 safeFloat(colourModel.getMin()),
6571 safeFloat(colourModel.getMax()));
6572 final List<String> attributeName = colourModel.getAttributeName();
6573 String[] attributes = attributeName
6574 .toArray(new String[attributeName.size()]);
6575 if (attributes != null && attributes.length > 0)
6577 colour.setAttributeName(attributes);
6579 if (colourModel.isAutoScale() != null)
6581 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6583 if (colourModel.isColourByLabel() != null)
6585 colour.setColourByLabel(
6586 colourModel.isColourByLabel().booleanValue());
6588 if (colourModel.getThreshold() != null)
6590 colour.setThreshold(colourModel.getThreshold().floatValue());
6592 ThresholdType ttyp = colourModel.getThreshType();
6593 if (ttyp == ThresholdType.ABOVE)
6595 colour.setAboveThreshold(true);
6597 else if (ttyp == ThresholdType.BELOW)
6599 colour.setBelowThreshold(true);
6604 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6605 colour = new FeatureColour(color);