2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Enumeration;
49 import java.util.GregorianCalendar;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Hashtable;
53 import java.util.IdentityHashMap;
54 import java.util.Iterator;
55 import java.util.LinkedHashMap;
56 import java.util.List;
57 import java.util.Locale;
59 import java.util.Map.Entry;
61 import java.util.Vector;
62 import java.util.jar.JarEntry;
63 import java.util.jar.JarInputStream;
64 import java.util.jar.JarOutputStream;
66 import javax.swing.JInternalFrame;
67 import javax.swing.SwingUtilities;
68 import javax.xml.bind.JAXBContext;
69 import javax.xml.bind.JAXBElement;
70 import javax.xml.bind.Marshaller;
71 import javax.xml.datatype.DatatypeConfigurationException;
72 import javax.xml.datatype.DatatypeFactory;
73 import javax.xml.datatype.XMLGregorianCalendar;
74 import javax.xml.stream.XMLInputFactory;
75 import javax.xml.stream.XMLStreamReader;
77 import jalview.analysis.Conservation;
78 import jalview.analysis.PCA;
79 import jalview.analysis.scoremodels.ScoreModels;
80 import jalview.analysis.scoremodels.SimilarityParams;
81 import jalview.api.FeatureColourI;
82 import jalview.api.ViewStyleI;
83 import jalview.api.analysis.ScoreModelI;
84 import jalview.api.analysis.SimilarityParamsI;
85 import jalview.api.structures.JalviewStructureDisplayI;
86 import jalview.bin.Cache;
87 import jalview.bin.Console;
88 import jalview.datamodel.AlignedCodonFrame;
89 import jalview.datamodel.Alignment;
90 import jalview.datamodel.AlignmentAnnotation;
91 import jalview.datamodel.AlignmentI;
92 import jalview.datamodel.DBRefEntry;
93 import jalview.datamodel.GeneLocus;
94 import jalview.datamodel.GraphLine;
95 import jalview.datamodel.PDBEntry;
96 import jalview.datamodel.Point;
97 import jalview.datamodel.RnaViewerModel;
98 import jalview.datamodel.SequenceFeature;
99 import jalview.datamodel.SequenceGroup;
100 import jalview.datamodel.SequenceI;
101 import jalview.datamodel.StructureViewerModel;
102 import jalview.datamodel.StructureViewerModel.StructureData;
103 import jalview.datamodel.features.FeatureMatcher;
104 import jalview.datamodel.features.FeatureMatcherI;
105 import jalview.datamodel.features.FeatureMatcherSet;
106 import jalview.datamodel.features.FeatureMatcherSetI;
107 import jalview.ext.varna.RnaModel;
108 import jalview.gui.AlignFrame;
109 import jalview.gui.AlignViewport;
110 import jalview.gui.AlignmentPanel;
111 import jalview.gui.AppVarna;
112 import jalview.gui.Desktop;
113 import jalview.gui.JvOptionPane;
114 import jalview.gui.OOMWarning;
115 import jalview.gui.OverviewPanel;
116 import jalview.gui.PCAPanel;
117 import jalview.gui.PaintRefresher;
118 import jalview.gui.SplitFrame;
119 import jalview.gui.StructureViewer;
120 import jalview.gui.StructureViewer.ViewerType;
121 import jalview.gui.StructureViewerBase;
122 import jalview.gui.TreePanel;
123 import jalview.io.BackupFiles;
124 import jalview.io.DataSourceType;
125 import jalview.io.FileFormat;
126 import jalview.io.NewickFile;
127 import jalview.math.Matrix;
128 import jalview.math.MatrixI;
129 import jalview.renderer.ResidueShaderI;
130 import jalview.schemes.AnnotationColourGradient;
131 import jalview.schemes.ColourSchemeI;
132 import jalview.schemes.ColourSchemeProperty;
133 import jalview.schemes.FeatureColour;
134 import jalview.schemes.ResidueProperties;
135 import jalview.schemes.UserColourScheme;
136 import jalview.structure.StructureSelectionManager;
137 import jalview.structures.models.AAStructureBindingModel;
138 import jalview.util.Format;
139 import jalview.util.HttpUtils;
140 import jalview.util.MessageManager;
141 import jalview.util.Platform;
142 import jalview.util.StringUtils;
143 import jalview.util.jarInputStreamProvider;
144 import jalview.util.matcher.Condition;
145 import jalview.viewmodel.AlignmentViewport;
146 import jalview.viewmodel.PCAModel;
147 import jalview.viewmodel.ViewportRanges;
148 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
149 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
150 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
151 import jalview.ws.jws2.Jws2Discoverer;
152 import jalview.ws.jws2.dm.AAConSettings;
153 import jalview.ws.jws2.jabaws2.Jws2Instance;
154 import jalview.ws.params.ArgumentI;
155 import jalview.ws.params.AutoCalcSetting;
156 import jalview.ws.params.WsParamSetI;
157 import jalview.xml.binding.jalview.AlcodonFrame;
158 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
159 import jalview.xml.binding.jalview.Annotation;
160 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
161 import jalview.xml.binding.jalview.AnnotationColourScheme;
162 import jalview.xml.binding.jalview.AnnotationElement;
163 import jalview.xml.binding.jalview.DoubleMatrix;
164 import jalview.xml.binding.jalview.DoubleVector;
165 import jalview.xml.binding.jalview.Feature;
166 import jalview.xml.binding.jalview.Feature.OtherData;
167 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
168 import jalview.xml.binding.jalview.FilterBy;
169 import jalview.xml.binding.jalview.JalviewModel;
170 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
171 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
172 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
173 import jalview.xml.binding.jalview.JalviewModel.JGroup;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
176 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
177 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
178 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
181 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
182 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
183 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
184 import jalview.xml.binding.jalview.JalviewModel.Tree;
185 import jalview.xml.binding.jalview.JalviewModel.UserColours;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport;
187 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
188 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
189 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
190 import jalview.xml.binding.jalview.JalviewUserColours;
191 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
192 import jalview.xml.binding.jalview.MapListType.MapListFrom;
193 import jalview.xml.binding.jalview.MapListType.MapListTo;
194 import jalview.xml.binding.jalview.Mapping;
195 import jalview.xml.binding.jalview.NoValueColour;
196 import jalview.xml.binding.jalview.ObjectFactory;
197 import jalview.xml.binding.jalview.PcaDataType;
198 import jalview.xml.binding.jalview.Pdbentry.Property;
199 import jalview.xml.binding.jalview.Sequence;
200 import jalview.xml.binding.jalview.Sequence.DBRef;
201 import jalview.xml.binding.jalview.SequenceSet;
202 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
203 import jalview.xml.binding.jalview.ThresholdType;
204 import jalview.xml.binding.jalview.VAMSAS;
207 * Write out the current jalview desktop state as a Jalview XML stream.
209 * Note: the vamsas objects referred to here are primitive versions of the
210 * VAMSAS project schema elements - they are not the same and most likely never
214 * @version $Revision: 1.134 $
216 public class Jalview2XML
219 // BH 2018 we add the .jvp binary extension to J2S so that
220 // it will declare that binary when we do the file save from the browser
224 Platform.addJ2SBinaryType(".jvp?");
227 private static final String VIEWER_PREFIX = "viewer_";
229 private static final String RNA_PREFIX = "rna_";
231 private static final String UTF_8 = "UTF-8";
234 * used in decision if quit confirmation should be issued
236 private static boolean stateSavedUpToDate = false;
239 * prefix for recovering datasets for alignments with multiple views where
240 * non-existent dataset IDs were written for some views
242 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
244 // use this with nextCounter() to make unique names for entities
245 private int counter = 0;
248 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
249 * of sequence objects are created.
251 IdentityHashMap<SequenceI, String> seqsToIds = null;
254 * jalview XML Sequence ID to jalview sequence object reference (both dataset
255 * and alignment sequences. Populated as XML reps of sequence objects are
258 Map<String, SequenceI> seqRefIds = null;
260 Map<String, SequenceI> incompleteSeqs = null;
262 List<SeqFref> frefedSequence = null;
264 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
267 * Map of reconstructed AlignFrame objects that appear to have come from
268 * SplitFrame objects (have a dna/protein complement view).
270 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
273 * Map from displayed rna structure models to their saved session state jar
276 private Map<RnaModel, String> rnaSessions = new HashMap<>();
279 * A helper method for safely using the value of an optional attribute that
280 * may be null if not present in the XML. Answers the boolean value, or false
286 public static boolean safeBoolean(Boolean b)
288 return b == null ? false : b.booleanValue();
292 * A helper method for safely using the value of an optional attribute that
293 * may be null if not present in the XML. Answers the integer value, or zero
299 public static int safeInt(Integer i)
301 return i == null ? 0 : i.intValue();
305 * A helper method for safely using the value of an optional attribute that
306 * may be null if not present in the XML. Answers the float value, or zero if
312 public static float safeFloat(Float f)
314 return f == null ? 0f : f.floatValue();
318 * create/return unique hash string for sq
321 * @return new or existing unique string for sq
323 String seqHash(SequenceI sq)
325 if (seqsToIds == null)
329 if (seqsToIds.containsKey(sq))
331 return seqsToIds.get(sq);
335 // create sequential key
336 String key = "sq" + (seqsToIds.size() + 1);
337 key = makeHashCode(sq, key); // check we don't have an external reference
339 seqsToIds.put(sq, key);
346 if (seqsToIds == null)
348 seqsToIds = new IdentityHashMap<>();
350 if (seqRefIds == null)
352 seqRefIds = new HashMap<>();
354 if (incompleteSeqs == null)
356 incompleteSeqs = new HashMap<>();
358 if (frefedSequence == null)
360 frefedSequence = new ArrayList<>();
368 public Jalview2XML(boolean raiseGUI)
370 this.raiseGUI = raiseGUI;
374 * base class for resolving forward references to sequences by their ID
379 abstract class SeqFref
385 public SeqFref(String _sref, String type)
391 public String getSref()
396 public SequenceI getSrefSeq()
398 return seqRefIds.get(sref);
401 public boolean isResolvable()
403 return seqRefIds.get(sref) != null;
406 public SequenceI getSrefDatasetSeq()
408 SequenceI sq = seqRefIds.get(sref);
411 while (sq.getDatasetSequence() != null)
413 sq = sq.getDatasetSequence();
420 * @return true if the forward reference was fully resolved
422 abstract boolean resolve();
425 public String toString()
427 return type + " reference to " + sref;
432 * create forward reference for a mapping
438 public SeqFref newMappingRef(final String sref,
439 final jalview.datamodel.Mapping _jmap)
441 SeqFref fref = new SeqFref(sref, "Mapping")
443 public jalview.datamodel.Mapping jmap = _jmap;
448 SequenceI seq = getSrefDatasetSeq();
460 public SeqFref newAlcodMapRef(final String sref,
461 final AlignedCodonFrame _cf,
462 final jalview.datamodel.Mapping _jmap)
465 SeqFref fref = new SeqFref(sref, "Codon Frame")
467 AlignedCodonFrame cf = _cf;
469 public jalview.datamodel.Mapping mp = _jmap;
472 public boolean isResolvable()
474 return super.isResolvable() && mp.getTo() != null;
480 SequenceI seq = getSrefDatasetSeq();
485 cf.addMap(seq, mp.getTo(), mp.getMap());
492 public void resolveFrefedSequences()
494 Iterator<SeqFref> nextFref = frefedSequence.iterator();
495 int toresolve = frefedSequence.size();
496 int unresolved = 0, failedtoresolve = 0;
497 while (nextFref.hasNext())
499 SeqFref ref = nextFref.next();
500 if (ref.isResolvable())
512 } catch (Exception x)
515 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
528 System.err.println("Jalview Project Import: There were " + unresolved
529 + " forward references left unresolved on the stack.");
531 if (failedtoresolve > 0)
533 System.err.println("SERIOUS! " + failedtoresolve
534 + " resolvable forward references failed to resolve.");
536 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
539 "Jalview Project Import: There are " + incompleteSeqs.size()
540 + " sequences which may have incomplete metadata.");
541 if (incompleteSeqs.size() < 10)
543 for (SequenceI s : incompleteSeqs.values())
545 System.err.println(s.toString());
551 "Too many to report. Skipping output of incomplete sequences.");
557 * This maintains a map of viewports, the key being the seqSetId. Important to
558 * set historyItem and redoList for multiple views
560 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
562 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
564 String uniqueSetSuffix = "";
567 * List of pdbfiles added to Jar
569 List<String> pdbfiles = null;
571 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
572 public void saveState(File statefile)
574 FileOutputStream fos = null;
579 fos = new FileOutputStream(statefile);
581 JarOutputStream jout = new JarOutputStream(fos);
585 } catch (Exception e)
587 Console.error("Couln't write Jalview state to " + statefile, e);
588 // TODO: inform user of the problem - they need to know if their data was
590 if (errorMessage == null)
592 errorMessage = "Did't write Jalview Archive to output file '"
593 + statefile + "' - See console error log for details";
597 errorMessage += "(Didn't write Jalview Archive to output file '"
608 } catch (IOException e)
618 * Writes a jalview project archive to the given Jar output stream.
622 public void saveState(JarOutputStream jout)
624 AlignFrame[] frames = Desktop.getAlignFrames();
626 setStateSavedUpToDate(true);
628 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
630 int n = debugDelaySave;
634 Console.debug("***** debugging save sleep " + i + "/" + n);
638 } catch (InterruptedException e)
640 // TODO Auto-generated catch block
651 saveAllFrames(Arrays.asList(frames), jout);
655 * core method for storing state for a set of AlignFrames.
658 * - frames involving all data to be exported (including containing
661 * - project output stream
663 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
665 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
668 * ensure cached data is clear before starting
670 // todo tidy up seqRefIds, seqsToIds initialisation / reset
672 splitFrameCandidates.clear();
677 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
678 // //////////////////////////////////////////////////
680 List<String> shortNames = new ArrayList<>();
681 List<String> viewIds = new ArrayList<>();
684 for (int i = frames.size() - 1; i > -1; i--)
686 AlignFrame af = frames.get(i);
688 if (skipList != null && skipList
689 .containsKey(af.getViewport().getSequenceSetId()))
694 String shortName = makeFilename(af, shortNames);
696 int apSize = af.getAlignPanels().size();
698 for (int ap = 0; ap < apSize; ap++)
700 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
702 String fileName = apSize == 1 ? shortName : ap + shortName;
703 if (!fileName.endsWith(".xml"))
705 fileName = fileName + ".xml";
708 saveState(apanel, fileName, jout, viewIds);
710 String dssid = getDatasetIdRef(
711 af.getViewport().getAlignment().getDataset());
712 if (!dsses.containsKey(dssid))
714 dsses.put(dssid, af);
719 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
725 } catch (Exception foo)
729 } catch (Exception ex)
731 // TODO: inform user of the problem - they need to know if their data was
733 if (errorMessage == null)
735 errorMessage = "Couldn't write Jalview Archive - see error output for details";
737 ex.printStackTrace();
742 * Generates a distinct file name, based on the title of the AlignFrame, by
743 * appending _n for increasing n until an unused name is generated. The new
744 * name (without its extension) is added to the list.
748 * @return the generated name, with .xml extension
750 protected String makeFilename(AlignFrame af, List<String> namesUsed)
752 String shortName = af.getTitle();
754 if (shortName.indexOf(File.separatorChar) > -1)
756 shortName = shortName
757 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
762 while (namesUsed.contains(shortName))
764 if (shortName.endsWith("_" + (count - 1)))
766 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
769 shortName = shortName.concat("_" + count);
773 namesUsed.add(shortName);
775 if (!shortName.endsWith(".xml"))
777 shortName = shortName + ".xml";
782 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
783 public boolean saveAlignment(AlignFrame af, String jarFile,
788 // create backupfiles object and get new temp filename destination
789 boolean doBackup = BackupFiles.getEnabled();
790 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
791 FileOutputStream fos = new FileOutputStream(
792 doBackup ? backupfiles.getTempFilePath() : jarFile);
794 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
796 int n = debugDelaySave;
800 Console.debug("***** debugging save sleep " + i + "/" + n);
804 } catch (InterruptedException e)
806 // TODO Auto-generated catch block
813 JarOutputStream jout = new JarOutputStream(fos);
814 List<AlignFrame> frames = new ArrayList<>();
816 // resolve splitframes
817 if (af.getViewport().getCodingComplement() != null)
819 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
825 saveAllFrames(frames, jout);
829 } catch (Exception foo)
833 boolean success = true;
837 backupfiles.setWriteSuccess(success);
838 success = backupfiles.rollBackupsAndRenameTempFile();
842 } catch (Exception ex)
844 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
845 ex.printStackTrace();
850 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
851 String fileName, JarOutputStream jout)
854 for (String dssids : dsses.keySet())
856 AlignFrame _af = dsses.get(dssids);
857 String jfileName = fileName + " Dataset for " + _af.getTitle();
858 if (!jfileName.endsWith(".xml"))
860 jfileName = jfileName + ".xml";
862 saveState(_af.alignPanel, jfileName, true, jout, null);
867 * create a JalviewModel from an alignment view and marshall it to a
871 * panel to create jalview model for
873 * name of alignment panel written to output stream
880 public JalviewModel saveState(AlignmentPanel ap, String fileName,
881 JarOutputStream jout, List<String> viewIds)
883 return saveState(ap, fileName, false, jout, viewIds);
887 * create a JalviewModel from an alignment view and marshall it to a
891 * panel to create jalview model for
893 * name of alignment panel written to output stream
895 * when true, only write the dataset for the alignment, not the data
896 * associated with the view.
902 public JalviewModel saveState(AlignmentPanel ap, String fileName,
903 boolean storeDS, JarOutputStream jout, List<String> viewIds)
907 viewIds = new ArrayList<>();
912 List<UserColourScheme> userColours = new ArrayList<>();
914 AlignViewport av = ap.av;
915 ViewportRanges vpRanges = av.getRanges();
917 final ObjectFactory objectFactory = new ObjectFactory();
918 JalviewModel object = objectFactory.createJalviewModel();
919 object.setVamsasModel(new VAMSAS());
921 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
924 GregorianCalendar c = new GregorianCalendar();
925 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
926 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
927 object.setCreationDate(now);
928 } catch (DatatypeConfigurationException e)
930 System.err.println("error writing date: " + e.toString());
932 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
935 * rjal is full height alignment, jal is actual alignment with full metadata
936 * but excludes hidden sequences.
938 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
940 if (av.hasHiddenRows())
942 rjal = jal.getHiddenSequences().getFullAlignment();
945 SequenceSet vamsasSet = new SequenceSet();
947 // JalviewModelSequence jms = new JalviewModelSequence();
949 vamsasSet.setGapChar(jal.getGapCharacter() + "");
951 if (jal.getDataset() != null)
953 // dataset id is the dataset's hashcode
954 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
957 // switch jal and the dataset
958 jal = jal.getDataset();
962 if (jal.getProperties() != null)
964 Enumeration en = jal.getProperties().keys();
965 while (en.hasMoreElements())
967 String key = en.nextElement().toString();
968 SequenceSetProperties ssp = new SequenceSetProperties();
970 ssp.setValue(jal.getProperties().get(key).toString());
971 // vamsasSet.addSequenceSetProperties(ssp);
972 vamsasSet.getSequenceSetProperties().add(ssp);
977 Set<String> calcIdSet = new HashSet<>();
978 // record the set of vamsas sequence XML POJO we create.
979 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
981 for (final SequenceI jds : rjal.getSequences())
983 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
984 : jds.getDatasetSequence();
985 String id = seqHash(jds);
986 if (vamsasSetIds.get(id) == null)
988 if (seqRefIds.get(id) != null && !storeDS)
990 // This happens for two reasons: 1. multiple views are being
992 // 2. the hashCode has collided with another sequence's code. This
994 // HAPPEN! (PF00072.15.stk does this)
995 // JBPNote: Uncomment to debug writing out of files that do not read
996 // back in due to ArrayOutOfBoundExceptions.
997 // System.err.println("vamsasSeq backref: "+id+"");
998 // System.err.println(jds.getName()+"
999 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1000 // System.err.println("Hashcode: "+seqHash(jds));
1001 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1002 // System.err.println(rsq.getName()+"
1003 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1004 // System.err.println("Hashcode: "+seqHash(rsq));
1008 vamsasSeq = createVamsasSequence(id, jds);
1009 // vamsasSet.addSequence(vamsasSeq);
1010 vamsasSet.getSequence().add(vamsasSeq);
1011 vamsasSetIds.put(id, vamsasSeq);
1012 seqRefIds.put(id, jds);
1016 jseq.setStart(jds.getStart());
1017 jseq.setEnd(jds.getEnd());
1018 jseq.setColour(av.getSequenceColour(jds).getRGB());
1020 jseq.setId(id); // jseq id should be a string not a number
1023 // Store any sequences this sequence represents
1024 if (av.hasHiddenRows())
1026 // use rjal, contains the full height alignment
1028 av.getAlignment().getHiddenSequences().isHidden(jds));
1030 if (av.isHiddenRepSequence(jds))
1032 jalview.datamodel.SequenceI[] reps = av
1033 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1035 for (int h = 0; h < reps.length; h++)
1039 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1040 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1045 // mark sequence as reference - if it is the reference for this view
1046 if (jal.hasSeqrep())
1048 jseq.setViewreference(jds == jal.getSeqrep());
1052 // TODO: omit sequence features from each alignment view's XML dump if we
1053 // are storing dataset
1054 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1055 for (SequenceFeature sf : sfs)
1057 // Features features = new Features();
1058 Feature features = new Feature();
1060 features.setBegin(sf.getBegin());
1061 features.setEnd(sf.getEnd());
1062 features.setDescription(sf.getDescription());
1063 features.setType(sf.getType());
1064 features.setFeatureGroup(sf.getFeatureGroup());
1065 features.setScore(sf.getScore());
1066 if (sf.links != null)
1068 for (int l = 0; l < sf.links.size(); l++)
1070 OtherData keyValue = new OtherData();
1071 keyValue.setKey("LINK_" + l);
1072 keyValue.setValue(sf.links.elementAt(l).toString());
1073 // features.addOtherData(keyValue);
1074 features.getOtherData().add(keyValue);
1077 if (sf.otherDetails != null)
1080 * save feature attributes, which may be simple strings or
1081 * map valued (have sub-attributes)
1083 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1085 String key = entry.getKey();
1086 Object value = entry.getValue();
1087 if (value instanceof Map<?, ?>)
1089 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1092 OtherData otherData = new OtherData();
1093 otherData.setKey(key);
1094 otherData.setKey2(subAttribute.getKey());
1095 otherData.setValue(subAttribute.getValue().toString());
1096 // features.addOtherData(otherData);
1097 features.getOtherData().add(otherData);
1102 OtherData otherData = new OtherData();
1103 otherData.setKey(key);
1104 otherData.setValue(value.toString());
1105 // features.addOtherData(otherData);
1106 features.getOtherData().add(otherData);
1111 // jseq.addFeatures(features);
1112 jseq.getFeatures().add(features);
1115 if (jdatasq.getAllPDBEntries() != null)
1117 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1118 while (en.hasMoreElements())
1120 Pdbids pdb = new Pdbids();
1121 jalview.datamodel.PDBEntry entry = en.nextElement();
1123 String pdbId = entry.getId();
1125 pdb.setType(entry.getType());
1128 * Store any structure views associated with this sequence. This
1129 * section copes with duplicate entries in the project, so a dataset
1130 * only view *should* be coped with sensibly.
1132 // This must have been loaded, is it still visible?
1133 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1134 String matchedFile = null;
1135 for (int f = frames.length - 1; f > -1; f--)
1137 if (frames[f] instanceof StructureViewerBase)
1139 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1140 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1141 viewIds, matchedFile, viewFrame);
1143 * Only store each structure viewer's state once in the project
1144 * jar. First time through only (storeDS==false)
1146 String viewId = viewFrame.getViewId();
1147 String viewerType = viewFrame.getViewerType().toString();
1148 if (!storeDS && !viewIds.contains(viewId))
1150 viewIds.add(viewId);
1151 File viewerState = viewFrame.saveSession();
1152 if (viewerState != null)
1154 copyFileToJar(jout, viewerState.getPath(),
1155 getViewerJarEntryName(viewId), viewerType);
1160 "Failed to save viewer state for " + viewerType);
1166 if (matchedFile != null || entry.getFile() != null)
1168 if (entry.getFile() != null)
1171 matchedFile = entry.getFile();
1173 pdb.setFile(matchedFile); // entry.getFile());
1174 if (pdbfiles == null)
1176 pdbfiles = new ArrayList<>();
1179 if (!pdbfiles.contains(pdbId))
1181 pdbfiles.add(pdbId);
1182 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1186 Enumeration<String> props = entry.getProperties();
1187 if (props.hasMoreElements())
1189 // PdbentryItem item = new PdbentryItem();
1190 while (props.hasMoreElements())
1192 Property prop = new Property();
1193 String key = props.nextElement();
1195 prop.setValue(entry.getProperty(key).toString());
1196 // item.addProperty(prop);
1197 pdb.getProperty().add(prop);
1199 // pdb.addPdbentryItem(item);
1202 // jseq.addPdbids(pdb);
1203 jseq.getPdbids().add(pdb);
1207 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1209 // jms.addJSeq(jseq);
1210 object.getJSeq().add(jseq);
1213 if (!storeDS && av.hasHiddenRows())
1215 jal = av.getAlignment();
1219 if (storeDS && jal.getCodonFrames() != null)
1221 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1222 for (AlignedCodonFrame acf : jac)
1224 AlcodonFrame alc = new AlcodonFrame();
1225 if (acf.getProtMappings() != null
1226 && acf.getProtMappings().length > 0)
1228 boolean hasMap = false;
1229 SequenceI[] dnas = acf.getdnaSeqs();
1230 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1231 for (int m = 0; m < pmaps.length; m++)
1233 AlcodMap alcmap = new AlcodMap();
1234 alcmap.setDnasq(seqHash(dnas[m]));
1236 createVamsasMapping(pmaps[m], dnas[m], null, false));
1237 // alc.addAlcodMap(alcmap);
1238 alc.getAlcodMap().add(alcmap);
1243 // vamsasSet.addAlcodonFrame(alc);
1244 vamsasSet.getAlcodonFrame().add(alc);
1247 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1249 // AlcodonFrame alc = new AlcodonFrame();
1250 // vamsasSet.addAlcodonFrame(alc);
1251 // for (int p = 0; p < acf.aaWidth; p++)
1253 // Alcodon cmap = new Alcodon();
1254 // if (acf.codons[p] != null)
1256 // // Null codons indicate a gapped column in the translated peptide
1258 // cmap.setPos1(acf.codons[p][0]);
1259 // cmap.setPos2(acf.codons[p][1]);
1260 // cmap.setPos3(acf.codons[p][2]);
1262 // alc.addAlcodon(cmap);
1264 // if (acf.getProtMappings() != null
1265 // && acf.getProtMappings().length > 0)
1267 // SequenceI[] dnas = acf.getdnaSeqs();
1268 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1269 // for (int m = 0; m < pmaps.length; m++)
1271 // AlcodMap alcmap = new AlcodMap();
1272 // alcmap.setDnasq(seqHash(dnas[m]));
1273 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1275 // alc.addAlcodMap(alcmap);
1282 // /////////////////////////////////
1283 if (!storeDS && av.getCurrentTree() != null)
1285 // FIND ANY ASSOCIATED TREES
1286 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1287 if (Desktop.desktop != null)
1289 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1291 for (int t = 0; t < frames.length; t++)
1293 if (frames[t] instanceof TreePanel)
1295 TreePanel tp = (TreePanel) frames[t];
1297 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1299 JalviewModel.Tree tree = new JalviewModel.Tree();
1300 tree.setTitle(tp.getTitle());
1301 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1302 tree.setNewick(tp.getTree().print());
1303 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1305 tree.setFitToWindow(tp.fitToWindow.getState());
1306 tree.setFontName(tp.getTreeFont().getName());
1307 tree.setFontSize(tp.getTreeFont().getSize());
1308 tree.setFontStyle(tp.getTreeFont().getStyle());
1309 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1311 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1312 tree.setShowDistances(tp.distanceMenu.getState());
1314 tree.setHeight(tp.getHeight());
1315 tree.setWidth(tp.getWidth());
1316 tree.setXpos(tp.getX());
1317 tree.setYpos(tp.getY());
1318 tree.setId(makeHashCode(tp, null));
1319 tree.setLinkToAllViews(
1320 tp.getTreeCanvas().isApplyToAllViews());
1322 // jms.addTree(tree);
1323 object.getTree().add(tree);
1333 if (!storeDS && Desktop.desktop != null)
1335 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1337 if (frame instanceof PCAPanel)
1339 PCAPanel panel = (PCAPanel) frame;
1340 if (panel.getAlignViewport().getAlignment() == jal)
1342 savePCA(panel, object);
1350 * store forward refs from an annotationRow to any groups
1352 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1355 for (SequenceI sq : jal.getSequences())
1357 // Store annotation on dataset sequences only
1358 AlignmentAnnotation[] aa = sq.getAnnotation();
1359 if (aa != null && aa.length > 0)
1361 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1368 if (jal.getAlignmentAnnotation() != null)
1370 // Store the annotation shown on the alignment.
1371 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1372 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1377 if (jal.getGroups() != null)
1379 JGroup[] groups = new JGroup[jal.getGroups().size()];
1381 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1383 JGroup jGroup = new JGroup();
1384 groups[++i] = jGroup;
1386 jGroup.setStart(sg.getStartRes());
1387 jGroup.setEnd(sg.getEndRes());
1388 jGroup.setName(sg.getName());
1389 if (groupRefs.containsKey(sg))
1391 // group has references so set its ID field
1392 jGroup.setId(groupRefs.get(sg));
1394 ColourSchemeI colourScheme = sg.getColourScheme();
1395 if (colourScheme != null)
1397 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1398 if (groupColourScheme.conservationApplied())
1400 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1402 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1404 jGroup.setColour(setUserColourScheme(colourScheme,
1405 userColours, object));
1409 jGroup.setColour(colourScheme.getSchemeName());
1412 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1414 jGroup.setColour("AnnotationColourGradient");
1415 jGroup.setAnnotationColours(constructAnnotationColours(
1416 (jalview.schemes.AnnotationColourGradient) colourScheme,
1417 userColours, object));
1419 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1422 setUserColourScheme(colourScheme, userColours, object));
1426 jGroup.setColour(colourScheme.getSchemeName());
1429 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1432 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1433 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1434 jGroup.setDisplayText(sg.getDisplayText());
1435 jGroup.setColourText(sg.getColourText());
1436 jGroup.setTextCol1(sg.textColour.getRGB());
1437 jGroup.setTextCol2(sg.textColour2.getRGB());
1438 jGroup.setTextColThreshold(sg.thresholdTextColour);
1439 jGroup.setShowUnconserved(sg.getShowNonconserved());
1440 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1441 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1442 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1443 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1444 for (SequenceI seq : sg.getSequences())
1446 // jGroup.addSeq(seqHash(seq));
1447 jGroup.getSeq().add(seqHash(seq));
1451 // jms.setJGroup(groups);
1453 for (JGroup grp : groups)
1455 object.getJGroup().add(grp);
1460 // /////////SAVE VIEWPORT
1461 Viewport view = new Viewport();
1462 view.setTitle(ap.alignFrame.getTitle());
1463 view.setSequenceSetId(
1464 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1465 view.setId(av.getViewId());
1466 if (av.getCodingComplement() != null)
1468 view.setComplementId(av.getCodingComplement().getViewId());
1470 view.setViewName(av.getViewName());
1471 view.setGatheredViews(av.isGatherViewsHere());
1473 Rectangle size = ap.av.getExplodedGeometry();
1474 Rectangle position = size;
1477 size = ap.alignFrame.getBounds();
1478 if (av.getCodingComplement() != null)
1480 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1488 view.setXpos(position.x);
1489 view.setYpos(position.y);
1491 view.setWidth(size.width);
1492 view.setHeight(size.height);
1494 view.setStartRes(vpRanges.getStartRes());
1495 view.setStartSeq(vpRanges.getStartSeq());
1497 OverviewPanel ov = ap.getOverviewPanel();
1500 Overview overview = new Overview();
1501 overview.setTitle(ov.getTitle());
1502 Rectangle bounds = ov.getFrameBounds();
1503 overview.setXpos(bounds.x);
1504 overview.setYpos(bounds.y);
1505 overview.setWidth(bounds.width);
1506 overview.setHeight(bounds.height);
1507 overview.setShowHidden(ov.isShowHiddenRegions());
1508 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1509 overview.setResidueColour(
1510 ov.getCanvas().getResidueColour().getRGB());
1511 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1512 view.setOverview(overview);
1514 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1516 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1517 userColours, object));
1520 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1522 AnnotationColourScheme ac = constructAnnotationColours(
1523 (jalview.schemes.AnnotationColourGradient) av
1524 .getGlobalColourScheme(),
1525 userColours, object);
1527 view.setAnnotationColours(ac);
1528 view.setBgColour("AnnotationColourGradient");
1532 view.setBgColour(ColourSchemeProperty
1533 .getColourName(av.getGlobalColourScheme()));
1536 ResidueShaderI vcs = av.getResidueShading();
1537 ColourSchemeI cs = av.getGlobalColourScheme();
1541 if (vcs.conservationApplied())
1543 view.setConsThreshold(vcs.getConservationInc());
1544 if (cs instanceof jalview.schemes.UserColourScheme)
1546 view.setBgColour(setUserColourScheme(cs, userColours, object));
1549 view.setPidThreshold(vcs.getThreshold());
1552 view.setConservationSelected(av.getConservationSelected());
1553 view.setPidSelected(av.getAbovePIDThreshold());
1554 final Font font = av.getFont();
1555 view.setFontName(font.getName());
1556 view.setFontSize(font.getSize());
1557 view.setFontStyle(font.getStyle());
1558 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1559 view.setRenderGaps(av.isRenderGaps());
1560 view.setShowAnnotation(av.isShowAnnotation());
1561 view.setShowBoxes(av.getShowBoxes());
1562 view.setShowColourText(av.getColourText());
1563 view.setShowFullId(av.getShowJVSuffix());
1564 view.setRightAlignIds(av.isRightAlignIds());
1565 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1566 view.setShowText(av.getShowText());
1567 view.setShowUnconserved(av.getShowUnconserved());
1568 view.setWrapAlignment(av.getWrapAlignment());
1569 view.setTextCol1(av.getTextColour().getRGB());
1570 view.setTextCol2(av.getTextColour2().getRGB());
1571 view.setTextColThreshold(av.getThresholdTextColour());
1572 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1573 view.setShowSequenceLogo(av.isShowSequenceLogo());
1574 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1575 view.setShowGroupConsensus(av.isShowGroupConsensus());
1576 view.setShowGroupConservation(av.isShowGroupConservation());
1577 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1578 view.setShowDbRefTooltip(av.isShowDBRefs());
1579 view.setFollowHighlight(av.isFollowHighlight());
1580 view.setFollowSelection(av.followSelection);
1581 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1582 view.setShowComplementFeatures(av.isShowComplementFeatures());
1583 view.setShowComplementFeaturesOnTop(
1584 av.isShowComplementFeaturesOnTop());
1585 if (av.getFeaturesDisplayed() != null)
1587 FeatureSettings fs = new FeatureSettings();
1589 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1590 .getFeatureRenderer();
1591 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1593 Vector<String> settingsAdded = new Vector<>();
1594 if (renderOrder != null)
1596 for (String featureType : renderOrder)
1598 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1599 setting.setType(featureType);
1602 * save any filter for the feature type
1604 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1607 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1609 FeatureMatcherI firstFilter = filters.next();
1610 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1611 filters, filter.isAnded()));
1615 * save colour scheme for the feature type
1617 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1618 if (!fcol.isSimpleColour())
1620 setting.setColour(fcol.getMaxColour().getRGB());
1621 setting.setMincolour(fcol.getMinColour().getRGB());
1622 setting.setMin(fcol.getMin());
1623 setting.setMax(fcol.getMax());
1624 setting.setColourByLabel(fcol.isColourByLabel());
1625 if (fcol.isColourByAttribute())
1627 String[] attName = fcol.getAttributeName();
1628 setting.getAttributeName().add(attName[0]);
1629 if (attName.length > 1)
1631 setting.getAttributeName().add(attName[1]);
1634 setting.setAutoScale(fcol.isAutoScaled());
1635 setting.setThreshold(fcol.getThreshold());
1636 Color noColour = fcol.getNoColour();
1637 if (noColour == null)
1639 setting.setNoValueColour(NoValueColour.NONE);
1641 else if (noColour.equals(fcol.getMaxColour()))
1643 setting.setNoValueColour(NoValueColour.MAX);
1647 setting.setNoValueColour(NoValueColour.MIN);
1649 // -1 = No threshold, 0 = Below, 1 = Above
1650 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1651 : (fcol.isBelowThreshold() ? 0 : -1));
1655 setting.setColour(fcol.getColour().getRGB());
1659 av.getFeaturesDisplayed().isVisible(featureType));
1660 float rorder = fr.getOrder(featureType);
1663 setting.setOrder(rorder);
1665 /// fs.addSetting(setting);
1666 fs.getSetting().add(setting);
1667 settingsAdded.addElement(featureType);
1671 // is groups actually supposed to be a map here ?
1672 Iterator<String> en = fr.getFeatureGroups().iterator();
1673 Vector<String> groupsAdded = new Vector<>();
1674 while (en.hasNext())
1676 String grp = en.next();
1677 if (groupsAdded.contains(grp))
1681 Group g = new Group();
1683 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1686 fs.getGroup().add(g);
1687 groupsAdded.addElement(grp);
1689 // jms.setFeatureSettings(fs);
1690 object.setFeatureSettings(fs);
1693 if (av.hasHiddenColumns())
1695 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1696 .getHiddenColumns();
1700 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1704 Iterator<int[]> hiddenRegions = hidden.iterator();
1705 while (hiddenRegions.hasNext())
1707 int[] region = hiddenRegions.next();
1708 HiddenColumns hc = new HiddenColumns();
1709 hc.setStart(region[0]);
1710 hc.setEnd(region[1]);
1711 // view.addHiddenColumns(hc);
1712 view.getHiddenColumns().add(hc);
1716 if (calcIdSet.size() > 0)
1718 for (String calcId : calcIdSet)
1720 if (calcId.trim().length() > 0)
1722 CalcIdParam cidp = createCalcIdParam(calcId, av);
1723 // Some calcIds have no parameters.
1726 // view.addCalcIdParam(cidp);
1727 view.getCalcIdParam().add(cidp);
1733 // jms.addViewport(view);
1734 object.getViewport().add(view);
1736 // object.setJalviewModelSequence(jms);
1737 // object.getVamsasModel().addSequenceSet(vamsasSet);
1738 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1740 if (jout != null && fileName != null)
1742 // We may not want to write the object to disk,
1743 // eg we can copy the alignViewport to a new view object
1744 // using save and then load
1747 fileName = fileName.replace('\\', '/');
1748 System.out.println("Writing jar entry " + fileName);
1749 JarEntry entry = new JarEntry(fileName);
1750 jout.putNextEntry(entry);
1751 PrintWriter pout = new PrintWriter(
1752 new OutputStreamWriter(jout, UTF_8));
1753 JAXBContext jaxbContext = JAXBContext
1754 .newInstance(JalviewModel.class);
1755 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1757 // output pretty printed
1758 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1759 jaxbMarshaller.marshal(
1760 new ObjectFactory().createJalviewModel(object), pout);
1762 // jaxbMarshaller.marshal(object, pout);
1763 // marshaller.marshal(object);
1766 } catch (Exception ex)
1768 // TODO: raise error in GUI if marshalling failed.
1769 System.err.println("Error writing Jalview project");
1770 ex.printStackTrace();
1777 * Writes PCA viewer attributes and computed values to an XML model object and
1778 * adds it to the JalviewModel. Any exceptions are reported by logging.
1780 protected void savePCA(PCAPanel panel, JalviewModel object)
1784 PcaViewer viewer = new PcaViewer();
1785 viewer.setHeight(panel.getHeight());
1786 viewer.setWidth(panel.getWidth());
1787 viewer.setXpos(panel.getX());
1788 viewer.setYpos(panel.getY());
1789 viewer.setTitle(panel.getTitle());
1790 PCAModel pcaModel = panel.getPcaModel();
1791 viewer.setScoreModelName(pcaModel.getScoreModelName());
1792 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1793 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1794 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1796 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1797 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1798 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1799 SeqPointMin spmin = new SeqPointMin();
1800 spmin.setXPos(spMin[0]);
1801 spmin.setYPos(spMin[1]);
1802 spmin.setZPos(spMin[2]);
1803 viewer.setSeqPointMin(spmin);
1804 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1805 SeqPointMax spmax = new SeqPointMax();
1806 spmax.setXPos(spMax[0]);
1807 spmax.setYPos(spMax[1]);
1808 spmax.setZPos(spMax[2]);
1809 viewer.setSeqPointMax(spmax);
1810 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1811 viewer.setLinkToAllViews(
1812 panel.getRotatableCanvas().isApplyToAllViews());
1813 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1814 viewer.setIncludeGaps(sp.includeGaps());
1815 viewer.setMatchGaps(sp.matchGaps());
1816 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1817 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1820 * sequence points on display
1822 for (jalview.datamodel.SequencePoint spt : pcaModel
1823 .getSequencePoints())
1825 SequencePoint point = new SequencePoint();
1826 point.setSequenceRef(seqHash(spt.getSequence()));
1827 point.setXPos(spt.coord.x);
1828 point.setYPos(spt.coord.y);
1829 point.setZPos(spt.coord.z);
1830 viewer.getSequencePoint().add(point);
1834 * (end points of) axes on display
1836 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1839 Axis axis = new Axis();
1843 viewer.getAxis().add(axis);
1847 * raw PCA data (note we are not restoring PCA inputs here -
1848 * alignment view, score model, similarity parameters)
1850 PcaDataType data = new PcaDataType();
1851 viewer.setPcaData(data);
1852 PCA pca = pcaModel.getPcaData();
1854 DoubleMatrix pm = new DoubleMatrix();
1855 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1856 data.setPairwiseMatrix(pm);
1858 DoubleMatrix tm = new DoubleMatrix();
1859 saveDoubleMatrix(pca.getTridiagonal(), tm);
1860 data.setTridiagonalMatrix(tm);
1862 DoubleMatrix eigenMatrix = new DoubleMatrix();
1863 data.setEigenMatrix(eigenMatrix);
1864 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1866 object.getPcaViewer().add(viewer);
1867 } catch (Throwable t)
1869 Console.error("Error saving PCA: " + t.getMessage());
1874 * Stores values from a matrix into an XML element, including (if present) the
1879 * @see #loadDoubleMatrix(DoubleMatrix)
1881 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1883 xmlMatrix.setRows(m.height());
1884 xmlMatrix.setColumns(m.width());
1885 for (int i = 0; i < m.height(); i++)
1887 DoubleVector row = new DoubleVector();
1888 for (int j = 0; j < m.width(); j++)
1890 row.getV().add(m.getValue(i, j));
1892 xmlMatrix.getRow().add(row);
1894 if (m.getD() != null)
1896 DoubleVector dVector = new DoubleVector();
1897 for (double d : m.getD())
1899 dVector.getV().add(d);
1901 xmlMatrix.setD(dVector);
1903 if (m.getE() != null)
1905 DoubleVector eVector = new DoubleVector();
1906 for (double e : m.getE())
1908 eVector.getV().add(e);
1910 xmlMatrix.setE(eVector);
1915 * Loads XML matrix data into a new Matrix object, including the D and/or E
1916 * vectors (if present)
1920 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1922 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1924 int rows = mData.getRows();
1925 double[][] vals = new double[rows][];
1927 for (int i = 0; i < rows; i++)
1929 List<Double> dVector = mData.getRow().get(i).getV();
1930 vals[i] = new double[dVector.size()];
1932 for (Double d : dVector)
1938 MatrixI m = new Matrix(vals);
1940 if (mData.getD() != null)
1942 List<Double> dVector = mData.getD().getV();
1943 double[] vec = new double[dVector.size()];
1945 for (Double d : dVector)
1951 if (mData.getE() != null)
1953 List<Double> dVector = mData.getE().getV();
1954 double[] vec = new double[dVector.size()];
1956 for (Double d : dVector)
1967 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1968 * for each viewer, with
1970 * <li>viewer geometry (position, size, split pane divider location)</li>
1971 * <li>index of the selected structure in the viewer (currently shows gapped
1973 * <li>the id of the annotation holding RNA secondary structure</li>
1974 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1976 * Varna viewer state is also written out (in native Varna XML) to separate
1977 * project jar entries. A separate entry is written for each RNA structure
1978 * displayed, with the naming convention
1980 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1988 * @param storeDataset
1990 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1991 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1992 boolean storeDataset)
1994 if (Desktop.desktop == null)
1998 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1999 for (int f = frames.length - 1; f > -1; f--)
2001 if (frames[f] instanceof AppVarna)
2003 AppVarna varna = (AppVarna) frames[f];
2005 * link the sequence to every viewer that is showing it and is linked to
2006 * its alignment panel
2008 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2010 String viewId = varna.getViewId();
2011 RnaViewer rna = new RnaViewer();
2012 rna.setViewId(viewId);
2013 rna.setTitle(varna.getTitle());
2014 rna.setXpos(varna.getX());
2015 rna.setYpos(varna.getY());
2016 rna.setWidth(varna.getWidth());
2017 rna.setHeight(varna.getHeight());
2018 rna.setDividerLocation(varna.getDividerLocation());
2019 rna.setSelectedRna(varna.getSelectedIndex());
2020 // jseq.addRnaViewer(rna);
2021 jseq.getRnaViewer().add(rna);
2024 * Store each Varna panel's state once in the project per sequence.
2025 * First time through only (storeDataset==false)
2027 // boolean storeSessions = false;
2028 // String sequenceViewId = viewId + seqsToIds.get(jds);
2029 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2031 // viewIds.add(sequenceViewId);
2032 // storeSessions = true;
2034 for (RnaModel model : varna.getModels())
2036 if (model.seq == jds)
2039 * VARNA saves each view (sequence or alignment secondary
2040 * structure, gapped or trimmed) as a separate XML file
2042 String jarEntryName = rnaSessions.get(model);
2043 if (jarEntryName == null)
2046 String varnaStateFile = varna.getStateInfo(model.rna);
2047 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2048 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2049 rnaSessions.put(model, jarEntryName);
2051 SecondaryStructure ss = new SecondaryStructure();
2052 String annotationId = varna.getAnnotation(jds).annotationId;
2053 ss.setAnnotationId(annotationId);
2054 ss.setViewerState(jarEntryName);
2055 ss.setGapped(model.gapped);
2056 ss.setTitle(model.title);
2057 // rna.addSecondaryStructure(ss);
2058 rna.getSecondaryStructure().add(ss);
2067 * Copy the contents of a file to a new entry added to the output jar
2071 * @param jarEntryName
2073 * additional identifying info to log to the console
2075 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2076 String jarEntryName, String msg)
2078 try (InputStream is = new FileInputStream(infilePath))
2080 File file = new File(infilePath);
2081 if (file.exists() && jout != null)
2084 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2085 jout.putNextEntry(new JarEntry(jarEntryName));
2088 // dis = new DataInputStream(new FileInputStream(file));
2089 // byte[] data = new byte[(int) file.length()];
2090 // dis.readFully(data);
2091 // writeJarEntry(jout, jarEntryName, data);
2093 } catch (Exception ex)
2095 ex.printStackTrace();
2100 * Copies input to output, in 4K buffers; handles any data (text or binary)
2104 * @throws IOException
2106 protected void copyAll(InputStream in, OutputStream out)
2109 byte[] buffer = new byte[4096];
2111 while ((bytesRead = in.read(buffer)) != -1)
2113 out.write(buffer, 0, bytesRead);
2118 * Save the state of a structure viewer
2123 * the archive XML element under which to save the state
2126 * @param matchedFile
2130 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2131 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2132 String matchedFile, StructureViewerBase viewFrame)
2134 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2137 * Look for any bindings for this viewer to the PDB file of interest
2138 * (including part matches excluding chain id)
2140 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2142 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2143 final String pdbId = pdbentry.getId();
2144 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2145 && entry.getId().toLowerCase(Locale.ROOT)
2146 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2149 * not interested in a binding to a different PDB entry here
2153 if (matchedFile == null)
2155 matchedFile = pdbentry.getFile();
2157 else if (!matchedFile.equals(pdbentry.getFile()))
2160 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2161 + pdbentry.getFile());
2165 // can get at it if the ID
2166 // match is ambiguous (e.g.
2169 for (int smap = 0; smap < viewFrame.getBinding()
2170 .getSequence()[peid].length; smap++)
2172 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2173 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2175 StructureState state = new StructureState();
2176 state.setVisible(true);
2177 state.setXpos(viewFrame.getX());
2178 state.setYpos(viewFrame.getY());
2179 state.setWidth(viewFrame.getWidth());
2180 state.setHeight(viewFrame.getHeight());
2181 final String viewId = viewFrame.getViewId();
2182 state.setViewId(viewId);
2183 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2184 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2185 state.setColourByJmol(viewFrame.isColouredByViewer());
2186 state.setType(viewFrame.getViewerType().toString());
2187 // pdb.addStructureState(state);
2188 pdb.getStructureState().add(state);
2196 * Populates the AnnotationColourScheme xml for save. This captures the
2197 * settings of the options in the 'Colour by Annotation' dialog.
2200 * @param userColours
2204 private AnnotationColourScheme constructAnnotationColours(
2205 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2208 AnnotationColourScheme ac = new AnnotationColourScheme();
2209 ac.setAboveThreshold(acg.getAboveThreshold());
2210 ac.setThreshold(acg.getAnnotationThreshold());
2211 // 2.10.2 save annotationId (unique) not annotation label
2212 ac.setAnnotation(acg.getAnnotation().annotationId);
2213 if (acg.getBaseColour() instanceof UserColourScheme)
2216 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2221 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2224 ac.setMaxColour(acg.getMaxColour().getRGB());
2225 ac.setMinColour(acg.getMinColour().getRGB());
2226 ac.setPerSequence(acg.isSeqAssociated());
2227 ac.setPredefinedColours(acg.isPredefinedColours());
2231 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2232 IdentityHashMap<SequenceGroup, String> groupRefs,
2233 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2234 SequenceSet vamsasSet)
2237 for (int i = 0; i < aa.length; i++)
2239 Annotation an = new Annotation();
2241 AlignmentAnnotation annotation = aa[i];
2242 if (annotation.annotationId != null)
2244 annotationIds.put(annotation.annotationId, annotation);
2247 an.setId(annotation.annotationId);
2249 an.setVisible(annotation.visible);
2251 an.setDescription(annotation.description);
2253 if (annotation.sequenceRef != null)
2255 // 2.9 JAL-1781 xref on sequence id rather than name
2256 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2258 if (annotation.groupRef != null)
2260 String groupIdr = groupRefs.get(annotation.groupRef);
2261 if (groupIdr == null)
2263 // make a locally unique String
2264 groupRefs.put(annotation.groupRef,
2265 groupIdr = ("" + System.currentTimeMillis()
2266 + annotation.groupRef.getName()
2267 + groupRefs.size()));
2269 an.setGroupRef(groupIdr.toString());
2272 // store all visualization attributes for annotation
2273 an.setGraphHeight(annotation.graphHeight);
2274 an.setCentreColLabels(annotation.centreColLabels);
2275 an.setScaleColLabels(annotation.scaleColLabel);
2276 an.setShowAllColLabels(annotation.showAllColLabels);
2277 an.setBelowAlignment(annotation.belowAlignment);
2279 if (annotation.graph > 0)
2282 an.setGraphType(annotation.graph);
2283 an.setGraphGroup(annotation.graphGroup);
2284 if (annotation.getThreshold() != null)
2286 ThresholdLine line = new ThresholdLine();
2287 line.setLabel(annotation.getThreshold().label);
2288 line.setValue(annotation.getThreshold().value);
2289 line.setColour(annotation.getThreshold().colour.getRGB());
2290 an.setThresholdLine(line);
2298 an.setLabel(annotation.label);
2300 if (annotation == av.getAlignmentQualityAnnot()
2301 || annotation == av.getAlignmentConservationAnnotation()
2302 || annotation == av.getAlignmentConsensusAnnotation()
2303 || annotation.autoCalculated)
2305 // new way of indicating autocalculated annotation -
2306 an.setAutoCalculated(annotation.autoCalculated);
2308 if (annotation.hasScore())
2310 an.setScore(annotation.getScore());
2313 if (annotation.getCalcId() != null)
2315 calcIdSet.add(annotation.getCalcId());
2316 an.setCalcId(annotation.getCalcId());
2318 if (annotation.hasProperties())
2320 for (String pr : annotation.getProperties())
2322 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2324 prop.setValue(annotation.getProperty(pr));
2325 // an.addProperty(prop);
2326 an.getProperty().add(prop);
2330 AnnotationElement ae;
2331 if (annotation.annotations != null)
2333 an.setScoreOnly(false);
2334 for (int a = 0; a < annotation.annotations.length; a++)
2336 if ((annotation == null) || (annotation.annotations[a] == null))
2341 ae = new AnnotationElement();
2342 if (annotation.annotations[a].description != null)
2344 ae.setDescription(annotation.annotations[a].description);
2346 if (annotation.annotations[a].displayCharacter != null)
2348 ae.setDisplayCharacter(
2349 annotation.annotations[a].displayCharacter);
2352 if (!Float.isNaN(annotation.annotations[a].value))
2354 ae.setValue(annotation.annotations[a].value);
2358 if (annotation.annotations[a].secondaryStructure > ' ')
2360 ae.setSecondaryStructure(
2361 annotation.annotations[a].secondaryStructure + "");
2364 if (annotation.annotations[a].colour != null
2365 && annotation.annotations[a].colour != java.awt.Color.black)
2367 ae.setColour(annotation.annotations[a].colour.getRGB());
2370 // an.addAnnotationElement(ae);
2371 an.getAnnotationElement().add(ae);
2372 if (annotation.autoCalculated)
2374 // only write one non-null entry into the annotation row -
2375 // sufficient to get the visualization attributes necessary to
2383 an.setScoreOnly(true);
2385 if (!storeDS || (storeDS && !annotation.autoCalculated))
2387 // skip autocalculated annotation - these are only provided for
2389 // vamsasSet.addAnnotation(an);
2390 vamsasSet.getAnnotation().add(an);
2396 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2398 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2399 if (settings != null)
2401 CalcIdParam vCalcIdParam = new CalcIdParam();
2402 vCalcIdParam.setCalcId(calcId);
2403 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2404 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2405 // generic URI allowing a third party to resolve another instance of the
2406 // service used for this calculation
2407 for (String url : settings.getServiceURLs())
2409 // vCalcIdParam.addServiceURL(urls);
2410 vCalcIdParam.getServiceURL().add(url);
2412 vCalcIdParam.setVersion("1.0");
2413 if (settings.getPreset() != null)
2415 WsParamSetI setting = settings.getPreset();
2416 vCalcIdParam.setName(setting.getName());
2417 vCalcIdParam.setDescription(setting.getDescription());
2421 vCalcIdParam.setName("");
2422 vCalcIdParam.setDescription("Last used parameters");
2424 // need to be able to recover 1) settings 2) user-defined presets or
2425 // recreate settings from preset 3) predefined settings provided by
2426 // service - or settings that can be transferred (or discarded)
2427 vCalcIdParam.setParameters(
2428 settings.getWsParamFile().replace("\n", "|\\n|"));
2429 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2430 // todo - decide if updateImmediately is needed for any projects.
2432 return vCalcIdParam;
2437 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2440 if (calcIdParam.getVersion().equals("1.0"))
2442 final String[] calcIds = calcIdParam.getServiceURL()
2443 .toArray(new String[0]);
2444 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2445 .getPreferredServiceFor(calcIds);
2446 if (service != null)
2448 WsParamSetI parmSet = null;
2451 parmSet = service.getParamStore().parseServiceParameterFile(
2452 calcIdParam.getName(), calcIdParam.getDescription(),
2454 calcIdParam.getParameters().replace("|\\n|", "\n"));
2455 } catch (IOException x)
2457 Console.warn("Couldn't parse parameter data for "
2458 + calcIdParam.getCalcId(), x);
2461 List<ArgumentI> argList = null;
2462 if (calcIdParam.getName().length() > 0)
2464 parmSet = service.getParamStore()
2465 .getPreset(calcIdParam.getName());
2466 if (parmSet != null)
2468 // TODO : check we have a good match with settings in AACon -
2469 // otherwise we'll need to create a new preset
2474 argList = parmSet.getArguments();
2477 AAConSettings settings = new AAConSettings(
2478 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2479 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2480 calcIdParam.isNeedsUpdate());
2486 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2490 throw new Error(MessageManager.formatMessage(
2491 "error.unsupported_version_calcIdparam", new Object[]
2492 { calcIdParam.toString() }));
2496 * External mapping between jalview objects and objects yielding a valid and
2497 * unique object ID string. This is null for normal Jalview project IO, but
2498 * non-null when a jalview project is being read or written as part of a
2501 IdentityHashMap jv2vobj = null;
2504 * Construct a unique ID for jvobj using either existing bindings or if none
2505 * exist, the result of the hashcode call for the object.
2508 * jalview data object
2509 * @return unique ID for referring to jvobj
2511 private String makeHashCode(Object jvobj, String altCode)
2513 if (jv2vobj != null)
2515 Object id = jv2vobj.get(jvobj);
2518 return id.toString();
2520 // check string ID mappings
2521 if (jvids2vobj != null && jvobj instanceof String)
2523 id = jvids2vobj.get(jvobj);
2527 return id.toString();
2529 // give up and warn that something has gone wrong
2531 "Cannot find ID for object in external mapping : " + jvobj);
2537 * return local jalview object mapped to ID, if it exists
2541 * @return null or object bound to idcode
2543 private Object retrieveExistingObj(String idcode)
2545 if (idcode != null && vobj2jv != null)
2547 return vobj2jv.get(idcode);
2553 * binding from ID strings from external mapping table to jalview data model
2556 private Hashtable vobj2jv;
2558 private Sequence createVamsasSequence(String id, SequenceI jds)
2560 return createVamsasSequence(true, id, jds, null);
2563 private Sequence createVamsasSequence(boolean recurse, String id,
2564 SequenceI jds, SequenceI parentseq)
2566 Sequence vamsasSeq = new Sequence();
2567 vamsasSeq.setId(id);
2568 vamsasSeq.setName(jds.getName());
2569 vamsasSeq.setSequence(jds.getSequenceAsString());
2570 vamsasSeq.setDescription(jds.getDescription());
2571 List<DBRefEntry> dbrefs = null;
2572 if (jds.getDatasetSequence() != null)
2574 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2578 // seqId==dsseqid so we can tell which sequences really are
2579 // dataset sequences only
2580 vamsasSeq.setDsseqid(id);
2581 dbrefs = jds.getDBRefs();
2582 if (parentseq == null)
2589 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2593 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2595 DBRef dbref = new DBRef();
2596 DBRefEntry ref = dbrefs.get(d);
2597 dbref.setSource(ref.getSource());
2598 dbref.setVersion(ref.getVersion());
2599 dbref.setAccessionId(ref.getAccessionId());
2600 dbref.setCanonical(ref.isCanonical());
2601 if (ref instanceof GeneLocus)
2603 dbref.setLocus(true);
2607 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2609 dbref.setMapping(mp);
2611 vamsasSeq.getDBRef().add(dbref);
2617 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2618 SequenceI parentseq, SequenceI jds, boolean recurse)
2621 if (jmp.getMap() != null)
2625 jalview.util.MapList mlst = jmp.getMap();
2626 List<int[]> r = mlst.getFromRanges();
2627 for (int[] range : r)
2629 MapListFrom mfrom = new MapListFrom();
2630 mfrom.setStart(range[0]);
2631 mfrom.setEnd(range[1]);
2632 // mp.addMapListFrom(mfrom);
2633 mp.getMapListFrom().add(mfrom);
2635 r = mlst.getToRanges();
2636 for (int[] range : r)
2638 MapListTo mto = new MapListTo();
2639 mto.setStart(range[0]);
2640 mto.setEnd(range[1]);
2641 // mp.addMapListTo(mto);
2642 mp.getMapListTo().add(mto);
2644 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2645 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2646 if (jmp.getTo() != null)
2648 // MappingChoice mpc = new MappingChoice();
2650 // check/create ID for the sequence referenced by getTo()
2653 SequenceI ps = null;
2654 if (parentseq != jmp.getTo()
2655 && parentseq.getDatasetSequence() != jmp.getTo())
2657 // chaining dbref rather than a handshaking one
2658 jmpid = seqHash(ps = jmp.getTo());
2662 jmpid = seqHash(ps = parentseq);
2664 // mpc.setDseqFor(jmpid);
2665 mp.setDseqFor(jmpid);
2666 if (!seqRefIds.containsKey(jmpid))
2668 Console.debug("creatign new DseqFor ID");
2669 seqRefIds.put(jmpid, ps);
2673 Console.debug("reusing DseqFor ID");
2676 // mp.setMappingChoice(mpc);
2682 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2683 List<UserColourScheme> userColours, JalviewModel jm)
2686 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2687 boolean newucs = false;
2688 if (!userColours.contains(ucs))
2690 userColours.add(ucs);
2693 id = "ucs" + userColours.indexOf(ucs);
2696 // actually create the scheme's entry in the XML model
2697 java.awt.Color[] colours = ucs.getColours();
2698 UserColours uc = new UserColours();
2699 // UserColourScheme jbucs = new UserColourScheme();
2700 JalviewUserColours jbucs = new JalviewUserColours();
2702 for (int i = 0; i < colours.length; i++)
2704 Colour col = new Colour();
2705 col.setName(ResidueProperties.aa[i]);
2706 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2707 // jbucs.addColour(col);
2708 jbucs.getColour().add(col);
2710 if (ucs.getLowerCaseColours() != null)
2712 colours = ucs.getLowerCaseColours();
2713 for (int i = 0; i < colours.length; i++)
2715 Colour col = new Colour();
2716 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2717 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2718 // jbucs.addColour(col);
2719 jbucs.getColour().add(col);
2724 uc.setUserColourScheme(jbucs);
2725 // jm.addUserColours(uc);
2726 jm.getUserColours().add(uc);
2732 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2735 List<UserColours> uc = jm.getUserColours();
2736 UserColours colours = null;
2738 for (int i = 0; i < uc.length; i++)
2740 if (uc[i].getId().equals(id))
2747 for (UserColours c : uc)
2749 if (c.getId().equals(id))
2756 java.awt.Color[] newColours = new java.awt.Color[24];
2758 for (int i = 0; i < 24; i++)
2760 newColours[i] = new java.awt.Color(Integer.parseInt(
2761 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2762 colours.getUserColourScheme().getColour().get(i).getRGB(),
2766 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2769 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2771 newColours = new java.awt.Color[23];
2772 for (int i = 0; i < 23; i++)
2774 newColours[i] = new java.awt.Color(
2775 Integer.parseInt(colours.getUserColourScheme().getColour()
2776 .get(i + 24).getRGB(), 16));
2778 ucs.setLowerCaseColours(newColours);
2785 * contains last error message (if any) encountered by XML loader.
2787 String errorMessage = null;
2790 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2791 * exceptions are raised during project XML parsing
2793 public boolean attemptversion1parse = false;
2796 * Load a jalview project archive from a jar file
2799 * - HTTP URL or filename
2801 public AlignFrame loadJalviewAlign(final Object file)
2804 jalview.gui.AlignFrame af = null;
2808 // create list to store references for any new Jmol viewers created
2809 newStructureViewers = new Vector<>();
2810 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2811 // Workaround is to make sure caller implements the JarInputStreamProvider
2813 // so we can re-open the jar input stream for each entry.
2815 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2816 af = loadJalviewAlign(jprovider);
2819 af.setMenusForViewport();
2821 } catch (MalformedURLException e)
2823 errorMessage = "Invalid URL format for '" + file + "'";
2829 SwingUtilities.invokeAndWait(new Runnable()
2834 setLoadingFinishedForNewStructureViewers();
2837 } catch (Exception x)
2839 System.err.println("Error loading alignment: " + x.getMessage());
2845 @SuppressWarnings("unused")
2846 private jarInputStreamProvider createjarInputStreamProvider(
2847 final Object ofile) throws MalformedURLException
2850 // BH 2018 allow for bytes already attached to File object
2853 String file = (ofile instanceof File
2854 ? ((File) ofile).getCanonicalPath()
2855 : ofile.toString());
2856 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2859 errorMessage = null;
2860 uniqueSetSuffix = null;
2862 viewportsAdded.clear();
2863 frefedSequence = null;
2865 if (HttpUtils.startsWithHttpOrHttps(file))
2867 url = new URL(file);
2869 final URL _url = url;
2870 return new jarInputStreamProvider()
2874 public JarInputStream getJarInputStream() throws IOException
2878 // System.out.println("Jalview2XML: opening byte jarInputStream for
2879 // bytes.length=" + bytes.length);
2880 return new JarInputStream(new ByteArrayInputStream(bytes));
2884 // System.out.println("Jalview2XML: opening url jarInputStream for "
2886 return new JarInputStream(_url.openStream());
2890 // System.out.println("Jalview2XML: opening file jarInputStream for
2892 return new JarInputStream(new FileInputStream(file));
2897 public String getFilename()
2902 } catch (IOException e)
2904 e.printStackTrace();
2910 * Recover jalview session from a jalview project archive. Caller may
2911 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2912 * themselves. Any null fields will be initialised with default values,
2913 * non-null fields are left alone.
2918 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2920 errorMessage = null;
2921 if (uniqueSetSuffix == null)
2923 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2925 if (seqRefIds == null)
2929 AlignFrame af = null, _af = null;
2930 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2931 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2932 final String file = jprovider.getFilename();
2935 JarInputStream jin = null;
2936 JarEntry jarentry = null;
2941 jin = jprovider.getJarInputStream();
2942 for (int i = 0; i < entryCount; i++)
2944 jarentry = jin.getNextJarEntry();
2947 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2949 JAXBContext jc = JAXBContext
2950 .newInstance("jalview.xml.binding.jalview");
2951 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2952 .createXMLStreamReader(jin);
2953 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2954 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2955 JalviewModel.class);
2956 JalviewModel object = jbe.getValue();
2958 if (true) // !skipViewport(object))
2960 _af = loadFromObject(object, file, true, jprovider);
2961 if (_af != null && object.getViewport().size() > 0)
2962 // getJalviewModelSequence().getViewportCount() > 0)
2966 // store a reference to the first view
2969 if (_af.getViewport().isGatherViewsHere())
2971 // if this is a gathered view, keep its reference since
2972 // after gathering views, only this frame will remain
2974 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2977 // Save dataset to register mappings once all resolved
2978 importedDatasets.put(
2979 af.getViewport().getAlignment().getDataset(),
2980 af.getViewport().getAlignment().getDataset());
2985 else if (jarentry != null)
2987 // Some other file here.
2990 } while (jarentry != null);
2992 resolveFrefedSequences();
2993 } catch (IOException ex)
2995 ex.printStackTrace();
2996 errorMessage = "Couldn't locate Jalview XML file : " + file;
2998 "Exception whilst loading jalview XML file : " + ex + "\n");
2999 } catch (Exception ex)
3001 System.err.println("Parsing as Jalview Version 2 file failed.");
3002 ex.printStackTrace(System.err);
3003 if (attemptversion1parse)
3005 // used to attempt to parse as V1 castor-generated xml
3007 if (Desktop.instance != null)
3009 Desktop.instance.stopLoading();
3013 System.out.println("Successfully loaded archive file");
3016 ex.printStackTrace();
3019 "Exception whilst loading jalview XML file : " + ex + "\n");
3020 } catch (OutOfMemoryError e)
3022 // Don't use the OOM Window here
3023 errorMessage = "Out of memory loading jalview XML file";
3024 System.err.println("Out of memory whilst loading jalview XML file");
3025 e.printStackTrace();
3029 * Regather multiple views (with the same sequence set id) to the frame (if
3030 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3031 * views instead of separate frames. Note this doesn't restore a state where
3032 * some expanded views in turn have tabbed views - the last "first tab" read
3033 * in will play the role of gatherer for all.
3035 for (AlignFrame fr : gatherToThisFrame.values())
3037 Desktop.instance.gatherViews(fr);
3040 restoreSplitFrames();
3041 for (AlignmentI ds : importedDatasets.keySet())
3043 if (ds.getCodonFrames() != null)
3045 StructureSelectionManager
3046 .getStructureSelectionManager(Desktop.instance)
3047 .registerMappings(ds.getCodonFrames());
3050 if (errorMessage != null)
3055 if (Desktop.instance != null)
3057 Desktop.instance.stopLoading();
3064 * Try to reconstruct and display SplitFrame windows, where each contains
3065 * complementary dna and protein alignments. Done by pairing up AlignFrame
3066 * objects (created earlier) which have complementary viewport ids associated.
3068 protected void restoreSplitFrames()
3070 List<SplitFrame> gatherTo = new ArrayList<>();
3071 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3072 Map<String, AlignFrame> dna = new HashMap<>();
3075 * Identify the DNA alignments
3077 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3080 AlignFrame af = candidate.getValue();
3081 if (af.getViewport().getAlignment().isNucleotide())
3083 dna.put(candidate.getKey().getId(), af);
3088 * Try to match up the protein complements
3090 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3093 AlignFrame af = candidate.getValue();
3094 if (!af.getViewport().getAlignment().isNucleotide())
3096 String complementId = candidate.getKey().getComplementId();
3097 // only non-null complements should be in the Map
3098 if (complementId != null && dna.containsKey(complementId))
3100 final AlignFrame dnaFrame = dna.get(complementId);
3101 SplitFrame sf = createSplitFrame(dnaFrame, af);
3102 addedToSplitFrames.add(dnaFrame);
3103 addedToSplitFrames.add(af);
3104 dnaFrame.setMenusForViewport();
3105 af.setMenusForViewport();
3106 if (af.getViewport().isGatherViewsHere())
3115 * Open any that we failed to pair up (which shouldn't happen!) as
3116 * standalone AlignFrame's.
3118 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3121 AlignFrame af = candidate.getValue();
3122 if (!addedToSplitFrames.contains(af))
3124 Viewport view = candidate.getKey();
3125 Desktop.addInternalFrame(af, view.getTitle(),
3126 safeInt(view.getWidth()), safeInt(view.getHeight()));
3127 af.setMenusForViewport();
3128 System.err.println("Failed to restore view " + view.getTitle()
3129 + " to split frame");
3134 * Gather back into tabbed views as flagged.
3136 for (SplitFrame sf : gatherTo)
3138 Desktop.instance.gatherViews(sf);
3141 splitFrameCandidates.clear();
3145 * Construct and display one SplitFrame holding DNA and protein alignments.
3148 * @param proteinFrame
3151 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3152 AlignFrame proteinFrame)
3154 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3155 String title = MessageManager.getString("label.linked_view_title");
3156 int width = (int) dnaFrame.getBounds().getWidth();
3157 int height = (int) (dnaFrame.getBounds().getHeight()
3158 + proteinFrame.getBounds().getHeight() + 50);
3161 * SplitFrame location is saved to both enclosed frames
3163 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3164 Desktop.addInternalFrame(splitFrame, title, width, height);
3167 * And compute cDNA consensus (couldn't do earlier with consensus as
3168 * mappings were not yet present)
3170 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3176 * check errorMessage for a valid error message and raise an error box in the
3177 * GUI or write the current errorMessage to stderr and then clear the error
3180 protected void reportErrors()
3182 reportErrors(false);
3185 protected void reportErrors(final boolean saving)
3187 if (errorMessage != null)
3189 final String finalErrorMessage = errorMessage;
3192 javax.swing.SwingUtilities.invokeLater(new Runnable()
3197 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3199 "Error " + (saving ? "saving" : "loading")
3201 JvOptionPane.WARNING_MESSAGE);
3207 System.err.println("Problem loading Jalview file: " + errorMessage);
3210 errorMessage = null;
3213 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3216 * when set, local views will be updated from view stored in JalviewXML
3217 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3218 * sync if this is set to true.
3220 private final boolean updateLocalViews = false;
3223 * Returns the path to a temporary file holding the PDB file for the given PDB
3224 * id. The first time of asking, searches for a file of that name in the
3225 * Jalview project jar, and copies it to a new temporary file. Any repeat
3226 * requests just return the path to the file previously created.
3232 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3235 if (alreadyLoadedPDB.containsKey(pdbId))
3237 return alreadyLoadedPDB.get(pdbId).toString();
3240 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3242 if (tempFile != null)
3244 alreadyLoadedPDB.put(pdbId, tempFile);
3250 * Copies the jar entry of given name to a new temporary file and returns the
3251 * path to the file, or null if the entry is not found.
3254 * @param jarEntryName
3256 * a prefix for the temporary file name, must be at least three
3258 * @param suffixModel
3259 * null or original file - so new file can be given the same suffix
3263 protected String copyJarEntry(jarInputStreamProvider jprovider,
3264 String jarEntryName, String prefix, String suffixModel)
3266 String suffix = ".tmp";
3267 if (suffixModel == null)
3269 suffixModel = jarEntryName;
3271 int sfpos = suffixModel.lastIndexOf(".");
3272 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3274 suffix = "." + suffixModel.substring(sfpos + 1);
3277 try (JarInputStream jin = jprovider.getJarInputStream())
3279 JarEntry entry = null;
3282 entry = jin.getNextJarEntry();
3283 } while (entry != null && !entry.getName().equals(jarEntryName));
3287 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3288 File outFile = File.createTempFile(prefix, suffix);
3289 outFile.deleteOnExit();
3290 try (OutputStream os = new FileOutputStream(outFile))
3294 String t = outFile.getAbsolutePath();
3300 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3302 } catch (Exception ex)
3304 ex.printStackTrace();
3310 private class JvAnnotRow
3312 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3319 * persisted version of annotation row from which to take vis properties
3321 public jalview.datamodel.AlignmentAnnotation template;
3324 * original position of the annotation row in the alignment
3330 * Load alignment frame from jalview XML DOM object
3332 * @param jalviewModel
3335 * filename source string
3336 * @param loadTreesAndStructures
3337 * when false only create Viewport
3339 * data source provider
3340 * @return alignment frame created from view stored in DOM
3342 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3343 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3345 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3347 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3349 // JalviewModelSequence jms = object.getJalviewModelSequence();
3351 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3353 Viewport view = (jalviewModel.getViewport().size() > 0)
3354 ? jalviewModel.getViewport().get(0)
3357 // ////////////////////////////////
3358 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3361 // If we just load in the same jar file again, the sequenceSetId
3362 // will be the same, and we end up with multiple references
3363 // to the same sequenceSet. We must modify this id on load
3364 // so that each load of the file gives a unique id
3367 * used to resolve correct alignment dataset for alignments with multiple
3370 String uniqueSeqSetId = null;
3371 String viewId = null;
3374 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3375 viewId = (view.getId() == null ? null
3376 : view.getId() + uniqueSetSuffix);
3379 // ////////////////////////////////
3382 List<SequenceI> hiddenSeqs = null;
3384 List<SequenceI> tmpseqs = new ArrayList<>();
3386 boolean multipleView = false;
3387 SequenceI referenceseqForView = null;
3388 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3389 List<JSeq> jseqs = jalviewModel.getJSeq();
3390 int vi = 0; // counter in vamsasSeq array
3391 for (int i = 0; i < jseqs.size(); i++)
3393 JSeq jseq = jseqs.get(i);
3394 String seqId = jseq.getId();
3396 SequenceI tmpSeq = seqRefIds.get(seqId);
3399 if (!incompleteSeqs.containsKey(seqId))
3401 // may not need this check, but keep it for at least 2.9,1 release
3402 if (tmpSeq.getStart() != jseq.getStart()
3403 || tmpSeq.getEnd() != jseq.getEnd())
3405 System.err.println(String.format(
3406 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3407 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3408 jseq.getStart(), jseq.getEnd()));
3413 incompleteSeqs.remove(seqId);
3415 if (vamsasSeqs.size() > vi
3416 && vamsasSeqs.get(vi).getId().equals(seqId))
3418 // most likely we are reading a dataset XML document so
3419 // update from vamsasSeq section of XML for this sequence
3420 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3421 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3422 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3427 // reading multiple views, so vamsasSeq set is a subset of JSeq
3428 multipleView = true;
3430 tmpSeq.setStart(jseq.getStart());
3431 tmpSeq.setEnd(jseq.getEnd());
3432 tmpseqs.add(tmpSeq);
3436 Sequence vamsasSeq = vamsasSeqs.get(vi);
3437 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3438 vamsasSeq.getSequence());
3439 tmpSeq.setDescription(vamsasSeq.getDescription());
3440 tmpSeq.setStart(jseq.getStart());
3441 tmpSeq.setEnd(jseq.getEnd());
3442 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3443 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3444 tmpseqs.add(tmpSeq);
3448 if (safeBoolean(jseq.isViewreference()))
3450 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3453 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3455 if (hiddenSeqs == null)
3457 hiddenSeqs = new ArrayList<>();
3460 hiddenSeqs.add(tmpSeq);
3465 // Create the alignment object from the sequence set
3466 // ///////////////////////////////
3467 SequenceI[] orderedSeqs = tmpseqs
3468 .toArray(new SequenceI[tmpseqs.size()]);
3470 AlignmentI al = null;
3471 // so we must create or recover the dataset alignment before going further
3472 // ///////////////////////////////
3473 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3475 // older jalview projects do not have a dataset - so creat alignment and
3477 al = new Alignment(orderedSeqs);
3478 al.setDataset(null);
3482 boolean isdsal = jalviewModel.getViewport().isEmpty();
3485 // we are importing a dataset record, so
3486 // recover reference to an alignment already materialsed as dataset
3487 al = getDatasetFor(vamsasSet.getDatasetId());
3491 // materialse the alignment
3492 al = new Alignment(orderedSeqs);
3496 addDatasetRef(vamsasSet.getDatasetId(), al);
3499 // finally, verify all data in vamsasSet is actually present in al
3500 // passing on flag indicating if it is actually a stored dataset
3501 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3504 if (referenceseqForView != null)
3506 al.setSeqrep(referenceseqForView);
3508 // / Add the alignment properties
3509 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3511 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3513 al.setProperty(ssp.getKey(), ssp.getValue());
3516 // ///////////////////////////////
3518 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3521 // load sequence features, database references and any associated PDB
3522 // structures for the alignment
3524 // prior to 2.10, this part would only be executed the first time a
3525 // sequence was encountered, but not afterwards.
3526 // now, for 2.10 projects, this is also done if the xml doc includes
3527 // dataset sequences not actually present in any particular view.
3529 for (int i = 0; i < vamsasSeqs.size(); i++)
3531 JSeq jseq = jseqs.get(i);
3532 if (jseq.getFeatures().size() > 0)
3534 List<Feature> features = jseq.getFeatures();
3535 for (int f = 0; f < features.size(); f++)
3537 Feature feat = features.get(f);
3538 SequenceFeature sf = new SequenceFeature(feat.getType(),
3539 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3540 safeFloat(feat.getScore()), feat.getFeatureGroup());
3541 sf.setStatus(feat.getStatus());
3544 * load any feature attributes - include map-valued attributes
3546 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3547 for (int od = 0; od < feat.getOtherData().size(); od++)
3549 OtherData keyValue = feat.getOtherData().get(od);
3550 String attributeName = keyValue.getKey();
3551 String attributeValue = keyValue.getValue();
3552 if (attributeName.startsWith("LINK"))
3554 sf.addLink(attributeValue);
3558 String subAttribute = keyValue.getKey2();
3559 if (subAttribute == null)
3561 // simple string-valued attribute
3562 sf.setValue(attributeName, attributeValue);
3566 // attribute 'key' has sub-attribute 'key2'
3567 if (!mapAttributes.containsKey(attributeName))
3569 mapAttributes.put(attributeName, new HashMap<>());
3571 mapAttributes.get(attributeName).put(subAttribute,
3576 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3579 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3582 // adds feature to datasequence's feature set (since Jalview 2.10)
3583 al.getSequenceAt(i).addSequenceFeature(sf);
3586 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3588 // adds dbrefs to datasequence's set (since Jalview 2.10)
3590 al.getSequenceAt(i).getDatasetSequence() == null
3591 ? al.getSequenceAt(i)
3592 : al.getSequenceAt(i).getDatasetSequence(),
3595 if (jseq.getPdbids().size() > 0)
3597 List<Pdbids> ids = jseq.getPdbids();
3598 for (int p = 0; p < ids.size(); p++)
3600 Pdbids pdbid = ids.get(p);
3601 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3602 entry.setId(pdbid.getId());
3603 if (pdbid.getType() != null)
3605 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3607 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3611 entry.setType(PDBEntry.Type.FILE);
3614 // jprovider is null when executing 'New View'
3615 if (pdbid.getFile() != null && jprovider != null)
3617 if (!pdbloaded.containsKey(pdbid.getFile()))
3619 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3624 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3628 if (pdbid.getPdbentryItem() != null)
3630 for (PdbentryItem item : pdbid.getPdbentryItem())
3632 for (Property pr : item.getProperty())
3634 entry.setProperty(pr.getName(), pr.getValue());
3639 for (Property prop : pdbid.getProperty())
3641 entry.setProperty(prop.getName(), prop.getValue());
3643 StructureSelectionManager
3644 .getStructureSelectionManager(Desktop.instance)
3645 .registerPDBEntry(entry);
3646 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3647 if (al.getSequenceAt(i).getDatasetSequence() != null)
3649 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3653 al.getSequenceAt(i).addPDBId(entry);
3658 } // end !multipleview
3660 // ///////////////////////////////
3661 // LOAD SEQUENCE MAPPINGS
3663 if (vamsasSet.getAlcodonFrame().size() > 0)
3665 // TODO Potentially this should only be done once for all views of an
3667 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3668 for (int i = 0; i < alc.size(); i++)
3670 AlignedCodonFrame cf = new AlignedCodonFrame();
3671 if (alc.get(i).getAlcodMap().size() > 0)
3673 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3674 for (int m = 0; m < maps.size(); m++)
3676 AlcodMap map = maps.get(m);
3677 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3679 jalview.datamodel.Mapping mapping = null;
3680 // attach to dna sequence reference.
3681 if (map.getMapping() != null)
3683 mapping = addMapping(map.getMapping());
3684 if (dnaseq != null && mapping.getTo() != null)
3686 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3692 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3696 al.addCodonFrame(cf);
3701 // ////////////////////////////////
3703 List<JvAnnotRow> autoAlan = new ArrayList<>();
3706 * store any annotations which forward reference a group's ID
3708 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3710 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3712 List<Annotation> an = vamsasSet.getAnnotation();
3714 for (int i = 0; i < an.size(); i++)
3716 Annotation annotation = an.get(i);
3719 * test if annotation is automatically calculated for this view only
3721 boolean autoForView = false;
3722 if (annotation.getLabel().equals("Quality")
3723 || annotation.getLabel().equals("Conservation")
3724 || annotation.getLabel().equals("Consensus"))
3726 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3728 // JAXB has no has() test; schema defaults value to false
3729 // if (!annotation.hasAutoCalculated())
3731 // annotation.setAutoCalculated(true);
3734 if (autoForView || annotation.isAutoCalculated())
3736 // remove ID - we don't recover annotation from other views for
3737 // view-specific annotation
3738 annotation.setId(null);
3741 // set visibility for other annotation in this view
3742 String annotationId = annotation.getId();
3743 if (annotationId != null && annotationIds.containsKey(annotationId))
3745 AlignmentAnnotation jda = annotationIds.get(annotationId);
3746 // in principle Visible should always be true for annotation displayed
3747 // in multiple views
3748 if (annotation.isVisible() != null)
3750 jda.visible = annotation.isVisible();
3753 al.addAnnotation(jda);
3757 // Construct new annotation from model.
3758 List<AnnotationElement> ae = annotation.getAnnotationElement();
3759 jalview.datamodel.Annotation[] anot = null;
3760 java.awt.Color firstColour = null;
3762 if (!annotation.isScoreOnly())
3764 anot = new jalview.datamodel.Annotation[al.getWidth()];
3765 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3767 AnnotationElement annElement = ae.get(aa);
3768 anpos = annElement.getPosition();
3770 if (anpos >= anot.length)
3775 float value = safeFloat(annElement.getValue());
3776 anot[anpos] = new jalview.datamodel.Annotation(
3777 annElement.getDisplayCharacter(),
3778 annElement.getDescription(),
3779 (annElement.getSecondaryStructure() == null
3780 || annElement.getSecondaryStructure()
3784 .getSecondaryStructure()
3787 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3788 if (firstColour == null)
3790 firstColour = anot[anpos].colour;
3794 jalview.datamodel.AlignmentAnnotation jaa = null;
3796 if (annotation.isGraph())
3798 float llim = 0, hlim = 0;
3799 // if (autoForView || an[i].isAutoCalculated()) {
3802 jaa = new jalview.datamodel.AlignmentAnnotation(
3803 annotation.getLabel(), annotation.getDescription(), anot,
3804 llim, hlim, safeInt(annotation.getGraphType()));
3806 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3807 jaa._linecolour = firstColour;
3808 if (annotation.getThresholdLine() != null)
3810 jaa.setThreshold(new jalview.datamodel.GraphLine(
3811 safeFloat(annotation.getThresholdLine().getValue()),
3812 annotation.getThresholdLine().getLabel(),
3813 new java.awt.Color(safeInt(
3814 annotation.getThresholdLine().getColour()))));
3816 if (autoForView || annotation.isAutoCalculated())
3818 // Hardwire the symbol display line to ensure that labels for
3819 // histograms are displayed
3825 jaa = new jalview.datamodel.AlignmentAnnotation(
3826 annotation.getLabel(), annotation.getDescription(), anot);
3827 jaa._linecolour = firstColour;
3829 // register new annotation
3830 if (annotation.getId() != null)
3832 annotationIds.put(annotation.getId(), jaa);
3833 jaa.annotationId = annotation.getId();
3835 // recover sequence association
3836 String sequenceRef = annotation.getSequenceRef();
3837 if (sequenceRef != null)
3839 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3840 SequenceI sequence = seqRefIds.get(sequenceRef);
3841 if (sequence == null)
3843 // in pre-2.9 projects sequence ref is to sequence name
3844 sequence = al.findName(sequenceRef);
3846 if (sequence != null)
3848 jaa.createSequenceMapping(sequence, 1, true);
3849 sequence.addAlignmentAnnotation(jaa);
3852 // and make a note of any group association
3853 if (annotation.getGroupRef() != null
3854 && annotation.getGroupRef().length() > 0)
3856 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3857 .get(annotation.getGroupRef());
3860 aal = new ArrayList<>();
3861 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3866 if (annotation.getScore() != null)
3868 jaa.setScore(annotation.getScore().doubleValue());
3870 if (annotation.isVisible() != null)
3872 jaa.visible = annotation.isVisible().booleanValue();
3875 if (annotation.isCentreColLabels() != null)
3877 jaa.centreColLabels = annotation.isCentreColLabels()
3881 if (annotation.isScaleColLabels() != null)
3883 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3885 if (annotation.isAutoCalculated())
3887 // newer files have an 'autoCalculated' flag and store calculation
3888 // state in viewport properties
3889 jaa.autoCalculated = true; // means annotation will be marked for
3890 // update at end of load.
3892 if (annotation.getGraphHeight() != null)
3894 jaa.graphHeight = annotation.getGraphHeight().intValue();
3896 jaa.belowAlignment = annotation.isBelowAlignment();
3897 jaa.setCalcId(annotation.getCalcId());
3898 if (annotation.getProperty().size() > 0)
3900 for (Annotation.Property prop : annotation.getProperty())
3902 jaa.setProperty(prop.getName(), prop.getValue());
3905 if (jaa.autoCalculated)
3907 autoAlan.add(new JvAnnotRow(i, jaa));
3910 // if (!autoForView)
3912 // add autocalculated group annotation and any user created annotation
3914 al.addAnnotation(jaa);
3918 // ///////////////////////
3920 // Create alignment markup and styles for this view
3921 if (jalviewModel.getJGroup().size() > 0)
3923 List<JGroup> groups = jalviewModel.getJGroup();
3924 boolean addAnnotSchemeGroup = false;
3925 for (int i = 0; i < groups.size(); i++)
3927 JGroup jGroup = groups.get(i);
3928 ColourSchemeI cs = null;
3929 if (jGroup.getColour() != null)
3931 if (jGroup.getColour().startsWith("ucs"))
3933 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3935 else if (jGroup.getColour().equals("AnnotationColourGradient")
3936 && jGroup.getAnnotationColours() != null)
3938 addAnnotSchemeGroup = true;
3942 cs = ColourSchemeProperty.getColourScheme(null, al,
3943 jGroup.getColour());
3946 int pidThreshold = safeInt(jGroup.getPidThreshold());
3948 Vector<SequenceI> seqs = new Vector<>();
3950 for (int s = 0; s < jGroup.getSeq().size(); s++)
3952 String seqId = jGroup.getSeq().get(s);
3953 SequenceI ts = seqRefIds.get(seqId);
3957 seqs.addElement(ts);
3961 if (seqs.size() < 1)
3966 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3967 safeBoolean(jGroup.isDisplayBoxes()),
3968 safeBoolean(jGroup.isDisplayText()),
3969 safeBoolean(jGroup.isColourText()),
3970 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3971 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3972 sg.getGroupColourScheme()
3973 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3974 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3976 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3977 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3978 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3979 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3980 // attributes with a default in the schema are never null
3981 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3982 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3983 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3984 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3985 if (jGroup.getConsThreshold() != null
3986 && jGroup.getConsThreshold().intValue() != 0)
3988 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3991 c.verdict(false, 25);
3992 sg.cs.setConservation(c);
3995 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3997 // re-instate unique group/annotation row reference
3998 List<AlignmentAnnotation> jaal = groupAnnotRefs
3999 .get(jGroup.getId());
4002 for (AlignmentAnnotation jaa : jaal)
4005 if (jaa.autoCalculated)
4007 // match up and try to set group autocalc alignment row for this
4009 if (jaa.label.startsWith("Consensus for "))
4011 sg.setConsensus(jaa);
4013 // match up and try to set group autocalc alignment row for this
4015 if (jaa.label.startsWith("Conservation for "))
4017 sg.setConservationRow(jaa);
4024 if (addAnnotSchemeGroup)
4026 // reconstruct the annotation colourscheme
4028 constructAnnotationColour(jGroup.getAnnotationColours(),
4029 null, al, jalviewModel, false));
4035 // only dataset in this model, so just return.
4038 // ///////////////////////////////
4041 AlignFrame af = null;
4042 AlignViewport av = null;
4043 // now check to see if we really need to create a new viewport.
4044 if (multipleView && viewportsAdded.size() == 0)
4046 // We recovered an alignment for which a viewport already exists.
4047 // TODO: fix up any settings necessary for overlaying stored state onto
4048 // state recovered from another document. (may not be necessary).
4049 // we may need a binding from a viewport in memory to one recovered from
4051 // and then recover its containing af to allow the settings to be applied.
4052 // TODO: fix for vamsas demo
4054 "About to recover a viewport for existing alignment: Sequence set ID is "
4056 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4057 if (seqsetobj != null)
4059 if (seqsetobj instanceof String)
4061 uniqueSeqSetId = (String) seqsetobj;
4063 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4069 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4075 * indicate that annotation colours are applied across all groups (pre
4076 * Jalview 2.8.1 behaviour)
4078 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4079 jalviewModel.getVersion());
4081 AlignmentPanel ap = null;
4082 boolean isnewview = true;
4085 // Check to see if this alignment already has a view id == viewId
4086 jalview.gui.AlignmentPanel views[] = Desktop
4087 .getAlignmentPanels(uniqueSeqSetId);
4088 if (views != null && views.length > 0)
4090 for (int v = 0; v < views.length; v++)
4092 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4094 // recover the existing alignpanel, alignframe, viewport
4095 af = views[v].alignFrame;
4098 // TODO: could even skip resetting view settings if we don't want to
4099 // change the local settings from other jalview processes
4108 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4109 uniqueSeqSetId, viewId, autoAlan);
4110 av = af.getViewport();
4115 * Load any trees, PDB structures and viewers, Overview
4117 * Not done if flag is false (when this method is used for New View)
4119 if (loadTreesAndStructures)
4121 loadTrees(jalviewModel, view, af, av, ap);
4122 loadPCAViewers(jalviewModel, ap);
4123 loadPDBStructures(jprovider, jseqs, af, ap);
4124 loadRnaViewers(jprovider, jseqs, ap);
4125 loadOverview(view, af);
4127 // and finally return.
4132 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4133 * and geometry as saved
4138 protected void loadOverview(Viewport view, AlignFrame af)
4141 * first close any Overview that was opened automatically
4142 * (if so configured in Preferences) so that the view is
4143 * restored in the same state as saved
4145 af.alignPanel.closeOverviewPanel();
4147 Overview overview = view.getOverview();
4148 if (overview != null)
4150 OverviewPanel overviewPanel = af
4151 .openOverviewPanel(overview.isShowHidden());
4152 overviewPanel.setTitle(overview.getTitle());
4153 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4154 overview.getWidth(), overview.getHeight());
4155 Color gap = new Color(overview.getGapColour());
4156 Color residue = new Color(overview.getResidueColour());
4157 Color hidden = new Color(overview.getHiddenColour());
4158 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4163 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4164 * panel is restored from separate jar entries, two (gapped and trimmed) per
4165 * sequence and secondary structure.
4167 * Currently each viewer shows just one sequence and structure (gapped and
4168 * trimmed), however this method is designed to support multiple sequences or
4169 * structures in viewers if wanted in future.
4175 private void loadRnaViewers(jarInputStreamProvider jprovider,
4176 List<JSeq> jseqs, AlignmentPanel ap)
4179 * scan the sequences for references to viewers; create each one the first
4180 * time it is referenced, add Rna models to existing viewers
4182 for (JSeq jseq : jseqs)
4184 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4186 RnaViewer viewer = jseq.getRnaViewer().get(i);
4187 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4190 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4192 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4193 SequenceI seq = seqRefIds.get(jseq.getId());
4194 AlignmentAnnotation ann = this.annotationIds
4195 .get(ss.getAnnotationId());
4198 * add the structure to the Varna display (with session state copied
4199 * from the jar to a temporary file)
4201 boolean gapped = safeBoolean(ss.isGapped());
4202 String rnaTitle = ss.getTitle();
4203 String sessionState = ss.getViewerState();
4204 String tempStateFile = copyJarEntry(jprovider, sessionState,
4206 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4207 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4209 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4215 * Locate and return an already instantiated matching AppVarna, or create one
4219 * @param viewIdSuffix
4223 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4224 String viewIdSuffix, AlignmentPanel ap)
4227 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4228 * if load is repeated
4230 String postLoadId = viewer.getViewId() + viewIdSuffix;
4231 for (JInternalFrame frame : getAllFrames())
4233 if (frame instanceof AppVarna)
4235 AppVarna varna = (AppVarna) frame;
4236 if (postLoadId.equals(varna.getViewId()))
4238 // this viewer is already instantiated
4239 // could in future here add ap as another 'parent' of the
4240 // AppVarna window; currently just 1-to-many
4247 * viewer not found - make it
4249 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4250 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4251 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4252 safeInt(viewer.getDividerLocation()));
4253 AppVarna varna = new AppVarna(model, ap);
4259 * Load any saved trees
4267 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4268 AlignViewport av, AlignmentPanel ap)
4270 // TODO result of automated refactoring - are all these parameters needed?
4273 for (int t = 0; t < jm.getTree().size(); t++)
4276 Tree tree = jm.getTree().get(t);
4278 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4281 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4282 tree.getTitle(), safeInt(tree.getWidth()),
4283 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4284 safeInt(tree.getYpos()));
4285 if (tree.getId() != null)
4287 // perhaps bind the tree id to something ?
4292 // update local tree attributes ?
4293 // TODO: should check if tp has been manipulated by user - if so its
4294 // settings shouldn't be modified
4295 tp.setTitle(tree.getTitle());
4296 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4297 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4298 safeInt(tree.getHeight())));
4299 tp.setViewport(av); // af.viewport;
4300 // TODO: verify 'associate with all views' works still
4301 tp.getTreeCanvas().setViewport(av); // af.viewport;
4302 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4304 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4308 "There was a problem recovering stored Newick tree: \n"
4309 + tree.getNewick());
4313 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4314 tp.fitToWindow_actionPerformed(null);
4316 if (tree.getFontName() != null)
4319 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4320 safeInt(tree.getFontSize())));
4325 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4326 safeInt(view.getFontSize())));
4329 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4330 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4331 tp.showDistances(safeBoolean(tree.isShowDistances()));
4333 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4335 if (safeBoolean(tree.isCurrentTree()))
4337 af.getViewport().setCurrentTree(tp.getTree());
4341 } catch (Exception ex)
4343 ex.printStackTrace();
4348 * Load and link any saved structure viewers.
4355 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4356 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4359 * Run through all PDB ids on the alignment, and collect mappings between
4360 * distinct view ids and all sequences referring to that view.
4362 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4364 for (int i = 0; i < jseqs.size(); i++)
4366 JSeq jseq = jseqs.get(i);
4367 if (jseq.getPdbids().size() > 0)
4369 List<Pdbids> ids = jseq.getPdbids();
4370 for (int p = 0; p < ids.size(); p++)
4372 Pdbids pdbid = ids.get(p);
4373 final int structureStateCount = pdbid.getStructureState().size();
4374 for (int s = 0; s < structureStateCount; s++)
4376 // check to see if we haven't already created this structure view
4377 final StructureState structureState = pdbid.getStructureState()
4379 String sviewid = (structureState.getViewId() == null) ? null
4380 : structureState.getViewId() + uniqueSetSuffix;
4381 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4382 // Originally : pdbid.getFile()
4383 // : TODO: verify external PDB file recovery still works in normal
4384 // jalview project load
4386 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4387 jpdb.setId(pdbid.getId());
4389 int x = safeInt(structureState.getXpos());
4390 int y = safeInt(structureState.getYpos());
4391 int width = safeInt(structureState.getWidth());
4392 int height = safeInt(structureState.getHeight());
4394 // Probably don't need to do this anymore...
4395 // Desktop.desktop.getComponentAt(x, y);
4396 // TODO: NOW: check that this recovers the PDB file correctly.
4397 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4399 jalview.datamodel.SequenceI seq = seqRefIds
4400 .get(jseq.getId() + "");
4401 if (sviewid == null)
4403 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4406 if (!structureViewers.containsKey(sviewid))
4408 String viewerType = structureState.getType();
4409 if (viewerType == null) // pre Jalview 2.9
4411 viewerType = ViewerType.JMOL.toString();
4413 structureViewers.put(sviewid,
4414 new StructureViewerModel(x, y, width, height, false,
4415 false, true, structureState.getViewId(),
4417 // Legacy pre-2.7 conversion JAL-823 :
4418 // do not assume any view has to be linked for colour by
4422 // assemble String[] { pdb files }, String[] { id for each
4423 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4424 // seqs_file 2}, boolean[] {
4425 // linkAlignPanel,superposeWithAlignpanel}} from hash
4426 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4427 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4428 || structureState.isAlignwithAlignPanel());
4431 * Default colour by linked panel to false if not specified (e.g.
4432 * for pre-2.7 projects)
4434 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4435 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4436 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4439 * Default colour by viewer to true if not specified (e.g. for
4442 boolean colourByViewer = jmoldat.isColourByViewer();
4443 colourByViewer &= structureState.isColourByJmol();
4444 jmoldat.setColourByViewer(colourByViewer);
4446 if (jmoldat.getStateData().length() < structureState.getValue()
4447 /*Content()*/.length())
4449 jmoldat.setStateData(structureState.getValue());// Content());
4451 if (pdbid.getFile() != null)
4453 File mapkey = new File(pdbid.getFile());
4454 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4455 if (seqstrmaps == null)
4457 jmoldat.getFileData().put(mapkey,
4458 seqstrmaps = jmoldat.new StructureData(pdbFile,
4461 if (!seqstrmaps.getSeqList().contains(seq))
4463 seqstrmaps.getSeqList().add(seq);
4469 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");
4470 Console.warn(errorMessage);
4476 // Instantiate the associated structure views
4477 for (Entry<String, StructureViewerModel> entry : structureViewers
4482 createOrLinkStructureViewer(entry, af, ap, jprovider);
4483 } catch (Exception e)
4486 "Error loading structure viewer: " + e.getMessage());
4487 // failed - try the next one
4499 protected void createOrLinkStructureViewer(
4500 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4501 AlignmentPanel ap, jarInputStreamProvider jprovider)
4503 final StructureViewerModel stateData = viewerData.getValue();
4506 * Search for any viewer windows already open from other alignment views
4507 * that exactly match the stored structure state
4509 StructureViewerBase comp = findMatchingViewer(viewerData);
4513 linkStructureViewer(ap, comp, stateData);
4517 String type = stateData.getType();
4520 ViewerType viewerType = ViewerType.valueOf(type);
4521 createStructureViewer(viewerType, viewerData, af, jprovider);
4522 } catch (IllegalArgumentException | NullPointerException e)
4524 // TODO JAL-3619 show error dialog / offer an alternative viewer
4525 Console.error("Invalid structure viewer type: " + type);
4530 * Generates a name for the entry in the project jar file to hold state
4531 * information for a structure viewer
4536 protected String getViewerJarEntryName(String viewId)
4538 return VIEWER_PREFIX + viewId;
4542 * Returns any open frame that matches given structure viewer data. The match
4543 * is based on the unique viewId, or (for older project versions) the frame's
4549 protected StructureViewerBase findMatchingViewer(
4550 Entry<String, StructureViewerModel> viewerData)
4552 final String sviewid = viewerData.getKey();
4553 final StructureViewerModel svattrib = viewerData.getValue();
4554 StructureViewerBase comp = null;
4555 JInternalFrame[] frames = getAllFrames();
4556 for (JInternalFrame frame : frames)
4558 if (frame instanceof StructureViewerBase)
4561 * Post jalview 2.4 schema includes structure view id
4563 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4566 comp = (StructureViewerBase) frame;
4567 break; // break added in 2.9
4570 * Otherwise test for matching position and size of viewer frame
4572 else if (frame.getX() == svattrib.getX()
4573 && frame.getY() == svattrib.getY()
4574 && frame.getHeight() == svattrib.getHeight()
4575 && frame.getWidth() == svattrib.getWidth())
4577 comp = (StructureViewerBase) frame;
4578 // no break in faint hope of an exact match on viewId
4586 * Link an AlignmentPanel to an existing structure viewer.
4591 * @param useinViewerSuperpos
4592 * @param usetoColourbyseq
4593 * @param viewerColouring
4595 protected void linkStructureViewer(AlignmentPanel ap,
4596 StructureViewerBase viewer, StructureViewerModel stateData)
4598 // NOTE: if the jalview project is part of a shared session then
4599 // view synchronization should/could be done here.
4601 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4602 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4603 final boolean viewerColouring = stateData.isColourByViewer();
4604 Map<File, StructureData> oldFiles = stateData.getFileData();
4607 * Add mapping for sequences in this view to an already open viewer
4609 final AAStructureBindingModel binding = viewer.getBinding();
4610 for (File id : oldFiles.keySet())
4612 // add this and any other pdb files that should be present in the
4614 StructureData filedat = oldFiles.get(id);
4615 String pdbFile = filedat.getFilePath();
4616 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4617 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4619 binding.addSequenceForStructFile(pdbFile, seq);
4621 // and add the AlignmentPanel's reference to the view panel
4622 viewer.addAlignmentPanel(ap);
4623 if (useinViewerSuperpos)
4625 viewer.useAlignmentPanelForSuperposition(ap);
4629 viewer.excludeAlignmentPanelForSuperposition(ap);
4631 if (usetoColourbyseq)
4633 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4637 viewer.excludeAlignmentPanelForColourbyseq(ap);
4642 * Get all frames within the Desktop.
4646 protected JInternalFrame[] getAllFrames()
4648 JInternalFrame[] frames = null;
4649 // TODO is this necessary - is it safe - risk of hanging?
4654 frames = Desktop.desktop.getAllFrames();
4655 } catch (ArrayIndexOutOfBoundsException e)
4657 // occasional No such child exceptions are thrown here...
4661 } catch (InterruptedException f)
4665 } while (frames == null);
4670 * Answers true if 'version' is equal to or later than 'supported', where each
4671 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4672 * changes. Development and test values for 'version' are leniently treated
4676 * - minimum version we are comparing against
4678 * - version of data being processsed
4681 public static boolean isVersionStringLaterThan(String supported,
4684 if (supported == null || version == null
4685 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4686 || version.equalsIgnoreCase("Test")
4687 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4689 System.err.println("Assuming project file with "
4690 + (version == null ? "null" : version)
4691 + " is compatible with Jalview version " + supported);
4696 return StringUtils.compareVersions(version, supported, "b") >= 0;
4700 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4702 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4704 if (newStructureViewers != null)
4706 sview.getBinding().setFinishedLoadingFromArchive(false);
4707 newStructureViewers.add(sview);
4711 protected void setLoadingFinishedForNewStructureViewers()
4713 if (newStructureViewers != null)
4715 for (JalviewStructureDisplayI sview : newStructureViewers)
4717 sview.getBinding().setFinishedLoadingFromArchive(true);
4719 newStructureViewers.clear();
4720 newStructureViewers = null;
4724 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4725 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4726 Viewport view, String uniqueSeqSetId, String viewId,
4727 List<JvAnnotRow> autoAlan)
4729 AlignFrame af = null;
4730 af = new AlignFrame(al, safeInt(view.getWidth()),
4731 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4735 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4736 // System.out.println("Jalview2XML AF " + e);
4737 // super.processKeyEvent(e);
4744 af.setFileName(file, FileFormat.Jalview);
4746 final AlignViewport viewport = af.getViewport();
4747 for (int i = 0; i < JSEQ.size(); i++)
4749 int colour = safeInt(JSEQ.get(i).getColour());
4750 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4756 viewport.setColourByReferenceSeq(true);
4757 viewport.setDisplayReferenceSeq(true);
4760 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4762 if (view.getSequenceSetId() != null)
4764 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4766 viewport.setSequenceSetId(uniqueSeqSetId);
4769 // propagate shared settings to this new view
4770 viewport.setHistoryList(av.getHistoryList());
4771 viewport.setRedoList(av.getRedoList());
4775 viewportsAdded.put(uniqueSeqSetId, viewport);
4777 // TODO: check if this method can be called repeatedly without
4778 // side-effects if alignpanel already registered.
4779 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4781 // apply Hidden regions to view.
4782 if (hiddenSeqs != null)
4784 for (int s = 0; s < JSEQ.size(); s++)
4786 SequenceGroup hidden = new SequenceGroup();
4787 boolean isRepresentative = false;
4788 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4790 isRepresentative = true;
4791 SequenceI sequenceToHide = al
4792 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4793 hidden.addSequence(sequenceToHide, false);
4794 // remove from hiddenSeqs list so we don't try to hide it twice
4795 hiddenSeqs.remove(sequenceToHide);
4797 if (isRepresentative)
4799 SequenceI representativeSequence = al.getSequenceAt(s);
4800 hidden.addSequence(representativeSequence, false);
4801 viewport.hideRepSequences(representativeSequence, hidden);
4805 SequenceI[] hseqs = hiddenSeqs
4806 .toArray(new SequenceI[hiddenSeqs.size()]);
4807 viewport.hideSequence(hseqs);
4810 // recover view properties and display parameters
4812 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4813 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4814 final int pidThreshold = safeInt(view.getPidThreshold());
4815 viewport.setThreshold(pidThreshold);
4817 viewport.setColourText(safeBoolean(view.isShowColourText()));
4819 viewport.setConservationSelected(
4820 safeBoolean(view.isConservationSelected()));
4821 viewport.setIncrement(safeInt(view.getConsThreshold()));
4822 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4823 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4824 viewport.setFont(new Font(view.getFontName(),
4825 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4827 ViewStyleI vs = viewport.getViewStyle();
4828 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4829 viewport.setViewStyle(vs);
4830 // TODO: allow custom charWidth/Heights to be restored by updating them
4831 // after setting font - which means set above to false
4832 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4833 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4834 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4836 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4838 viewport.setShowText(safeBoolean(view.isShowText()));
4840 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4841 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4842 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4843 viewport.setShowUnconserved(view.isShowUnconserved());
4844 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4846 if (view.getViewName() != null)
4848 viewport.setViewName(view.getViewName());
4849 af.setInitialTabVisible();
4851 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4852 safeInt(view.getWidth()), safeInt(view.getHeight()));
4853 // startSeq set in af.alignPanel.updateLayout below
4854 af.alignPanel.updateLayout();
4855 ColourSchemeI cs = null;
4856 // apply colourschemes
4857 if (view.getBgColour() != null)
4859 if (view.getBgColour().startsWith("ucs"))
4861 cs = getUserColourScheme(jm, view.getBgColour());
4863 else if (view.getBgColour().startsWith("Annotation"))
4865 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4866 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4873 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4874 view.getBgColour());
4879 * turn off 'alignment colour applies to all groups'
4880 * while restoring global colour scheme
4882 viewport.setColourAppliesToAllGroups(false);
4883 viewport.setGlobalColourScheme(cs);
4884 viewport.getResidueShading().setThreshold(pidThreshold,
4885 view.isIgnoreGapsinConsensus());
4886 viewport.getResidueShading()
4887 .setConsensus(viewport.getSequenceConsensusHash());
4888 if (safeBoolean(view.isConservationSelected()) && cs != null)
4890 viewport.getResidueShading()
4891 .setConservationInc(safeInt(view.getConsThreshold()));
4893 af.changeColour(cs);
4894 viewport.setColourAppliesToAllGroups(true);
4896 viewport.setShowSequenceFeatures(
4897 safeBoolean(view.isShowSequenceFeatures()));
4899 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4900 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4901 viewport.setFollowHighlight(view.isFollowHighlight());
4902 viewport.followSelection = view.isFollowSelection();
4903 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4904 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4905 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4906 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4907 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4908 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4909 viewport.setShowGroupConservation(view.isShowGroupConservation());
4910 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4911 viewport.setShowComplementFeaturesOnTop(
4912 view.isShowComplementFeaturesOnTop());
4914 // recover feature settings
4915 if (jm.getFeatureSettings() != null)
4917 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4918 .getFeatureRenderer();
4919 FeaturesDisplayed fdi;
4920 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4921 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
4923 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4924 Map<String, Float> featureOrder = new Hashtable<>();
4926 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
4929 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4930 String featureType = setting.getType();
4933 * restore feature filters (if any)
4935 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4937 if (filters != null)
4939 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
4941 if (!filter.isEmpty())
4943 fr.setFeatureFilter(featureType, filter);
4948 * restore feature colour scheme
4950 Color maxColour = new Color(setting.getColour());
4951 if (setting.getMincolour() != null)
4954 * minColour is always set unless a simple colour
4955 * (including for colour by label though it doesn't use it)
4957 Color minColour = new Color(setting.getMincolour().intValue());
4958 Color noValueColour = minColour;
4959 NoValueColour noColour = setting.getNoValueColour();
4960 if (noColour == NoValueColour.NONE)
4962 noValueColour = null;
4964 else if (noColour == NoValueColour.MAX)
4966 noValueColour = maxColour;
4968 float min = safeFloat(safeFloat(setting.getMin()));
4969 float max = setting.getMax() == null ? 1f
4970 : setting.getMax().floatValue();
4971 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4972 maxColour, noValueColour, min, max);
4973 if (setting.getAttributeName().size() > 0)
4975 gc.setAttributeName(setting.getAttributeName().toArray(
4976 new String[setting.getAttributeName().size()]));
4978 if (setting.getThreshold() != null)
4980 gc.setThreshold(setting.getThreshold().floatValue());
4981 int threshstate = safeInt(setting.getThreshstate());
4982 // -1 = None, 0 = Below, 1 = Above threshold
4983 if (threshstate == 0)
4985 gc.setBelowThreshold(true);
4987 else if (threshstate == 1)
4989 gc.setAboveThreshold(true);
4992 gc.setAutoScaled(true); // default
4993 if (setting.isAutoScale() != null)
4995 gc.setAutoScaled(setting.isAutoScale());
4997 if (setting.isColourByLabel() != null)
4999 gc.setColourByLabel(setting.isColourByLabel());
5001 // and put in the feature colour table.
5002 featureColours.put(featureType, gc);
5006 featureColours.put(featureType, new FeatureColour(maxColour));
5008 renderOrder[fs] = featureType;
5009 if (setting.getOrder() != null)
5011 featureOrder.put(featureType, setting.getOrder().floatValue());
5015 featureOrder.put(featureType, Float.valueOf(
5016 fs / jm.getFeatureSettings().getSetting().size()));
5018 if (safeBoolean(setting.isDisplay()))
5020 fdi.setVisible(featureType);
5023 Map<String, Boolean> fgtable = new Hashtable<>();
5024 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5026 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5027 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5029 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5030 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5031 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5032 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5033 fgtable, featureColours, 1.0f, featureOrder);
5034 fr.transferSettings(frs);
5037 if (view.getHiddenColumns().size() > 0)
5039 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5041 final HiddenColumns hc = view.getHiddenColumns().get(c);
5042 viewport.hideColumns(safeInt(hc.getStart()),
5043 safeInt(hc.getEnd()) /* +1 */);
5046 if (view.getCalcIdParam() != null)
5048 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5050 if (calcIdParam != null)
5052 if (recoverCalcIdParam(calcIdParam, viewport))
5057 Console.warn("Couldn't recover parameters for "
5058 + calcIdParam.getCalcId());
5063 af.setMenusFromViewport(viewport);
5064 af.setTitle(view.getTitle());
5065 // TODO: we don't need to do this if the viewport is aready visible.
5067 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5068 * has a 'cdna/protein complement' view, in which case save it in order to
5069 * populate a SplitFrame once all views have been read in.
5071 String complementaryViewId = view.getComplementId();
5072 if (complementaryViewId == null)
5074 Desktop.addInternalFrame(af, view.getTitle(),
5075 safeInt(view.getWidth()), safeInt(view.getHeight()));
5076 // recompute any autoannotation
5077 af.alignPanel.updateAnnotation(false, true);
5078 reorderAutoannotation(af, al, autoAlan);
5079 af.alignPanel.alignmentChanged();
5083 splitFrameCandidates.put(view, af);
5090 * Reads saved data to restore Colour by Annotation settings
5092 * @param viewAnnColour
5096 * @param checkGroupAnnColour
5099 private ColourSchemeI constructAnnotationColour(
5100 AnnotationColourScheme viewAnnColour, AlignFrame af,
5101 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5103 boolean propagateAnnColour = false;
5104 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5106 if (checkGroupAnnColour && al.getGroups() != null
5107 && al.getGroups().size() > 0)
5109 // pre 2.8.1 behaviour
5110 // check to see if we should transfer annotation colours
5111 propagateAnnColour = true;
5112 for (SequenceGroup sg : al.getGroups())
5114 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5116 propagateAnnColour = false;
5122 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5124 String annotationId = viewAnnColour.getAnnotation();
5125 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5128 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5130 if (matchedAnnotation == null
5131 && annAlignment.getAlignmentAnnotation() != null)
5133 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5136 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5138 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5143 if (matchedAnnotation == null)
5145 System.err.println("Failed to match annotation colour scheme for "
5149 if (matchedAnnotation.getThreshold() == null)
5151 matchedAnnotation.setThreshold(
5152 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5153 "Threshold", Color.black));
5156 AnnotationColourGradient cs = null;
5157 if (viewAnnColour.getColourScheme().equals("None"))
5159 cs = new AnnotationColourGradient(matchedAnnotation,
5160 new Color(safeInt(viewAnnColour.getMinColour())),
5161 new Color(safeInt(viewAnnColour.getMaxColour())),
5162 safeInt(viewAnnColour.getAboveThreshold()));
5164 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5166 cs = new AnnotationColourGradient(matchedAnnotation,
5167 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5168 safeInt(viewAnnColour.getAboveThreshold()));
5172 cs = new AnnotationColourGradient(matchedAnnotation,
5173 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5174 viewAnnColour.getColourScheme()),
5175 safeInt(viewAnnColour.getAboveThreshold()));
5178 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5179 boolean useOriginalColours = safeBoolean(
5180 viewAnnColour.isPredefinedColours());
5181 cs.setSeqAssociated(perSequenceOnly);
5182 cs.setPredefinedColours(useOriginalColours);
5184 if (propagateAnnColour && al.getGroups() != null)
5186 // Also use these settings for all the groups
5187 for (int g = 0; g < al.getGroups().size(); g++)
5189 SequenceGroup sg = al.getGroups().get(g);
5190 if (sg.getGroupColourScheme() == null)
5195 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5196 matchedAnnotation, sg.getColourScheme(),
5197 safeInt(viewAnnColour.getAboveThreshold()));
5198 sg.setColourScheme(groupScheme);
5199 groupScheme.setSeqAssociated(perSequenceOnly);
5200 groupScheme.setPredefinedColours(useOriginalColours);
5206 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5207 List<JvAnnotRow> autoAlan)
5209 // copy over visualization settings for autocalculated annotation in the
5211 if (al.getAlignmentAnnotation() != null)
5214 * Kludge for magic autoannotation names (see JAL-811)
5216 String[] magicNames = new String[] { "Consensus", "Quality",
5218 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5219 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5220 for (String nm : magicNames)
5222 visan.put(nm, nullAnnot);
5224 for (JvAnnotRow auan : autoAlan)
5226 visan.put(auan.template.label
5227 + (auan.template.getCalcId() == null ? ""
5228 : "\t" + auan.template.getCalcId()),
5231 int hSize = al.getAlignmentAnnotation().length;
5232 List<JvAnnotRow> reorder = new ArrayList<>();
5233 // work through any autoCalculated annotation already on the view
5234 // removing it if it should be placed in a different location on the
5235 // annotation panel.
5236 List<String> remains = new ArrayList<>(visan.keySet());
5237 for (int h = 0; h < hSize; h++)
5239 jalview.datamodel.AlignmentAnnotation jalan = al
5240 .getAlignmentAnnotation()[h];
5241 if (jalan.autoCalculated)
5244 JvAnnotRow valan = visan.get(k = jalan.label);
5245 if (jalan.getCalcId() != null)
5247 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5252 // delete the auto calculated row from the alignment
5253 al.deleteAnnotation(jalan, false);
5257 if (valan != nullAnnot)
5259 if (jalan != valan.template)
5261 // newly created autoannotation row instance
5262 // so keep a reference to the visible annotation row
5263 // and copy over all relevant attributes
5264 if (valan.template.graphHeight >= 0)
5267 jalan.graphHeight = valan.template.graphHeight;
5269 jalan.visible = valan.template.visible;
5271 reorder.add(new JvAnnotRow(valan.order, jalan));
5276 // Add any (possibly stale) autocalculated rows that were not appended to
5277 // the view during construction
5278 for (String other : remains)
5280 JvAnnotRow othera = visan.get(other);
5281 if (othera != nullAnnot && othera.template.getCalcId() != null
5282 && othera.template.getCalcId().length() > 0)
5284 reorder.add(othera);
5287 // now put the automatic annotation in its correct place
5288 int s = 0, srt[] = new int[reorder.size()];
5289 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5290 for (JvAnnotRow jvar : reorder)
5293 srt[s++] = jvar.order;
5296 jalview.util.QuickSort.sort(srt, rws);
5297 // and re-insert the annotation at its correct position
5298 for (JvAnnotRow jvar : rws)
5300 al.addAnnotation(jvar.template, jvar.order);
5302 af.alignPanel.adjustAnnotationHeight();
5306 Hashtable skipList = null;
5309 * TODO remove this method
5312 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5313 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5314 * throw new Error("Implementation Error. No skipList defined for this
5315 * Jalview2XML instance."); } return (AlignFrame)
5316 * skipList.get(view.getSequenceSetId()); }
5320 * Check if the Jalview view contained in object should be skipped or not.
5323 * @return true if view's sequenceSetId is a key in skipList
5325 private boolean skipViewport(JalviewModel object)
5327 if (skipList == null)
5331 String id = object.getViewport().get(0).getSequenceSetId();
5332 if (skipList.containsKey(id))
5334 Console.debug("Skipping seuqence set id " + id);
5340 public void addToSkipList(AlignFrame af)
5342 if (skipList == null)
5344 skipList = new Hashtable();
5346 skipList.put(af.getViewport().getSequenceSetId(), af);
5349 public void clearSkipList()
5351 if (skipList != null)
5358 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5359 boolean ignoreUnrefed, String uniqueSeqSetId)
5361 jalview.datamodel.AlignmentI ds = getDatasetFor(
5362 vamsasSet.getDatasetId());
5363 AlignmentI xtant_ds = ds;
5364 if (xtant_ds == null)
5366 // good chance we are about to create a new dataset, but check if we've
5367 // seen some of the dataset sequence IDs before.
5368 // TODO: skip this check if we are working with project generated by
5369 // version 2.11 or later
5370 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5371 if (xtant_ds != null)
5374 addDatasetRef(vamsasSet.getDatasetId(), ds);
5377 Vector<SequenceI> dseqs = null;
5380 // recovering an alignment View
5381 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5382 if (seqSetDS != null)
5384 if (ds != null && ds != seqSetDS)
5387 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5388 + " - CDS/Protein crossreference data may be lost");
5389 if (xtant_ds != null)
5391 // This can only happen if the unique sequence set ID was bound to a
5392 // dataset that did not contain any of the sequences in the view
5393 // currently being restored.
5395 "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.");
5399 addDatasetRef(vamsasSet.getDatasetId(), ds);
5404 // try even harder to restore dataset
5405 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5406 // create a list of new dataset sequences
5407 dseqs = new Vector<>();
5409 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5411 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5412 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5414 // create a new dataset
5417 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5418 dseqs.copyInto(dsseqs);
5419 ds = new jalview.datamodel.Alignment(dsseqs);
5420 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5421 + " for alignment " + System.identityHashCode(al));
5422 addDatasetRef(vamsasSet.getDatasetId(), ds);
5424 // set the dataset for the newly imported alignment.
5425 if (al.getDataset() == null && !ignoreUnrefed)
5428 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5429 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5431 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5435 * XML dataset sequence ID to materialised dataset reference
5437 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5440 * @return the first materialised dataset reference containing a dataset
5441 * sequence referenced in the given view
5443 * - sequences from the view
5445 AlignmentI checkIfHasDataset(List<Sequence> list)
5447 for (Sequence restoredSeq : list)
5449 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5450 if (datasetFor != null)
5459 * Register ds as the containing dataset for the dataset sequences referenced
5460 * by sequences in list
5463 * - sequences in a view
5466 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5468 for (Sequence restoredSeq : list)
5470 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5471 if (prevDS != null && prevDS != ds)
5473 Console.warn("Dataset sequence appears in many datasets: "
5474 + restoredSeq.getDsseqid());
5475 // TODO: try to merge!
5483 * sequence definition to create/merge dataset sequence for
5487 * vector to add new dataset sequence to
5488 * @param ignoreUnrefed
5489 * - when true, don't create new sequences from vamsasSeq if it's id
5490 * doesn't already have an asssociated Jalview sequence.
5492 * - used to reorder the sequence in the alignment according to the
5493 * vamsasSeq array ordering, to preserve ordering of dataset
5495 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5496 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5499 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5501 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5502 boolean reorder = false;
5503 SequenceI dsq = null;
5504 if (sq != null && sq.getDatasetSequence() != null)
5506 dsq = sq.getDatasetSequence();
5512 if (sq == null && ignoreUnrefed)
5516 String sqid = vamsasSeq.getDsseqid();
5519 // need to create or add a new dataset sequence reference to this sequence
5522 dsq = seqRefIds.get(sqid);
5527 // make a new dataset sequence
5528 dsq = sq.createDatasetSequence();
5531 // make up a new dataset reference for this sequence
5532 sqid = seqHash(dsq);
5534 dsq.setVamsasId(uniqueSetSuffix + sqid);
5535 seqRefIds.put(sqid, dsq);
5540 dseqs.addElement(dsq);
5545 ds.addSequence(dsq);
5551 { // make this dataset sequence sq's dataset sequence
5552 sq.setDatasetSequence(dsq);
5553 // and update the current dataset alignment
5558 if (!dseqs.contains(dsq))
5565 if (ds.findIndex(dsq) < 0)
5567 ds.addSequence(dsq);
5574 // TODO: refactor this as a merge dataset sequence function
5575 // now check that sq (the dataset sequence) sequence really is the union of
5576 // all references to it
5577 // boolean pre = sq.getStart() < dsq.getStart();
5578 // boolean post = sq.getEnd() > dsq.getEnd();
5582 // StringBuffer sb = new StringBuffer();
5583 String newres = jalview.analysis.AlignSeq.extractGaps(
5584 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5585 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5586 && newres.length() > dsq.getLength())
5588 // Update with the longer sequence.
5592 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5593 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5594 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5595 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5597 dsq.setSequence(newres);
5599 // TODO: merges will never happen if we 'know' we have the real dataset
5600 // sequence - this should be detected when id==dssid
5602 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5603 // + (pre ? "prepended" : "") + " "
5604 // + (post ? "appended" : ""));
5609 // sequence refs are identical. We may need to update the existing dataset
5610 // alignment with this one, though.
5611 if (ds != null && dseqs == null)
5613 int opos = ds.findIndex(dsq);
5614 SequenceI tseq = null;
5615 if (opos != -1 && vseqpos != opos)
5617 // remove from old position
5618 ds.deleteSequence(dsq);
5620 if (vseqpos < ds.getHeight())
5622 if (vseqpos != opos)
5624 // save sequence at destination position
5625 tseq = ds.getSequenceAt(vseqpos);
5626 ds.replaceSequenceAt(vseqpos, dsq);
5627 ds.addSequence(tseq);
5632 ds.addSequence(dsq);
5639 * TODO use AlignmentI here and in related methods - needs
5640 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5642 Hashtable<String, AlignmentI> datasetIds = null;
5644 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5646 private AlignmentI getDatasetFor(String datasetId)
5648 if (datasetIds == null)
5650 datasetIds = new Hashtable<>();
5653 if (datasetIds.containsKey(datasetId))
5655 return datasetIds.get(datasetId);
5660 private void addDatasetRef(String datasetId, AlignmentI dataset)
5662 if (datasetIds == null)
5664 datasetIds = new Hashtable<>();
5666 datasetIds.put(datasetId, dataset);
5670 * make a new dataset ID for this jalview dataset alignment
5675 private String getDatasetIdRef(AlignmentI dataset)
5677 if (dataset.getDataset() != null)
5680 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5682 String datasetId = makeHashCode(dataset, null);
5683 if (datasetId == null)
5685 // make a new datasetId and record it
5686 if (dataset2Ids == null)
5688 dataset2Ids = new IdentityHashMap<>();
5692 datasetId = dataset2Ids.get(dataset);
5694 if (datasetId == null)
5696 datasetId = "ds" + dataset2Ids.size() + 1;
5697 dataset2Ids.put(dataset, datasetId);
5704 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5705 * constructed as a special subclass GeneLocus.
5707 * @param datasetSequence
5710 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5712 for (int d = 0; d < sequence.getDBRef().size(); d++)
5714 DBRef dr = sequence.getDBRef().get(d);
5718 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5719 dr.getAccessionId());
5723 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5724 dr.getAccessionId());
5726 if (dr.getMapping() != null)
5728 entry.setMap(addMapping(dr.getMapping()));
5730 entry.setCanonical(dr.isCanonical());
5731 datasetSequence.addDBRef(entry);
5735 private jalview.datamodel.Mapping addMapping(Mapping m)
5737 SequenceI dsto = null;
5738 // Mapping m = dr.getMapping();
5739 int fr[] = new int[m.getMapListFrom().size() * 2];
5740 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5741 for (int _i = 0; from.hasNext(); _i += 2)
5743 MapListFrom mf = from.next();
5744 fr[_i] = mf.getStart();
5745 fr[_i + 1] = mf.getEnd();
5747 int fto[] = new int[m.getMapListTo().size() * 2];
5748 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5749 for (int _i = 0; to.hasNext(); _i += 2)
5751 MapListTo mf = to.next();
5752 fto[_i] = mf.getStart();
5753 fto[_i + 1] = mf.getEnd();
5755 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5756 fto, m.getMapFromUnit().intValue(),
5757 m.getMapToUnit().intValue());
5760 * (optional) choice of dseqFor or Sequence
5762 if (m.getDseqFor() != null)
5764 String dsfor = m.getDseqFor();
5765 if (seqRefIds.containsKey(dsfor))
5770 jmap.setTo(seqRefIds.get(dsfor));
5774 frefedSequence.add(newMappingRef(dsfor, jmap));
5777 else if (m.getSequence() != null)
5780 * local sequence definition
5782 Sequence ms = m.getSequence();
5783 SequenceI djs = null;
5784 String sqid = ms.getDsseqid();
5785 if (sqid != null && sqid.length() > 0)
5788 * recover dataset sequence
5790 djs = seqRefIds.get(sqid);
5795 "Warning - making up dataset sequence id for DbRef sequence map reference");
5796 sqid = ((Object) ms).toString(); // make up a new hascode for
5797 // undefined dataset sequence hash
5798 // (unlikely to happen)
5804 * make a new dataset sequence and add it to refIds hash
5806 djs = new jalview.datamodel.Sequence(ms.getName(),
5808 djs.setStart(jmap.getMap().getToLowest());
5809 djs.setEnd(jmap.getMap().getToHighest());
5810 djs.setVamsasId(uniqueSetSuffix + sqid);
5812 incompleteSeqs.put(sqid, djs);
5813 seqRefIds.put(sqid, djs);
5816 Console.debug("about to recurse on addDBRefs.");
5825 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5826 * view as XML (but not to file), and then reloading it
5831 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5834 JalviewModel jm = saveState(ap, null, null, null);
5837 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5838 ap.getAlignment().getDataset());
5840 uniqueSetSuffix = "";
5841 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5842 jm.getViewport().get(0).setId(null);
5843 // we don't overwrite the view we just copied
5845 if (this.frefedSequence == null)
5847 frefedSequence = new Vector<>();
5850 viewportsAdded.clear();
5852 AlignFrame af = loadFromObject(jm, null, false, null);
5853 af.getAlignPanels().clear();
5854 af.closeMenuItem_actionPerformed(true);
5857 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5858 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5859 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5860 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5861 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5864 return af.alignPanel;
5867 private Hashtable jvids2vobj;
5870 * set the object to ID mapping tables used to write/recover objects and XML
5871 * ID strings for the jalview project. If external tables are provided then
5872 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5873 * object goes out of scope. - also populates the datasetIds hashtable with
5874 * alignment objects containing dataset sequences
5877 * Map from ID strings to jalview datamodel
5879 * Map from jalview datamodel to ID strings
5883 public void setObjectMappingTables(Hashtable vobj2jv,
5884 IdentityHashMap jv2vobj)
5886 this.jv2vobj = jv2vobj;
5887 this.vobj2jv = vobj2jv;
5888 Iterator ds = jv2vobj.keySet().iterator();
5890 while (ds.hasNext())
5892 Object jvobj = ds.next();
5893 id = jv2vobj.get(jvobj).toString();
5894 if (jvobj instanceof jalview.datamodel.Alignment)
5896 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5898 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5901 else if (jvobj instanceof jalview.datamodel.Sequence)
5903 // register sequence object so the XML parser can recover it.
5904 if (seqRefIds == null)
5906 seqRefIds = new HashMap<>();
5908 if (seqsToIds == null)
5910 seqsToIds = new IdentityHashMap<>();
5912 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5913 seqsToIds.put((SequenceI) jvobj, id);
5915 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5918 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5919 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5920 if (jvann.annotationId == null)
5922 jvann.annotationId = anid;
5924 if (!jvann.annotationId.equals(anid))
5926 // TODO verify that this is the correct behaviour
5927 Console.warn("Overriding Annotation ID for " + anid
5928 + " from different id : " + jvann.annotationId);
5929 jvann.annotationId = anid;
5932 else if (jvobj instanceof String)
5934 if (jvids2vobj == null)
5936 jvids2vobj = new Hashtable();
5937 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5942 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5948 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5949 * objects created from the project archive. If string is null (default for
5950 * construction) then suffix will be set automatically.
5954 public void setUniqueSetSuffix(String string)
5956 uniqueSetSuffix = string;
5961 * uses skipList2 as the skipList for skipping views on sequence sets
5962 * associated with keys in the skipList
5966 public void setSkipList(Hashtable skipList2)
5968 skipList = skipList2;
5972 * Reads the jar entry of given name and returns its contents, or null if the
5973 * entry is not found.
5976 * @param jarEntryName
5979 protected String readJarEntry(jarInputStreamProvider jprovider,
5980 String jarEntryName)
5982 String result = null;
5983 BufferedReader in = null;
5988 * Reopen the jar input stream and traverse its entries to find a matching
5991 JarInputStream jin = jprovider.getJarInputStream();
5992 JarEntry entry = null;
5995 entry = jin.getNextJarEntry();
5996 } while (entry != null && !entry.getName().equals(jarEntryName));
6000 StringBuilder out = new StringBuilder(256);
6001 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6004 while ((data = in.readLine()) != null)
6008 result = out.toString();
6013 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6015 } catch (Exception ex)
6017 ex.printStackTrace();
6025 } catch (IOException e)
6036 * Returns an incrementing counter (0, 1, 2...)
6040 private synchronized int nextCounter()
6046 * Loads any saved PCA viewers
6051 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6055 List<PcaViewer> pcaviewers = model.getPcaViewer();
6056 for (PcaViewer viewer : pcaviewers)
6058 String modelName = viewer.getScoreModelName();
6059 SimilarityParamsI params = new SimilarityParams(
6060 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6061 viewer.isIncludeGaps(),
6062 viewer.isDenominateByShortestLength());
6065 * create the panel (without computing the PCA)
6067 PCAPanel panel = new PCAPanel(ap, modelName, params);
6069 panel.setTitle(viewer.getTitle());
6070 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6071 viewer.getWidth(), viewer.getHeight()));
6073 boolean showLabels = viewer.isShowLabels();
6074 panel.setShowLabels(showLabels);
6075 panel.getRotatableCanvas().setShowLabels(showLabels);
6076 panel.getRotatableCanvas()
6077 .setBgColour(new Color(viewer.getBgColour()));
6078 panel.getRotatableCanvas()
6079 .setApplyToAllViews(viewer.isLinkToAllViews());
6082 * load PCA output data
6084 ScoreModelI scoreModel = ScoreModels.getInstance()
6085 .getScoreModel(modelName, ap);
6086 PCA pca = new PCA(null, scoreModel, params);
6087 PcaDataType pcaData = viewer.getPcaData();
6089 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6090 pca.setPairwiseScores(pairwise);
6092 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6093 pca.setTridiagonal(triDiag);
6095 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6096 pca.setEigenmatrix(result);
6098 panel.getPcaModel().setPCA(pca);
6101 * we haven't saved the input data! (JAL-2647 to do)
6103 panel.setInputData(null);
6106 * add the sequence points for the PCA display
6108 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6109 for (SequencePoint sp : viewer.getSequencePoint())
6111 String seqId = sp.getSequenceRef();
6112 SequenceI seq = seqRefIds.get(seqId);
6115 throw new IllegalStateException(
6116 "Unmatched seqref for PCA: " + seqId);
6118 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6119 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6121 seqPoints.add(seqPoint);
6123 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6126 * set min-max ranges and scale after setPoints (which recomputes them)
6128 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6129 SeqPointMin spMin = viewer.getSeqPointMin();
6130 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6132 SeqPointMax spMax = viewer.getSeqPointMax();
6133 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6135 panel.getRotatableCanvas().setSeqMinMax(min, max);
6137 // todo: hold points list in PCAModel only
6138 panel.getPcaModel().setSequencePoints(seqPoints);
6140 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6141 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6142 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6144 // is this duplication needed?
6145 panel.setTop(seqPoints.size() - 1);
6146 panel.getPcaModel().setTop(seqPoints.size() - 1);
6149 * add the axes' end points for the display
6151 for (int i = 0; i < 3; i++)
6153 Axis axis = viewer.getAxis().get(i);
6154 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6155 axis.getXPos(), axis.getYPos(), axis.getZPos());
6158 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6159 "label.calc_title", "PCA", modelName), 475, 450);
6161 } catch (Exception ex)
6163 Console.error("Error loading PCA: " + ex.toString());
6168 * Creates a new structure viewer window
6175 protected void createStructureViewer(ViewerType viewerType,
6176 final Entry<String, StructureViewerModel> viewerData,
6177 AlignFrame af, jarInputStreamProvider jprovider)
6179 final StructureViewerModel viewerModel = viewerData.getValue();
6180 String sessionFilePath = null;
6182 if (viewerType == ViewerType.JMOL)
6184 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6188 String viewerJarEntryName = getViewerJarEntryName(
6189 viewerModel.getViewId());
6190 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6191 "viewerSession", ".tmp");
6193 final String sessionPath = sessionFilePath;
6194 final String sviewid = viewerData.getKey();
6197 SwingUtilities.invokeAndWait(new Runnable()
6202 JalviewStructureDisplayI sview = null;
6205 sview = StructureViewer.createView(viewerType, af.alignPanel,
6206 viewerModel, sessionPath, sviewid);
6207 addNewStructureViewer(sview);
6208 } catch (OutOfMemoryError ex)
6210 new OOMWarning("Restoring structure view for " + viewerType,
6211 (OutOfMemoryError) ex.getCause());
6212 if (sview != null && sview.isVisible())
6214 sview.closeViewer(false);
6215 sview.setVisible(false);
6221 } catch (InvocationTargetException | InterruptedException ex)
6223 Console.warn("Unexpected error when opening " + viewerType
6224 + " structure viewer", ex);
6229 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6230 * the path of the file. "load file" commands are rewritten to change the
6231 * original PDB file names to those created as the Jalview project is loaded.
6237 private String rewriteJmolSession(StructureViewerModel svattrib,
6238 jarInputStreamProvider jprovider)
6240 String state = svattrib.getStateData(); // Jalview < 2.9
6241 if (state == null || state.isEmpty()) // Jalview >= 2.9
6243 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6244 state = readJarEntry(jprovider, jarEntryName);
6246 // TODO or simpler? for each key in oldFiles,
6247 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6248 // (allowing for different path escapings)
6249 StringBuilder rewritten = new StringBuilder(state.length());
6250 int cp = 0, ncp, ecp;
6251 Map<File, StructureData> oldFiles = svattrib.getFileData();
6252 while ((ncp = state.indexOf("load ", cp)) > -1)
6256 // look for next filename in load statement
6257 rewritten.append(state.substring(cp,
6258 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6259 String oldfilenam = state.substring(ncp,
6260 ecp = state.indexOf("\"", ncp));
6261 // recover the new mapping data for this old filename
6262 // have to normalize filename - since Jmol and jalview do
6263 // filename translation differently.
6264 StructureData filedat = oldFiles.get(new File(oldfilenam));
6265 if (filedat == null)
6267 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6268 filedat = oldFiles.get(new File(reformatedOldFilename));
6270 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6271 rewritten.append("\"");
6272 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6273 // look for next file statement.
6274 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6278 // just append rest of state
6279 rewritten.append(state.substring(cp));
6283 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6284 rewritten = new StringBuilder(state);
6285 rewritten.append("; load append ");
6286 for (File id : oldFiles.keySet())
6288 // add pdb files that should be present in the viewer
6289 StructureData filedat = oldFiles.get(id);
6290 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6292 rewritten.append(";");
6295 if (rewritten.length() == 0)
6299 final String history = "history = ";
6300 int historyIndex = rewritten.indexOf(history);
6301 if (historyIndex > -1)
6304 * change "history = [true|false];" to "history = [1|0];"
6306 historyIndex += history.length();
6307 String val = rewritten.substring(historyIndex, historyIndex + 5);
6308 if (val.startsWith("true"))
6310 rewritten.replace(historyIndex, historyIndex + 4, "1");
6312 else if (val.startsWith("false"))
6314 rewritten.replace(historyIndex, historyIndex + 5, "0");
6320 File tmp = File.createTempFile("viewerSession", ".tmp");
6321 try (OutputStream os = new FileOutputStream(tmp))
6323 InputStream is = new ByteArrayInputStream(
6324 rewritten.toString().getBytes());
6326 return tmp.getAbsolutePath();
6328 } catch (IOException e)
6330 Console.error("Error restoring Jmol session: " + e.toString());
6336 * Populates an XML model of the feature colour scheme for one feature type
6338 * @param featureType
6342 public static Colour marshalColour(String featureType,
6343 FeatureColourI fcol)
6345 Colour col = new Colour();
6346 if (fcol.isSimpleColour())
6348 col.setRGB(Format.getHexString(fcol.getColour()));
6352 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6353 col.setMin(fcol.getMin());
6354 col.setMax(fcol.getMax());
6355 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6356 col.setAutoScale(fcol.isAutoScaled());
6357 col.setThreshold(fcol.getThreshold());
6358 col.setColourByLabel(fcol.isColourByLabel());
6359 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6360 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6361 : ThresholdType.NONE));
6362 if (fcol.isColourByAttribute())
6364 final String[] attName = fcol.getAttributeName();
6365 col.getAttributeName().add(attName[0]);
6366 if (attName.length > 1)
6368 col.getAttributeName().add(attName[1]);
6371 Color noColour = fcol.getNoColour();
6372 if (noColour == null)
6374 col.setNoValueColour(NoValueColour.NONE);
6376 else if (noColour == fcol.getMaxColour())
6378 col.setNoValueColour(NoValueColour.MAX);
6382 col.setNoValueColour(NoValueColour.MIN);
6385 col.setName(featureType);
6390 * Populates an XML model of the feature filter(s) for one feature type
6392 * @param firstMatcher
6393 * the first (or only) match condition)
6395 * remaining match conditions (if any)
6397 * if true, conditions are and-ed, else or-ed
6399 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6400 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6403 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6405 if (filters.hasNext())
6410 CompoundMatcher compound = new CompoundMatcher();
6411 compound.setAnd(and);
6412 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6413 firstMatcher, Collections.emptyIterator(), and);
6414 // compound.addMatcherSet(matcher1);
6415 compound.getMatcherSet().add(matcher1);
6416 FeatureMatcherI nextMatcher = filters.next();
6417 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6418 nextMatcher, filters, and);
6419 // compound.addMatcherSet(matcher2);
6420 compound.getMatcherSet().add(matcher2);
6421 result.setCompoundMatcher(compound);
6426 * single condition matcher
6428 // MatchCondition matcherModel = new MatchCondition();
6429 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6430 matcherModel.setCondition(
6431 firstMatcher.getMatcher().getCondition().getStableName());
6432 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6433 if (firstMatcher.isByAttribute())
6435 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6436 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6437 String[] attName = firstMatcher.getAttribute();
6438 matcherModel.getAttributeName().add(attName[0]); // attribute
6439 if (attName.length > 1)
6441 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6444 else if (firstMatcher.isByLabel())
6446 matcherModel.setBy(FilterBy.BY_LABEL);
6448 else if (firstMatcher.isByScore())
6450 matcherModel.setBy(FilterBy.BY_SCORE);
6452 result.setMatchCondition(matcherModel);
6459 * Loads one XML model of a feature filter to a Jalview object
6461 * @param featureType
6462 * @param matcherSetModel
6465 public static FeatureMatcherSetI parseFilter(String featureType,
6466 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6468 FeatureMatcherSetI result = new FeatureMatcherSet();
6471 parseFilterConditions(result, matcherSetModel, true);
6472 } catch (IllegalStateException e)
6474 // mixing AND and OR conditions perhaps
6476 String.format("Error reading filter conditions for '%s': %s",
6477 featureType, e.getMessage()));
6478 // return as much as was parsed up to the error
6485 * Adds feature match conditions to matcherSet as unmarshalled from XML
6486 * (possibly recursively for compound conditions)
6489 * @param matcherSetModel
6491 * if true, multiple conditions are AND-ed, else they are OR-ed
6492 * @throws IllegalStateException
6493 * if AND and OR conditions are mixed
6495 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6496 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6499 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6500 .getMatchCondition();
6506 FilterBy filterBy = mc.getBy();
6507 Condition cond = Condition.fromString(mc.getCondition());
6508 String pattern = mc.getValue();
6509 FeatureMatcherI matchCondition = null;
6510 if (filterBy == FilterBy.BY_LABEL)
6512 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6514 else if (filterBy == FilterBy.BY_SCORE)
6516 matchCondition = FeatureMatcher.byScore(cond, pattern);
6519 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6521 final List<String> attributeName = mc.getAttributeName();
6522 String[] attNames = attributeName
6523 .toArray(new String[attributeName.size()]);
6524 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6529 * note this throws IllegalStateException if AND-ing to a
6530 * previously OR-ed compound condition, or vice versa
6534 matcherSet.and(matchCondition);
6538 matcherSet.or(matchCondition);
6544 * compound condition
6546 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6547 .getCompoundMatcher().getMatcherSet();
6548 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6549 if (matchers.size() == 2)
6551 parseFilterConditions(matcherSet, matchers.get(0), anded);
6552 parseFilterConditions(matcherSet, matchers.get(1), anded);
6556 System.err.println("Malformed compound filter condition");
6562 * Loads one XML model of a feature colour to a Jalview object
6564 * @param colourModel
6567 public static FeatureColourI parseColour(Colour colourModel)
6569 FeatureColourI colour = null;
6571 if (colourModel.getMax() != null)
6573 Color mincol = null;
6574 Color maxcol = null;
6575 Color noValueColour = null;
6579 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6580 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6581 } catch (Exception e)
6583 Console.warn("Couldn't parse out graduated feature color.", e);
6586 NoValueColour noCol = colourModel.getNoValueColour();
6587 if (noCol == NoValueColour.MIN)
6589 noValueColour = mincol;
6591 else if (noCol == NoValueColour.MAX)
6593 noValueColour = maxcol;
6596 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6597 safeFloat(colourModel.getMin()),
6598 safeFloat(colourModel.getMax()));
6599 final List<String> attributeName = colourModel.getAttributeName();
6600 String[] attributes = attributeName
6601 .toArray(new String[attributeName.size()]);
6602 if (attributes != null && attributes.length > 0)
6604 colour.setAttributeName(attributes);
6606 if (colourModel.isAutoScale() != null)
6608 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6610 if (colourModel.isColourByLabel() != null)
6612 colour.setColourByLabel(
6613 colourModel.isColourByLabel().booleanValue());
6615 if (colourModel.getThreshold() != null)
6617 colour.setThreshold(colourModel.getThreshold().floatValue());
6619 ThresholdType ttyp = colourModel.getThreshType();
6620 if (ttyp == ThresholdType.ABOVE)
6622 colour.setAboveThreshold(true);
6624 else if (ttyp == ThresholdType.BELOW)
6626 colour.setBelowThreshold(true);
6631 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6632 colour = new FeatureColour(color);
6638 public static void setStateSavedUpToDate(boolean s)
6640 Console.debug("Setting overall stateSavedUpToDate to " + s);
6641 stateSavedUpToDate = s;
6644 public static boolean stateSavedUpToDate()
6646 Console.debug("Returning overall stateSavedUpToDate value: "
6647 + stateSavedUpToDate);
6648 return stateSavedUpToDate;
6651 public static boolean allSavedUpToDate()
6653 if (stateSavedUpToDate()) // nothing happened since last project save
6656 AlignFrame[] frames = Desktop.getAlignFrames();
6659 for (int i = 0; i < frames.length; i++)
6661 if (frames[i] == null)
6663 if (!frames[i].getViewport().savedUpToDate())
6664 return false; // at least one alignment is not individually saved
6670 // used for debugging and tests
6671 private static int debugDelaySave = 20;
6673 public static void setDebugDelaySave(int n)