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.FontMetrics;
30 import java.awt.Rectangle;
31 import java.io.BufferedReader;
32 import java.io.ByteArrayInputStream;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.OutputStream;
40 import java.io.OutputStreamWriter;
41 import java.io.PrintWriter;
42 import java.lang.reflect.InvocationTargetException;
43 import java.math.BigInteger;
44 import java.net.MalformedURLException;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.BitSet;
49 import java.util.Collections;
50 import java.util.Enumeration;
51 import java.util.GregorianCalendar;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Hashtable;
55 import java.util.IdentityHashMap;
56 import java.util.Iterator;
57 import java.util.LinkedHashMap;
58 import java.util.List;
59 import java.util.Locale;
61 import java.util.Map.Entry;
63 import java.util.Vector;
64 import java.util.jar.JarEntry;
65 import java.util.jar.JarInputStream;
66 import java.util.jar.JarOutputStream;
68 import javax.swing.JInternalFrame;
69 import javax.swing.SwingUtilities;
70 import javax.xml.bind.JAXBContext;
71 import javax.xml.bind.JAXBElement;
72 import javax.xml.bind.Marshaller;
73 import javax.xml.datatype.DatatypeConfigurationException;
74 import javax.xml.datatype.DatatypeFactory;
75 import javax.xml.datatype.XMLGregorianCalendar;
76 import javax.xml.stream.XMLInputFactory;
77 import javax.xml.stream.XMLStreamReader;
79 import jalview.analysis.Conservation;
80 import jalview.analysis.PCA;
81 import jalview.analysis.scoremodels.ScoreModels;
82 import jalview.analysis.scoremodels.SimilarityParams;
83 import jalview.api.FeatureColourI;
84 import jalview.api.ViewStyleI;
85 import jalview.api.analysis.ScoreModelI;
86 import jalview.api.analysis.SimilarityParamsI;
87 import jalview.api.structures.JalviewStructureDisplayI;
88 import jalview.bin.Cache;
89 import jalview.bin.Console;
90 import jalview.datamodel.AlignedCodonFrame;
91 import jalview.datamodel.Alignment;
92 import jalview.datamodel.AlignmentAnnotation;
93 import jalview.datamodel.AlignmentI;
94 import jalview.datamodel.ContactMatrix;
95 import jalview.datamodel.ContactMatrixI;
96 import jalview.datamodel.DBRefEntry;
97 import jalview.datamodel.GeneLocus;
98 import jalview.datamodel.GraphLine;
99 import jalview.datamodel.PDBEntry;
100 import jalview.datamodel.Point;
101 import jalview.datamodel.RnaViewerModel;
102 import jalview.datamodel.SequenceFeature;
103 import jalview.datamodel.SequenceGroup;
104 import jalview.datamodel.SequenceI;
105 import jalview.datamodel.StructureViewerModel;
106 import jalview.datamodel.StructureViewerModel.StructureData;
107 import jalview.datamodel.features.FeatureMatcher;
108 import jalview.datamodel.features.FeatureMatcherI;
109 import jalview.datamodel.features.FeatureMatcherSet;
110 import jalview.datamodel.features.FeatureMatcherSetI;
111 import jalview.ext.varna.RnaModel;
112 import jalview.gui.AlignFrame;
113 import jalview.gui.AlignViewport;
114 import jalview.gui.AlignmentPanel;
115 import jalview.gui.AppVarna;
116 import jalview.gui.Desktop;
117 import jalview.gui.JvOptionPane;
118 import jalview.gui.OOMWarning;
119 import jalview.gui.OverviewPanel;
120 import jalview.gui.PCAPanel;
121 import jalview.gui.PaintRefresher;
122 import jalview.gui.SplitFrame;
123 import jalview.gui.StructureViewer;
124 import jalview.gui.StructureViewer.ViewerType;
125 import jalview.gui.StructureViewerBase;
126 import jalview.gui.TreePanel;
127 import jalview.io.BackupFiles;
128 import jalview.io.DataSourceType;
129 import jalview.io.FileFormat;
130 import jalview.io.NewickFile;
131 import jalview.math.Matrix;
132 import jalview.math.MatrixI;
133 import jalview.renderer.ResidueShaderI;
134 import jalview.schemes.AnnotationColourGradient;
135 import jalview.schemes.ColourSchemeI;
136 import jalview.schemes.ColourSchemeProperty;
137 import jalview.schemes.FeatureColour;
138 import jalview.schemes.ResidueProperties;
139 import jalview.schemes.UserColourScheme;
140 import jalview.structure.StructureSelectionManager;
141 import jalview.structures.models.AAStructureBindingModel;
142 import jalview.util.Format;
143 import jalview.util.HttpUtils;
144 import jalview.util.MessageManager;
145 import jalview.util.Platform;
146 import jalview.util.StringUtils;
147 import jalview.util.jarInputStreamProvider;
148 import jalview.util.matcher.Condition;
149 import jalview.viewmodel.AlignmentViewport;
150 import jalview.viewmodel.PCAModel;
151 import jalview.viewmodel.ViewportRanges;
152 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
153 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
154 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
155 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
156 import jalview.ws.jws2.Jws2Discoverer;
157 import jalview.ws.jws2.dm.AAConSettings;
158 import jalview.ws.jws2.jabaws2.Jws2Instance;
159 import jalview.ws.params.ArgumentI;
160 import jalview.ws.params.AutoCalcSetting;
161 import jalview.ws.params.WsParamSetI;
162 import jalview.xml.binding.jalview.AlcodonFrame;
163 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
164 import jalview.xml.binding.jalview.Annotation;
165 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
166 import jalview.xml.binding.jalview.AnnotationColourScheme;
167 import jalview.xml.binding.jalview.AnnotationElement;
168 import jalview.xml.binding.jalview.DoubleMatrix;
169 import jalview.xml.binding.jalview.DoubleVector;
170 import jalview.xml.binding.jalview.Feature;
171 import jalview.xml.binding.jalview.Feature.OtherData;
172 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
173 import jalview.xml.binding.jalview.FilterBy;
174 import jalview.xml.binding.jalview.JalviewModel;
175 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
176 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
177 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
178 import jalview.xml.binding.jalview.JalviewModel.JGroup;
179 import jalview.xml.binding.jalview.JalviewModel.JSeq;
180 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
181 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
182 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
183 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
184 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
185 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
186 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
187 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
188 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
189 import jalview.xml.binding.jalview.JalviewModel.Tree;
190 import jalview.xml.binding.jalview.JalviewModel.UserColours;
191 import jalview.xml.binding.jalview.JalviewModel.Viewport;
192 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
193 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
194 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
195 import jalview.xml.binding.jalview.JalviewUserColours;
196 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
197 import jalview.xml.binding.jalview.MapListType.MapListFrom;
198 import jalview.xml.binding.jalview.MapListType.MapListTo;
199 import jalview.xml.binding.jalview.Mapping;
200 import jalview.xml.binding.jalview.MatrixType;
201 import jalview.xml.binding.jalview.NoValueColour;
202 import jalview.xml.binding.jalview.ObjectFactory;
203 import jalview.xml.binding.jalview.PcaDataType;
204 import jalview.xml.binding.jalview.Pdbentry.Property;
205 import jalview.xml.binding.jalview.Sequence;
206 import jalview.xml.binding.jalview.Sequence.DBRef;
207 import jalview.xml.binding.jalview.SequenceSet;
208 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
209 import jalview.xml.binding.jalview.ThresholdType;
210 import jalview.xml.binding.jalview.VAMSAS;
213 * Write out the current jalview desktop state as a Jalview XML stream.
215 * Note: the vamsas objects referred to here are primitive versions of the
216 * VAMSAS project schema elements - they are not the same and most likely never
220 * @version $Revision: 1.134 $
222 public class Jalview2XML
225 // BH 2018 we add the .jvp binary extension to J2S so that
226 // it will declare that binary when we do the file save from the browser
230 Platform.addJ2SBinaryType(".jvp?");
233 private static final String VIEWER_PREFIX = "viewer_";
235 private static final String RNA_PREFIX = "rna_";
237 private static final String UTF_8 = "UTF-8";
240 * used in decision if quit confirmation should be issued
242 private static boolean stateSavedUpToDate = false;
245 * prefix for recovering datasets for alignments with multiple views where
246 * non-existent dataset IDs were written for some views
248 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
250 // use this with nextCounter() to make unique names for entities
251 private int counter = 0;
254 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
255 * of sequence objects are created.
257 IdentityHashMap<SequenceI, String> seqsToIds = null;
260 * jalview XML Sequence ID to jalview sequence object reference (both dataset
261 * and alignment sequences. Populated as XML reps of sequence objects are
264 Map<String, SequenceI> seqRefIds = null;
266 Map<String, SequenceI> incompleteSeqs = null;
268 List<SeqFref> frefedSequence = null;
270 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
273 * Map of reconstructed AlignFrame objects that appear to have come from
274 * SplitFrame objects (have a dna/protein complement view).
276 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
279 * Map from displayed rna structure models to their saved session state jar
282 private Map<RnaModel, String> rnaSessions = new HashMap<>();
285 * A helper method for safely using the value of an optional attribute that
286 * may be null if not present in the XML. Answers the boolean value, or false
292 public static boolean safeBoolean(Boolean b)
294 return b == null ? false : b.booleanValue();
298 * A helper method for safely using the value of an optional attribute that
299 * may be null if not present in the XML. Answers the integer value, or zero
305 public static int safeInt(Integer i)
307 return i == null ? 0 : i.intValue();
311 * A helper method for safely using the value of an optional attribute that
312 * may be null if not present in the XML. Answers the float value, or zero if
318 public static float safeFloat(Float f)
320 return f == null ? 0f : f.floatValue();
324 * create/return unique hash string for sq
327 * @return new or existing unique string for sq
329 String seqHash(SequenceI sq)
331 if (seqsToIds == null)
335 if (seqsToIds.containsKey(sq))
337 return seqsToIds.get(sq);
341 // create sequential key
342 String key = "sq" + (seqsToIds.size() + 1);
343 key = makeHashCode(sq, key); // check we don't have an external reference
345 seqsToIds.put(sq, key);
352 if (seqsToIds == null)
354 seqsToIds = new IdentityHashMap<>();
356 if (seqRefIds == null)
358 seqRefIds = new HashMap<>();
360 if (incompleteSeqs == null)
362 incompleteSeqs = new HashMap<>();
364 if (frefedSequence == null)
366 frefedSequence = new ArrayList<>();
374 public Jalview2XML(boolean raiseGUI)
376 this.raiseGUI = raiseGUI;
380 * base class for resolving forward references to sequences by their ID
385 abstract class SeqFref
391 public SeqFref(String _sref, String type)
397 public String getSref()
402 public SequenceI getSrefSeq()
404 return seqRefIds.get(sref);
407 public boolean isResolvable()
409 return seqRefIds.get(sref) != null;
412 public SequenceI getSrefDatasetSeq()
414 SequenceI sq = seqRefIds.get(sref);
417 while (sq.getDatasetSequence() != null)
419 sq = sq.getDatasetSequence();
426 * @return true if the forward reference was fully resolved
428 abstract boolean resolve();
431 public String toString()
433 return type + " reference to " + sref;
438 * create forward reference for a mapping
444 public SeqFref newMappingRef(final String sref,
445 final jalview.datamodel.Mapping _jmap)
447 SeqFref fref = new SeqFref(sref, "Mapping")
449 public jalview.datamodel.Mapping jmap = _jmap;
454 SequenceI seq = getSrefDatasetSeq();
466 public SeqFref newAlcodMapRef(final String sref,
467 final AlignedCodonFrame _cf,
468 final jalview.datamodel.Mapping _jmap)
471 SeqFref fref = new SeqFref(sref, "Codon Frame")
473 AlignedCodonFrame cf = _cf;
475 public jalview.datamodel.Mapping mp = _jmap;
478 public boolean isResolvable()
480 return super.isResolvable() && mp.getTo() != null;
486 SequenceI seq = getSrefDatasetSeq();
491 cf.addMap(seq, mp.getTo(), mp.getMap());
498 public void resolveFrefedSequences()
500 Iterator<SeqFref> nextFref = frefedSequence.iterator();
501 int toresolve = frefedSequence.size();
502 int unresolved = 0, failedtoresolve = 0;
503 while (nextFref.hasNext())
505 SeqFref ref = nextFref.next();
506 if (ref.isResolvable())
518 } catch (Exception x)
521 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
534 System.err.println("Jalview Project Import: There were " + unresolved
535 + " forward references left unresolved on the stack.");
537 if (failedtoresolve > 0)
539 System.err.println("SERIOUS! " + failedtoresolve
540 + " resolvable forward references failed to resolve.");
542 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
545 "Jalview Project Import: There are " + incompleteSeqs.size()
546 + " sequences which may have incomplete metadata.");
547 if (incompleteSeqs.size() < 10)
549 for (SequenceI s : incompleteSeqs.values())
551 System.err.println(s.toString());
557 "Too many to report. Skipping output of incomplete sequences.");
563 * This maintains a map of viewports, the key being the seqSetId. Important to
564 * set historyItem and redoList for multiple views
566 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
568 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
570 String uniqueSetSuffix = "";
573 * List of pdbfiles added to Jar
575 List<String> pdbfiles = null;
577 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
578 public void saveState(File statefile)
580 FileOutputStream fos = null;
585 fos = new FileOutputStream(statefile);
587 JarOutputStream jout = new JarOutputStream(fos);
591 } catch (Exception e)
593 Console.error("Couln't write Jalview state to " + statefile, e);
594 // TODO: inform user of the problem - they need to know if their data was
596 if (errorMessage == null)
598 errorMessage = "Did't write Jalview Archive to output file '"
599 + statefile + "' - See console error log for details";
603 errorMessage += "(Didn't write Jalview Archive to output file '"
614 } catch (IOException e)
624 * Writes a jalview project archive to the given Jar output stream.
628 public void saveState(JarOutputStream jout)
630 AlignFrame[] frames = Desktop.getAlignFrames();
632 setStateSavedUpToDate(true);
634 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
636 int n = debugDelaySave;
640 Console.debug("***** debugging save sleep " + i + "/" + n);
644 } catch (InterruptedException e)
646 // TODO Auto-generated catch block
657 saveAllFrames(Arrays.asList(frames), jout);
661 * core method for storing state for a set of AlignFrames.
664 * - frames involving all data to be exported (including containing
667 * - project output stream
669 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
671 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
674 * ensure cached data is clear before starting
676 // todo tidy up seqRefIds, seqsToIds initialisation / reset
678 splitFrameCandidates.clear();
683 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
684 // //////////////////////////////////////////////////
686 List<String> shortNames = new ArrayList<>();
687 List<String> viewIds = new ArrayList<>();
690 for (int i = frames.size() - 1; i > -1; i--)
692 AlignFrame af = frames.get(i);
694 if (skipList != null && skipList
695 .containsKey(af.getViewport().getSequenceSetId()))
700 String shortName = makeFilename(af, shortNames);
702 int apSize = af.getAlignPanels().size();
704 for (int ap = 0; ap < apSize; ap++)
706 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
708 String fileName = apSize == 1 ? shortName : ap + shortName;
709 if (!fileName.endsWith(".xml"))
711 fileName = fileName + ".xml";
714 saveState(apanel, fileName, jout, viewIds);
716 String dssid = getDatasetIdRef(
717 af.getViewport().getAlignment().getDataset());
718 if (!dsses.containsKey(dssid))
720 dsses.put(dssid, af);
725 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
731 } catch (Exception foo)
735 } catch (Exception ex)
737 // TODO: inform user of the problem - they need to know if their data was
739 if (errorMessage == null)
741 errorMessage = "Couldn't write Jalview Archive - see error output for details";
743 ex.printStackTrace();
748 * Generates a distinct file name, based on the title of the AlignFrame, by
749 * appending _n for increasing n until an unused name is generated. The new
750 * name (without its extension) is added to the list.
754 * @return the generated name, with .xml extension
756 protected String makeFilename(AlignFrame af, List<String> namesUsed)
758 String shortName = af.getTitle();
760 if (shortName.indexOf(File.separatorChar) > -1)
762 shortName = shortName
763 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
768 while (namesUsed.contains(shortName))
770 if (shortName.endsWith("_" + (count - 1)))
772 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
775 shortName = shortName.concat("_" + count);
779 namesUsed.add(shortName);
781 if (!shortName.endsWith(".xml"))
783 shortName = shortName + ".xml";
788 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
789 public boolean saveAlignment(AlignFrame af, String jarFile,
794 // create backupfiles object and get new temp filename destination
795 boolean doBackup = BackupFiles.getEnabled();
796 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
797 FileOutputStream fos = new FileOutputStream(
798 doBackup ? backupfiles.getTempFilePath() : jarFile);
800 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
802 int n = debugDelaySave;
806 Console.debug("***** debugging save sleep " + i + "/" + n);
810 } catch (InterruptedException e)
812 // TODO Auto-generated catch block
819 JarOutputStream jout = new JarOutputStream(fos);
820 List<AlignFrame> frames = new ArrayList<>();
822 // resolve splitframes
823 if (af.getViewport().getCodingComplement() != null)
825 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
831 saveAllFrames(frames, jout);
835 } catch (Exception foo)
839 boolean success = true;
843 backupfiles.setWriteSuccess(success);
844 success = backupfiles.rollBackupsAndRenameTempFile();
848 } catch (Exception ex)
850 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
851 ex.printStackTrace();
856 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
857 String fileName, JarOutputStream jout)
860 for (String dssids : dsses.keySet())
862 AlignFrame _af = dsses.get(dssids);
863 String jfileName = fileName + " Dataset for " + _af.getTitle();
864 if (!jfileName.endsWith(".xml"))
866 jfileName = jfileName + ".xml";
868 saveState(_af.alignPanel, jfileName, true, jout, null);
873 * create a JalviewModel from an alignment view and marshall it to a
877 * panel to create jalview model for
879 * name of alignment panel written to output stream
886 public JalviewModel saveState(AlignmentPanel ap, String fileName,
887 JarOutputStream jout, List<String> viewIds)
889 return saveState(ap, fileName, false, jout, viewIds);
893 * create a JalviewModel from an alignment view and marshall it to a
897 * panel to create jalview model for
899 * name of alignment panel written to output stream
901 * when true, only write the dataset for the alignment, not the data
902 * associated with the view.
908 public JalviewModel saveState(AlignmentPanel ap, String fileName,
909 boolean storeDS, JarOutputStream jout, List<String> viewIds)
913 viewIds = new ArrayList<>();
918 List<UserColourScheme> userColours = new ArrayList<>();
920 AlignViewport av = ap.av;
921 ViewportRanges vpRanges = av.getRanges();
923 final ObjectFactory objectFactory = new ObjectFactory();
924 JalviewModel object = objectFactory.createJalviewModel();
925 object.setVamsasModel(new VAMSAS());
927 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
930 GregorianCalendar c = new GregorianCalendar();
931 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
932 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
933 object.setCreationDate(now);
934 } catch (DatatypeConfigurationException e)
936 System.err.println("error writing date: " + e.toString());
938 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
941 * rjal is full height alignment, jal is actual alignment with full metadata
942 * but excludes hidden sequences.
944 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
946 if (av.hasHiddenRows())
948 rjal = jal.getHiddenSequences().getFullAlignment();
951 SequenceSet vamsasSet = new SequenceSet();
953 // JalviewModelSequence jms = new JalviewModelSequence();
955 vamsasSet.setGapChar(jal.getGapCharacter() + "");
957 if (jal.getDataset() != null)
959 // dataset id is the dataset's hashcode
960 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
963 // switch jal and the dataset
964 jal = jal.getDataset();
968 if (jal.getProperties() != null)
970 Enumeration en = jal.getProperties().keys();
971 while (en.hasMoreElements())
973 String key = en.nextElement().toString();
974 SequenceSetProperties ssp = new SequenceSetProperties();
976 ssp.setValue(jal.getProperties().get(key).toString());
977 // vamsasSet.addSequenceSetProperties(ssp);
978 vamsasSet.getSequenceSetProperties().add(ssp);
983 Set<String> calcIdSet = new HashSet<>();
984 // record the set of vamsas sequence XML POJO we create.
985 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
987 for (final SequenceI jds : rjal.getSequences())
989 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
990 : jds.getDatasetSequence();
991 String id = seqHash(jds);
992 if (vamsasSetIds.get(id) == null)
994 if (seqRefIds.get(id) != null && !storeDS)
996 // This happens for two reasons: 1. multiple views are being
998 // 2. the hashCode has collided with another sequence's code. This
1000 // HAPPEN! (PF00072.15.stk does this)
1001 // JBPNote: Uncomment to debug writing out of files that do not read
1002 // back in due to ArrayOutOfBoundExceptions.
1003 // System.err.println("vamsasSeq backref: "+id+"");
1004 // System.err.println(jds.getName()+"
1005 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1006 // System.err.println("Hashcode: "+seqHash(jds));
1007 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1008 // System.err.println(rsq.getName()+"
1009 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1010 // System.err.println("Hashcode: "+seqHash(rsq));
1014 vamsasSeq = createVamsasSequence(id, jds);
1015 // vamsasSet.addSequence(vamsasSeq);
1016 vamsasSet.getSequence().add(vamsasSeq);
1017 vamsasSetIds.put(id, vamsasSeq);
1018 seqRefIds.put(id, jds);
1022 jseq.setStart(jds.getStart());
1023 jseq.setEnd(jds.getEnd());
1024 jseq.setColour(av.getSequenceColour(jds).getRGB());
1026 jseq.setId(id); // jseq id should be a string not a number
1029 // Store any sequences this sequence represents
1030 if (av.hasHiddenRows())
1032 // use rjal, contains the full height alignment
1034 av.getAlignment().getHiddenSequences().isHidden(jds));
1036 if (av.isHiddenRepSequence(jds))
1038 jalview.datamodel.SequenceI[] reps = av
1039 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1041 for (int h = 0; h < reps.length; h++)
1045 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1046 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1051 // mark sequence as reference - if it is the reference for this view
1052 if (jal.hasSeqrep())
1054 jseq.setViewreference(jds == jal.getSeqrep());
1058 // TODO: omit sequence features from each alignment view's XML dump if we
1059 // are storing dataset
1060 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1061 for (SequenceFeature sf : sfs)
1063 // Features features = new Features();
1064 Feature features = new Feature();
1066 features.setBegin(sf.getBegin());
1067 features.setEnd(sf.getEnd());
1068 features.setDescription(sf.getDescription());
1069 features.setType(sf.getType());
1070 features.setFeatureGroup(sf.getFeatureGroup());
1071 features.setScore(sf.getScore());
1072 if (sf.links != null)
1074 for (int l = 0; l < sf.links.size(); l++)
1076 OtherData keyValue = new OtherData();
1077 keyValue.setKey("LINK_" + l);
1078 keyValue.setValue(sf.links.elementAt(l).toString());
1079 // features.addOtherData(keyValue);
1080 features.getOtherData().add(keyValue);
1083 if (sf.otherDetails != null)
1086 * save feature attributes, which may be simple strings or
1087 * map valued (have sub-attributes)
1089 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1091 String key = entry.getKey();
1092 Object value = entry.getValue();
1093 if (value instanceof Map<?, ?>)
1095 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1098 OtherData otherData = new OtherData();
1099 otherData.setKey(key);
1100 otherData.setKey2(subAttribute.getKey());
1101 otherData.setValue(subAttribute.getValue().toString());
1102 // features.addOtherData(otherData);
1103 features.getOtherData().add(otherData);
1108 OtherData otherData = new OtherData();
1109 otherData.setKey(key);
1110 otherData.setValue(value.toString());
1111 // features.addOtherData(otherData);
1112 features.getOtherData().add(otherData);
1117 // jseq.addFeatures(features);
1118 jseq.getFeatures().add(features);
1121 if (jdatasq.getAllPDBEntries() != null)
1123 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1124 while (en.hasMoreElements())
1126 Pdbids pdb = new Pdbids();
1127 jalview.datamodel.PDBEntry entry = en.nextElement();
1129 String pdbId = entry.getId();
1131 pdb.setType(entry.getType());
1134 * Store any structure views associated with this sequence. This
1135 * section copes with duplicate entries in the project, so a dataset
1136 * only view *should* be coped with sensibly.
1138 // This must have been loaded, is it still visible?
1139 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1140 String matchedFile = null;
1141 for (int f = frames.length - 1; f > -1; f--)
1143 if (frames[f] instanceof StructureViewerBase)
1145 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1146 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1147 viewIds, matchedFile, viewFrame);
1149 * Only store each structure viewer's state once in the project
1150 * jar. First time through only (storeDS==false)
1152 String viewId = viewFrame.getViewId();
1153 String viewerType = viewFrame.getViewerType().toString();
1154 if (!storeDS && !viewIds.contains(viewId))
1156 viewIds.add(viewId);
1157 File viewerState = viewFrame.saveSession();
1158 if (viewerState != null)
1160 copyFileToJar(jout, viewerState.getPath(),
1161 getViewerJarEntryName(viewId), viewerType);
1166 "Failed to save viewer state for " + viewerType);
1172 if (matchedFile != null || entry.getFile() != null)
1174 if (entry.getFile() != null)
1177 matchedFile = entry.getFile();
1179 pdb.setFile(matchedFile); // entry.getFile());
1180 if (pdbfiles == null)
1182 pdbfiles = new ArrayList<>();
1185 if (!pdbfiles.contains(pdbId))
1187 pdbfiles.add(pdbId);
1188 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1192 Enumeration<String> props = entry.getProperties();
1193 if (props.hasMoreElements())
1195 // PdbentryItem item = new PdbentryItem();
1196 while (props.hasMoreElements())
1198 Property prop = new Property();
1199 String key = props.nextElement();
1201 prop.setValue(entry.getProperty(key).toString());
1202 // item.addProperty(prop);
1203 pdb.getProperty().add(prop);
1205 // pdb.addPdbentryItem(item);
1208 // jseq.addPdbids(pdb);
1209 jseq.getPdbids().add(pdb);
1213 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1215 // jms.addJSeq(jseq);
1216 object.getJSeq().add(jseq);
1219 if (!storeDS && av.hasHiddenRows())
1221 jal = av.getAlignment();
1225 if (storeDS && jal.getCodonFrames() != null)
1227 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1228 for (AlignedCodonFrame acf : jac)
1230 AlcodonFrame alc = new AlcodonFrame();
1231 if (acf.getProtMappings() != null
1232 && acf.getProtMappings().length > 0)
1234 boolean hasMap = false;
1235 SequenceI[] dnas = acf.getdnaSeqs();
1236 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1237 for (int m = 0; m < pmaps.length; m++)
1239 AlcodMap alcmap = new AlcodMap();
1240 alcmap.setDnasq(seqHash(dnas[m]));
1242 createVamsasMapping(pmaps[m], dnas[m], null, false));
1243 // alc.addAlcodMap(alcmap);
1244 alc.getAlcodMap().add(alcmap);
1249 // vamsasSet.addAlcodonFrame(alc);
1250 vamsasSet.getAlcodonFrame().add(alc);
1253 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1255 // AlcodonFrame alc = new AlcodonFrame();
1256 // vamsasSet.addAlcodonFrame(alc);
1257 // for (int p = 0; p < acf.aaWidth; p++)
1259 // Alcodon cmap = new Alcodon();
1260 // if (acf.codons[p] != null)
1262 // // Null codons indicate a gapped column in the translated peptide
1264 // cmap.setPos1(acf.codons[p][0]);
1265 // cmap.setPos2(acf.codons[p][1]);
1266 // cmap.setPos3(acf.codons[p][2]);
1268 // alc.addAlcodon(cmap);
1270 // if (acf.getProtMappings() != null
1271 // && acf.getProtMappings().length > 0)
1273 // SequenceI[] dnas = acf.getdnaSeqs();
1274 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1275 // for (int m = 0; m < pmaps.length; m++)
1277 // AlcodMap alcmap = new AlcodMap();
1278 // alcmap.setDnasq(seqHash(dnas[m]));
1279 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1281 // alc.addAlcodMap(alcmap);
1288 // /////////////////////////////////
1289 if (!storeDS && av.getCurrentTree() != null)
1291 // FIND ANY ASSOCIATED TREES
1292 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1293 if (Desktop.desktop != null)
1295 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1297 for (int t = 0; t < frames.length; t++)
1299 if (frames[t] instanceof TreePanel)
1301 TreePanel tp = (TreePanel) frames[t];
1303 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1305 JalviewModel.Tree tree = new JalviewModel.Tree();
1306 tree.setTitle(tp.getTitle());
1307 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1308 tree.setNewick(tp.getTree().print());
1309 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1311 tree.setFitToWindow(tp.fitToWindow.getState());
1312 tree.setFontName(tp.getTreeFont().getName());
1313 tree.setFontSize(tp.getTreeFont().getSize());
1314 tree.setFontStyle(tp.getTreeFont().getStyle());
1315 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1317 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1318 tree.setShowDistances(tp.distanceMenu.getState());
1320 tree.setHeight(tp.getHeight());
1321 tree.setWidth(tp.getWidth());
1322 tree.setXpos(tp.getX());
1323 tree.setYpos(tp.getY());
1324 tree.setId(makeHashCode(tp, null));
1325 tree.setLinkToAllViews(
1326 tp.getTreeCanvas().isApplyToAllViews());
1328 // jms.addTree(tree);
1329 object.getTree().add(tree);
1339 if (!storeDS && Desktop.desktop != null)
1341 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1343 if (frame instanceof PCAPanel)
1345 PCAPanel panel = (PCAPanel) frame;
1346 if (panel.getAlignViewport().getAlignment() == jal)
1348 savePCA(panel, object);
1356 * store forward refs from an annotationRow to any groups
1358 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1361 for (SequenceI sq : jal.getSequences())
1363 // Store annotation on dataset sequences only
1364 AlignmentAnnotation[] aa = sq.getAnnotation();
1365 if (aa != null && aa.length > 0)
1367 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1374 if (jal.getAlignmentAnnotation() != null)
1376 // Store the annotation shown on the alignment.
1377 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1378 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1383 if (jal.getGroups() != null)
1385 JGroup[] groups = new JGroup[jal.getGroups().size()];
1387 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1389 JGroup jGroup = new JGroup();
1390 groups[++i] = jGroup;
1392 jGroup.setStart(sg.getStartRes());
1393 jGroup.setEnd(sg.getEndRes());
1394 jGroup.setName(sg.getName());
1395 if (groupRefs.containsKey(sg))
1397 // group has references so set its ID field
1398 jGroup.setId(groupRefs.get(sg));
1400 ColourSchemeI colourScheme = sg.getColourScheme();
1401 if (colourScheme != null)
1403 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1404 if (groupColourScheme.conservationApplied())
1406 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1408 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1410 jGroup.setColour(setUserColourScheme(colourScheme,
1411 userColours, object));
1415 jGroup.setColour(colourScheme.getSchemeName());
1418 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1420 jGroup.setColour("AnnotationColourGradient");
1421 jGroup.setAnnotationColours(constructAnnotationColours(
1422 (jalview.schemes.AnnotationColourGradient) colourScheme,
1423 userColours, object));
1425 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1428 setUserColourScheme(colourScheme, userColours, object));
1432 jGroup.setColour(colourScheme.getSchemeName());
1435 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1438 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1439 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1440 jGroup.setDisplayText(sg.getDisplayText());
1441 jGroup.setColourText(sg.getColourText());
1442 jGroup.setTextCol1(sg.textColour.getRGB());
1443 jGroup.setTextCol2(sg.textColour2.getRGB());
1444 jGroup.setTextColThreshold(sg.thresholdTextColour);
1445 jGroup.setShowUnconserved(sg.getShowNonconserved());
1446 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1447 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1448 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1449 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1450 for (SequenceI seq : sg.getSequences())
1452 // jGroup.addSeq(seqHash(seq));
1453 jGroup.getSeq().add(seqHash(seq));
1457 // jms.setJGroup(groups);
1459 for (JGroup grp : groups)
1461 object.getJGroup().add(grp);
1466 // /////////SAVE VIEWPORT
1467 Viewport view = new Viewport();
1468 view.setTitle(ap.alignFrame.getTitle());
1469 view.setSequenceSetId(
1470 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1471 view.setId(av.getViewId());
1472 if (av.getCodingComplement() != null)
1474 view.setComplementId(av.getCodingComplement().getViewId());
1476 view.setViewName(av.getViewName());
1477 view.setGatheredViews(av.isGatherViewsHere());
1479 Rectangle size = ap.av.getExplodedGeometry();
1480 Rectangle position = size;
1483 size = ap.alignFrame.getBounds();
1484 if (av.getCodingComplement() != null)
1486 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1494 view.setXpos(position.x);
1495 view.setYpos(position.y);
1497 view.setWidth(size.width);
1498 view.setHeight(size.height);
1500 view.setStartRes(vpRanges.getStartRes());
1501 view.setStartSeq(vpRanges.getStartSeq());
1503 OverviewPanel ov = ap.getOverviewPanel();
1506 Overview overview = new Overview();
1507 overview.setTitle(ov.getTitle());
1508 Rectangle bounds = ov.getFrameBounds();
1509 overview.setXpos(bounds.x);
1510 overview.setYpos(bounds.y);
1511 overview.setWidth(bounds.width);
1512 overview.setHeight(bounds.height);
1513 overview.setShowHidden(ov.isShowHiddenRegions());
1514 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1515 overview.setResidueColour(
1516 ov.getCanvas().getResidueColour().getRGB());
1517 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1518 view.setOverview(overview);
1520 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1522 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1523 userColours, object));
1526 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1528 AnnotationColourScheme ac = constructAnnotationColours(
1529 (jalview.schemes.AnnotationColourGradient) av
1530 .getGlobalColourScheme(),
1531 userColours, object);
1533 view.setAnnotationColours(ac);
1534 view.setBgColour("AnnotationColourGradient");
1538 view.setBgColour(ColourSchemeProperty
1539 .getColourName(av.getGlobalColourScheme()));
1542 ResidueShaderI vcs = av.getResidueShading();
1543 ColourSchemeI cs = av.getGlobalColourScheme();
1547 if (vcs.conservationApplied())
1549 view.setConsThreshold(vcs.getConservationInc());
1550 if (cs instanceof jalview.schemes.UserColourScheme)
1552 view.setBgColour(setUserColourScheme(cs, userColours, object));
1555 view.setPidThreshold(vcs.getThreshold());
1558 view.setConservationSelected(av.getConservationSelected());
1559 view.setPidSelected(av.getAbovePIDThreshold());
1560 view.setCharHeight(av.getCharHeight());
1561 view.setCharWidth(av.getCharWidth());
1562 final Font font = av.getFont();
1563 view.setFontName(font.getName());
1564 view.setFontSize(font.getSize());
1565 view.setFontStyle(font.getStyle());
1566 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1567 view.setRenderGaps(av.isRenderGaps());
1568 view.setShowAnnotation(av.isShowAnnotation());
1569 view.setShowBoxes(av.getShowBoxes());
1570 view.setShowColourText(av.getColourText());
1571 view.setShowFullId(av.getShowJVSuffix());
1572 view.setRightAlignIds(av.isRightAlignIds());
1573 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1574 view.setShowText(av.getShowText());
1575 view.setShowUnconserved(av.getShowUnconserved());
1576 view.setWrapAlignment(av.getWrapAlignment());
1577 view.setTextCol1(av.getTextColour().getRGB());
1578 view.setTextCol2(av.getTextColour2().getRGB());
1579 view.setTextColThreshold(av.getThresholdTextColour());
1580 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1581 view.setShowSequenceLogo(av.isShowSequenceLogo());
1582 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1583 view.setShowGroupConsensus(av.isShowGroupConsensus());
1584 view.setShowGroupConservation(av.isShowGroupConservation());
1585 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1586 view.setShowDbRefTooltip(av.isShowDBRefs());
1587 view.setFollowHighlight(av.isFollowHighlight());
1588 view.setFollowSelection(av.followSelection);
1589 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1590 view.setShowComplementFeatures(av.isShowComplementFeatures());
1591 view.setShowComplementFeaturesOnTop(
1592 av.isShowComplementFeaturesOnTop());
1593 if (av.getFeaturesDisplayed() != null)
1595 FeatureSettings fs = new FeatureSettings();
1597 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1598 .getFeatureRenderer();
1599 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1601 Vector<String> settingsAdded = new Vector<>();
1602 if (renderOrder != null)
1604 for (String featureType : renderOrder)
1606 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1607 setting.setType(featureType);
1610 * save any filter for the feature type
1612 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1615 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1617 FeatureMatcherI firstFilter = filters.next();
1618 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1619 filters, filter.isAnded()));
1623 * save colour scheme for the feature type
1625 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1626 if (!fcol.isSimpleColour())
1628 setting.setColour(fcol.getMaxColour().getRGB());
1629 setting.setMincolour(fcol.getMinColour().getRGB());
1630 setting.setMin(fcol.getMin());
1631 setting.setMax(fcol.getMax());
1632 setting.setColourByLabel(fcol.isColourByLabel());
1633 if (fcol.isColourByAttribute())
1635 String[] attName = fcol.getAttributeName();
1636 setting.getAttributeName().add(attName[0]);
1637 if (attName.length > 1)
1639 setting.getAttributeName().add(attName[1]);
1642 setting.setAutoScale(fcol.isAutoScaled());
1643 setting.setThreshold(fcol.getThreshold());
1644 Color noColour = fcol.getNoColour();
1645 if (noColour == null)
1647 setting.setNoValueColour(NoValueColour.NONE);
1649 else if (noColour.equals(fcol.getMaxColour()))
1651 setting.setNoValueColour(NoValueColour.MAX);
1655 setting.setNoValueColour(NoValueColour.MIN);
1657 // -1 = No threshold, 0 = Below, 1 = Above
1658 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1659 : (fcol.isBelowThreshold() ? 0 : -1));
1663 setting.setColour(fcol.getColour().getRGB());
1667 av.getFeaturesDisplayed().isVisible(featureType));
1668 float rorder = fr.getOrder(featureType);
1671 setting.setOrder(rorder);
1673 /// fs.addSetting(setting);
1674 fs.getSetting().add(setting);
1675 settingsAdded.addElement(featureType);
1679 // is groups actually supposed to be a map here ?
1680 Iterator<String> en = fr.getFeatureGroups().iterator();
1681 Vector<String> groupsAdded = new Vector<>();
1682 while (en.hasNext())
1684 String grp = en.next();
1685 if (groupsAdded.contains(grp))
1689 Group g = new Group();
1691 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1694 fs.getGroup().add(g);
1695 groupsAdded.addElement(grp);
1697 // jms.setFeatureSettings(fs);
1698 object.setFeatureSettings(fs);
1701 if (av.hasHiddenColumns())
1703 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1704 .getHiddenColumns();
1708 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1712 Iterator<int[]> hiddenRegions = hidden.iterator();
1713 while (hiddenRegions.hasNext())
1715 int[] region = hiddenRegions.next();
1716 HiddenColumns hc = new HiddenColumns();
1717 hc.setStart(region[0]);
1718 hc.setEnd(region[1]);
1719 // view.addHiddenColumns(hc);
1720 view.getHiddenColumns().add(hc);
1724 if (calcIdSet.size() > 0)
1726 for (String calcId : calcIdSet)
1728 if (calcId.trim().length() > 0)
1730 CalcIdParam cidp = createCalcIdParam(calcId, av);
1731 // Some calcIds have no parameters.
1734 // view.addCalcIdParam(cidp);
1735 view.getCalcIdParam().add(cidp);
1741 // jms.addViewport(view);
1742 object.getViewport().add(view);
1744 // object.setJalviewModelSequence(jms);
1745 // object.getVamsasModel().addSequenceSet(vamsasSet);
1746 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1748 if (jout != null && fileName != null)
1750 // We may not want to write the object to disk,
1751 // eg we can copy the alignViewport to a new view object
1752 // using save and then load
1755 fileName = fileName.replace('\\', '/');
1756 System.out.println("Writing jar entry " + fileName);
1757 JarEntry entry = new JarEntry(fileName);
1758 jout.putNextEntry(entry);
1759 PrintWriter pout = new PrintWriter(
1760 new OutputStreamWriter(jout, UTF_8));
1761 JAXBContext jaxbContext = JAXBContext
1762 .newInstance(JalviewModel.class);
1763 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1765 // output pretty printed
1766 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1767 jaxbMarshaller.marshal(
1768 new ObjectFactory().createJalviewModel(object), pout);
1770 // jaxbMarshaller.marshal(object, pout);
1771 // marshaller.marshal(object);
1774 } catch (Exception ex)
1776 // TODO: raise error in GUI if marshalling failed.
1777 System.err.println("Error writing Jalview project");
1778 ex.printStackTrace();
1785 * Writes PCA viewer attributes and computed values to an XML model object and
1786 * adds it to the JalviewModel. Any exceptions are reported by logging.
1788 protected void savePCA(PCAPanel panel, JalviewModel object)
1792 PcaViewer viewer = new PcaViewer();
1793 viewer.setHeight(panel.getHeight());
1794 viewer.setWidth(panel.getWidth());
1795 viewer.setXpos(panel.getX());
1796 viewer.setYpos(panel.getY());
1797 viewer.setTitle(panel.getTitle());
1798 PCAModel pcaModel = panel.getPcaModel();
1799 viewer.setScoreModelName(pcaModel.getScoreModelName());
1800 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1801 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1802 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1804 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1805 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1806 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1807 SeqPointMin spmin = new SeqPointMin();
1808 spmin.setXPos(spMin[0]);
1809 spmin.setYPos(spMin[1]);
1810 spmin.setZPos(spMin[2]);
1811 viewer.setSeqPointMin(spmin);
1812 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1813 SeqPointMax spmax = new SeqPointMax();
1814 spmax.setXPos(spMax[0]);
1815 spmax.setYPos(spMax[1]);
1816 spmax.setZPos(spMax[2]);
1817 viewer.setSeqPointMax(spmax);
1818 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1819 viewer.setLinkToAllViews(
1820 panel.getRotatableCanvas().isApplyToAllViews());
1821 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1822 viewer.setIncludeGaps(sp.includeGaps());
1823 viewer.setMatchGaps(sp.matchGaps());
1824 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1825 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1828 * sequence points on display
1830 for (jalview.datamodel.SequencePoint spt : pcaModel
1831 .getSequencePoints())
1833 SequencePoint point = new SequencePoint();
1834 point.setSequenceRef(seqHash(spt.getSequence()));
1835 point.setXPos(spt.coord.x);
1836 point.setYPos(spt.coord.y);
1837 point.setZPos(spt.coord.z);
1838 viewer.getSequencePoint().add(point);
1842 * (end points of) axes on display
1844 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1847 Axis axis = new Axis();
1851 viewer.getAxis().add(axis);
1855 * raw PCA data (note we are not restoring PCA inputs here -
1856 * alignment view, score model, similarity parameters)
1858 PcaDataType data = new PcaDataType();
1859 viewer.setPcaData(data);
1860 PCA pca = pcaModel.getPcaData();
1862 DoubleMatrix pm = new DoubleMatrix();
1863 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1864 data.setPairwiseMatrix(pm);
1866 DoubleMatrix tm = new DoubleMatrix();
1867 saveDoubleMatrix(pca.getTridiagonal(), tm);
1868 data.setTridiagonalMatrix(tm);
1870 DoubleMatrix eigenMatrix = new DoubleMatrix();
1871 data.setEigenMatrix(eigenMatrix);
1872 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1874 object.getPcaViewer().add(viewer);
1875 } catch (Throwable t)
1877 Console.error("Error saving PCA: " + t.getMessage());
1882 * Stores values from a matrix into an XML element, including (if present) the
1887 * @see #loadDoubleMatrix(DoubleMatrix)
1889 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1891 xmlMatrix.setRows(m.height());
1892 xmlMatrix.setColumns(m.width());
1893 for (int i = 0; i < m.height(); i++)
1895 DoubleVector row = new DoubleVector();
1896 for (int j = 0; j < m.width(); j++)
1898 row.getV().add(m.getValue(i, j));
1900 xmlMatrix.getRow().add(row);
1902 if (m.getD() != null)
1904 DoubleVector dVector = new DoubleVector();
1905 for (double d : m.getD())
1907 dVector.getV().add(d);
1909 xmlMatrix.setD(dVector);
1911 if (m.getE() != null)
1913 DoubleVector eVector = new DoubleVector();
1914 for (double e : m.getE())
1916 eVector.getV().add(e);
1918 xmlMatrix.setE(eVector);
1923 * Loads XML matrix data into a new Matrix object, including the D and/or E
1924 * vectors (if present)
1928 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1930 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1932 int rows = mData.getRows();
1933 double[][] vals = new double[rows][];
1935 for (int i = 0; i < rows; i++)
1937 List<Double> dVector = mData.getRow().get(i).getV();
1938 vals[i] = new double[dVector.size()];
1940 for (Double d : dVector)
1946 MatrixI m = new Matrix(vals);
1948 if (mData.getD() != null)
1950 List<Double> dVector = mData.getD().getV();
1951 double[] vec = new double[dVector.size()];
1953 for (Double d : dVector)
1959 if (mData.getE() != null)
1961 List<Double> dVector = mData.getE().getV();
1962 double[] vec = new double[dVector.size()];
1964 for (Double d : dVector)
1975 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1976 * for each viewer, with
1978 * <li>viewer geometry (position, size, split pane divider location)</li>
1979 * <li>index of the selected structure in the viewer (currently shows gapped
1981 * <li>the id of the annotation holding RNA secondary structure</li>
1982 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1984 * Varna viewer state is also written out (in native Varna XML) to separate
1985 * project jar entries. A separate entry is written for each RNA structure
1986 * displayed, with the naming convention
1988 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1996 * @param storeDataset
1998 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1999 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2000 boolean storeDataset)
2002 if (Desktop.desktop == null)
2006 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2007 for (int f = frames.length - 1; f > -1; f--)
2009 if (frames[f] instanceof AppVarna)
2011 AppVarna varna = (AppVarna) frames[f];
2013 * link the sequence to every viewer that is showing it and is linked to
2014 * its alignment panel
2016 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2018 String viewId = varna.getViewId();
2019 RnaViewer rna = new RnaViewer();
2020 rna.setViewId(viewId);
2021 rna.setTitle(varna.getTitle());
2022 rna.setXpos(varna.getX());
2023 rna.setYpos(varna.getY());
2024 rna.setWidth(varna.getWidth());
2025 rna.setHeight(varna.getHeight());
2026 rna.setDividerLocation(varna.getDividerLocation());
2027 rna.setSelectedRna(varna.getSelectedIndex());
2028 // jseq.addRnaViewer(rna);
2029 jseq.getRnaViewer().add(rna);
2032 * Store each Varna panel's state once in the project per sequence.
2033 * First time through only (storeDataset==false)
2035 // boolean storeSessions = false;
2036 // String sequenceViewId = viewId + seqsToIds.get(jds);
2037 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2039 // viewIds.add(sequenceViewId);
2040 // storeSessions = true;
2042 for (RnaModel model : varna.getModels())
2044 if (model.seq == jds)
2047 * VARNA saves each view (sequence or alignment secondary
2048 * structure, gapped or trimmed) as a separate XML file
2050 String jarEntryName = rnaSessions.get(model);
2051 if (jarEntryName == null)
2054 String varnaStateFile = varna.getStateInfo(model.rna);
2055 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2056 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2057 rnaSessions.put(model, jarEntryName);
2059 SecondaryStructure ss = new SecondaryStructure();
2060 String annotationId = varna.getAnnotation(jds).annotationId;
2061 ss.setAnnotationId(annotationId);
2062 ss.setViewerState(jarEntryName);
2063 ss.setGapped(model.gapped);
2064 ss.setTitle(model.title);
2065 // rna.addSecondaryStructure(ss);
2066 rna.getSecondaryStructure().add(ss);
2075 * Copy the contents of a file to a new entry added to the output jar
2079 * @param jarEntryName
2081 * additional identifying info to log to the console
2083 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2084 String jarEntryName, String msg)
2086 try (InputStream is = new FileInputStream(infilePath))
2088 File file = new File(infilePath);
2089 if (file.exists() && jout != null)
2092 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2093 jout.putNextEntry(new JarEntry(jarEntryName));
2096 // dis = new DataInputStream(new FileInputStream(file));
2097 // byte[] data = new byte[(int) file.length()];
2098 // dis.readFully(data);
2099 // writeJarEntry(jout, jarEntryName, data);
2101 } catch (Exception ex)
2103 ex.printStackTrace();
2108 * Copies input to output, in 4K buffers; handles any data (text or binary)
2112 * @throws IOException
2114 protected void copyAll(InputStream in, OutputStream out)
2117 byte[] buffer = new byte[4096];
2119 while ((bytesRead = in.read(buffer)) != -1)
2121 out.write(buffer, 0, bytesRead);
2126 * Save the state of a structure viewer
2131 * the archive XML element under which to save the state
2134 * @param matchedFile
2138 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2139 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2140 String matchedFile, StructureViewerBase viewFrame)
2142 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2145 * Look for any bindings for this viewer to the PDB file of interest
2146 * (including part matches excluding chain id)
2148 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2150 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2151 final String pdbId = pdbentry.getId();
2152 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2153 && entry.getId().toLowerCase(Locale.ROOT)
2154 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2157 * not interested in a binding to a different PDB entry here
2161 if (matchedFile == null)
2163 matchedFile = pdbentry.getFile();
2165 else if (!matchedFile.equals(pdbentry.getFile()))
2168 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2169 + pdbentry.getFile());
2173 // can get at it if the ID
2174 // match is ambiguous (e.g.
2177 for (int smap = 0; smap < viewFrame.getBinding()
2178 .getSequence()[peid].length; smap++)
2180 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2181 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2183 StructureState state = new StructureState();
2184 state.setVisible(true);
2185 state.setXpos(viewFrame.getX());
2186 state.setYpos(viewFrame.getY());
2187 state.setWidth(viewFrame.getWidth());
2188 state.setHeight(viewFrame.getHeight());
2189 final String viewId = viewFrame.getViewId();
2190 state.setViewId(viewId);
2191 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2192 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2193 state.setColourByJmol(viewFrame.isColouredByViewer());
2194 state.setType(viewFrame.getViewerType().toString());
2195 // pdb.addStructureState(state);
2196 pdb.getStructureState().add(state);
2204 * Populates the AnnotationColourScheme xml for save. This captures the
2205 * settings of the options in the 'Colour by Annotation' dialog.
2208 * @param userColours
2212 private AnnotationColourScheme constructAnnotationColours(
2213 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2216 AnnotationColourScheme ac = new AnnotationColourScheme();
2217 ac.setAboveThreshold(acg.getAboveThreshold());
2218 ac.setThreshold(acg.getAnnotationThreshold());
2219 // 2.10.2 save annotationId (unique) not annotation label
2220 ac.setAnnotation(acg.getAnnotation().annotationId);
2221 if (acg.getBaseColour() instanceof UserColourScheme)
2224 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2229 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2232 ac.setMaxColour(acg.getMaxColour().getRGB());
2233 ac.setMinColour(acg.getMinColour().getRGB());
2234 ac.setPerSequence(acg.isSeqAssociated());
2235 ac.setPredefinedColours(acg.isPredefinedColours());
2239 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2240 IdentityHashMap<SequenceGroup, String> groupRefs,
2241 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2242 SequenceSet vamsasSet)
2245 for (int i = 0; i < aa.length; i++)
2247 Annotation an = new Annotation();
2249 AlignmentAnnotation annotation = aa[i];
2250 if (annotation.annotationId != null)
2252 annotationIds.put(annotation.annotationId, annotation);
2255 an.setId(annotation.annotationId);
2257 an.setVisible(annotation.visible);
2259 an.setDescription(annotation.description);
2261 if (annotation.sequenceRef != null)
2263 // 2.9 JAL-1781 xref on sequence id rather than name
2264 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2266 if (annotation.groupRef != null)
2268 String groupIdr = groupRefs.get(annotation.groupRef);
2269 if (groupIdr == null)
2271 // make a locally unique String
2272 groupRefs.put(annotation.groupRef,
2273 groupIdr = ("" + System.currentTimeMillis()
2274 + annotation.groupRef.getName()
2275 + groupRefs.size()));
2277 an.setGroupRef(groupIdr.toString());
2280 // store all visualization attributes for annotation
2281 an.setGraphHeight(annotation.graphHeight);
2282 an.setCentreColLabels(annotation.centreColLabels);
2283 an.setScaleColLabels(annotation.scaleColLabel);
2284 an.setShowAllColLabels(annotation.showAllColLabels);
2285 an.setBelowAlignment(annotation.belowAlignment);
2287 if (annotation.graph > 0)
2290 an.setGraphType(annotation.graph);
2291 an.setGraphGroup(annotation.graphGroup);
2292 if (annotation.getThreshold() != null)
2294 ThresholdLine line = new ThresholdLine();
2295 line.setLabel(annotation.getThreshold().label);
2296 line.setValue(annotation.getThreshold().value);
2297 line.setColour(annotation.getThreshold().colour.getRGB());
2298 an.setThresholdLine(line);
2300 if (annotation.graph==AlignmentAnnotation.CONTACT_MAP)
2302 if (annotation.sequenceRef.getContactMaps()!=null)
2304 ContactMatrixI cm = annotation.sequenceRef.getContactMatrixFor(annotation);
2307 MatrixType xmlmat = new MatrixType();
2308 xmlmat.setType(cm.getType());
2309 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2310 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2311 // consider using an opaque to/from -> allow instance to control its representation ?
2312 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2315 for (BitSet gp: cm.getGroups())
2317 BigInteger val = new BigInteger(gp.toByteArray());
2318 xmlmat.getGroups().add(val.toString());
2323 // provenance object for tree ?
2324 xmlmat.getNewick().add(cm.getNewick());
2325 xmlmat.setTreeMethod(cm.getTreeMethod());
2327 if (cm.hasCutHeight())
2329 xmlmat.setCutHeight(cm.getCutHeight());
2332 // set/get properties
2333 an.getContactmatrix().add(xmlmat);
2343 an.setLabel(annotation.label);
2345 if (annotation == av.getAlignmentQualityAnnot()
2346 || annotation == av.getAlignmentConservationAnnotation()
2347 || annotation == av.getAlignmentConsensusAnnotation()
2348 || annotation.autoCalculated)
2350 // new way of indicating autocalculated annotation -
2351 an.setAutoCalculated(annotation.autoCalculated);
2353 if (annotation.hasScore())
2355 an.setScore(annotation.getScore());
2358 if (annotation.getCalcId() != null)
2360 calcIdSet.add(annotation.getCalcId());
2361 an.setCalcId(annotation.getCalcId());
2363 if (annotation.hasProperties())
2365 for (String pr : annotation.getProperties())
2367 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2369 prop.setValue(annotation.getProperty(pr));
2370 an.getProperty().add(prop);
2374 AnnotationElement ae;
2375 if (annotation.annotations != null)
2377 an.setScoreOnly(false);
2378 for (int a = 0; a < annotation.annotations.length; a++)
2380 if ((annotation == null) || (annotation.annotations[a] == null))
2385 ae = new AnnotationElement();
2386 if (annotation.annotations[a].description != null)
2388 ae.setDescription(annotation.annotations[a].description);
2390 if (annotation.annotations[a].displayCharacter != null)
2392 ae.setDisplayCharacter(
2393 annotation.annotations[a].displayCharacter);
2396 if (!Float.isNaN(annotation.annotations[a].value))
2398 ae.setValue(annotation.annotations[a].value);
2402 if (annotation.annotations[a].secondaryStructure > ' ')
2404 ae.setSecondaryStructure(
2405 annotation.annotations[a].secondaryStructure + "");
2408 if (annotation.annotations[a].colour != null
2409 && annotation.annotations[a].colour != java.awt.Color.black)
2411 ae.setColour(annotation.annotations[a].colour.getRGB());
2414 // an.addAnnotationElement(ae);
2415 an.getAnnotationElement().add(ae);
2416 if (annotation.autoCalculated)
2418 // only write one non-null entry into the annotation row -
2419 // sufficient to get the visualization attributes necessary to
2427 an.setScoreOnly(true);
2429 if (!storeDS || (storeDS && !annotation.autoCalculated))
2431 // skip autocalculated annotation - these are only provided for
2433 // vamsasSet.addAnnotation(an);
2434 vamsasSet.getAnnotation().add(an);
2440 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2442 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2443 if (settings != null)
2445 CalcIdParam vCalcIdParam = new CalcIdParam();
2446 vCalcIdParam.setCalcId(calcId);
2447 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2448 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2449 // generic URI allowing a third party to resolve another instance of the
2450 // service used for this calculation
2451 for (String url : settings.getServiceURLs())
2453 // vCalcIdParam.addServiceURL(urls);
2454 vCalcIdParam.getServiceURL().add(url);
2456 vCalcIdParam.setVersion("1.0");
2457 if (settings.getPreset() != null)
2459 WsParamSetI setting = settings.getPreset();
2460 vCalcIdParam.setName(setting.getName());
2461 vCalcIdParam.setDescription(setting.getDescription());
2465 vCalcIdParam.setName("");
2466 vCalcIdParam.setDescription("Last used parameters");
2468 // need to be able to recover 1) settings 2) user-defined presets or
2469 // recreate settings from preset 3) predefined settings provided by
2470 // service - or settings that can be transferred (or discarded)
2471 vCalcIdParam.setParameters(
2472 settings.getWsParamFile().replace("\n", "|\\n|"));
2473 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2474 // todo - decide if updateImmediately is needed for any projects.
2476 return vCalcIdParam;
2481 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2484 if (calcIdParam.getVersion().equals("1.0"))
2486 final String[] calcIds = calcIdParam.getServiceURL()
2487 .toArray(new String[0]);
2488 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2489 .getPreferredServiceFor(calcIds);
2490 if (service != null)
2492 WsParamSetI parmSet = null;
2495 parmSet = service.getParamStore().parseServiceParameterFile(
2496 calcIdParam.getName(), calcIdParam.getDescription(),
2498 calcIdParam.getParameters().replace("|\\n|", "\n"));
2499 } catch (IOException x)
2501 Console.warn("Couldn't parse parameter data for "
2502 + calcIdParam.getCalcId(), x);
2505 List<ArgumentI> argList = null;
2506 if (calcIdParam.getName().length() > 0)
2508 parmSet = service.getParamStore()
2509 .getPreset(calcIdParam.getName());
2510 if (parmSet != null)
2512 // TODO : check we have a good match with settings in AACon -
2513 // otherwise we'll need to create a new preset
2518 argList = parmSet.getArguments();
2521 AAConSettings settings = new AAConSettings(
2522 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2523 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2524 calcIdParam.isNeedsUpdate());
2530 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2534 throw new Error(MessageManager.formatMessage(
2535 "error.unsupported_version_calcIdparam", new Object[]
2536 { calcIdParam.toString() }));
2540 * External mapping between jalview objects and objects yielding a valid and
2541 * unique object ID string. This is null for normal Jalview project IO, but
2542 * non-null when a jalview project is being read or written as part of a
2545 IdentityHashMap jv2vobj = null;
2548 * Construct a unique ID for jvobj using either existing bindings or if none
2549 * exist, the result of the hashcode call for the object.
2552 * jalview data object
2553 * @return unique ID for referring to jvobj
2555 private String makeHashCode(Object jvobj, String altCode)
2557 if (jv2vobj != null)
2559 Object id = jv2vobj.get(jvobj);
2562 return id.toString();
2564 // check string ID mappings
2565 if (jvids2vobj != null && jvobj instanceof String)
2567 id = jvids2vobj.get(jvobj);
2571 return id.toString();
2573 // give up and warn that something has gone wrong
2575 "Cannot find ID for object in external mapping : " + jvobj);
2581 * return local jalview object mapped to ID, if it exists
2585 * @return null or object bound to idcode
2587 private Object retrieveExistingObj(String idcode)
2589 if (idcode != null && vobj2jv != null)
2591 return vobj2jv.get(idcode);
2597 * binding from ID strings from external mapping table to jalview data model
2600 private Hashtable vobj2jv;
2602 private Sequence createVamsasSequence(String id, SequenceI jds)
2604 return createVamsasSequence(true, id, jds, null);
2607 private Sequence createVamsasSequence(boolean recurse, String id,
2608 SequenceI jds, SequenceI parentseq)
2610 Sequence vamsasSeq = new Sequence();
2611 vamsasSeq.setId(id);
2612 vamsasSeq.setName(jds.getName());
2613 vamsasSeq.setSequence(jds.getSequenceAsString());
2614 vamsasSeq.setDescription(jds.getDescription());
2615 List<DBRefEntry> dbrefs = null;
2616 if (jds.getDatasetSequence() != null)
2618 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2622 // seqId==dsseqid so we can tell which sequences really are
2623 // dataset sequences only
2624 vamsasSeq.setDsseqid(id);
2625 dbrefs = jds.getDBRefs();
2626 if (parentseq == null)
2633 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2637 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2639 DBRef dbref = new DBRef();
2640 DBRefEntry ref = dbrefs.get(d);
2641 dbref.setSource(ref.getSource());
2642 dbref.setVersion(ref.getVersion());
2643 dbref.setAccessionId(ref.getAccessionId());
2644 dbref.setCanonical(ref.isCanonical());
2645 if (ref instanceof GeneLocus)
2647 dbref.setLocus(true);
2651 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2653 dbref.setMapping(mp);
2655 vamsasSeq.getDBRef().add(dbref);
2661 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2662 SequenceI parentseq, SequenceI jds, boolean recurse)
2665 if (jmp.getMap() != null)
2669 jalview.util.MapList mlst = jmp.getMap();
2670 List<int[]> r = mlst.getFromRanges();
2671 for (int[] range : r)
2673 MapListFrom mfrom = new MapListFrom();
2674 mfrom.setStart(range[0]);
2675 mfrom.setEnd(range[1]);
2676 // mp.addMapListFrom(mfrom);
2677 mp.getMapListFrom().add(mfrom);
2679 r = mlst.getToRanges();
2680 for (int[] range : r)
2682 MapListTo mto = new MapListTo();
2683 mto.setStart(range[0]);
2684 mto.setEnd(range[1]);
2685 // mp.addMapListTo(mto);
2686 mp.getMapListTo().add(mto);
2688 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2689 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2690 if (jmp.getTo() != null)
2692 // MappingChoice mpc = new MappingChoice();
2694 // check/create ID for the sequence referenced by getTo()
2697 SequenceI ps = null;
2698 if (parentseq != jmp.getTo()
2699 && parentseq.getDatasetSequence() != jmp.getTo())
2701 // chaining dbref rather than a handshaking one
2702 jmpid = seqHash(ps = jmp.getTo());
2706 jmpid = seqHash(ps = parentseq);
2708 // mpc.setDseqFor(jmpid);
2709 mp.setDseqFor(jmpid);
2710 if (!seqRefIds.containsKey(jmpid))
2712 Console.debug("creatign new DseqFor ID");
2713 seqRefIds.put(jmpid, ps);
2717 Console.debug("reusing DseqFor ID");
2720 // mp.setMappingChoice(mpc);
2726 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2727 List<UserColourScheme> userColours, JalviewModel jm)
2730 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2731 boolean newucs = false;
2732 if (!userColours.contains(ucs))
2734 userColours.add(ucs);
2737 id = "ucs" + userColours.indexOf(ucs);
2740 // actually create the scheme's entry in the XML model
2741 java.awt.Color[] colours = ucs.getColours();
2742 UserColours uc = new UserColours();
2743 // UserColourScheme jbucs = new UserColourScheme();
2744 JalviewUserColours jbucs = new JalviewUserColours();
2746 for (int i = 0; i < colours.length; i++)
2748 Colour col = new Colour();
2749 col.setName(ResidueProperties.aa[i]);
2750 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2751 // jbucs.addColour(col);
2752 jbucs.getColour().add(col);
2754 if (ucs.getLowerCaseColours() != null)
2756 colours = ucs.getLowerCaseColours();
2757 for (int i = 0; i < colours.length; i++)
2759 Colour col = new Colour();
2760 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2761 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2762 // jbucs.addColour(col);
2763 jbucs.getColour().add(col);
2768 uc.setUserColourScheme(jbucs);
2769 // jm.addUserColours(uc);
2770 jm.getUserColours().add(uc);
2776 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2779 List<UserColours> uc = jm.getUserColours();
2780 UserColours colours = null;
2782 for (int i = 0; i < uc.length; i++)
2784 if (uc[i].getId().equals(id))
2791 for (UserColours c : uc)
2793 if (c.getId().equals(id))
2800 java.awt.Color[] newColours = new java.awt.Color[24];
2802 for (int i = 0; i < 24; i++)
2804 newColours[i] = new java.awt.Color(Integer.parseInt(
2805 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2806 colours.getUserColourScheme().getColour().get(i).getRGB(),
2810 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2813 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2815 newColours = new java.awt.Color[23];
2816 for (int i = 0; i < 23; i++)
2818 newColours[i] = new java.awt.Color(
2819 Integer.parseInt(colours.getUserColourScheme().getColour()
2820 .get(i + 24).getRGB(), 16));
2822 ucs.setLowerCaseColours(newColours);
2829 * contains last error message (if any) encountered by XML loader.
2831 String errorMessage = null;
2834 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2835 * exceptions are raised during project XML parsing
2837 public boolean attemptversion1parse = false;
2840 * Load a jalview project archive from a jar file
2843 * - HTTP URL or filename
2845 public AlignFrame loadJalviewAlign(final Object file)
2848 jalview.gui.AlignFrame af = null;
2852 // create list to store references for any new Jmol viewers created
2853 newStructureViewers = new Vector<>();
2854 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2855 // Workaround is to make sure caller implements the JarInputStreamProvider
2857 // so we can re-open the jar input stream for each entry.
2859 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2860 af = loadJalviewAlign(jprovider);
2863 af.setMenusForViewport();
2865 } catch (MalformedURLException e)
2867 errorMessage = "Invalid URL format for '" + file + "'";
2873 SwingUtilities.invokeAndWait(new Runnable()
2878 setLoadingFinishedForNewStructureViewers();
2881 } catch (Exception x)
2883 System.err.println("Error loading alignment: " + x.getMessage());
2889 @SuppressWarnings("unused")
2890 private jarInputStreamProvider createjarInputStreamProvider(
2891 final Object ofile) throws MalformedURLException
2894 // BH 2018 allow for bytes already attached to File object
2897 String file = (ofile instanceof File
2898 ? ((File) ofile).getCanonicalPath()
2899 : ofile.toString());
2900 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2903 errorMessage = null;
2904 uniqueSetSuffix = null;
2906 viewportsAdded.clear();
2907 frefedSequence = null;
2909 if (HttpUtils.startsWithHttpOrHttps(file))
2911 url = new URL(file);
2913 final URL _url = url;
2914 return new jarInputStreamProvider()
2918 public JarInputStream getJarInputStream() throws IOException
2922 // System.out.println("Jalview2XML: opening byte jarInputStream for
2923 // bytes.length=" + bytes.length);
2924 return new JarInputStream(new ByteArrayInputStream(bytes));
2928 // System.out.println("Jalview2XML: opening url jarInputStream for "
2930 return new JarInputStream(_url.openStream());
2934 // System.out.println("Jalview2XML: opening file jarInputStream for
2936 return new JarInputStream(new FileInputStream(file));
2941 public String getFilename()
2946 } catch (IOException e)
2948 e.printStackTrace();
2954 * Recover jalview session from a jalview project archive. Caller may
2955 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2956 * themselves. Any null fields will be initialised with default values,
2957 * non-null fields are left alone.
2962 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2964 errorMessage = null;
2965 if (uniqueSetSuffix == null)
2967 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2969 if (seqRefIds == null)
2973 AlignFrame af = null, _af = null;
2974 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2975 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2976 final String file = jprovider.getFilename();
2979 JarInputStream jin = null;
2980 JarEntry jarentry = null;
2985 jin = jprovider.getJarInputStream();
2986 for (int i = 0; i < entryCount; i++)
2988 jarentry = jin.getNextJarEntry();
2991 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2993 JAXBContext jc = JAXBContext
2994 .newInstance("jalview.xml.binding.jalview");
2995 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2996 .createXMLStreamReader(jin);
2997 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2998 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2999 JalviewModel.class);
3000 JalviewModel object = jbe.getValue();
3002 if (true) // !skipViewport(object))
3004 _af = loadFromObject(object, file, true, jprovider);
3005 if (_af != null && object.getViewport().size() > 0)
3006 // getJalviewModelSequence().getViewportCount() > 0)
3010 // store a reference to the first view
3013 if (_af.getViewport().isGatherViewsHere())
3015 // if this is a gathered view, keep its reference since
3016 // after gathering views, only this frame will remain
3018 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3021 // Save dataset to register mappings once all resolved
3022 importedDatasets.put(
3023 af.getViewport().getAlignment().getDataset(),
3024 af.getViewport().getAlignment().getDataset());
3029 else if (jarentry != null)
3031 // Some other file here.
3034 } while (jarentry != null);
3036 resolveFrefedSequences();
3037 } catch (IOException ex)
3039 ex.printStackTrace();
3040 errorMessage = "Couldn't locate Jalview XML file : " + file;
3042 "Exception whilst loading jalview XML file : " + ex + "\n");
3043 } catch (Exception ex)
3045 System.err.println("Parsing as Jalview Version 2 file failed.");
3046 ex.printStackTrace(System.err);
3047 if (attemptversion1parse)
3049 // used to attempt to parse as V1 castor-generated xml
3051 if (Desktop.instance != null)
3053 Desktop.instance.stopLoading();
3057 System.out.println("Successfully loaded archive file");
3060 ex.printStackTrace();
3063 "Exception whilst loading jalview XML file : " + ex + "\n");
3064 } catch (OutOfMemoryError e)
3066 // Don't use the OOM Window here
3067 errorMessage = "Out of memory loading jalview XML file";
3068 System.err.println("Out of memory whilst loading jalview XML file");
3069 e.printStackTrace();
3073 * Regather multiple views (with the same sequence set id) to the frame (if
3074 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3075 * views instead of separate frames. Note this doesn't restore a state where
3076 * some expanded views in turn have tabbed views - the last "first tab" read
3077 * in will play the role of gatherer for all.
3079 for (AlignFrame fr : gatherToThisFrame.values())
3081 Desktop.instance.gatherViews(fr);
3084 restoreSplitFrames();
3085 for (AlignmentI ds : importedDatasets.keySet())
3087 if (ds.getCodonFrames() != null)
3089 StructureSelectionManager
3090 .getStructureSelectionManager(Desktop.instance)
3091 .registerMappings(ds.getCodonFrames());
3094 if (errorMessage != null)
3099 if (Desktop.instance != null)
3101 Desktop.instance.stopLoading();
3108 * Try to reconstruct and display SplitFrame windows, where each contains
3109 * complementary dna and protein alignments. Done by pairing up AlignFrame
3110 * objects (created earlier) which have complementary viewport ids associated.
3112 protected void restoreSplitFrames()
3114 List<SplitFrame> gatherTo = new ArrayList<>();
3115 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3116 Map<String, AlignFrame> dna = new HashMap<>();
3119 * Identify the DNA alignments
3121 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3124 AlignFrame af = candidate.getValue();
3125 if (af.getViewport().getAlignment().isNucleotide())
3127 dna.put(candidate.getKey().getId(), af);
3132 * Try to match up the protein complements
3134 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3137 AlignFrame af = candidate.getValue();
3138 if (!af.getViewport().getAlignment().isNucleotide())
3140 String complementId = candidate.getKey().getComplementId();
3141 // only non-null complements should be in the Map
3142 if (complementId != null && dna.containsKey(complementId))
3144 final AlignFrame dnaFrame = dna.get(complementId);
3145 SplitFrame sf = createSplitFrame(dnaFrame, af);
3146 addedToSplitFrames.add(dnaFrame);
3147 addedToSplitFrames.add(af);
3148 dnaFrame.setMenusForViewport();
3149 af.setMenusForViewport();
3150 if (af.getViewport().isGatherViewsHere())
3159 * Open any that we failed to pair up (which shouldn't happen!) as
3160 * standalone AlignFrame's.
3162 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3165 AlignFrame af = candidate.getValue();
3166 if (!addedToSplitFrames.contains(af))
3168 Viewport view = candidate.getKey();
3169 Desktop.addInternalFrame(af, view.getTitle(),
3170 safeInt(view.getWidth()), safeInt(view.getHeight()));
3171 af.setMenusForViewport();
3172 System.err.println("Failed to restore view " + view.getTitle()
3173 + " to split frame");
3178 * Gather back into tabbed views as flagged.
3180 for (SplitFrame sf : gatherTo)
3182 Desktop.instance.gatherViews(sf);
3185 splitFrameCandidates.clear();
3189 * Construct and display one SplitFrame holding DNA and protein alignments.
3192 * @param proteinFrame
3195 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3196 AlignFrame proteinFrame)
3198 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3199 String title = MessageManager.getString("label.linked_view_title");
3200 int width = (int) dnaFrame.getBounds().getWidth();
3201 int height = (int) (dnaFrame.getBounds().getHeight()
3202 + proteinFrame.getBounds().getHeight() + 50);
3205 * SplitFrame location is saved to both enclosed frames
3207 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3208 Desktop.addInternalFrame(splitFrame, title, width, height);
3211 * And compute cDNA consensus (couldn't do earlier with consensus as
3212 * mappings were not yet present)
3214 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3220 * check errorMessage for a valid error message and raise an error box in the
3221 * GUI or write the current errorMessage to stderr and then clear the error
3224 protected void reportErrors()
3226 reportErrors(false);
3229 protected void reportErrors(final boolean saving)
3231 if (errorMessage != null)
3233 final String finalErrorMessage = errorMessage;
3236 javax.swing.SwingUtilities.invokeLater(new Runnable()
3241 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3243 "Error " + (saving ? "saving" : "loading")
3245 JvOptionPane.WARNING_MESSAGE);
3251 System.err.println("Problem loading Jalview file: " + errorMessage);
3254 errorMessage = null;
3257 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3260 * when set, local views will be updated from view stored in JalviewXML
3261 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3262 * sync if this is set to true.
3264 private final boolean updateLocalViews = false;
3267 * Returns the path to a temporary file holding the PDB file for the given PDB
3268 * id. The first time of asking, searches for a file of that name in the
3269 * Jalview project jar, and copies it to a new temporary file. Any repeat
3270 * requests just return the path to the file previously created.
3276 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3279 if (alreadyLoadedPDB.containsKey(pdbId))
3281 return alreadyLoadedPDB.get(pdbId).toString();
3284 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3286 if (tempFile != null)
3288 alreadyLoadedPDB.put(pdbId, tempFile);
3294 * Copies the jar entry of given name to a new temporary file and returns the
3295 * path to the file, or null if the entry is not found.
3298 * @param jarEntryName
3300 * a prefix for the temporary file name, must be at least three
3302 * @param suffixModel
3303 * null or original file - so new file can be given the same suffix
3307 protected String copyJarEntry(jarInputStreamProvider jprovider,
3308 String jarEntryName, String prefix, String suffixModel)
3310 String suffix = ".tmp";
3311 if (suffixModel == null)
3313 suffixModel = jarEntryName;
3315 int sfpos = suffixModel.lastIndexOf(".");
3316 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3318 suffix = "." + suffixModel.substring(sfpos + 1);
3321 try (JarInputStream jin = jprovider.getJarInputStream())
3323 JarEntry entry = null;
3326 entry = jin.getNextJarEntry();
3327 } while (entry != null && !entry.getName().equals(jarEntryName));
3331 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3332 File outFile = File.createTempFile(prefix, suffix);
3333 outFile.deleteOnExit();
3334 try (OutputStream os = new FileOutputStream(outFile))
3338 String t = outFile.getAbsolutePath();
3344 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3346 } catch (Exception ex)
3348 ex.printStackTrace();
3354 private class JvAnnotRow
3356 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3363 * persisted version of annotation row from which to take vis properties
3365 public jalview.datamodel.AlignmentAnnotation template;
3368 * original position of the annotation row in the alignment
3374 * Load alignment frame from jalview XML DOM object
3376 * @param jalviewModel
3379 * filename source string
3380 * @param loadTreesAndStructures
3381 * when false only create Viewport
3383 * data source provider
3384 * @return alignment frame created from view stored in DOM
3386 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3387 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3389 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3391 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3393 // JalviewModelSequence jms = object.getJalviewModelSequence();
3395 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3397 Viewport view = (jalviewModel.getViewport().size() > 0)
3398 ? jalviewModel.getViewport().get(0)
3401 // ////////////////////////////////
3402 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3405 // If we just load in the same jar file again, the sequenceSetId
3406 // will be the same, and we end up with multiple references
3407 // to the same sequenceSet. We must modify this id on load
3408 // so that each load of the file gives a unique id
3411 * used to resolve correct alignment dataset for alignments with multiple
3414 String uniqueSeqSetId = null;
3415 String viewId = null;
3418 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3419 viewId = (view.getId() == null ? null
3420 : view.getId() + uniqueSetSuffix);
3423 // ////////////////////////////////
3426 List<SequenceI> hiddenSeqs = null;
3428 List<SequenceI> tmpseqs = new ArrayList<>();
3430 boolean multipleView = false;
3431 SequenceI referenceseqForView = null;
3432 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3433 List<JSeq> jseqs = jalviewModel.getJSeq();
3434 int vi = 0; // counter in vamsasSeq array
3435 for (int i = 0; i < jseqs.size(); i++)
3437 JSeq jseq = jseqs.get(i);
3438 String seqId = jseq.getId();
3440 SequenceI tmpSeq = seqRefIds.get(seqId);
3443 if (!incompleteSeqs.containsKey(seqId))
3445 // may not need this check, but keep it for at least 2.9,1 release
3446 if (tmpSeq.getStart() != jseq.getStart()
3447 || tmpSeq.getEnd() != jseq.getEnd())
3449 System.err.println(String.format(
3450 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3451 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3452 jseq.getStart(), jseq.getEnd()));
3457 incompleteSeqs.remove(seqId);
3459 if (vamsasSeqs.size() > vi
3460 && vamsasSeqs.get(vi).getId().equals(seqId))
3462 // most likely we are reading a dataset XML document so
3463 // update from vamsasSeq section of XML for this sequence
3464 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3465 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3466 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3471 // reading multiple views, so vamsasSeq set is a subset of JSeq
3472 multipleView = true;
3474 tmpSeq.setStart(jseq.getStart());
3475 tmpSeq.setEnd(jseq.getEnd());
3476 tmpseqs.add(tmpSeq);
3480 Sequence vamsasSeq = vamsasSeqs.get(vi);
3481 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3482 vamsasSeq.getSequence());
3483 tmpSeq.setDescription(vamsasSeq.getDescription());
3484 tmpSeq.setStart(jseq.getStart());
3485 tmpSeq.setEnd(jseq.getEnd());
3486 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3487 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3488 tmpseqs.add(tmpSeq);
3492 if (safeBoolean(jseq.isViewreference()))
3494 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3497 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3499 if (hiddenSeqs == null)
3501 hiddenSeqs = new ArrayList<>();
3504 hiddenSeqs.add(tmpSeq);
3509 // Create the alignment object from the sequence set
3510 // ///////////////////////////////
3511 SequenceI[] orderedSeqs = tmpseqs
3512 .toArray(new SequenceI[tmpseqs.size()]);
3514 AlignmentI al = null;
3515 // so we must create or recover the dataset alignment before going further
3516 // ///////////////////////////////
3517 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3519 // older jalview projects do not have a dataset - so creat alignment and
3521 al = new Alignment(orderedSeqs);
3522 al.setDataset(null);
3526 boolean isdsal = jalviewModel.getViewport().isEmpty();
3529 // we are importing a dataset record, so
3530 // recover reference to an alignment already materialsed as dataset
3531 al = getDatasetFor(vamsasSet.getDatasetId());
3535 // materialse the alignment
3536 al = new Alignment(orderedSeqs);
3540 addDatasetRef(vamsasSet.getDatasetId(), al);
3543 // finally, verify all data in vamsasSet is actually present in al
3544 // passing on flag indicating if it is actually a stored dataset
3545 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3548 if (referenceseqForView != null)
3550 al.setSeqrep(referenceseqForView);
3552 // / Add the alignment properties
3553 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3555 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3557 al.setProperty(ssp.getKey(), ssp.getValue());
3560 // ///////////////////////////////
3562 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3565 // load sequence features, database references and any associated PDB
3566 // structures for the alignment
3568 // prior to 2.10, this part would only be executed the first time a
3569 // sequence was encountered, but not afterwards.
3570 // now, for 2.10 projects, this is also done if the xml doc includes
3571 // dataset sequences not actually present in any particular view.
3573 for (int i = 0; i < vamsasSeqs.size(); i++)
3575 JSeq jseq = jseqs.get(i);
3576 if (jseq.getFeatures().size() > 0)
3578 List<Feature> features = jseq.getFeatures();
3579 for (int f = 0; f < features.size(); f++)
3581 Feature feat = features.get(f);
3582 SequenceFeature sf = new SequenceFeature(feat.getType(),
3583 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3584 safeFloat(feat.getScore()), feat.getFeatureGroup());
3585 sf.setStatus(feat.getStatus());
3588 * load any feature attributes - include map-valued attributes
3590 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3591 for (int od = 0; od < feat.getOtherData().size(); od++)
3593 OtherData keyValue = feat.getOtherData().get(od);
3594 String attributeName = keyValue.getKey();
3595 String attributeValue = keyValue.getValue();
3596 if (attributeName.startsWith("LINK"))
3598 sf.addLink(attributeValue);
3602 String subAttribute = keyValue.getKey2();
3603 if (subAttribute == null)
3605 // simple string-valued attribute
3606 sf.setValue(attributeName, attributeValue);
3610 // attribute 'key' has sub-attribute 'key2'
3611 if (!mapAttributes.containsKey(attributeName))
3613 mapAttributes.put(attributeName, new HashMap<>());
3615 mapAttributes.get(attributeName).put(subAttribute,
3620 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3623 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3626 // adds feature to datasequence's feature set (since Jalview 2.10)
3627 al.getSequenceAt(i).addSequenceFeature(sf);
3630 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3632 // adds dbrefs to datasequence's set (since Jalview 2.10)
3634 al.getSequenceAt(i).getDatasetSequence() == null
3635 ? al.getSequenceAt(i)
3636 : al.getSequenceAt(i).getDatasetSequence(),
3639 if (jseq.getPdbids().size() > 0)
3641 List<Pdbids> ids = jseq.getPdbids();
3642 for (int p = 0; p < ids.size(); p++)
3644 Pdbids pdbid = ids.get(p);
3645 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3646 entry.setId(pdbid.getId());
3647 if (pdbid.getType() != null)
3649 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3651 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3655 entry.setType(PDBEntry.Type.FILE);
3658 // jprovider is null when executing 'New View'
3659 if (pdbid.getFile() != null && jprovider != null)
3661 if (!pdbloaded.containsKey(pdbid.getFile()))
3663 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3668 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3672 if (pdbid.getPdbentryItem() != null)
3674 for (PdbentryItem item : pdbid.getPdbentryItem())
3676 for (Property pr : item.getProperty())
3678 entry.setProperty(pr.getName(), pr.getValue());
3683 for (Property prop : pdbid.getProperty())
3685 entry.setProperty(prop.getName(), prop.getValue());
3687 StructureSelectionManager
3688 .getStructureSelectionManager(Desktop.instance)
3689 .registerPDBEntry(entry);
3690 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3691 if (al.getSequenceAt(i).getDatasetSequence() != null)
3693 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3697 al.getSequenceAt(i).addPDBId(entry);
3702 } // end !multipleview
3704 // ///////////////////////////////
3705 // LOAD SEQUENCE MAPPINGS
3707 if (vamsasSet.getAlcodonFrame().size() > 0)
3709 // TODO Potentially this should only be done once for all views of an
3711 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3712 for (int i = 0; i < alc.size(); i++)
3714 AlignedCodonFrame cf = new AlignedCodonFrame();
3715 if (alc.get(i).getAlcodMap().size() > 0)
3717 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3718 for (int m = 0; m < maps.size(); m++)
3720 AlcodMap map = maps.get(m);
3721 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3723 jalview.datamodel.Mapping mapping = null;
3724 // attach to dna sequence reference.
3725 if (map.getMapping() != null)
3727 mapping = addMapping(map.getMapping());
3728 if (dnaseq != null && mapping.getTo() != null)
3730 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3736 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3740 al.addCodonFrame(cf);
3745 // ////////////////////////////////
3747 List<JvAnnotRow> autoAlan = new ArrayList<>();
3750 * store any annotations which forward reference a group's ID
3752 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3754 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3756 List<Annotation> an = vamsasSet.getAnnotation();
3758 for (int i = 0; i < an.size(); i++)
3760 Annotation annotation = an.get(i);
3763 * test if annotation is automatically calculated for this view only
3765 boolean autoForView = false;
3766 if (annotation.getLabel().equals("Quality")
3767 || annotation.getLabel().equals("Conservation")
3768 || annotation.getLabel().equals("Consensus"))
3770 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3772 // JAXB has no has() test; schema defaults value to false
3773 // if (!annotation.hasAutoCalculated())
3775 // annotation.setAutoCalculated(true);
3778 if (autoForView || annotation.isAutoCalculated())
3780 // remove ID - we don't recover annotation from other views for
3781 // view-specific annotation
3782 annotation.setId(null);
3785 // set visibility for other annotation in this view
3786 String annotationId = annotation.getId();
3787 if (annotationId != null && annotationIds.containsKey(annotationId))
3789 AlignmentAnnotation jda = annotationIds.get(annotationId);
3790 // in principle Visible should always be true for annotation displayed
3791 // in multiple views
3792 if (annotation.isVisible() != null)
3794 jda.visible = annotation.isVisible();
3797 al.addAnnotation(jda);
3801 // Construct new annotation from model.
3802 List<AnnotationElement> ae = annotation.getAnnotationElement();
3803 jalview.datamodel.Annotation[] anot = null;
3804 java.awt.Color firstColour = null;
3806 if (!annotation.isScoreOnly())
3808 anot = new jalview.datamodel.Annotation[al.getWidth()];
3809 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3811 AnnotationElement annElement = ae.get(aa);
3812 anpos = annElement.getPosition();
3814 if (anpos >= anot.length)
3819 float value = safeFloat(annElement.getValue());
3820 anot[anpos] = new jalview.datamodel.Annotation(
3821 annElement.getDisplayCharacter(),
3822 annElement.getDescription(),
3823 (annElement.getSecondaryStructure() == null
3824 || annElement.getSecondaryStructure()
3828 .getSecondaryStructure()
3831 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3832 if (firstColour == null)
3834 firstColour = anot[anpos].colour;
3838 jalview.datamodel.AlignmentAnnotation jaa = null;
3840 if (annotation.isGraph())
3842 float llim = 0, hlim = 0;
3843 // if (autoForView || an[i].isAutoCalculated()) {
3846 jaa = new jalview.datamodel.AlignmentAnnotation(
3847 annotation.getLabel(), annotation.getDescription(), anot,
3848 llim, hlim, safeInt(annotation.getGraphType()));
3850 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3851 jaa._linecolour = firstColour;
3852 if (annotation.getThresholdLine() != null)
3854 jaa.setThreshold(new jalview.datamodel.GraphLine(
3855 safeFloat(annotation.getThresholdLine().getValue()),
3856 annotation.getThresholdLine().getLabel(),
3857 new java.awt.Color(safeInt(
3858 annotation.getThresholdLine().getColour()))));
3860 if (autoForView || annotation.isAutoCalculated())
3862 // Hardwire the symbol display line to ensure that labels for
3863 // histograms are displayed
3869 jaa = new jalview.datamodel.AlignmentAnnotation(
3870 annotation.getLabel(), annotation.getDescription(), anot);
3871 jaa._linecolour = firstColour;
3873 // register new annotation
3874 if (annotation.getId() != null)
3876 annotationIds.put(annotation.getId(), jaa);
3877 jaa.annotationId = annotation.getId();
3879 // recover sequence association
3880 String sequenceRef = annotation.getSequenceRef();
3881 if (sequenceRef != null)
3883 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3884 SequenceI sequence = seqRefIds.get(sequenceRef);
3885 if (sequence == null)
3887 // in pre-2.9 projects sequence ref is to sequence name
3888 sequence = al.findName(sequenceRef);
3890 if (sequence != null)
3892 jaa.createSequenceMapping(sequence, 1, true);
3893 sequence.addAlignmentAnnotation(jaa);
3896 // and make a note of any group association
3897 if (annotation.getGroupRef() != null
3898 && annotation.getGroupRef().length() > 0)
3900 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3901 .get(annotation.getGroupRef());
3904 aal = new ArrayList<>();
3905 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3910 if (annotation.getScore() != null)
3912 jaa.setScore(annotation.getScore().doubleValue());
3914 if (annotation.isVisible() != null)
3916 jaa.visible = annotation.isVisible().booleanValue();
3919 if (annotation.isCentreColLabels() != null)
3921 jaa.centreColLabels = annotation.isCentreColLabels()
3925 if (annotation.isScaleColLabels() != null)
3927 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3929 if (annotation.isAutoCalculated())
3931 // newer files have an 'autoCalculated' flag and store calculation
3932 // state in viewport properties
3933 jaa.autoCalculated = true; // means annotation will be marked for
3934 // update at end of load.
3936 if (annotation.getGraphHeight() != null)
3938 jaa.graphHeight = annotation.getGraphHeight().intValue();
3940 jaa.belowAlignment = annotation.isBelowAlignment();
3941 jaa.setCalcId(annotation.getCalcId());
3942 if (annotation.getProperty().size() > 0)
3944 for (jalview.xml.binding.jalview.Property prop : annotation.getProperty())
3946 jaa.setProperty(prop.getName(), prop.getValue());
3949 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
3951 if (annotation.getContactmatrix() != null
3952 && annotation.getContactmatrix().size() > 0)
3954 for (MatrixType xmlmat : annotation.getContactmatrix())
3956 if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
3958 if (!xmlmat.getRows().equals(xmlmat.getCols()))
3960 Console.error("Can't handle non square PAE Matrices");
3964 float[][] elements = ContactMatrix
3965 .fromFloatStringToContacts(xmlmat.getElements(),
3966 xmlmat.getCols().intValue(),
3967 xmlmat.getRows().intValue());
3969 PAEContactMatrix newpae = new PAEContactMatrix(
3970 jaa.sequenceRef, elements);
3971 List<BitSet> newgroups=new ArrayList<BitSet>();
3972 if (xmlmat.getGroups().size()>0)
3974 for (String sgroup:xmlmat.getGroups())
3977 BigInteger group = new BigInteger(sgroup);
3978 newgroups.add(BitSet.valueOf(group.toByteArray()));
3979 } catch (NumberFormatException nfe)
3981 Console.error("Problem parsing groups for a contact matrix (\""+sgroup+"\"",nfe);
3985 String nwk=xmlmat.getNewick().size()>0 ? xmlmat.getNewick().get(0):null;
3986 if (xmlmat.getNewick().size()>1)
3989 "Ignoring additional clusterings for contact matrix");
3992 String treeMethod = xmlmat.getTreeMethod();
3993 double thresh = xmlmat.getCutHeight()!=null ? xmlmat.getCutHeight() : 0;
3994 newpae.restoreGroups(newgroups, treeMethod, nwk, thresh);
3995 jaa.sequenceRef.addContactListFor(jaa, newpae);
4000 Console.error("Ignoring CONTACT_MAP annotation with type "
4001 + xmlmat.getType());
4007 if (jaa.autoCalculated)
4009 autoAlan.add(new JvAnnotRow(i, jaa));
4012 // if (!autoForView)
4014 // add autocalculated group annotation and any user created annotation
4016 al.addAnnotation(jaa);
4020 // ///////////////////////
4022 // Create alignment markup and styles for this view
4023 if (jalviewModel.getJGroup().size() > 0)
4025 List<JGroup> groups = jalviewModel.getJGroup();
4026 boolean addAnnotSchemeGroup = false;
4027 for (int i = 0; i < groups.size(); i++)
4029 JGroup jGroup = groups.get(i);
4030 ColourSchemeI cs = null;
4031 if (jGroup.getColour() != null)
4033 if (jGroup.getColour().startsWith("ucs"))
4035 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4037 else if (jGroup.getColour().equals("AnnotationColourGradient")
4038 && jGroup.getAnnotationColours() != null)
4040 addAnnotSchemeGroup = true;
4044 cs = ColourSchemeProperty.getColourScheme(null, al,
4045 jGroup.getColour());
4048 int pidThreshold = safeInt(jGroup.getPidThreshold());
4050 Vector<SequenceI> seqs = new Vector<>();
4052 for (int s = 0; s < jGroup.getSeq().size(); s++)
4054 String seqId = jGroup.getSeq().get(s);
4055 SequenceI ts = seqRefIds.get(seqId);
4059 seqs.addElement(ts);
4063 if (seqs.size() < 1)
4068 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4069 safeBoolean(jGroup.isDisplayBoxes()),
4070 safeBoolean(jGroup.isDisplayText()),
4071 safeBoolean(jGroup.isColourText()),
4072 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4073 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4074 sg.getGroupColourScheme()
4075 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4076 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4078 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4079 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4080 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4081 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4082 // attributes with a default in the schema are never null
4083 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4084 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4085 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4086 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4087 if (jGroup.getConsThreshold() != null
4088 && jGroup.getConsThreshold().intValue() != 0)
4090 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4093 c.verdict(false, 25);
4094 sg.cs.setConservation(c);
4097 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4099 // re-instate unique group/annotation row reference
4100 List<AlignmentAnnotation> jaal = groupAnnotRefs
4101 .get(jGroup.getId());
4104 for (AlignmentAnnotation jaa : jaal)
4107 if (jaa.autoCalculated)
4109 // match up and try to set group autocalc alignment row for this
4111 if (jaa.label.startsWith("Consensus for "))
4113 sg.setConsensus(jaa);
4115 // match up and try to set group autocalc alignment row for this
4117 if (jaa.label.startsWith("Conservation for "))
4119 sg.setConservationRow(jaa);
4126 if (addAnnotSchemeGroup)
4128 // reconstruct the annotation colourscheme
4130 constructAnnotationColour(jGroup.getAnnotationColours(),
4131 null, al, jalviewModel, false));
4137 // only dataset in this model, so just return.
4140 // ///////////////////////////////
4143 AlignFrame af = null;
4144 AlignViewport av = null;
4145 // now check to see if we really need to create a new viewport.
4146 if (multipleView && viewportsAdded.size() == 0)
4148 // We recovered an alignment for which a viewport already exists.
4149 // TODO: fix up any settings necessary for overlaying stored state onto
4150 // state recovered from another document. (may not be necessary).
4151 // we may need a binding from a viewport in memory to one recovered from
4153 // and then recover its containing af to allow the settings to be applied.
4154 // TODO: fix for vamsas demo
4156 "About to recover a viewport for existing alignment: Sequence set ID is "
4158 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4159 if (seqsetobj != null)
4161 if (seqsetobj instanceof String)
4163 uniqueSeqSetId = (String) seqsetobj;
4165 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4171 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4177 * indicate that annotation colours are applied across all groups (pre
4178 * Jalview 2.8.1 behaviour)
4180 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4181 jalviewModel.getVersion());
4183 AlignmentPanel ap = null;
4184 boolean isnewview = true;
4187 // Check to see if this alignment already has a view id == viewId
4188 jalview.gui.AlignmentPanel views[] = Desktop
4189 .getAlignmentPanels(uniqueSeqSetId);
4190 if (views != null && views.length > 0)
4192 for (int v = 0; v < views.length; v++)
4194 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4196 // recover the existing alignpanel, alignframe, viewport
4197 af = views[v].alignFrame;
4200 // TODO: could even skip resetting view settings if we don't want to
4201 // change the local settings from other jalview processes
4210 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4211 uniqueSeqSetId, viewId, autoAlan);
4212 av = af.getViewport();
4217 * Load any trees, PDB structures and viewers, Overview
4219 * Not done if flag is false (when this method is used for New View)
4221 if (loadTreesAndStructures)
4223 loadTrees(jalviewModel, view, af, av, ap);
4224 loadPCAViewers(jalviewModel, ap);
4225 loadPDBStructures(jprovider, jseqs, af, ap);
4226 loadRnaViewers(jprovider, jseqs, ap);
4227 loadOverview(view, jalviewModel.getVersion(), af);
4229 // and finally return.
4234 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4235 * and geometry as saved
4240 protected void loadOverview(Viewport view, String version, AlignFrame af)
4242 if (!isVersionStringLaterThan("2.11.3",
4243 version) && view.getOverview()==null)
4248 * first close any Overview that was opened automatically
4249 * (if so configured in Preferences) so that the view is
4250 * restored in the same state as saved
4252 af.alignPanel.closeOverviewPanel();
4254 Overview overview = view.getOverview();
4255 if (overview != null)
4257 OverviewPanel overviewPanel = af
4258 .openOverviewPanel(overview.isShowHidden());
4259 overviewPanel.setTitle(overview.getTitle());
4260 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4261 overview.getWidth(), overview.getHeight());
4262 Color gap = new Color(overview.getGapColour());
4263 Color residue = new Color(overview.getResidueColour());
4264 Color hidden = new Color(overview.getHiddenColour());
4265 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4270 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4271 * panel is restored from separate jar entries, two (gapped and trimmed) per
4272 * sequence and secondary structure.
4274 * Currently each viewer shows just one sequence and structure (gapped and
4275 * trimmed), however this method is designed to support multiple sequences or
4276 * structures in viewers if wanted in future.
4282 private void loadRnaViewers(jarInputStreamProvider jprovider,
4283 List<JSeq> jseqs, AlignmentPanel ap)
4286 * scan the sequences for references to viewers; create each one the first
4287 * time it is referenced, add Rna models to existing viewers
4289 for (JSeq jseq : jseqs)
4291 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4293 RnaViewer viewer = jseq.getRnaViewer().get(i);
4294 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4297 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4299 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4300 SequenceI seq = seqRefIds.get(jseq.getId());
4301 AlignmentAnnotation ann = this.annotationIds
4302 .get(ss.getAnnotationId());
4305 * add the structure to the Varna display (with session state copied
4306 * from the jar to a temporary file)
4308 boolean gapped = safeBoolean(ss.isGapped());
4309 String rnaTitle = ss.getTitle();
4310 String sessionState = ss.getViewerState();
4311 String tempStateFile = copyJarEntry(jprovider, sessionState,
4313 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4314 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4316 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4322 * Locate and return an already instantiated matching AppVarna, or create one
4326 * @param viewIdSuffix
4330 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4331 String viewIdSuffix, AlignmentPanel ap)
4334 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4335 * if load is repeated
4337 String postLoadId = viewer.getViewId() + viewIdSuffix;
4338 for (JInternalFrame frame : getAllFrames())
4340 if (frame instanceof AppVarna)
4342 AppVarna varna = (AppVarna) frame;
4343 if (postLoadId.equals(varna.getViewId()))
4345 // this viewer is already instantiated
4346 // could in future here add ap as another 'parent' of the
4347 // AppVarna window; currently just 1-to-many
4354 * viewer not found - make it
4356 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4357 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4358 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4359 safeInt(viewer.getDividerLocation()));
4360 AppVarna varna = new AppVarna(model, ap);
4366 * Load any saved trees
4374 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4375 AlignViewport av, AlignmentPanel ap)
4377 // TODO result of automated refactoring - are all these parameters needed?
4380 for (int t = 0; t < jm.getTree().size(); t++)
4383 Tree tree = jm.getTree().get(t);
4385 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4388 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4389 tree.getTitle(), safeInt(tree.getWidth()),
4390 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4391 safeInt(tree.getYpos()));
4392 if (tree.getId() != null)
4394 // perhaps bind the tree id to something ?
4399 // update local tree attributes ?
4400 // TODO: should check if tp has been manipulated by user - if so its
4401 // settings shouldn't be modified
4402 tp.setTitle(tree.getTitle());
4403 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4404 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4405 safeInt(tree.getHeight())));
4406 tp.setViewport(av); // af.viewport;
4407 // TODO: verify 'associate with all views' works still
4408 tp.getTreeCanvas().setViewport(av); // af.viewport;
4409 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4411 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4415 "There was a problem recovering stored Newick tree: \n"
4416 + tree.getNewick());
4420 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4421 tp.fitToWindow_actionPerformed(null);
4423 if (tree.getFontName() != null)
4426 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4427 safeInt(tree.getFontSize())));
4432 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4433 safeInt(view.getFontSize())));
4436 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4437 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4438 tp.showDistances(safeBoolean(tree.isShowDistances()));
4440 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4442 if (safeBoolean(tree.isCurrentTree()))
4444 af.getViewport().setCurrentTree(tp.getTree());
4448 } catch (Exception ex)
4450 ex.printStackTrace();
4455 * Load and link any saved structure viewers.
4462 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4463 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4466 * Run through all PDB ids on the alignment, and collect mappings between
4467 * distinct view ids and all sequences referring to that view.
4469 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4471 for (int i = 0; i < jseqs.size(); i++)
4473 JSeq jseq = jseqs.get(i);
4474 if (jseq.getPdbids().size() > 0)
4476 List<Pdbids> ids = jseq.getPdbids();
4477 for (int p = 0; p < ids.size(); p++)
4479 Pdbids pdbid = ids.get(p);
4480 final int structureStateCount = pdbid.getStructureState().size();
4481 for (int s = 0; s < structureStateCount; s++)
4483 // check to see if we haven't already created this structure view
4484 final StructureState structureState = pdbid.getStructureState()
4486 String sviewid = (structureState.getViewId() == null) ? null
4487 : structureState.getViewId() + uniqueSetSuffix;
4488 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4489 // Originally : pdbid.getFile()
4490 // : TODO: verify external PDB file recovery still works in normal
4491 // jalview project load
4493 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4494 jpdb.setId(pdbid.getId());
4496 int x = safeInt(structureState.getXpos());
4497 int y = safeInt(structureState.getYpos());
4498 int width = safeInt(structureState.getWidth());
4499 int height = safeInt(structureState.getHeight());
4501 // Probably don't need to do this anymore...
4502 // Desktop.desktop.getComponentAt(x, y);
4503 // TODO: NOW: check that this recovers the PDB file correctly.
4504 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4506 jalview.datamodel.SequenceI seq = seqRefIds
4507 .get(jseq.getId() + "");
4508 if (sviewid == null)
4510 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4513 if (!structureViewers.containsKey(sviewid))
4515 String viewerType = structureState.getType();
4516 if (viewerType == null) // pre Jalview 2.9
4518 viewerType = ViewerType.JMOL.toString();
4520 structureViewers.put(sviewid,
4521 new StructureViewerModel(x, y, width, height, false,
4522 false, true, structureState.getViewId(),
4524 // Legacy pre-2.7 conversion JAL-823 :
4525 // do not assume any view has to be linked for colour by
4529 // assemble String[] { pdb files }, String[] { id for each
4530 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4531 // seqs_file 2}, boolean[] {
4532 // linkAlignPanel,superposeWithAlignpanel}} from hash
4533 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4534 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4535 || structureState.isAlignwithAlignPanel());
4538 * Default colour by linked panel to false if not specified (e.g.
4539 * for pre-2.7 projects)
4541 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4542 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4543 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4546 * Default colour by viewer to true if not specified (e.g. for
4549 boolean colourByViewer = jmoldat.isColourByViewer();
4550 colourByViewer &= structureState.isColourByJmol();
4551 jmoldat.setColourByViewer(colourByViewer);
4553 if (jmoldat.getStateData().length() < structureState.getValue()
4554 /*Content()*/.length())
4556 jmoldat.setStateData(structureState.getValue());// Content());
4558 if (pdbid.getFile() != null)
4560 File mapkey = new File(pdbid.getFile());
4561 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4562 if (seqstrmaps == null)
4564 jmoldat.getFileData().put(mapkey,
4565 seqstrmaps = jmoldat.new StructureData(pdbFile,
4568 if (!seqstrmaps.getSeqList().contains(seq))
4570 seqstrmaps.getSeqList().add(seq);
4576 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");
4577 Console.warn(errorMessage);
4583 // Instantiate the associated structure views
4584 for (Entry<String, StructureViewerModel> entry : structureViewers
4589 createOrLinkStructureViewer(entry, af, ap, jprovider);
4590 } catch (Exception e)
4593 "Error loading structure viewer: " + e.getMessage());
4594 // failed - try the next one
4606 protected void createOrLinkStructureViewer(
4607 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4608 AlignmentPanel ap, jarInputStreamProvider jprovider)
4610 final StructureViewerModel stateData = viewerData.getValue();
4613 * Search for any viewer windows already open from other alignment views
4614 * that exactly match the stored structure state
4616 StructureViewerBase comp = findMatchingViewer(viewerData);
4620 linkStructureViewer(ap, comp, stateData);
4624 String type = stateData.getType();
4627 ViewerType viewerType = ViewerType.valueOf(type);
4628 createStructureViewer(viewerType, viewerData, af, jprovider);
4629 } catch (IllegalArgumentException | NullPointerException e)
4631 // TODO JAL-3619 show error dialog / offer an alternative viewer
4632 Console.error("Invalid structure viewer type: " + type);
4637 * Generates a name for the entry in the project jar file to hold state
4638 * information for a structure viewer
4643 protected String getViewerJarEntryName(String viewId)
4645 return VIEWER_PREFIX + viewId;
4649 * Returns any open frame that matches given structure viewer data. The match
4650 * is based on the unique viewId, or (for older project versions) the frame's
4656 protected StructureViewerBase findMatchingViewer(
4657 Entry<String, StructureViewerModel> viewerData)
4659 final String sviewid = viewerData.getKey();
4660 final StructureViewerModel svattrib = viewerData.getValue();
4661 StructureViewerBase comp = null;
4662 JInternalFrame[] frames = getAllFrames();
4663 for (JInternalFrame frame : frames)
4665 if (frame instanceof StructureViewerBase)
4668 * Post jalview 2.4 schema includes structure view id
4670 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4673 comp = (StructureViewerBase) frame;
4674 break; // break added in 2.9
4677 * Otherwise test for matching position and size of viewer frame
4679 else if (frame.getX() == svattrib.getX()
4680 && frame.getY() == svattrib.getY()
4681 && frame.getHeight() == svattrib.getHeight()
4682 && frame.getWidth() == svattrib.getWidth())
4684 comp = (StructureViewerBase) frame;
4685 // no break in faint hope of an exact match on viewId
4693 * Link an AlignmentPanel to an existing structure viewer.
4698 * @param useinViewerSuperpos
4699 * @param usetoColourbyseq
4700 * @param viewerColouring
4702 protected void linkStructureViewer(AlignmentPanel ap,
4703 StructureViewerBase viewer, StructureViewerModel stateData)
4705 // NOTE: if the jalview project is part of a shared session then
4706 // view synchronization should/could be done here.
4708 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4709 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4710 final boolean viewerColouring = stateData.isColourByViewer();
4711 Map<File, StructureData> oldFiles = stateData.getFileData();
4714 * Add mapping for sequences in this view to an already open viewer
4716 final AAStructureBindingModel binding = viewer.getBinding();
4717 for (File id : oldFiles.keySet())
4719 // add this and any other pdb files that should be present in the
4721 StructureData filedat = oldFiles.get(id);
4722 String pdbFile = filedat.getFilePath();
4723 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4724 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4726 binding.addSequenceForStructFile(pdbFile, seq);
4728 // and add the AlignmentPanel's reference to the view panel
4729 viewer.addAlignmentPanel(ap);
4730 if (useinViewerSuperpos)
4732 viewer.useAlignmentPanelForSuperposition(ap);
4736 viewer.excludeAlignmentPanelForSuperposition(ap);
4738 if (usetoColourbyseq)
4740 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4744 viewer.excludeAlignmentPanelForColourbyseq(ap);
4749 * Get all frames within the Desktop.
4753 protected JInternalFrame[] getAllFrames()
4755 JInternalFrame[] frames = null;
4756 // TODO is this necessary - is it safe - risk of hanging?
4761 frames = Desktop.desktop.getAllFrames();
4762 } catch (ArrayIndexOutOfBoundsException e)
4764 // occasional No such child exceptions are thrown here...
4768 } catch (InterruptedException f)
4772 } while (frames == null);
4777 * Answers true if 'version' is equal to or later than 'supported', where each
4778 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4779 * changes. Development and test values for 'version' are leniently treated
4783 * - minimum version we are comparing against
4785 * - version of data being processsed
4786 * @return true if version is equal to or later than supported
4788 public static boolean isVersionStringLaterThan(String supported,
4791 if (supported == null || version == null
4792 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4793 || version.equalsIgnoreCase("Test")
4794 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4796 System.err.println("Assuming project file with "
4797 + (version == null ? "null" : version)
4798 + " is compatible with Jalview version " + supported);
4803 return StringUtils.compareVersions(version, supported, "b") >= 0;
4807 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4809 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4811 if (newStructureViewers != null)
4813 sview.getBinding().setFinishedLoadingFromArchive(false);
4814 newStructureViewers.add(sview);
4818 protected void setLoadingFinishedForNewStructureViewers()
4820 if (newStructureViewers != null)
4822 for (JalviewStructureDisplayI sview : newStructureViewers)
4824 sview.getBinding().setFinishedLoadingFromArchive(true);
4826 newStructureViewers.clear();
4827 newStructureViewers = null;
4831 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4832 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4833 Viewport view, String uniqueSeqSetId, String viewId,
4834 List<JvAnnotRow> autoAlan)
4836 AlignFrame af = null;
4837 af = new AlignFrame(al, safeInt(view.getWidth()),
4838 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4842 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4843 // System.out.println("Jalview2XML AF " + e);
4844 // super.processKeyEvent(e);
4851 af.setFileName(file, FileFormat.Jalview);
4853 final AlignViewport viewport = af.getViewport();
4854 for (int i = 0; i < JSEQ.size(); i++)
4856 int colour = safeInt(JSEQ.get(i).getColour());
4857 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4863 viewport.setColourByReferenceSeq(true);
4864 viewport.setDisplayReferenceSeq(true);
4867 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4869 if (view.getSequenceSetId() != null)
4871 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4873 viewport.setSequenceSetId(uniqueSeqSetId);
4876 // propagate shared settings to this new view
4877 viewport.setHistoryList(av.getHistoryList());
4878 viewport.setRedoList(av.getRedoList());
4882 viewportsAdded.put(uniqueSeqSetId, viewport);
4884 // TODO: check if this method can be called repeatedly without
4885 // side-effects if alignpanel already registered.
4886 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4888 // apply Hidden regions to view.
4889 if (hiddenSeqs != null)
4891 for (int s = 0; s < JSEQ.size(); s++)
4893 SequenceGroup hidden = new SequenceGroup();
4894 boolean isRepresentative = false;
4895 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4897 isRepresentative = true;
4898 SequenceI sequenceToHide = al
4899 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4900 hidden.addSequence(sequenceToHide, false);
4901 // remove from hiddenSeqs list so we don't try to hide it twice
4902 hiddenSeqs.remove(sequenceToHide);
4904 if (isRepresentative)
4906 SequenceI representativeSequence = al.getSequenceAt(s);
4907 hidden.addSequence(representativeSequence, false);
4908 viewport.hideRepSequences(representativeSequence, hidden);
4912 SequenceI[] hseqs = hiddenSeqs
4913 .toArray(new SequenceI[hiddenSeqs.size()]);
4914 viewport.hideSequence(hseqs);
4917 // recover view properties and display parameters
4919 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4920 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4921 final int pidThreshold = safeInt(view.getPidThreshold());
4922 viewport.setThreshold(pidThreshold);
4924 viewport.setColourText(safeBoolean(view.isShowColourText()));
4926 viewport.setConservationSelected(
4927 safeBoolean(view.isConservationSelected()));
4928 viewport.setIncrement(safeInt(view.getConsThreshold()));
4929 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4930 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4931 viewport.setFont(new Font(view.getFontName(),
4932 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4933 (view.getCharWidth()!=null) ? false : true);
4934 if (view.getCharWidth()!=null)
4936 viewport.setCharWidth(view.getCharWidth());
4937 viewport.setCharHeight(view.getCharHeight());
4939 ViewStyleI vs = viewport.getViewStyle();
4940 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4941 viewport.setViewStyle(vs);
4942 // TODO: allow custom charWidth/Heights to be restored by updating them
4943 // after setting font - which means set above to false
4944 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4945 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4946 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4948 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4950 viewport.setShowText(safeBoolean(view.isShowText()));
4952 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4953 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4954 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4955 viewport.setShowUnconserved(view.isShowUnconserved());
4956 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4958 if (view.getViewName() != null)
4960 viewport.setViewName(view.getViewName());
4961 af.setInitialTabVisible();
4963 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4964 safeInt(view.getWidth()), safeInt(view.getHeight()));
4965 // startSeq set in af.alignPanel.updateLayout below
4966 af.alignPanel.updateLayout();
4967 ColourSchemeI cs = null;
4968 // apply colourschemes
4969 if (view.getBgColour() != null)
4971 if (view.getBgColour().startsWith("ucs"))
4973 cs = getUserColourScheme(jm, view.getBgColour());
4975 else if (view.getBgColour().startsWith("Annotation"))
4977 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4978 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4985 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4986 view.getBgColour());
4991 * turn off 'alignment colour applies to all groups'
4992 * while restoring global colour scheme
4994 viewport.setColourAppliesToAllGroups(false);
4995 viewport.setGlobalColourScheme(cs);
4996 viewport.getResidueShading().setThreshold(pidThreshold,
4997 view.isIgnoreGapsinConsensus());
4998 viewport.getResidueShading()
4999 .setConsensus(viewport.getSequenceConsensusHash());
5000 if (safeBoolean(view.isConservationSelected()) && cs != null)
5002 viewport.getResidueShading()
5003 .setConservationInc(safeInt(view.getConsThreshold()));
5005 af.changeColour(cs);
5006 viewport.setColourAppliesToAllGroups(true);
5008 viewport.setShowSequenceFeatures(
5009 safeBoolean(view.isShowSequenceFeatures()));
5011 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5012 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5013 viewport.setFollowHighlight(view.isFollowHighlight());
5014 viewport.followSelection = view.isFollowSelection();
5015 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5016 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5017 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5018 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5019 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5020 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5021 viewport.setShowGroupConservation(view.isShowGroupConservation());
5022 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5023 viewport.setShowComplementFeaturesOnTop(
5024 view.isShowComplementFeaturesOnTop());
5026 // recover feature settings
5027 if (jm.getFeatureSettings() != null)
5029 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5030 .getFeatureRenderer();
5031 FeaturesDisplayed fdi;
5032 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5033 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5035 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5036 Map<String, Float> featureOrder = new Hashtable<>();
5038 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5041 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5042 String featureType = setting.getType();
5045 * restore feature filters (if any)
5047 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5049 if (filters != null)
5051 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5053 if (!filter.isEmpty())
5055 fr.setFeatureFilter(featureType, filter);
5060 * restore feature colour scheme
5062 Color maxColour = new Color(setting.getColour());
5063 if (setting.getMincolour() != null)
5066 * minColour is always set unless a simple colour
5067 * (including for colour by label though it doesn't use it)
5069 Color minColour = new Color(setting.getMincolour().intValue());
5070 Color noValueColour = minColour;
5071 NoValueColour noColour = setting.getNoValueColour();
5072 if (noColour == NoValueColour.NONE)
5074 noValueColour = null;
5076 else if (noColour == NoValueColour.MAX)
5078 noValueColour = maxColour;
5080 float min = safeFloat(safeFloat(setting.getMin()));
5081 float max = setting.getMax() == null ? 1f
5082 : setting.getMax().floatValue();
5083 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5084 maxColour, noValueColour, min, max);
5085 if (setting.getAttributeName().size() > 0)
5087 gc.setAttributeName(setting.getAttributeName().toArray(
5088 new String[setting.getAttributeName().size()]));
5090 if (setting.getThreshold() != null)
5092 gc.setThreshold(setting.getThreshold().floatValue());
5093 int threshstate = safeInt(setting.getThreshstate());
5094 // -1 = None, 0 = Below, 1 = Above threshold
5095 if (threshstate == 0)
5097 gc.setBelowThreshold(true);
5099 else if (threshstate == 1)
5101 gc.setAboveThreshold(true);
5104 gc.setAutoScaled(true); // default
5105 if (setting.isAutoScale() != null)
5107 gc.setAutoScaled(setting.isAutoScale());
5109 if (setting.isColourByLabel() != null)
5111 gc.setColourByLabel(setting.isColourByLabel());
5113 // and put in the feature colour table.
5114 featureColours.put(featureType, gc);
5118 featureColours.put(featureType, new FeatureColour(maxColour));
5120 renderOrder[fs] = featureType;
5121 if (setting.getOrder() != null)
5123 featureOrder.put(featureType, setting.getOrder().floatValue());
5127 featureOrder.put(featureType, Float.valueOf(
5128 fs / jm.getFeatureSettings().getSetting().size()));
5130 if (safeBoolean(setting.isDisplay()))
5132 fdi.setVisible(featureType);
5135 Map<String, Boolean> fgtable = new Hashtable<>();
5136 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5138 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5139 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5141 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5142 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5143 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5144 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5145 fgtable, featureColours, 1.0f, featureOrder);
5146 fr.transferSettings(frs);
5149 if (view.getHiddenColumns().size() > 0)
5151 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5153 final HiddenColumns hc = view.getHiddenColumns().get(c);
5154 viewport.hideColumns(safeInt(hc.getStart()),
5155 safeInt(hc.getEnd()) /* +1 */);
5158 if (view.getCalcIdParam() != null)
5160 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5162 if (calcIdParam != null)
5164 if (recoverCalcIdParam(calcIdParam, viewport))
5169 Console.warn("Couldn't recover parameters for "
5170 + calcIdParam.getCalcId());
5175 af.setMenusFromViewport(viewport);
5176 af.setTitle(view.getTitle());
5177 // TODO: we don't need to do this if the viewport is aready visible.
5179 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5180 * has a 'cdna/protein complement' view, in which case save it in order to
5181 * populate a SplitFrame once all views have been read in.
5183 String complementaryViewId = view.getComplementId();
5184 if (complementaryViewId == null)
5186 Desktop.addInternalFrame(af, view.getTitle(),
5187 safeInt(view.getWidth()), safeInt(view.getHeight()));
5188 // recompute any autoannotation
5189 af.alignPanel.updateAnnotation(false, true);
5190 reorderAutoannotation(af, al, autoAlan);
5191 af.alignPanel.alignmentChanged();
5195 splitFrameCandidates.put(view, af);
5202 * Reads saved data to restore Colour by Annotation settings
5204 * @param viewAnnColour
5208 * @param checkGroupAnnColour
5211 private ColourSchemeI constructAnnotationColour(
5212 AnnotationColourScheme viewAnnColour, AlignFrame af,
5213 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5215 boolean propagateAnnColour = false;
5216 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5218 if (checkGroupAnnColour && al.getGroups() != null
5219 && al.getGroups().size() > 0)
5221 // pre 2.8.1 behaviour
5222 // check to see if we should transfer annotation colours
5223 propagateAnnColour = true;
5224 for (SequenceGroup sg : al.getGroups())
5226 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5228 propagateAnnColour = false;
5234 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5236 String annotationId = viewAnnColour.getAnnotation();
5237 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5240 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5242 if (matchedAnnotation == null
5243 && annAlignment.getAlignmentAnnotation() != null)
5245 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5248 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5250 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5255 if (matchedAnnotation == null)
5257 System.err.println("Failed to match annotation colour scheme for "
5261 // belt-and-braces create a threshold line if the
5262 // colourscheme needs one but the matchedAnnotation doesn't have one
5263 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5264 && matchedAnnotation.getThreshold() == null)
5266 matchedAnnotation.setThreshold(
5267 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5268 "Threshold", Color.black));
5271 AnnotationColourGradient cs = null;
5272 if (viewAnnColour.getColourScheme().equals("None"))
5274 cs = new AnnotationColourGradient(matchedAnnotation,
5275 new Color(safeInt(viewAnnColour.getMinColour())),
5276 new Color(safeInt(viewAnnColour.getMaxColour())),
5277 safeInt(viewAnnColour.getAboveThreshold()));
5279 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5281 cs = new AnnotationColourGradient(matchedAnnotation,
5282 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5283 safeInt(viewAnnColour.getAboveThreshold()));
5287 cs = new AnnotationColourGradient(matchedAnnotation,
5288 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5289 viewAnnColour.getColourScheme()),
5290 safeInt(viewAnnColour.getAboveThreshold()));
5293 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5294 boolean useOriginalColours = safeBoolean(
5295 viewAnnColour.isPredefinedColours());
5296 cs.setSeqAssociated(perSequenceOnly);
5297 cs.setPredefinedColours(useOriginalColours);
5299 if (propagateAnnColour && al.getGroups() != null)
5301 // Also use these settings for all the groups
5302 for (int g = 0; g < al.getGroups().size(); g++)
5304 SequenceGroup sg = al.getGroups().get(g);
5305 if (sg.getGroupColourScheme() == null)
5310 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5311 matchedAnnotation, sg.getColourScheme(),
5312 safeInt(viewAnnColour.getAboveThreshold()));
5313 sg.setColourScheme(groupScheme);
5314 groupScheme.setSeqAssociated(perSequenceOnly);
5315 groupScheme.setPredefinedColours(useOriginalColours);
5321 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5322 List<JvAnnotRow> autoAlan)
5324 // copy over visualization settings for autocalculated annotation in the
5326 if (al.getAlignmentAnnotation() != null)
5329 * Kludge for magic autoannotation names (see JAL-811)
5331 String[] magicNames = new String[] { "Consensus", "Quality",
5333 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5334 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5335 for (String nm : magicNames)
5337 visan.put(nm, nullAnnot);
5339 for (JvAnnotRow auan : autoAlan)
5341 visan.put(auan.template.label
5342 + (auan.template.getCalcId() == null ? ""
5343 : "\t" + auan.template.getCalcId()),
5346 int hSize = al.getAlignmentAnnotation().length;
5347 List<JvAnnotRow> reorder = new ArrayList<>();
5348 // work through any autoCalculated annotation already on the view
5349 // removing it if it should be placed in a different location on the
5350 // annotation panel.
5351 List<String> remains = new ArrayList<>(visan.keySet());
5352 for (int h = 0; h < hSize; h++)
5354 jalview.datamodel.AlignmentAnnotation jalan = al
5355 .getAlignmentAnnotation()[h];
5356 if (jalan.autoCalculated)
5359 JvAnnotRow valan = visan.get(k = jalan.label);
5360 if (jalan.getCalcId() != null)
5362 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5367 // delete the auto calculated row from the alignment
5368 al.deleteAnnotation(jalan, false);
5372 if (valan != nullAnnot)
5374 if (jalan != valan.template)
5376 // newly created autoannotation row instance
5377 // so keep a reference to the visible annotation row
5378 // and copy over all relevant attributes
5379 if (valan.template.graphHeight >= 0)
5382 jalan.graphHeight = valan.template.graphHeight;
5384 jalan.visible = valan.template.visible;
5386 reorder.add(new JvAnnotRow(valan.order, jalan));
5391 // Add any (possibly stale) autocalculated rows that were not appended to
5392 // the view during construction
5393 for (String other : remains)
5395 JvAnnotRow othera = visan.get(other);
5396 if (othera != nullAnnot && othera.template.getCalcId() != null
5397 && othera.template.getCalcId().length() > 0)
5399 reorder.add(othera);
5402 // now put the automatic annotation in its correct place
5403 int s = 0, srt[] = new int[reorder.size()];
5404 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5405 for (JvAnnotRow jvar : reorder)
5408 srt[s++] = jvar.order;
5411 jalview.util.QuickSort.sort(srt, rws);
5412 // and re-insert the annotation at its correct position
5413 for (JvAnnotRow jvar : rws)
5415 al.addAnnotation(jvar.template, jvar.order);
5417 af.alignPanel.adjustAnnotationHeight();
5421 Hashtable skipList = null;
5424 * TODO remove this method
5427 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5428 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5429 * throw new Error("Implementation Error. No skipList defined for this
5430 * Jalview2XML instance."); } return (AlignFrame)
5431 * skipList.get(view.getSequenceSetId()); }
5435 * Check if the Jalview view contained in object should be skipped or not.
5438 * @return true if view's sequenceSetId is a key in skipList
5440 private boolean skipViewport(JalviewModel object)
5442 if (skipList == null)
5446 String id = object.getViewport().get(0).getSequenceSetId();
5447 if (skipList.containsKey(id))
5449 Console.debug("Skipping seuqence set id " + id);
5455 public void addToSkipList(AlignFrame af)
5457 if (skipList == null)
5459 skipList = new Hashtable();
5461 skipList.put(af.getViewport().getSequenceSetId(), af);
5464 public void clearSkipList()
5466 if (skipList != null)
5473 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5474 boolean ignoreUnrefed, String uniqueSeqSetId)
5476 jalview.datamodel.AlignmentI ds = getDatasetFor(
5477 vamsasSet.getDatasetId());
5478 AlignmentI xtant_ds = ds;
5479 if (xtant_ds == null)
5481 // good chance we are about to create a new dataset, but check if we've
5482 // seen some of the dataset sequence IDs before.
5483 // TODO: skip this check if we are working with project generated by
5484 // version 2.11 or later
5485 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5486 if (xtant_ds != null)
5489 addDatasetRef(vamsasSet.getDatasetId(), ds);
5492 Vector<SequenceI> dseqs = null;
5495 // recovering an alignment View
5496 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5497 if (seqSetDS != null)
5499 if (ds != null && ds != seqSetDS)
5502 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5503 + " - CDS/Protein crossreference data may be lost");
5504 if (xtant_ds != null)
5506 // This can only happen if the unique sequence set ID was bound to a
5507 // dataset that did not contain any of the sequences in the view
5508 // currently being restored.
5510 "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.");
5514 addDatasetRef(vamsasSet.getDatasetId(), ds);
5519 // try even harder to restore dataset
5520 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5521 // create a list of new dataset sequences
5522 dseqs = new Vector<>();
5524 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5526 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5527 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5529 // create a new dataset
5532 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5533 dseqs.copyInto(dsseqs);
5534 ds = new jalview.datamodel.Alignment(dsseqs);
5535 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5536 + " for alignment " + System.identityHashCode(al));
5537 addDatasetRef(vamsasSet.getDatasetId(), ds);
5539 // set the dataset for the newly imported alignment.
5540 if (al.getDataset() == null && !ignoreUnrefed)
5543 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5544 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5546 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5550 * XML dataset sequence ID to materialised dataset reference
5552 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5555 * @return the first materialised dataset reference containing a dataset
5556 * sequence referenced in the given view
5558 * - sequences from the view
5560 AlignmentI checkIfHasDataset(List<Sequence> list)
5562 for (Sequence restoredSeq : list)
5564 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5565 if (datasetFor != null)
5574 * Register ds as the containing dataset for the dataset sequences referenced
5575 * by sequences in list
5578 * - sequences in a view
5581 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5583 for (Sequence restoredSeq : list)
5585 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5586 if (prevDS != null && prevDS != ds)
5588 Console.warn("Dataset sequence appears in many datasets: "
5589 + restoredSeq.getDsseqid());
5590 // TODO: try to merge!
5598 * sequence definition to create/merge dataset sequence for
5602 * vector to add new dataset sequence to
5603 * @param ignoreUnrefed
5604 * - when true, don't create new sequences from vamsasSeq if it's id
5605 * doesn't already have an asssociated Jalview sequence.
5607 * - used to reorder the sequence in the alignment according to the
5608 * vamsasSeq array ordering, to preserve ordering of dataset
5610 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5611 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5614 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5616 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5617 boolean reorder = false;
5618 SequenceI dsq = null;
5619 if (sq != null && sq.getDatasetSequence() != null)
5621 dsq = sq.getDatasetSequence();
5627 if (sq == null && ignoreUnrefed)
5631 String sqid = vamsasSeq.getDsseqid();
5634 // need to create or add a new dataset sequence reference to this sequence
5637 dsq = seqRefIds.get(sqid);
5642 // make a new dataset sequence
5643 dsq = sq.createDatasetSequence();
5646 // make up a new dataset reference for this sequence
5647 sqid = seqHash(dsq);
5649 dsq.setVamsasId(uniqueSetSuffix + sqid);
5650 seqRefIds.put(sqid, dsq);
5655 dseqs.addElement(dsq);
5660 ds.addSequence(dsq);
5666 { // make this dataset sequence sq's dataset sequence
5667 sq.setDatasetSequence(dsq);
5668 // and update the current dataset alignment
5673 if (!dseqs.contains(dsq))
5680 if (ds.findIndex(dsq) < 0)
5682 ds.addSequence(dsq);
5689 // TODO: refactor this as a merge dataset sequence function
5690 // now check that sq (the dataset sequence) sequence really is the union of
5691 // all references to it
5692 // boolean pre = sq.getStart() < dsq.getStart();
5693 // boolean post = sq.getEnd() > dsq.getEnd();
5697 // StringBuffer sb = new StringBuffer();
5698 String newres = jalview.analysis.AlignSeq.extractGaps(
5699 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5700 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5701 && newres.length() > dsq.getLength())
5703 // Update with the longer sequence.
5707 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5708 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5709 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5710 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5712 dsq.setSequence(newres);
5714 // TODO: merges will never happen if we 'know' we have the real dataset
5715 // sequence - this should be detected when id==dssid
5717 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5718 // + (pre ? "prepended" : "") + " "
5719 // + (post ? "appended" : ""));
5724 // sequence refs are identical. We may need to update the existing dataset
5725 // alignment with this one, though.
5726 if (ds != null && dseqs == null)
5728 int opos = ds.findIndex(dsq);
5729 SequenceI tseq = null;
5730 if (opos != -1 && vseqpos != opos)
5732 // remove from old position
5733 ds.deleteSequence(dsq);
5735 if (vseqpos < ds.getHeight())
5737 if (vseqpos != opos)
5739 // save sequence at destination position
5740 tseq = ds.getSequenceAt(vseqpos);
5741 ds.replaceSequenceAt(vseqpos, dsq);
5742 ds.addSequence(tseq);
5747 ds.addSequence(dsq);
5754 * TODO use AlignmentI here and in related methods - needs
5755 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5757 Hashtable<String, AlignmentI> datasetIds = null;
5759 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5761 private AlignmentI getDatasetFor(String datasetId)
5763 if (datasetIds == null)
5765 datasetIds = new Hashtable<>();
5768 if (datasetIds.containsKey(datasetId))
5770 return datasetIds.get(datasetId);
5775 private void addDatasetRef(String datasetId, AlignmentI dataset)
5777 if (datasetIds == null)
5779 datasetIds = new Hashtable<>();
5781 datasetIds.put(datasetId, dataset);
5785 * make a new dataset ID for this jalview dataset alignment
5790 private String getDatasetIdRef(AlignmentI dataset)
5792 if (dataset.getDataset() != null)
5795 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5797 String datasetId = makeHashCode(dataset, null);
5798 if (datasetId == null)
5800 // make a new datasetId and record it
5801 if (dataset2Ids == null)
5803 dataset2Ids = new IdentityHashMap<>();
5807 datasetId = dataset2Ids.get(dataset);
5809 if (datasetId == null)
5811 datasetId = "ds" + dataset2Ids.size() + 1;
5812 dataset2Ids.put(dataset, datasetId);
5819 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5820 * constructed as a special subclass GeneLocus.
5822 * @param datasetSequence
5825 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5827 for (int d = 0; d < sequence.getDBRef().size(); d++)
5829 DBRef dr = sequence.getDBRef().get(d);
5833 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5834 dr.getAccessionId());
5838 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5839 dr.getAccessionId());
5841 if (dr.getMapping() != null)
5843 entry.setMap(addMapping(dr.getMapping()));
5845 entry.setCanonical(dr.isCanonical());
5846 datasetSequence.addDBRef(entry);
5850 private jalview.datamodel.Mapping addMapping(Mapping m)
5852 SequenceI dsto = null;
5853 // Mapping m = dr.getMapping();
5854 int fr[] = new int[m.getMapListFrom().size() * 2];
5855 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5856 for (int _i = 0; from.hasNext(); _i += 2)
5858 MapListFrom mf = from.next();
5859 fr[_i] = mf.getStart();
5860 fr[_i + 1] = mf.getEnd();
5862 int fto[] = new int[m.getMapListTo().size() * 2];
5863 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5864 for (int _i = 0; to.hasNext(); _i += 2)
5866 MapListTo mf = to.next();
5867 fto[_i] = mf.getStart();
5868 fto[_i + 1] = mf.getEnd();
5870 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5871 fto, m.getMapFromUnit().intValue(),
5872 m.getMapToUnit().intValue());
5875 * (optional) choice of dseqFor or Sequence
5877 if (m.getDseqFor() != null)
5879 String dsfor = m.getDseqFor();
5880 if (seqRefIds.containsKey(dsfor))
5885 jmap.setTo(seqRefIds.get(dsfor));
5889 frefedSequence.add(newMappingRef(dsfor, jmap));
5892 else if (m.getSequence() != null)
5895 * local sequence definition
5897 Sequence ms = m.getSequence();
5898 SequenceI djs = null;
5899 String sqid = ms.getDsseqid();
5900 if (sqid != null && sqid.length() > 0)
5903 * recover dataset sequence
5905 djs = seqRefIds.get(sqid);
5910 "Warning - making up dataset sequence id for DbRef sequence map reference");
5911 sqid = ((Object) ms).toString(); // make up a new hascode for
5912 // undefined dataset sequence hash
5913 // (unlikely to happen)
5919 * make a new dataset sequence and add it to refIds hash
5921 djs = new jalview.datamodel.Sequence(ms.getName(),
5923 djs.setStart(jmap.getMap().getToLowest());
5924 djs.setEnd(jmap.getMap().getToHighest());
5925 djs.setVamsasId(uniqueSetSuffix + sqid);
5927 incompleteSeqs.put(sqid, djs);
5928 seqRefIds.put(sqid, djs);
5931 Console.debug("about to recurse on addDBRefs.");
5940 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5941 * view as XML (but not to file), and then reloading it
5946 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5949 JalviewModel jm = saveState(ap, null, null, null);
5952 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5953 ap.getAlignment().getDataset());
5955 uniqueSetSuffix = "";
5956 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5957 jm.getViewport().get(0).setId(null);
5958 // we don't overwrite the view we just copied
5960 if (this.frefedSequence == null)
5962 frefedSequence = new Vector<>();
5965 viewportsAdded.clear();
5967 AlignFrame af = loadFromObject(jm, null, false, null);
5968 af.getAlignPanels().clear();
5969 af.closeMenuItem_actionPerformed(true);
5972 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5973 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5974 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5975 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5976 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5979 return af.alignPanel;
5982 private Hashtable jvids2vobj;
5985 * set the object to ID mapping tables used to write/recover objects and XML
5986 * ID strings for the jalview project. If external tables are provided then
5987 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5988 * object goes out of scope. - also populates the datasetIds hashtable with
5989 * alignment objects containing dataset sequences
5992 * Map from ID strings to jalview datamodel
5994 * Map from jalview datamodel to ID strings
5998 public void setObjectMappingTables(Hashtable vobj2jv,
5999 IdentityHashMap jv2vobj)
6001 this.jv2vobj = jv2vobj;
6002 this.vobj2jv = vobj2jv;
6003 Iterator ds = jv2vobj.keySet().iterator();
6005 while (ds.hasNext())
6007 Object jvobj = ds.next();
6008 id = jv2vobj.get(jvobj).toString();
6009 if (jvobj instanceof jalview.datamodel.Alignment)
6011 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6013 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6016 else if (jvobj instanceof jalview.datamodel.Sequence)
6018 // register sequence object so the XML parser can recover it.
6019 if (seqRefIds == null)
6021 seqRefIds = new HashMap<>();
6023 if (seqsToIds == null)
6025 seqsToIds = new IdentityHashMap<>();
6027 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6028 seqsToIds.put((SequenceI) jvobj, id);
6030 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6033 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6034 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6035 if (jvann.annotationId == null)
6037 jvann.annotationId = anid;
6039 if (!jvann.annotationId.equals(anid))
6041 // TODO verify that this is the correct behaviour
6042 Console.warn("Overriding Annotation ID for " + anid
6043 + " from different id : " + jvann.annotationId);
6044 jvann.annotationId = anid;
6047 else if (jvobj instanceof String)
6049 if (jvids2vobj == null)
6051 jvids2vobj = new Hashtable();
6052 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6057 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6063 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6064 * objects created from the project archive. If string is null (default for
6065 * construction) then suffix will be set automatically.
6069 public void setUniqueSetSuffix(String string)
6071 uniqueSetSuffix = string;
6076 * uses skipList2 as the skipList for skipping views on sequence sets
6077 * associated with keys in the skipList
6081 public void setSkipList(Hashtable skipList2)
6083 skipList = skipList2;
6087 * Reads the jar entry of given name and returns its contents, or null if the
6088 * entry is not found.
6091 * @param jarEntryName
6094 protected String readJarEntry(jarInputStreamProvider jprovider,
6095 String jarEntryName)
6097 String result = null;
6098 BufferedReader in = null;
6103 * Reopen the jar input stream and traverse its entries to find a matching
6106 JarInputStream jin = jprovider.getJarInputStream();
6107 JarEntry entry = null;
6110 entry = jin.getNextJarEntry();
6111 } while (entry != null && !entry.getName().equals(jarEntryName));
6115 StringBuilder out = new StringBuilder(256);
6116 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6119 while ((data = in.readLine()) != null)
6123 result = out.toString();
6128 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6130 } catch (Exception ex)
6132 ex.printStackTrace();
6140 } catch (IOException e)
6151 * Returns an incrementing counter (0, 1, 2...)
6155 private synchronized int nextCounter()
6161 * Loads any saved PCA viewers
6166 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6170 List<PcaViewer> pcaviewers = model.getPcaViewer();
6171 for (PcaViewer viewer : pcaviewers)
6173 String modelName = viewer.getScoreModelName();
6174 SimilarityParamsI params = new SimilarityParams(
6175 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6176 viewer.isIncludeGaps(),
6177 viewer.isDenominateByShortestLength());
6180 * create the panel (without computing the PCA)
6182 PCAPanel panel = new PCAPanel(ap, modelName, params);
6184 panel.setTitle(viewer.getTitle());
6185 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6186 viewer.getWidth(), viewer.getHeight()));
6188 boolean showLabels = viewer.isShowLabels();
6189 panel.setShowLabels(showLabels);
6190 panel.getRotatableCanvas().setShowLabels(showLabels);
6191 panel.getRotatableCanvas()
6192 .setBgColour(new Color(viewer.getBgColour()));
6193 panel.getRotatableCanvas()
6194 .setApplyToAllViews(viewer.isLinkToAllViews());
6197 * load PCA output data
6199 ScoreModelI scoreModel = ScoreModels.getInstance()
6200 .getScoreModel(modelName, ap);
6201 PCA pca = new PCA(null, scoreModel, params);
6202 PcaDataType pcaData = viewer.getPcaData();
6204 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6205 pca.setPairwiseScores(pairwise);
6207 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6208 pca.setTridiagonal(triDiag);
6210 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6211 pca.setEigenmatrix(result);
6213 panel.getPcaModel().setPCA(pca);
6216 * we haven't saved the input data! (JAL-2647 to do)
6218 panel.setInputData(null);
6221 * add the sequence points for the PCA display
6223 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6224 for (SequencePoint sp : viewer.getSequencePoint())
6226 String seqId = sp.getSequenceRef();
6227 SequenceI seq = seqRefIds.get(seqId);
6230 throw new IllegalStateException(
6231 "Unmatched seqref for PCA: " + seqId);
6233 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6234 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6236 seqPoints.add(seqPoint);
6238 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6241 * set min-max ranges and scale after setPoints (which recomputes them)
6243 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6244 SeqPointMin spMin = viewer.getSeqPointMin();
6245 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6247 SeqPointMax spMax = viewer.getSeqPointMax();
6248 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6250 panel.getRotatableCanvas().setSeqMinMax(min, max);
6252 // todo: hold points list in PCAModel only
6253 panel.getPcaModel().setSequencePoints(seqPoints);
6255 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6256 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6257 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6259 // is this duplication needed?
6260 panel.setTop(seqPoints.size() - 1);
6261 panel.getPcaModel().setTop(seqPoints.size() - 1);
6264 * add the axes' end points for the display
6266 for (int i = 0; i < 3; i++)
6268 Axis axis = viewer.getAxis().get(i);
6269 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6270 axis.getXPos(), axis.getYPos(), axis.getZPos());
6273 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6274 "label.calc_title", "PCA", modelName), 475, 450);
6276 } catch (Exception ex)
6278 Console.error("Error loading PCA: " + ex.toString());
6283 * Creates a new structure viewer window
6290 protected void createStructureViewer(ViewerType viewerType,
6291 final Entry<String, StructureViewerModel> viewerData,
6292 AlignFrame af, jarInputStreamProvider jprovider)
6294 final StructureViewerModel viewerModel = viewerData.getValue();
6295 String sessionFilePath = null;
6297 if (viewerType == ViewerType.JMOL)
6299 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6303 String viewerJarEntryName = getViewerJarEntryName(
6304 viewerModel.getViewId());
6305 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6306 "viewerSession", ".tmp");
6308 final String sessionPath = sessionFilePath;
6309 final String sviewid = viewerData.getKey();
6312 SwingUtilities.invokeAndWait(new Runnable()
6317 JalviewStructureDisplayI sview = null;
6320 sview = StructureViewer.createView(viewerType, af.alignPanel,
6321 viewerModel, sessionPath, sviewid);
6322 addNewStructureViewer(sview);
6323 } catch (OutOfMemoryError ex)
6325 new OOMWarning("Restoring structure view for " + viewerType,
6326 (OutOfMemoryError) ex.getCause());
6327 if (sview != null && sview.isVisible())
6329 sview.closeViewer(false);
6330 sview.setVisible(false);
6336 } catch (InvocationTargetException | InterruptedException ex)
6338 Console.warn("Unexpected error when opening " + viewerType
6339 + " structure viewer", ex);
6344 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6345 * the path of the file. "load file" commands are rewritten to change the
6346 * original PDB file names to those created as the Jalview project is loaded.
6352 private String rewriteJmolSession(StructureViewerModel svattrib,
6353 jarInputStreamProvider jprovider)
6355 String state = svattrib.getStateData(); // Jalview < 2.9
6356 if (state == null || state.isEmpty()) // Jalview >= 2.9
6358 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6359 state = readJarEntry(jprovider, jarEntryName);
6361 // TODO or simpler? for each key in oldFiles,
6362 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6363 // (allowing for different path escapings)
6364 StringBuilder rewritten = new StringBuilder(state.length());
6365 int cp = 0, ncp, ecp;
6366 Map<File, StructureData> oldFiles = svattrib.getFileData();
6367 while ((ncp = state.indexOf("load ", cp)) > -1)
6371 // look for next filename in load statement
6372 rewritten.append(state.substring(cp,
6373 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6374 String oldfilenam = state.substring(ncp,
6375 ecp = state.indexOf("\"", ncp));
6376 // recover the new mapping data for this old filename
6377 // have to normalize filename - since Jmol and jalview do
6378 // filename translation differently.
6379 StructureData filedat = oldFiles.get(new File(oldfilenam));
6380 if (filedat == null)
6382 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6383 filedat = oldFiles.get(new File(reformatedOldFilename));
6385 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6386 rewritten.append("\"");
6387 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6388 // look for next file statement.
6389 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6393 // just append rest of state
6394 rewritten.append(state.substring(cp));
6398 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6399 rewritten = new StringBuilder(state);
6400 rewritten.append("; load append ");
6401 for (File id : oldFiles.keySet())
6403 // add pdb files that should be present in the viewer
6404 StructureData filedat = oldFiles.get(id);
6405 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6407 rewritten.append(";");
6410 if (rewritten.length() == 0)
6414 final String history = "history = ";
6415 int historyIndex = rewritten.indexOf(history);
6416 if (historyIndex > -1)
6419 * change "history = [true|false];" to "history = [1|0];"
6421 historyIndex += history.length();
6422 String val = rewritten.substring(historyIndex, historyIndex + 5);
6423 if (val.startsWith("true"))
6425 rewritten.replace(historyIndex, historyIndex + 4, "1");
6427 else if (val.startsWith("false"))
6429 rewritten.replace(historyIndex, historyIndex + 5, "0");
6435 File tmp = File.createTempFile("viewerSession", ".tmp");
6436 try (OutputStream os = new FileOutputStream(tmp))
6438 InputStream is = new ByteArrayInputStream(
6439 rewritten.toString().getBytes());
6441 return tmp.getAbsolutePath();
6443 } catch (IOException e)
6445 Console.error("Error restoring Jmol session: " + e.toString());
6451 * Populates an XML model of the feature colour scheme for one feature type
6453 * @param featureType
6457 public static Colour marshalColour(String featureType,
6458 FeatureColourI fcol)
6460 Colour col = new Colour();
6461 if (fcol.isSimpleColour())
6463 col.setRGB(Format.getHexString(fcol.getColour()));
6467 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6468 col.setMin(fcol.getMin());
6469 col.setMax(fcol.getMax());
6470 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6471 col.setAutoScale(fcol.isAutoScaled());
6472 col.setThreshold(fcol.getThreshold());
6473 col.setColourByLabel(fcol.isColourByLabel());
6474 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6475 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6476 : ThresholdType.NONE));
6477 if (fcol.isColourByAttribute())
6479 final String[] attName = fcol.getAttributeName();
6480 col.getAttributeName().add(attName[0]);
6481 if (attName.length > 1)
6483 col.getAttributeName().add(attName[1]);
6486 Color noColour = fcol.getNoColour();
6487 if (noColour == null)
6489 col.setNoValueColour(NoValueColour.NONE);
6491 else if (noColour == fcol.getMaxColour())
6493 col.setNoValueColour(NoValueColour.MAX);
6497 col.setNoValueColour(NoValueColour.MIN);
6500 col.setName(featureType);
6505 * Populates an XML model of the feature filter(s) for one feature type
6507 * @param firstMatcher
6508 * the first (or only) match condition)
6510 * remaining match conditions (if any)
6512 * if true, conditions are and-ed, else or-ed
6514 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6515 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6518 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6520 if (filters.hasNext())
6525 CompoundMatcher compound = new CompoundMatcher();
6526 compound.setAnd(and);
6527 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6528 firstMatcher, Collections.emptyIterator(), and);
6529 // compound.addMatcherSet(matcher1);
6530 compound.getMatcherSet().add(matcher1);
6531 FeatureMatcherI nextMatcher = filters.next();
6532 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6533 nextMatcher, filters, and);
6534 // compound.addMatcherSet(matcher2);
6535 compound.getMatcherSet().add(matcher2);
6536 result.setCompoundMatcher(compound);
6541 * single condition matcher
6543 // MatchCondition matcherModel = new MatchCondition();
6544 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6545 matcherModel.setCondition(
6546 firstMatcher.getMatcher().getCondition().getStableName());
6547 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6548 if (firstMatcher.isByAttribute())
6550 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6551 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6552 String[] attName = firstMatcher.getAttribute();
6553 matcherModel.getAttributeName().add(attName[0]); // attribute
6554 if (attName.length > 1)
6556 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6559 else if (firstMatcher.isByLabel())
6561 matcherModel.setBy(FilterBy.BY_LABEL);
6563 else if (firstMatcher.isByScore())
6565 matcherModel.setBy(FilterBy.BY_SCORE);
6567 result.setMatchCondition(matcherModel);
6574 * Loads one XML model of a feature filter to a Jalview object
6576 * @param featureType
6577 * @param matcherSetModel
6580 public static FeatureMatcherSetI parseFilter(String featureType,
6581 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6583 FeatureMatcherSetI result = new FeatureMatcherSet();
6586 parseFilterConditions(result, matcherSetModel, true);
6587 } catch (IllegalStateException e)
6589 // mixing AND and OR conditions perhaps
6591 String.format("Error reading filter conditions for '%s': %s",
6592 featureType, e.getMessage()));
6593 // return as much as was parsed up to the error
6600 * Adds feature match conditions to matcherSet as unmarshalled from XML
6601 * (possibly recursively for compound conditions)
6604 * @param matcherSetModel
6606 * if true, multiple conditions are AND-ed, else they are OR-ed
6607 * @throws IllegalStateException
6608 * if AND and OR conditions are mixed
6610 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6611 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6614 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6615 .getMatchCondition();
6621 FilterBy filterBy = mc.getBy();
6622 Condition cond = Condition.fromString(mc.getCondition());
6623 String pattern = mc.getValue();
6624 FeatureMatcherI matchCondition = null;
6625 if (filterBy == FilterBy.BY_LABEL)
6627 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6629 else if (filterBy == FilterBy.BY_SCORE)
6631 matchCondition = FeatureMatcher.byScore(cond, pattern);
6634 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6636 final List<String> attributeName = mc.getAttributeName();
6637 String[] attNames = attributeName
6638 .toArray(new String[attributeName.size()]);
6639 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6644 * note this throws IllegalStateException if AND-ing to a
6645 * previously OR-ed compound condition, or vice versa
6649 matcherSet.and(matchCondition);
6653 matcherSet.or(matchCondition);
6659 * compound condition
6661 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6662 .getCompoundMatcher().getMatcherSet();
6663 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6664 if (matchers.size() == 2)
6666 parseFilterConditions(matcherSet, matchers.get(0), anded);
6667 parseFilterConditions(matcherSet, matchers.get(1), anded);
6671 System.err.println("Malformed compound filter condition");
6677 * Loads one XML model of a feature colour to a Jalview object
6679 * @param colourModel
6682 public static FeatureColourI parseColour(Colour colourModel)
6684 FeatureColourI colour = null;
6686 if (colourModel.getMax() != null)
6688 Color mincol = null;
6689 Color maxcol = null;
6690 Color noValueColour = null;
6694 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6695 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6696 } catch (Exception e)
6698 Console.warn("Couldn't parse out graduated feature color.", e);
6701 NoValueColour noCol = colourModel.getNoValueColour();
6702 if (noCol == NoValueColour.MIN)
6704 noValueColour = mincol;
6706 else if (noCol == NoValueColour.MAX)
6708 noValueColour = maxcol;
6711 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6712 safeFloat(colourModel.getMin()),
6713 safeFloat(colourModel.getMax()));
6714 final List<String> attributeName = colourModel.getAttributeName();
6715 String[] attributes = attributeName
6716 .toArray(new String[attributeName.size()]);
6717 if (attributes != null && attributes.length > 0)
6719 colour.setAttributeName(attributes);
6721 if (colourModel.isAutoScale() != null)
6723 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6725 if (colourModel.isColourByLabel() != null)
6727 colour.setColourByLabel(
6728 colourModel.isColourByLabel().booleanValue());
6730 if (colourModel.getThreshold() != null)
6732 colour.setThreshold(colourModel.getThreshold().floatValue());
6734 ThresholdType ttyp = colourModel.getThreshType();
6735 if (ttyp == ThresholdType.ABOVE)
6737 colour.setAboveThreshold(true);
6739 else if (ttyp == ThresholdType.BELOW)
6741 colour.setBelowThreshold(true);
6746 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6747 colour = new FeatureColour(color);
6753 public static void setStateSavedUpToDate(boolean s)
6755 Console.debug("Setting overall stateSavedUpToDate to " + s);
6756 stateSavedUpToDate = s;
6759 public static boolean stateSavedUpToDate()
6761 Console.debug("Returning overall stateSavedUpToDate value: "
6762 + stateSavedUpToDate);
6763 return stateSavedUpToDate;
6766 public static boolean allSavedUpToDate()
6768 if (stateSavedUpToDate()) // nothing happened since last project save
6771 AlignFrame[] frames = Desktop.getAlignFrames();
6774 for (int i = 0; i < frames.length; i++)
6776 if (frames[i] == null)
6778 if (!frames[i].getViewport().savedUpToDate())
6779 return false; // at least one alignment is not individually saved
6785 // used for debugging and tests
6786 private static int debugDelaySave = 20;
6788 public static void setDebugDelaySave(int n)