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, jalviewModel.getVersion(), 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, String version, AlignFrame af)
4140 if (!isVersionStringLaterThan("2.11.3",
4141 version) && view.getOverview()==null)
4146 * first close any Overview that was opened automatically
4147 * (if so configured in Preferences) so that the view is
4148 * restored in the same state as saved
4150 af.alignPanel.closeOverviewPanel();
4152 Overview overview = view.getOverview();
4153 if (overview != null)
4155 OverviewPanel overviewPanel = af
4156 .openOverviewPanel(overview.isShowHidden());
4157 overviewPanel.setTitle(overview.getTitle());
4158 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4159 overview.getWidth(), overview.getHeight());
4160 Color gap = new Color(overview.getGapColour());
4161 Color residue = new Color(overview.getResidueColour());
4162 Color hidden = new Color(overview.getHiddenColour());
4163 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4168 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4169 * panel is restored from separate jar entries, two (gapped and trimmed) per
4170 * sequence and secondary structure.
4172 * Currently each viewer shows just one sequence and structure (gapped and
4173 * trimmed), however this method is designed to support multiple sequences or
4174 * structures in viewers if wanted in future.
4180 private void loadRnaViewers(jarInputStreamProvider jprovider,
4181 List<JSeq> jseqs, AlignmentPanel ap)
4184 * scan the sequences for references to viewers; create each one the first
4185 * time it is referenced, add Rna models to existing viewers
4187 for (JSeq jseq : jseqs)
4189 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4191 RnaViewer viewer = jseq.getRnaViewer().get(i);
4192 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4195 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4197 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4198 SequenceI seq = seqRefIds.get(jseq.getId());
4199 AlignmentAnnotation ann = this.annotationIds
4200 .get(ss.getAnnotationId());
4203 * add the structure to the Varna display (with session state copied
4204 * from the jar to a temporary file)
4206 boolean gapped = safeBoolean(ss.isGapped());
4207 String rnaTitle = ss.getTitle();
4208 String sessionState = ss.getViewerState();
4209 String tempStateFile = copyJarEntry(jprovider, sessionState,
4211 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4212 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4214 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4220 * Locate and return an already instantiated matching AppVarna, or create one
4224 * @param viewIdSuffix
4228 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4229 String viewIdSuffix, AlignmentPanel ap)
4232 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4233 * if load is repeated
4235 String postLoadId = viewer.getViewId() + viewIdSuffix;
4236 for (JInternalFrame frame : getAllFrames())
4238 if (frame instanceof AppVarna)
4240 AppVarna varna = (AppVarna) frame;
4241 if (postLoadId.equals(varna.getViewId()))
4243 // this viewer is already instantiated
4244 // could in future here add ap as another 'parent' of the
4245 // AppVarna window; currently just 1-to-many
4252 * viewer not found - make it
4254 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4255 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4256 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4257 safeInt(viewer.getDividerLocation()));
4258 AppVarna varna = new AppVarna(model, ap);
4264 * Load any saved trees
4272 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4273 AlignViewport av, AlignmentPanel ap)
4275 // TODO result of automated refactoring - are all these parameters needed?
4278 for (int t = 0; t < jm.getTree().size(); t++)
4281 Tree tree = jm.getTree().get(t);
4283 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4286 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4287 tree.getTitle(), safeInt(tree.getWidth()),
4288 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4289 safeInt(tree.getYpos()));
4290 if (tree.getId() != null)
4292 // perhaps bind the tree id to something ?
4297 // update local tree attributes ?
4298 // TODO: should check if tp has been manipulated by user - if so its
4299 // settings shouldn't be modified
4300 tp.setTitle(tree.getTitle());
4301 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4302 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4303 safeInt(tree.getHeight())));
4304 tp.setViewport(av); // af.viewport;
4305 // TODO: verify 'associate with all views' works still
4306 tp.getTreeCanvas().setViewport(av); // af.viewport;
4307 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4309 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4313 "There was a problem recovering stored Newick tree: \n"
4314 + tree.getNewick());
4318 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4319 tp.fitToWindow_actionPerformed(null);
4321 if (tree.getFontName() != null)
4324 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4325 safeInt(tree.getFontSize())));
4330 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4331 safeInt(view.getFontSize())));
4334 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4335 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4336 tp.showDistances(safeBoolean(tree.isShowDistances()));
4338 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4340 if (safeBoolean(tree.isCurrentTree()))
4342 af.getViewport().setCurrentTree(tp.getTree());
4346 } catch (Exception ex)
4348 ex.printStackTrace();
4353 * Load and link any saved structure viewers.
4360 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4361 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4364 * Run through all PDB ids on the alignment, and collect mappings between
4365 * distinct view ids and all sequences referring to that view.
4367 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4369 for (int i = 0; i < jseqs.size(); i++)
4371 JSeq jseq = jseqs.get(i);
4372 if (jseq.getPdbids().size() > 0)
4374 List<Pdbids> ids = jseq.getPdbids();
4375 for (int p = 0; p < ids.size(); p++)
4377 Pdbids pdbid = ids.get(p);
4378 final int structureStateCount = pdbid.getStructureState().size();
4379 for (int s = 0; s < structureStateCount; s++)
4381 // check to see if we haven't already created this structure view
4382 final StructureState structureState = pdbid.getStructureState()
4384 String sviewid = (structureState.getViewId() == null) ? null
4385 : structureState.getViewId() + uniqueSetSuffix;
4386 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4387 // Originally : pdbid.getFile()
4388 // : TODO: verify external PDB file recovery still works in normal
4389 // jalview project load
4391 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4392 jpdb.setId(pdbid.getId());
4394 int x = safeInt(structureState.getXpos());
4395 int y = safeInt(structureState.getYpos());
4396 int width = safeInt(structureState.getWidth());
4397 int height = safeInt(structureState.getHeight());
4399 // Probably don't need to do this anymore...
4400 // Desktop.desktop.getComponentAt(x, y);
4401 // TODO: NOW: check that this recovers the PDB file correctly.
4402 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4404 jalview.datamodel.SequenceI seq = seqRefIds
4405 .get(jseq.getId() + "");
4406 if (sviewid == null)
4408 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4411 if (!structureViewers.containsKey(sviewid))
4413 String viewerType = structureState.getType();
4414 if (viewerType == null) // pre Jalview 2.9
4416 viewerType = ViewerType.JMOL.toString();
4418 structureViewers.put(sviewid,
4419 new StructureViewerModel(x, y, width, height, false,
4420 false, true, structureState.getViewId(),
4422 // Legacy pre-2.7 conversion JAL-823 :
4423 // do not assume any view has to be linked for colour by
4427 // assemble String[] { pdb files }, String[] { id for each
4428 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4429 // seqs_file 2}, boolean[] {
4430 // linkAlignPanel,superposeWithAlignpanel}} from hash
4431 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4432 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4433 || structureState.isAlignwithAlignPanel());
4436 * Default colour by linked panel to false if not specified (e.g.
4437 * for pre-2.7 projects)
4439 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4440 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4441 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4444 * Default colour by viewer to true if not specified (e.g. for
4447 boolean colourByViewer = jmoldat.isColourByViewer();
4448 colourByViewer &= structureState.isColourByJmol();
4449 jmoldat.setColourByViewer(colourByViewer);
4451 if (jmoldat.getStateData().length() < structureState.getValue()
4452 /*Content()*/.length())
4454 jmoldat.setStateData(structureState.getValue());// Content());
4456 if (pdbid.getFile() != null)
4458 File mapkey = new File(pdbid.getFile());
4459 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4460 if (seqstrmaps == null)
4462 jmoldat.getFileData().put(mapkey,
4463 seqstrmaps = jmoldat.new StructureData(pdbFile,
4466 if (!seqstrmaps.getSeqList().contains(seq))
4468 seqstrmaps.getSeqList().add(seq);
4474 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");
4475 Console.warn(errorMessage);
4481 // Instantiate the associated structure views
4482 for (Entry<String, StructureViewerModel> entry : structureViewers
4487 createOrLinkStructureViewer(entry, af, ap, jprovider);
4488 } catch (Exception e)
4491 "Error loading structure viewer: " + e.getMessage());
4492 // failed - try the next one
4504 protected void createOrLinkStructureViewer(
4505 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4506 AlignmentPanel ap, jarInputStreamProvider jprovider)
4508 final StructureViewerModel stateData = viewerData.getValue();
4511 * Search for any viewer windows already open from other alignment views
4512 * that exactly match the stored structure state
4514 StructureViewerBase comp = findMatchingViewer(viewerData);
4518 linkStructureViewer(ap, comp, stateData);
4522 String type = stateData.getType();
4525 ViewerType viewerType = ViewerType.valueOf(type);
4526 createStructureViewer(viewerType, viewerData, af, jprovider);
4527 } catch (IllegalArgumentException | NullPointerException e)
4529 // TODO JAL-3619 show error dialog / offer an alternative viewer
4530 Console.error("Invalid structure viewer type: " + type);
4535 * Generates a name for the entry in the project jar file to hold state
4536 * information for a structure viewer
4541 protected String getViewerJarEntryName(String viewId)
4543 return VIEWER_PREFIX + viewId;
4547 * Returns any open frame that matches given structure viewer data. The match
4548 * is based on the unique viewId, or (for older project versions) the frame's
4554 protected StructureViewerBase findMatchingViewer(
4555 Entry<String, StructureViewerModel> viewerData)
4557 final String sviewid = viewerData.getKey();
4558 final StructureViewerModel svattrib = viewerData.getValue();
4559 StructureViewerBase comp = null;
4560 JInternalFrame[] frames = getAllFrames();
4561 for (JInternalFrame frame : frames)
4563 if (frame instanceof StructureViewerBase)
4566 * Post jalview 2.4 schema includes structure view id
4568 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4571 comp = (StructureViewerBase) frame;
4572 break; // break added in 2.9
4575 * Otherwise test for matching position and size of viewer frame
4577 else if (frame.getX() == svattrib.getX()
4578 && frame.getY() == svattrib.getY()
4579 && frame.getHeight() == svattrib.getHeight()
4580 && frame.getWidth() == svattrib.getWidth())
4582 comp = (StructureViewerBase) frame;
4583 // no break in faint hope of an exact match on viewId
4591 * Link an AlignmentPanel to an existing structure viewer.
4596 * @param useinViewerSuperpos
4597 * @param usetoColourbyseq
4598 * @param viewerColouring
4600 protected void linkStructureViewer(AlignmentPanel ap,
4601 StructureViewerBase viewer, StructureViewerModel stateData)
4603 // NOTE: if the jalview project is part of a shared session then
4604 // view synchronization should/could be done here.
4606 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4607 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4608 final boolean viewerColouring = stateData.isColourByViewer();
4609 Map<File, StructureData> oldFiles = stateData.getFileData();
4612 * Add mapping for sequences in this view to an already open viewer
4614 final AAStructureBindingModel binding = viewer.getBinding();
4615 for (File id : oldFiles.keySet())
4617 // add this and any other pdb files that should be present in the
4619 StructureData filedat = oldFiles.get(id);
4620 String pdbFile = filedat.getFilePath();
4621 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4622 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4624 binding.addSequenceForStructFile(pdbFile, seq);
4626 // and add the AlignmentPanel's reference to the view panel
4627 viewer.addAlignmentPanel(ap);
4628 if (useinViewerSuperpos)
4630 viewer.useAlignmentPanelForSuperposition(ap);
4634 viewer.excludeAlignmentPanelForSuperposition(ap);
4636 if (usetoColourbyseq)
4638 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4642 viewer.excludeAlignmentPanelForColourbyseq(ap);
4647 * Get all frames within the Desktop.
4651 protected JInternalFrame[] getAllFrames()
4653 JInternalFrame[] frames = null;
4654 // TODO is this necessary - is it safe - risk of hanging?
4659 frames = Desktop.desktop.getAllFrames();
4660 } catch (ArrayIndexOutOfBoundsException e)
4662 // occasional No such child exceptions are thrown here...
4666 } catch (InterruptedException f)
4670 } while (frames == null);
4675 * Answers true if 'version' is equal to or later than 'supported', where each
4676 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4677 * changes. Development and test values for 'version' are leniently treated
4681 * - minimum version we are comparing against
4683 * - version of data being processsed
4684 * @return true if version is equal to or later than supported
4686 public static boolean isVersionStringLaterThan(String supported,
4689 if (supported == null || version == null
4690 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4691 || version.equalsIgnoreCase("Test")
4692 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4694 System.err.println("Assuming project file with "
4695 + (version == null ? "null" : version)
4696 + " is compatible with Jalview version " + supported);
4701 return StringUtils.compareVersions(version, supported, "b") >= 0;
4705 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4707 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4709 if (newStructureViewers != null)
4711 sview.getBinding().setFinishedLoadingFromArchive(false);
4712 newStructureViewers.add(sview);
4716 protected void setLoadingFinishedForNewStructureViewers()
4718 if (newStructureViewers != null)
4720 for (JalviewStructureDisplayI sview : newStructureViewers)
4722 sview.getBinding().setFinishedLoadingFromArchive(true);
4724 newStructureViewers.clear();
4725 newStructureViewers = null;
4729 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4730 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4731 Viewport view, String uniqueSeqSetId, String viewId,
4732 List<JvAnnotRow> autoAlan)
4734 AlignFrame af = null;
4735 af = new AlignFrame(al, safeInt(view.getWidth()),
4736 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4740 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4741 // System.out.println("Jalview2XML AF " + e);
4742 // super.processKeyEvent(e);
4749 af.setFileName(file, FileFormat.Jalview);
4751 final AlignViewport viewport = af.getViewport();
4752 for (int i = 0; i < JSEQ.size(); i++)
4754 int colour = safeInt(JSEQ.get(i).getColour());
4755 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4761 viewport.setColourByReferenceSeq(true);
4762 viewport.setDisplayReferenceSeq(true);
4765 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4767 if (view.getSequenceSetId() != null)
4769 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4771 viewport.setSequenceSetId(uniqueSeqSetId);
4774 // propagate shared settings to this new view
4775 viewport.setHistoryList(av.getHistoryList());
4776 viewport.setRedoList(av.getRedoList());
4780 viewportsAdded.put(uniqueSeqSetId, viewport);
4782 // TODO: check if this method can be called repeatedly without
4783 // side-effects if alignpanel already registered.
4784 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4786 // apply Hidden regions to view.
4787 if (hiddenSeqs != null)
4789 for (int s = 0; s < JSEQ.size(); s++)
4791 SequenceGroup hidden = new SequenceGroup();
4792 boolean isRepresentative = false;
4793 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4795 isRepresentative = true;
4796 SequenceI sequenceToHide = al
4797 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4798 hidden.addSequence(sequenceToHide, false);
4799 // remove from hiddenSeqs list so we don't try to hide it twice
4800 hiddenSeqs.remove(sequenceToHide);
4802 if (isRepresentative)
4804 SequenceI representativeSequence = al.getSequenceAt(s);
4805 hidden.addSequence(representativeSequence, false);
4806 viewport.hideRepSequences(representativeSequence, hidden);
4810 SequenceI[] hseqs = hiddenSeqs
4811 .toArray(new SequenceI[hiddenSeqs.size()]);
4812 viewport.hideSequence(hseqs);
4815 // recover view properties and display parameters
4817 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4818 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4819 final int pidThreshold = safeInt(view.getPidThreshold());
4820 viewport.setThreshold(pidThreshold);
4822 viewport.setColourText(safeBoolean(view.isShowColourText()));
4824 viewport.setConservationSelected(
4825 safeBoolean(view.isConservationSelected()));
4826 viewport.setIncrement(safeInt(view.getConsThreshold()));
4827 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4828 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4829 viewport.setFont(new Font(view.getFontName(),
4830 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4832 ViewStyleI vs = viewport.getViewStyle();
4833 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4834 viewport.setViewStyle(vs);
4835 // TODO: allow custom charWidth/Heights to be restored by updating them
4836 // after setting font - which means set above to false
4837 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4838 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4839 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4841 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4843 viewport.setShowText(safeBoolean(view.isShowText()));
4845 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4846 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4847 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4848 viewport.setShowUnconserved(view.isShowUnconserved());
4849 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4851 if (view.getViewName() != null)
4853 viewport.setViewName(view.getViewName());
4854 af.setInitialTabVisible();
4856 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4857 safeInt(view.getWidth()), safeInt(view.getHeight()));
4858 // startSeq set in af.alignPanel.updateLayout below
4859 af.alignPanel.updateLayout();
4860 ColourSchemeI cs = null;
4861 // apply colourschemes
4862 if (view.getBgColour() != null)
4864 if (view.getBgColour().startsWith("ucs"))
4866 cs = getUserColourScheme(jm, view.getBgColour());
4868 else if (view.getBgColour().startsWith("Annotation"))
4870 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4871 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4878 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4879 view.getBgColour());
4884 * turn off 'alignment colour applies to all groups'
4885 * while restoring global colour scheme
4887 viewport.setColourAppliesToAllGroups(false);
4888 viewport.setGlobalColourScheme(cs);
4889 viewport.getResidueShading().setThreshold(pidThreshold,
4890 view.isIgnoreGapsinConsensus());
4891 viewport.getResidueShading()
4892 .setConsensus(viewport.getSequenceConsensusHash());
4893 if (safeBoolean(view.isConservationSelected()) && cs != null)
4895 viewport.getResidueShading()
4896 .setConservationInc(safeInt(view.getConsThreshold()));
4898 af.changeColour(cs);
4899 viewport.setColourAppliesToAllGroups(true);
4901 viewport.setShowSequenceFeatures(
4902 safeBoolean(view.isShowSequenceFeatures()));
4904 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4905 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4906 viewport.setFollowHighlight(view.isFollowHighlight());
4907 viewport.followSelection = view.isFollowSelection();
4908 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4909 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4910 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4911 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4912 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4913 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4914 viewport.setShowGroupConservation(view.isShowGroupConservation());
4915 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4916 viewport.setShowComplementFeaturesOnTop(
4917 view.isShowComplementFeaturesOnTop());
4919 // recover feature settings
4920 if (jm.getFeatureSettings() != null)
4922 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4923 .getFeatureRenderer();
4924 FeaturesDisplayed fdi;
4925 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4926 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
4928 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4929 Map<String, Float> featureOrder = new Hashtable<>();
4931 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
4934 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4935 String featureType = setting.getType();
4938 * restore feature filters (if any)
4940 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4942 if (filters != null)
4944 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
4946 if (!filter.isEmpty())
4948 fr.setFeatureFilter(featureType, filter);
4953 * restore feature colour scheme
4955 Color maxColour = new Color(setting.getColour());
4956 if (setting.getMincolour() != null)
4959 * minColour is always set unless a simple colour
4960 * (including for colour by label though it doesn't use it)
4962 Color minColour = new Color(setting.getMincolour().intValue());
4963 Color noValueColour = minColour;
4964 NoValueColour noColour = setting.getNoValueColour();
4965 if (noColour == NoValueColour.NONE)
4967 noValueColour = null;
4969 else if (noColour == NoValueColour.MAX)
4971 noValueColour = maxColour;
4973 float min = safeFloat(safeFloat(setting.getMin()));
4974 float max = setting.getMax() == null ? 1f
4975 : setting.getMax().floatValue();
4976 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4977 maxColour, noValueColour, min, max);
4978 if (setting.getAttributeName().size() > 0)
4980 gc.setAttributeName(setting.getAttributeName().toArray(
4981 new String[setting.getAttributeName().size()]));
4983 if (setting.getThreshold() != null)
4985 gc.setThreshold(setting.getThreshold().floatValue());
4986 int threshstate = safeInt(setting.getThreshstate());
4987 // -1 = None, 0 = Below, 1 = Above threshold
4988 if (threshstate == 0)
4990 gc.setBelowThreshold(true);
4992 else if (threshstate == 1)
4994 gc.setAboveThreshold(true);
4997 gc.setAutoScaled(true); // default
4998 if (setting.isAutoScale() != null)
5000 gc.setAutoScaled(setting.isAutoScale());
5002 if (setting.isColourByLabel() != null)
5004 gc.setColourByLabel(setting.isColourByLabel());
5006 // and put in the feature colour table.
5007 featureColours.put(featureType, gc);
5011 featureColours.put(featureType, new FeatureColour(maxColour));
5013 renderOrder[fs] = featureType;
5014 if (setting.getOrder() != null)
5016 featureOrder.put(featureType, setting.getOrder().floatValue());
5020 featureOrder.put(featureType, Float.valueOf(
5021 fs / jm.getFeatureSettings().getSetting().size()));
5023 if (safeBoolean(setting.isDisplay()))
5025 fdi.setVisible(featureType);
5028 Map<String, Boolean> fgtable = new Hashtable<>();
5029 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5031 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5032 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5034 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5035 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5036 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5037 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5038 fgtable, featureColours, 1.0f, featureOrder);
5039 fr.transferSettings(frs);
5042 if (view.getHiddenColumns().size() > 0)
5044 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5046 final HiddenColumns hc = view.getHiddenColumns().get(c);
5047 viewport.hideColumns(safeInt(hc.getStart()),
5048 safeInt(hc.getEnd()) /* +1 */);
5051 if (view.getCalcIdParam() != null)
5053 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5055 if (calcIdParam != null)
5057 if (recoverCalcIdParam(calcIdParam, viewport))
5062 Console.warn("Couldn't recover parameters for "
5063 + calcIdParam.getCalcId());
5068 af.setMenusFromViewport(viewport);
5069 af.setTitle(view.getTitle());
5070 // TODO: we don't need to do this if the viewport is aready visible.
5072 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5073 * has a 'cdna/protein complement' view, in which case save it in order to
5074 * populate a SplitFrame once all views have been read in.
5076 String complementaryViewId = view.getComplementId();
5077 if (complementaryViewId == null)
5079 Desktop.addInternalFrame(af, view.getTitle(),
5080 safeInt(view.getWidth()), safeInt(view.getHeight()));
5081 // recompute any autoannotation
5082 af.alignPanel.updateAnnotation(false, true);
5083 reorderAutoannotation(af, al, autoAlan);
5084 af.alignPanel.alignmentChanged();
5088 splitFrameCandidates.put(view, af);
5095 * Reads saved data to restore Colour by Annotation settings
5097 * @param viewAnnColour
5101 * @param checkGroupAnnColour
5104 private ColourSchemeI constructAnnotationColour(
5105 AnnotationColourScheme viewAnnColour, AlignFrame af,
5106 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5108 boolean propagateAnnColour = false;
5109 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5111 if (checkGroupAnnColour && al.getGroups() != null
5112 && al.getGroups().size() > 0)
5114 // pre 2.8.1 behaviour
5115 // check to see if we should transfer annotation colours
5116 propagateAnnColour = true;
5117 for (SequenceGroup sg : al.getGroups())
5119 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5121 propagateAnnColour = false;
5127 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5129 String annotationId = viewAnnColour.getAnnotation();
5130 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5133 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5135 if (matchedAnnotation == null
5136 && annAlignment.getAlignmentAnnotation() != null)
5138 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5141 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5143 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5148 if (matchedAnnotation == null)
5150 System.err.println("Failed to match annotation colour scheme for "
5154 // belt-and-braces create a threshold line if the
5155 // colourscheme needs one but the matchedAnnotation doesn't have one
5156 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5157 && matchedAnnotation.getThreshold() == null)
5159 matchedAnnotation.setThreshold(
5160 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5161 "Threshold", Color.black));
5164 AnnotationColourGradient cs = null;
5165 if (viewAnnColour.getColourScheme().equals("None"))
5167 cs = new AnnotationColourGradient(matchedAnnotation,
5168 new Color(safeInt(viewAnnColour.getMinColour())),
5169 new Color(safeInt(viewAnnColour.getMaxColour())),
5170 safeInt(viewAnnColour.getAboveThreshold()));
5172 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5174 cs = new AnnotationColourGradient(matchedAnnotation,
5175 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5176 safeInt(viewAnnColour.getAboveThreshold()));
5180 cs = new AnnotationColourGradient(matchedAnnotation,
5181 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5182 viewAnnColour.getColourScheme()),
5183 safeInt(viewAnnColour.getAboveThreshold()));
5186 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5187 boolean useOriginalColours = safeBoolean(
5188 viewAnnColour.isPredefinedColours());
5189 cs.setSeqAssociated(perSequenceOnly);
5190 cs.setPredefinedColours(useOriginalColours);
5192 if (propagateAnnColour && al.getGroups() != null)
5194 // Also use these settings for all the groups
5195 for (int g = 0; g < al.getGroups().size(); g++)
5197 SequenceGroup sg = al.getGroups().get(g);
5198 if (sg.getGroupColourScheme() == null)
5203 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5204 matchedAnnotation, sg.getColourScheme(),
5205 safeInt(viewAnnColour.getAboveThreshold()));
5206 sg.setColourScheme(groupScheme);
5207 groupScheme.setSeqAssociated(perSequenceOnly);
5208 groupScheme.setPredefinedColours(useOriginalColours);
5214 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5215 List<JvAnnotRow> autoAlan)
5217 // copy over visualization settings for autocalculated annotation in the
5219 if (al.getAlignmentAnnotation() != null)
5222 * Kludge for magic autoannotation names (see JAL-811)
5224 String[] magicNames = new String[] { "Consensus", "Quality",
5226 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5227 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5228 for (String nm : magicNames)
5230 visan.put(nm, nullAnnot);
5232 for (JvAnnotRow auan : autoAlan)
5234 visan.put(auan.template.label
5235 + (auan.template.getCalcId() == null ? ""
5236 : "\t" + auan.template.getCalcId()),
5239 int hSize = al.getAlignmentAnnotation().length;
5240 List<JvAnnotRow> reorder = new ArrayList<>();
5241 // work through any autoCalculated annotation already on the view
5242 // removing it if it should be placed in a different location on the
5243 // annotation panel.
5244 List<String> remains = new ArrayList<>(visan.keySet());
5245 for (int h = 0; h < hSize; h++)
5247 jalview.datamodel.AlignmentAnnotation jalan = al
5248 .getAlignmentAnnotation()[h];
5249 if (jalan.autoCalculated)
5252 JvAnnotRow valan = visan.get(k = jalan.label);
5253 if (jalan.getCalcId() != null)
5255 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5260 // delete the auto calculated row from the alignment
5261 al.deleteAnnotation(jalan, false);
5265 if (valan != nullAnnot)
5267 if (jalan != valan.template)
5269 // newly created autoannotation row instance
5270 // so keep a reference to the visible annotation row
5271 // and copy over all relevant attributes
5272 if (valan.template.graphHeight >= 0)
5275 jalan.graphHeight = valan.template.graphHeight;
5277 jalan.visible = valan.template.visible;
5279 reorder.add(new JvAnnotRow(valan.order, jalan));
5284 // Add any (possibly stale) autocalculated rows that were not appended to
5285 // the view during construction
5286 for (String other : remains)
5288 JvAnnotRow othera = visan.get(other);
5289 if (othera != nullAnnot && othera.template.getCalcId() != null
5290 && othera.template.getCalcId().length() > 0)
5292 reorder.add(othera);
5295 // now put the automatic annotation in its correct place
5296 int s = 0, srt[] = new int[reorder.size()];
5297 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5298 for (JvAnnotRow jvar : reorder)
5301 srt[s++] = jvar.order;
5304 jalview.util.QuickSort.sort(srt, rws);
5305 // and re-insert the annotation at its correct position
5306 for (JvAnnotRow jvar : rws)
5308 al.addAnnotation(jvar.template, jvar.order);
5310 af.alignPanel.adjustAnnotationHeight();
5314 Hashtable skipList = null;
5317 * TODO remove this method
5320 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5321 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5322 * throw new Error("Implementation Error. No skipList defined for this
5323 * Jalview2XML instance."); } return (AlignFrame)
5324 * skipList.get(view.getSequenceSetId()); }
5328 * Check if the Jalview view contained in object should be skipped or not.
5331 * @return true if view's sequenceSetId is a key in skipList
5333 private boolean skipViewport(JalviewModel object)
5335 if (skipList == null)
5339 String id = object.getViewport().get(0).getSequenceSetId();
5340 if (skipList.containsKey(id))
5342 Console.debug("Skipping seuqence set id " + id);
5348 public void addToSkipList(AlignFrame af)
5350 if (skipList == null)
5352 skipList = new Hashtable();
5354 skipList.put(af.getViewport().getSequenceSetId(), af);
5357 public void clearSkipList()
5359 if (skipList != null)
5366 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5367 boolean ignoreUnrefed, String uniqueSeqSetId)
5369 jalview.datamodel.AlignmentI ds = getDatasetFor(
5370 vamsasSet.getDatasetId());
5371 AlignmentI xtant_ds = ds;
5372 if (xtant_ds == null)
5374 // good chance we are about to create a new dataset, but check if we've
5375 // seen some of the dataset sequence IDs before.
5376 // TODO: skip this check if we are working with project generated by
5377 // version 2.11 or later
5378 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5379 if (xtant_ds != null)
5382 addDatasetRef(vamsasSet.getDatasetId(), ds);
5385 Vector<SequenceI> dseqs = null;
5388 // recovering an alignment View
5389 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5390 if (seqSetDS != null)
5392 if (ds != null && ds != seqSetDS)
5395 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5396 + " - CDS/Protein crossreference data may be lost");
5397 if (xtant_ds != null)
5399 // This can only happen if the unique sequence set ID was bound to a
5400 // dataset that did not contain any of the sequences in the view
5401 // currently being restored.
5403 "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.");
5407 addDatasetRef(vamsasSet.getDatasetId(), ds);
5412 // try even harder to restore dataset
5413 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5414 // create a list of new dataset sequences
5415 dseqs = new Vector<>();
5417 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5419 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5420 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5422 // create a new dataset
5425 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5426 dseqs.copyInto(dsseqs);
5427 ds = new jalview.datamodel.Alignment(dsseqs);
5428 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5429 + " for alignment " + System.identityHashCode(al));
5430 addDatasetRef(vamsasSet.getDatasetId(), ds);
5432 // set the dataset for the newly imported alignment.
5433 if (al.getDataset() == null && !ignoreUnrefed)
5436 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5437 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5439 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5443 * XML dataset sequence ID to materialised dataset reference
5445 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5448 * @return the first materialised dataset reference containing a dataset
5449 * sequence referenced in the given view
5451 * - sequences from the view
5453 AlignmentI checkIfHasDataset(List<Sequence> list)
5455 for (Sequence restoredSeq : list)
5457 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5458 if (datasetFor != null)
5467 * Register ds as the containing dataset for the dataset sequences referenced
5468 * by sequences in list
5471 * - sequences in a view
5474 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5476 for (Sequence restoredSeq : list)
5478 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5479 if (prevDS != null && prevDS != ds)
5481 Console.warn("Dataset sequence appears in many datasets: "
5482 + restoredSeq.getDsseqid());
5483 // TODO: try to merge!
5491 * sequence definition to create/merge dataset sequence for
5495 * vector to add new dataset sequence to
5496 * @param ignoreUnrefed
5497 * - when true, don't create new sequences from vamsasSeq if it's id
5498 * doesn't already have an asssociated Jalview sequence.
5500 * - used to reorder the sequence in the alignment according to the
5501 * vamsasSeq array ordering, to preserve ordering of dataset
5503 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5504 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5507 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5509 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5510 boolean reorder = false;
5511 SequenceI dsq = null;
5512 if (sq != null && sq.getDatasetSequence() != null)
5514 dsq = sq.getDatasetSequence();
5520 if (sq == null && ignoreUnrefed)
5524 String sqid = vamsasSeq.getDsseqid();
5527 // need to create or add a new dataset sequence reference to this sequence
5530 dsq = seqRefIds.get(sqid);
5535 // make a new dataset sequence
5536 dsq = sq.createDatasetSequence();
5539 // make up a new dataset reference for this sequence
5540 sqid = seqHash(dsq);
5542 dsq.setVamsasId(uniqueSetSuffix + sqid);
5543 seqRefIds.put(sqid, dsq);
5548 dseqs.addElement(dsq);
5553 ds.addSequence(dsq);
5559 { // make this dataset sequence sq's dataset sequence
5560 sq.setDatasetSequence(dsq);
5561 // and update the current dataset alignment
5566 if (!dseqs.contains(dsq))
5573 if (ds.findIndex(dsq) < 0)
5575 ds.addSequence(dsq);
5582 // TODO: refactor this as a merge dataset sequence function
5583 // now check that sq (the dataset sequence) sequence really is the union of
5584 // all references to it
5585 // boolean pre = sq.getStart() < dsq.getStart();
5586 // boolean post = sq.getEnd() > dsq.getEnd();
5590 // StringBuffer sb = new StringBuffer();
5591 String newres = jalview.analysis.AlignSeq.extractGaps(
5592 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5593 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5594 && newres.length() > dsq.getLength())
5596 // Update with the longer sequence.
5600 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5601 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5602 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5603 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5605 dsq.setSequence(newres);
5607 // TODO: merges will never happen if we 'know' we have the real dataset
5608 // sequence - this should be detected when id==dssid
5610 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5611 // + (pre ? "prepended" : "") + " "
5612 // + (post ? "appended" : ""));
5617 // sequence refs are identical. We may need to update the existing dataset
5618 // alignment with this one, though.
5619 if (ds != null && dseqs == null)
5621 int opos = ds.findIndex(dsq);
5622 SequenceI tseq = null;
5623 if (opos != -1 && vseqpos != opos)
5625 // remove from old position
5626 ds.deleteSequence(dsq);
5628 if (vseqpos < ds.getHeight())
5630 if (vseqpos != opos)
5632 // save sequence at destination position
5633 tseq = ds.getSequenceAt(vseqpos);
5634 ds.replaceSequenceAt(vseqpos, dsq);
5635 ds.addSequence(tseq);
5640 ds.addSequence(dsq);
5647 * TODO use AlignmentI here and in related methods - needs
5648 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5650 Hashtable<String, AlignmentI> datasetIds = null;
5652 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5654 private AlignmentI getDatasetFor(String datasetId)
5656 if (datasetIds == null)
5658 datasetIds = new Hashtable<>();
5661 if (datasetIds.containsKey(datasetId))
5663 return datasetIds.get(datasetId);
5668 private void addDatasetRef(String datasetId, AlignmentI dataset)
5670 if (datasetIds == null)
5672 datasetIds = new Hashtable<>();
5674 datasetIds.put(datasetId, dataset);
5678 * make a new dataset ID for this jalview dataset alignment
5683 private String getDatasetIdRef(AlignmentI dataset)
5685 if (dataset.getDataset() != null)
5688 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5690 String datasetId = makeHashCode(dataset, null);
5691 if (datasetId == null)
5693 // make a new datasetId and record it
5694 if (dataset2Ids == null)
5696 dataset2Ids = new IdentityHashMap<>();
5700 datasetId = dataset2Ids.get(dataset);
5702 if (datasetId == null)
5704 datasetId = "ds" + dataset2Ids.size() + 1;
5705 dataset2Ids.put(dataset, datasetId);
5712 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5713 * constructed as a special subclass GeneLocus.
5715 * @param datasetSequence
5718 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5720 for (int d = 0; d < sequence.getDBRef().size(); d++)
5722 DBRef dr = sequence.getDBRef().get(d);
5726 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5727 dr.getAccessionId());
5731 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5732 dr.getAccessionId());
5734 if (dr.getMapping() != null)
5736 entry.setMap(addMapping(dr.getMapping()));
5738 entry.setCanonical(dr.isCanonical());
5739 datasetSequence.addDBRef(entry);
5743 private jalview.datamodel.Mapping addMapping(Mapping m)
5745 SequenceI dsto = null;
5746 // Mapping m = dr.getMapping();
5747 int fr[] = new int[m.getMapListFrom().size() * 2];
5748 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5749 for (int _i = 0; from.hasNext(); _i += 2)
5751 MapListFrom mf = from.next();
5752 fr[_i] = mf.getStart();
5753 fr[_i + 1] = mf.getEnd();
5755 int fto[] = new int[m.getMapListTo().size() * 2];
5756 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5757 for (int _i = 0; to.hasNext(); _i += 2)
5759 MapListTo mf = to.next();
5760 fto[_i] = mf.getStart();
5761 fto[_i + 1] = mf.getEnd();
5763 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5764 fto, m.getMapFromUnit().intValue(),
5765 m.getMapToUnit().intValue());
5768 * (optional) choice of dseqFor or Sequence
5770 if (m.getDseqFor() != null)
5772 String dsfor = m.getDseqFor();
5773 if (seqRefIds.containsKey(dsfor))
5778 jmap.setTo(seqRefIds.get(dsfor));
5782 frefedSequence.add(newMappingRef(dsfor, jmap));
5785 else if (m.getSequence() != null)
5788 * local sequence definition
5790 Sequence ms = m.getSequence();
5791 SequenceI djs = null;
5792 String sqid = ms.getDsseqid();
5793 if (sqid != null && sqid.length() > 0)
5796 * recover dataset sequence
5798 djs = seqRefIds.get(sqid);
5803 "Warning - making up dataset sequence id for DbRef sequence map reference");
5804 sqid = ((Object) ms).toString(); // make up a new hascode for
5805 // undefined dataset sequence hash
5806 // (unlikely to happen)
5812 * make a new dataset sequence and add it to refIds hash
5814 djs = new jalview.datamodel.Sequence(ms.getName(),
5816 djs.setStart(jmap.getMap().getToLowest());
5817 djs.setEnd(jmap.getMap().getToHighest());
5818 djs.setVamsasId(uniqueSetSuffix + sqid);
5820 incompleteSeqs.put(sqid, djs);
5821 seqRefIds.put(sqid, djs);
5824 Console.debug("about to recurse on addDBRefs.");
5833 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5834 * view as XML (but not to file), and then reloading it
5839 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5842 JalviewModel jm = saveState(ap, null, null, null);
5845 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5846 ap.getAlignment().getDataset());
5848 uniqueSetSuffix = "";
5849 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5850 jm.getViewport().get(0).setId(null);
5851 // we don't overwrite the view we just copied
5853 if (this.frefedSequence == null)
5855 frefedSequence = new Vector<>();
5858 viewportsAdded.clear();
5860 AlignFrame af = loadFromObject(jm, null, false, null);
5861 af.getAlignPanels().clear();
5862 af.closeMenuItem_actionPerformed(true);
5865 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5866 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5867 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5868 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5869 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5872 return af.alignPanel;
5875 private Hashtable jvids2vobj;
5878 * set the object to ID mapping tables used to write/recover objects and XML
5879 * ID strings for the jalview project. If external tables are provided then
5880 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5881 * object goes out of scope. - also populates the datasetIds hashtable with
5882 * alignment objects containing dataset sequences
5885 * Map from ID strings to jalview datamodel
5887 * Map from jalview datamodel to ID strings
5891 public void setObjectMappingTables(Hashtable vobj2jv,
5892 IdentityHashMap jv2vobj)
5894 this.jv2vobj = jv2vobj;
5895 this.vobj2jv = vobj2jv;
5896 Iterator ds = jv2vobj.keySet().iterator();
5898 while (ds.hasNext())
5900 Object jvobj = ds.next();
5901 id = jv2vobj.get(jvobj).toString();
5902 if (jvobj instanceof jalview.datamodel.Alignment)
5904 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5906 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5909 else if (jvobj instanceof jalview.datamodel.Sequence)
5911 // register sequence object so the XML parser can recover it.
5912 if (seqRefIds == null)
5914 seqRefIds = new HashMap<>();
5916 if (seqsToIds == null)
5918 seqsToIds = new IdentityHashMap<>();
5920 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5921 seqsToIds.put((SequenceI) jvobj, id);
5923 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5926 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5927 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5928 if (jvann.annotationId == null)
5930 jvann.annotationId = anid;
5932 if (!jvann.annotationId.equals(anid))
5934 // TODO verify that this is the correct behaviour
5935 Console.warn("Overriding Annotation ID for " + anid
5936 + " from different id : " + jvann.annotationId);
5937 jvann.annotationId = anid;
5940 else if (jvobj instanceof String)
5942 if (jvids2vobj == null)
5944 jvids2vobj = new Hashtable();
5945 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5950 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5956 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5957 * objects created from the project archive. If string is null (default for
5958 * construction) then suffix will be set automatically.
5962 public void setUniqueSetSuffix(String string)
5964 uniqueSetSuffix = string;
5969 * uses skipList2 as the skipList for skipping views on sequence sets
5970 * associated with keys in the skipList
5974 public void setSkipList(Hashtable skipList2)
5976 skipList = skipList2;
5980 * Reads the jar entry of given name and returns its contents, or null if the
5981 * entry is not found.
5984 * @param jarEntryName
5987 protected String readJarEntry(jarInputStreamProvider jprovider,
5988 String jarEntryName)
5990 String result = null;
5991 BufferedReader in = null;
5996 * Reopen the jar input stream and traverse its entries to find a matching
5999 JarInputStream jin = jprovider.getJarInputStream();
6000 JarEntry entry = null;
6003 entry = jin.getNextJarEntry();
6004 } while (entry != null && !entry.getName().equals(jarEntryName));
6008 StringBuilder out = new StringBuilder(256);
6009 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6012 while ((data = in.readLine()) != null)
6016 result = out.toString();
6021 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6023 } catch (Exception ex)
6025 ex.printStackTrace();
6033 } catch (IOException e)
6044 * Returns an incrementing counter (0, 1, 2...)
6048 private synchronized int nextCounter()
6054 * Loads any saved PCA viewers
6059 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6063 List<PcaViewer> pcaviewers = model.getPcaViewer();
6064 for (PcaViewer viewer : pcaviewers)
6066 String modelName = viewer.getScoreModelName();
6067 SimilarityParamsI params = new SimilarityParams(
6068 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6069 viewer.isIncludeGaps(),
6070 viewer.isDenominateByShortestLength());
6073 * create the panel (without computing the PCA)
6075 PCAPanel panel = new PCAPanel(ap, modelName, params);
6077 panel.setTitle(viewer.getTitle());
6078 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6079 viewer.getWidth(), viewer.getHeight()));
6081 boolean showLabels = viewer.isShowLabels();
6082 panel.setShowLabels(showLabels);
6083 panel.getRotatableCanvas().setShowLabels(showLabels);
6084 panel.getRotatableCanvas()
6085 .setBgColour(new Color(viewer.getBgColour()));
6086 panel.getRotatableCanvas()
6087 .setApplyToAllViews(viewer.isLinkToAllViews());
6090 * load PCA output data
6092 ScoreModelI scoreModel = ScoreModels.getInstance()
6093 .getScoreModel(modelName, ap);
6094 PCA pca = new PCA(null, scoreModel, params);
6095 PcaDataType pcaData = viewer.getPcaData();
6097 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6098 pca.setPairwiseScores(pairwise);
6100 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6101 pca.setTridiagonal(triDiag);
6103 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6104 pca.setEigenmatrix(result);
6106 panel.getPcaModel().setPCA(pca);
6109 * we haven't saved the input data! (JAL-2647 to do)
6111 panel.setInputData(null);
6114 * add the sequence points for the PCA display
6116 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6117 for (SequencePoint sp : viewer.getSequencePoint())
6119 String seqId = sp.getSequenceRef();
6120 SequenceI seq = seqRefIds.get(seqId);
6123 throw new IllegalStateException(
6124 "Unmatched seqref for PCA: " + seqId);
6126 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6127 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6129 seqPoints.add(seqPoint);
6131 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6134 * set min-max ranges and scale after setPoints (which recomputes them)
6136 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6137 SeqPointMin spMin = viewer.getSeqPointMin();
6138 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6140 SeqPointMax spMax = viewer.getSeqPointMax();
6141 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6143 panel.getRotatableCanvas().setSeqMinMax(min, max);
6145 // todo: hold points list in PCAModel only
6146 panel.getPcaModel().setSequencePoints(seqPoints);
6148 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6149 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6150 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6152 // is this duplication needed?
6153 panel.setTop(seqPoints.size() - 1);
6154 panel.getPcaModel().setTop(seqPoints.size() - 1);
6157 * add the axes' end points for the display
6159 for (int i = 0; i < 3; i++)
6161 Axis axis = viewer.getAxis().get(i);
6162 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6163 axis.getXPos(), axis.getYPos(), axis.getZPos());
6166 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6167 "label.calc_title", "PCA", modelName), 475, 450);
6169 } catch (Exception ex)
6171 Console.error("Error loading PCA: " + ex.toString());
6176 * Creates a new structure viewer window
6183 protected void createStructureViewer(ViewerType viewerType,
6184 final Entry<String, StructureViewerModel> viewerData,
6185 AlignFrame af, jarInputStreamProvider jprovider)
6187 final StructureViewerModel viewerModel = viewerData.getValue();
6188 String sessionFilePath = null;
6190 if (viewerType == ViewerType.JMOL)
6192 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6196 String viewerJarEntryName = getViewerJarEntryName(
6197 viewerModel.getViewId());
6198 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6199 "viewerSession", ".tmp");
6201 final String sessionPath = sessionFilePath;
6202 final String sviewid = viewerData.getKey();
6205 SwingUtilities.invokeAndWait(new Runnable()
6210 JalviewStructureDisplayI sview = null;
6213 sview = StructureViewer.createView(viewerType, af.alignPanel,
6214 viewerModel, sessionPath, sviewid);
6215 addNewStructureViewer(sview);
6216 } catch (OutOfMemoryError ex)
6218 new OOMWarning("Restoring structure view for " + viewerType,
6219 (OutOfMemoryError) ex.getCause());
6220 if (sview != null && sview.isVisible())
6222 sview.closeViewer(false);
6223 sview.setVisible(false);
6229 } catch (InvocationTargetException | InterruptedException ex)
6231 Console.warn("Unexpected error when opening " + viewerType
6232 + " structure viewer", ex);
6237 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6238 * the path of the file. "load file" commands are rewritten to change the
6239 * original PDB file names to those created as the Jalview project is loaded.
6245 private String rewriteJmolSession(StructureViewerModel svattrib,
6246 jarInputStreamProvider jprovider)
6248 String state = svattrib.getStateData(); // Jalview < 2.9
6249 if (state == null || state.isEmpty()) // Jalview >= 2.9
6251 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6252 state = readJarEntry(jprovider, jarEntryName);
6254 // TODO or simpler? for each key in oldFiles,
6255 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6256 // (allowing for different path escapings)
6257 StringBuilder rewritten = new StringBuilder(state.length());
6258 int cp = 0, ncp, ecp;
6259 Map<File, StructureData> oldFiles = svattrib.getFileData();
6260 while ((ncp = state.indexOf("load ", cp)) > -1)
6264 // look for next filename in load statement
6265 rewritten.append(state.substring(cp,
6266 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6267 String oldfilenam = state.substring(ncp,
6268 ecp = state.indexOf("\"", ncp));
6269 // recover the new mapping data for this old filename
6270 // have to normalize filename - since Jmol and jalview do
6271 // filename translation differently.
6272 StructureData filedat = oldFiles.get(new File(oldfilenam));
6273 if (filedat == null)
6275 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6276 filedat = oldFiles.get(new File(reformatedOldFilename));
6278 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6279 rewritten.append("\"");
6280 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6281 // look for next file statement.
6282 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6286 // just append rest of state
6287 rewritten.append(state.substring(cp));
6291 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6292 rewritten = new StringBuilder(state);
6293 rewritten.append("; load append ");
6294 for (File id : oldFiles.keySet())
6296 // add pdb files that should be present in the viewer
6297 StructureData filedat = oldFiles.get(id);
6298 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6300 rewritten.append(";");
6303 if (rewritten.length() == 0)
6307 final String history = "history = ";
6308 int historyIndex = rewritten.indexOf(history);
6309 if (historyIndex > -1)
6312 * change "history = [true|false];" to "history = [1|0];"
6314 historyIndex += history.length();
6315 String val = rewritten.substring(historyIndex, historyIndex + 5);
6316 if (val.startsWith("true"))
6318 rewritten.replace(historyIndex, historyIndex + 4, "1");
6320 else if (val.startsWith("false"))
6322 rewritten.replace(historyIndex, historyIndex + 5, "0");
6328 File tmp = File.createTempFile("viewerSession", ".tmp");
6329 try (OutputStream os = new FileOutputStream(tmp))
6331 InputStream is = new ByteArrayInputStream(
6332 rewritten.toString().getBytes());
6334 return tmp.getAbsolutePath();
6336 } catch (IOException e)
6338 Console.error("Error restoring Jmol session: " + e.toString());
6344 * Populates an XML model of the feature colour scheme for one feature type
6346 * @param featureType
6350 public static Colour marshalColour(String featureType,
6351 FeatureColourI fcol)
6353 Colour col = new Colour();
6354 if (fcol.isSimpleColour())
6356 col.setRGB(Format.getHexString(fcol.getColour()));
6360 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6361 col.setMin(fcol.getMin());
6362 col.setMax(fcol.getMax());
6363 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6364 col.setAutoScale(fcol.isAutoScaled());
6365 col.setThreshold(fcol.getThreshold());
6366 col.setColourByLabel(fcol.isColourByLabel());
6367 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6368 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6369 : ThresholdType.NONE));
6370 if (fcol.isColourByAttribute())
6372 final String[] attName = fcol.getAttributeName();
6373 col.getAttributeName().add(attName[0]);
6374 if (attName.length > 1)
6376 col.getAttributeName().add(attName[1]);
6379 Color noColour = fcol.getNoColour();
6380 if (noColour == null)
6382 col.setNoValueColour(NoValueColour.NONE);
6384 else if (noColour == fcol.getMaxColour())
6386 col.setNoValueColour(NoValueColour.MAX);
6390 col.setNoValueColour(NoValueColour.MIN);
6393 col.setName(featureType);
6398 * Populates an XML model of the feature filter(s) for one feature type
6400 * @param firstMatcher
6401 * the first (or only) match condition)
6403 * remaining match conditions (if any)
6405 * if true, conditions are and-ed, else or-ed
6407 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6408 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6411 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6413 if (filters.hasNext())
6418 CompoundMatcher compound = new CompoundMatcher();
6419 compound.setAnd(and);
6420 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6421 firstMatcher, Collections.emptyIterator(), and);
6422 // compound.addMatcherSet(matcher1);
6423 compound.getMatcherSet().add(matcher1);
6424 FeatureMatcherI nextMatcher = filters.next();
6425 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6426 nextMatcher, filters, and);
6427 // compound.addMatcherSet(matcher2);
6428 compound.getMatcherSet().add(matcher2);
6429 result.setCompoundMatcher(compound);
6434 * single condition matcher
6436 // MatchCondition matcherModel = new MatchCondition();
6437 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6438 matcherModel.setCondition(
6439 firstMatcher.getMatcher().getCondition().getStableName());
6440 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6441 if (firstMatcher.isByAttribute())
6443 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6444 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6445 String[] attName = firstMatcher.getAttribute();
6446 matcherModel.getAttributeName().add(attName[0]); // attribute
6447 if (attName.length > 1)
6449 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6452 else if (firstMatcher.isByLabel())
6454 matcherModel.setBy(FilterBy.BY_LABEL);
6456 else if (firstMatcher.isByScore())
6458 matcherModel.setBy(FilterBy.BY_SCORE);
6460 result.setMatchCondition(matcherModel);
6467 * Loads one XML model of a feature filter to a Jalview object
6469 * @param featureType
6470 * @param matcherSetModel
6473 public static FeatureMatcherSetI parseFilter(String featureType,
6474 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6476 FeatureMatcherSetI result = new FeatureMatcherSet();
6479 parseFilterConditions(result, matcherSetModel, true);
6480 } catch (IllegalStateException e)
6482 // mixing AND and OR conditions perhaps
6484 String.format("Error reading filter conditions for '%s': %s",
6485 featureType, e.getMessage()));
6486 // return as much as was parsed up to the error
6493 * Adds feature match conditions to matcherSet as unmarshalled from XML
6494 * (possibly recursively for compound conditions)
6497 * @param matcherSetModel
6499 * if true, multiple conditions are AND-ed, else they are OR-ed
6500 * @throws IllegalStateException
6501 * if AND and OR conditions are mixed
6503 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6504 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6507 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6508 .getMatchCondition();
6514 FilterBy filterBy = mc.getBy();
6515 Condition cond = Condition.fromString(mc.getCondition());
6516 String pattern = mc.getValue();
6517 FeatureMatcherI matchCondition = null;
6518 if (filterBy == FilterBy.BY_LABEL)
6520 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6522 else if (filterBy == FilterBy.BY_SCORE)
6524 matchCondition = FeatureMatcher.byScore(cond, pattern);
6527 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6529 final List<String> attributeName = mc.getAttributeName();
6530 String[] attNames = attributeName
6531 .toArray(new String[attributeName.size()]);
6532 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6537 * note this throws IllegalStateException if AND-ing to a
6538 * previously OR-ed compound condition, or vice versa
6542 matcherSet.and(matchCondition);
6546 matcherSet.or(matchCondition);
6552 * compound condition
6554 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6555 .getCompoundMatcher().getMatcherSet();
6556 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6557 if (matchers.size() == 2)
6559 parseFilterConditions(matcherSet, matchers.get(0), anded);
6560 parseFilterConditions(matcherSet, matchers.get(1), anded);
6564 System.err.println("Malformed compound filter condition");
6570 * Loads one XML model of a feature colour to a Jalview object
6572 * @param colourModel
6575 public static FeatureColourI parseColour(Colour colourModel)
6577 FeatureColourI colour = null;
6579 if (colourModel.getMax() != null)
6581 Color mincol = null;
6582 Color maxcol = null;
6583 Color noValueColour = null;
6587 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6588 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6589 } catch (Exception e)
6591 Console.warn("Couldn't parse out graduated feature color.", e);
6594 NoValueColour noCol = colourModel.getNoValueColour();
6595 if (noCol == NoValueColour.MIN)
6597 noValueColour = mincol;
6599 else if (noCol == NoValueColour.MAX)
6601 noValueColour = maxcol;
6604 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6605 safeFloat(colourModel.getMin()),
6606 safeFloat(colourModel.getMax()));
6607 final List<String> attributeName = colourModel.getAttributeName();
6608 String[] attributes = attributeName
6609 .toArray(new String[attributeName.size()]);
6610 if (attributes != null && attributes.length > 0)
6612 colour.setAttributeName(attributes);
6614 if (colourModel.isAutoScale() != null)
6616 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6618 if (colourModel.isColourByLabel() != null)
6620 colour.setColourByLabel(
6621 colourModel.isColourByLabel().booleanValue());
6623 if (colourModel.getThreshold() != null)
6625 colour.setThreshold(colourModel.getThreshold().floatValue());
6627 ThresholdType ttyp = colourModel.getThreshType();
6628 if (ttyp == ThresholdType.ABOVE)
6630 colour.setAboveThreshold(true);
6632 else if (ttyp == ThresholdType.BELOW)
6634 colour.setBelowThreshold(true);
6639 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6640 colour = new FeatureColour(color);
6646 public static void setStateSavedUpToDate(boolean s)
6648 Console.debug("Setting overall stateSavedUpToDate to " + s);
6649 stateSavedUpToDate = s;
6652 public static boolean stateSavedUpToDate()
6654 Console.debug("Returning overall stateSavedUpToDate value: "
6655 + stateSavedUpToDate);
6656 return stateSavedUpToDate;
6659 public static boolean allSavedUpToDate()
6661 if (stateSavedUpToDate()) // nothing happened since last project save
6664 AlignFrame[] frames = Desktop.getAlignFrames();
6667 for (int i = 0; i < frames.length; i++)
6669 if (frames[i] == null)
6671 if (!frames[i].getViewport().savedUpToDate())
6672 return false; // at least one alignment is not individually saved
6678 // used for debugging and tests
6679 private static int debugDelaySave = 20;
6681 public static void setDebugDelaySave(int n)