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());
1329 if (tp.isColumnWise())
1331 tree.setColumnWise(true);
1332 String annId = tp.getAssocAnnotation().annotationId;
1333 tree.setColumnReference(annId);
1335 // jms.addTree(tree);
1336 object.getTree().add(tree);
1346 if (!storeDS && Desktop.desktop != null)
1348 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1350 if (frame instanceof PCAPanel)
1352 PCAPanel panel = (PCAPanel) frame;
1353 if (panel.getAlignViewport().getAlignment() == jal)
1355 savePCA(panel, object);
1363 * store forward refs from an annotationRow to any groups
1365 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1368 for (SequenceI sq : jal.getSequences())
1370 // Store annotation on dataset sequences only
1371 AlignmentAnnotation[] aa = sq.getAnnotation();
1372 if (aa != null && aa.length > 0)
1374 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1381 if (jal.getAlignmentAnnotation() != null)
1383 // Store the annotation shown on the alignment.
1384 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1385 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1390 if (jal.getGroups() != null)
1392 JGroup[] groups = new JGroup[jal.getGroups().size()];
1394 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1396 JGroup jGroup = new JGroup();
1397 groups[++i] = jGroup;
1399 jGroup.setStart(sg.getStartRes());
1400 jGroup.setEnd(sg.getEndRes());
1401 jGroup.setName(sg.getName());
1402 if (groupRefs.containsKey(sg))
1404 // group has references so set its ID field
1405 jGroup.setId(groupRefs.get(sg));
1407 ColourSchemeI colourScheme = sg.getColourScheme();
1408 if (colourScheme != null)
1410 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1411 if (groupColourScheme.conservationApplied())
1413 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1415 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1417 jGroup.setColour(setUserColourScheme(colourScheme,
1418 userColours, object));
1422 jGroup.setColour(colourScheme.getSchemeName());
1425 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1427 jGroup.setColour("AnnotationColourGradient");
1428 jGroup.setAnnotationColours(constructAnnotationColours(
1429 (jalview.schemes.AnnotationColourGradient) colourScheme,
1430 userColours, object));
1432 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1435 setUserColourScheme(colourScheme, userColours, object));
1439 jGroup.setColour(colourScheme.getSchemeName());
1442 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1445 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1446 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1447 jGroup.setDisplayText(sg.getDisplayText());
1448 jGroup.setColourText(sg.getColourText());
1449 jGroup.setTextCol1(sg.textColour.getRGB());
1450 jGroup.setTextCol2(sg.textColour2.getRGB());
1451 jGroup.setTextColThreshold(sg.thresholdTextColour);
1452 jGroup.setShowUnconserved(sg.getShowNonconserved());
1453 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1454 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1455 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1456 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1457 for (SequenceI seq : sg.getSequences())
1459 // jGroup.addSeq(seqHash(seq));
1460 jGroup.getSeq().add(seqHash(seq));
1464 // jms.setJGroup(groups);
1466 for (JGroup grp : groups)
1468 object.getJGroup().add(grp);
1473 // /////////SAVE VIEWPORT
1474 Viewport view = new Viewport();
1475 view.setTitle(ap.alignFrame.getTitle());
1476 view.setSequenceSetId(
1477 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1478 view.setId(av.getViewId());
1479 if (av.getCodingComplement() != null)
1481 view.setComplementId(av.getCodingComplement().getViewId());
1483 view.setViewName(av.getViewName());
1484 view.setGatheredViews(av.isGatherViewsHere());
1486 Rectangle size = ap.av.getExplodedGeometry();
1487 Rectangle position = size;
1490 size = ap.alignFrame.getBounds();
1491 if (av.getCodingComplement() != null)
1493 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1501 view.setXpos(position.x);
1502 view.setYpos(position.y);
1504 view.setWidth(size.width);
1505 view.setHeight(size.height);
1507 view.setStartRes(vpRanges.getStartRes());
1508 view.setStartSeq(vpRanges.getStartSeq());
1510 OverviewPanel ov = ap.getOverviewPanel();
1513 Overview overview = new Overview();
1514 overview.setTitle(ov.getTitle());
1515 Rectangle bounds = ov.getFrameBounds();
1516 overview.setXpos(bounds.x);
1517 overview.setYpos(bounds.y);
1518 overview.setWidth(bounds.width);
1519 overview.setHeight(bounds.height);
1520 overview.setShowHidden(ov.isShowHiddenRegions());
1521 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1522 overview.setResidueColour(
1523 ov.getCanvas().getResidueColour().getRGB());
1524 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1525 view.setOverview(overview);
1527 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1529 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1530 userColours, object));
1533 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1535 AnnotationColourScheme ac = constructAnnotationColours(
1536 (jalview.schemes.AnnotationColourGradient) av
1537 .getGlobalColourScheme(),
1538 userColours, object);
1540 view.setAnnotationColours(ac);
1541 view.setBgColour("AnnotationColourGradient");
1545 view.setBgColour(ColourSchemeProperty
1546 .getColourName(av.getGlobalColourScheme()));
1549 ResidueShaderI vcs = av.getResidueShading();
1550 ColourSchemeI cs = av.getGlobalColourScheme();
1554 if (vcs.conservationApplied())
1556 view.setConsThreshold(vcs.getConservationInc());
1557 if (cs instanceof jalview.schemes.UserColourScheme)
1559 view.setBgColour(setUserColourScheme(cs, userColours, object));
1562 view.setPidThreshold(vcs.getThreshold());
1565 view.setConservationSelected(av.getConservationSelected());
1566 view.setPidSelected(av.getAbovePIDThreshold());
1567 view.setCharHeight(av.getCharHeight());
1568 view.setCharWidth(av.getCharWidth());
1569 final Font font = av.getFont();
1570 view.setFontName(font.getName());
1571 view.setFontSize(font.getSize());
1572 view.setFontStyle(font.getStyle());
1573 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1574 view.setRenderGaps(av.isRenderGaps());
1575 view.setShowAnnotation(av.isShowAnnotation());
1576 view.setShowBoxes(av.getShowBoxes());
1577 view.setShowColourText(av.getColourText());
1578 view.setShowFullId(av.getShowJVSuffix());
1579 view.setRightAlignIds(av.isRightAlignIds());
1580 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1581 view.setShowText(av.getShowText());
1582 view.setShowUnconserved(av.getShowUnconserved());
1583 view.setWrapAlignment(av.getWrapAlignment());
1584 view.setTextCol1(av.getTextColour().getRGB());
1585 view.setTextCol2(av.getTextColour2().getRGB());
1586 view.setTextColThreshold(av.getThresholdTextColour());
1587 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1588 view.setShowSequenceLogo(av.isShowSequenceLogo());
1589 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1590 view.setShowGroupConsensus(av.isShowGroupConsensus());
1591 view.setShowGroupConservation(av.isShowGroupConservation());
1592 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1593 view.setShowDbRefTooltip(av.isShowDBRefs());
1594 view.setFollowHighlight(av.isFollowHighlight());
1595 view.setFollowSelection(av.followSelection);
1596 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1597 view.setShowComplementFeatures(av.isShowComplementFeatures());
1598 view.setShowComplementFeaturesOnTop(
1599 av.isShowComplementFeaturesOnTop());
1600 if (av.getFeaturesDisplayed() != null)
1602 FeatureSettings fs = new FeatureSettings();
1604 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1605 .getFeatureRenderer();
1606 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1608 Vector<String> settingsAdded = new Vector<>();
1609 if (renderOrder != null)
1611 for (String featureType : renderOrder)
1613 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1614 setting.setType(featureType);
1617 * save any filter for the feature type
1619 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1622 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1624 FeatureMatcherI firstFilter = filters.next();
1625 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1626 filters, filter.isAnded()));
1630 * save colour scheme for the feature type
1632 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1633 if (!fcol.isSimpleColour())
1635 setting.setColour(fcol.getMaxColour().getRGB());
1636 setting.setMincolour(fcol.getMinColour().getRGB());
1637 setting.setMin(fcol.getMin());
1638 setting.setMax(fcol.getMax());
1639 setting.setColourByLabel(fcol.isColourByLabel());
1640 if (fcol.isColourByAttribute())
1642 String[] attName = fcol.getAttributeName();
1643 setting.getAttributeName().add(attName[0]);
1644 if (attName.length > 1)
1646 setting.getAttributeName().add(attName[1]);
1649 setting.setAutoScale(fcol.isAutoScaled());
1650 setting.setThreshold(fcol.getThreshold());
1651 Color noColour = fcol.getNoColour();
1652 if (noColour == null)
1654 setting.setNoValueColour(NoValueColour.NONE);
1656 else if (noColour.equals(fcol.getMaxColour()))
1658 setting.setNoValueColour(NoValueColour.MAX);
1662 setting.setNoValueColour(NoValueColour.MIN);
1664 // -1 = No threshold, 0 = Below, 1 = Above
1665 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1666 : (fcol.isBelowThreshold() ? 0 : -1));
1670 setting.setColour(fcol.getColour().getRGB());
1674 av.getFeaturesDisplayed().isVisible(featureType));
1675 float rorder = fr.getOrder(featureType);
1678 setting.setOrder(rorder);
1680 /// fs.addSetting(setting);
1681 fs.getSetting().add(setting);
1682 settingsAdded.addElement(featureType);
1686 // is groups actually supposed to be a map here ?
1687 Iterator<String> en = fr.getFeatureGroups().iterator();
1688 Vector<String> groupsAdded = new Vector<>();
1689 while (en.hasNext())
1691 String grp = en.next();
1692 if (groupsAdded.contains(grp))
1696 Group g = new Group();
1698 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1701 fs.getGroup().add(g);
1702 groupsAdded.addElement(grp);
1704 // jms.setFeatureSettings(fs);
1705 object.setFeatureSettings(fs);
1708 if (av.hasHiddenColumns())
1710 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1711 .getHiddenColumns();
1715 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1719 Iterator<int[]> hiddenRegions = hidden.iterator();
1720 while (hiddenRegions.hasNext())
1722 int[] region = hiddenRegions.next();
1723 HiddenColumns hc = new HiddenColumns();
1724 hc.setStart(region[0]);
1725 hc.setEnd(region[1]);
1726 // view.addHiddenColumns(hc);
1727 view.getHiddenColumns().add(hc);
1731 if (calcIdSet.size() > 0)
1733 for (String calcId : calcIdSet)
1735 if (calcId.trim().length() > 0)
1737 CalcIdParam cidp = createCalcIdParam(calcId, av);
1738 // Some calcIds have no parameters.
1741 // view.addCalcIdParam(cidp);
1742 view.getCalcIdParam().add(cidp);
1748 // jms.addViewport(view);
1749 object.getViewport().add(view);
1751 // object.setJalviewModelSequence(jms);
1752 // object.getVamsasModel().addSequenceSet(vamsasSet);
1753 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1755 if (jout != null && fileName != null)
1757 // We may not want to write the object to disk,
1758 // eg we can copy the alignViewport to a new view object
1759 // using save and then load
1762 fileName = fileName.replace('\\', '/');
1763 System.out.println("Writing jar entry " + fileName);
1764 JarEntry entry = new JarEntry(fileName);
1765 jout.putNextEntry(entry);
1766 PrintWriter pout = new PrintWriter(
1767 new OutputStreamWriter(jout, UTF_8));
1768 JAXBContext jaxbContext = JAXBContext
1769 .newInstance(JalviewModel.class);
1770 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1772 // output pretty printed
1773 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1774 jaxbMarshaller.marshal(
1775 new ObjectFactory().createJalviewModel(object), pout);
1777 // jaxbMarshaller.marshal(object, pout);
1778 // marshaller.marshal(object);
1781 } catch (Exception ex)
1783 // TODO: raise error in GUI if marshalling failed.
1784 System.err.println("Error writing Jalview project");
1785 ex.printStackTrace();
1792 * Writes PCA viewer attributes and computed values to an XML model object and
1793 * adds it to the JalviewModel. Any exceptions are reported by logging.
1795 protected void savePCA(PCAPanel panel, JalviewModel object)
1799 PcaViewer viewer = new PcaViewer();
1800 viewer.setHeight(panel.getHeight());
1801 viewer.setWidth(panel.getWidth());
1802 viewer.setXpos(panel.getX());
1803 viewer.setYpos(panel.getY());
1804 viewer.setTitle(panel.getTitle());
1805 PCAModel pcaModel = panel.getPcaModel();
1806 viewer.setScoreModelName(pcaModel.getScoreModelName());
1807 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1808 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1809 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1811 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1812 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1813 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1814 SeqPointMin spmin = new SeqPointMin();
1815 spmin.setXPos(spMin[0]);
1816 spmin.setYPos(spMin[1]);
1817 spmin.setZPos(spMin[2]);
1818 viewer.setSeqPointMin(spmin);
1819 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1820 SeqPointMax spmax = new SeqPointMax();
1821 spmax.setXPos(spMax[0]);
1822 spmax.setYPos(spMax[1]);
1823 spmax.setZPos(spMax[2]);
1824 viewer.setSeqPointMax(spmax);
1825 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1826 viewer.setLinkToAllViews(
1827 panel.getRotatableCanvas().isApplyToAllViews());
1828 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1829 viewer.setIncludeGaps(sp.includeGaps());
1830 viewer.setMatchGaps(sp.matchGaps());
1831 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1832 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1835 * sequence points on display
1837 for (jalview.datamodel.SequencePoint spt : pcaModel
1838 .getSequencePoints())
1840 SequencePoint point = new SequencePoint();
1841 point.setSequenceRef(seqHash(spt.getSequence()));
1842 point.setXPos(spt.coord.x);
1843 point.setYPos(spt.coord.y);
1844 point.setZPos(spt.coord.z);
1845 viewer.getSequencePoint().add(point);
1849 * (end points of) axes on display
1851 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1854 Axis axis = new Axis();
1858 viewer.getAxis().add(axis);
1862 * raw PCA data (note we are not restoring PCA inputs here -
1863 * alignment view, score model, similarity parameters)
1865 PcaDataType data = new PcaDataType();
1866 viewer.setPcaData(data);
1867 PCA pca = pcaModel.getPcaData();
1869 DoubleMatrix pm = new DoubleMatrix();
1870 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1871 data.setPairwiseMatrix(pm);
1873 DoubleMatrix tm = new DoubleMatrix();
1874 saveDoubleMatrix(pca.getTridiagonal(), tm);
1875 data.setTridiagonalMatrix(tm);
1877 DoubleMatrix eigenMatrix = new DoubleMatrix();
1878 data.setEigenMatrix(eigenMatrix);
1879 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1881 object.getPcaViewer().add(viewer);
1882 } catch (Throwable t)
1884 Console.error("Error saving PCA: " + t.getMessage());
1889 * Stores values from a matrix into an XML element, including (if present) the
1894 * @see #loadDoubleMatrix(DoubleMatrix)
1896 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1898 xmlMatrix.setRows(m.height());
1899 xmlMatrix.setColumns(m.width());
1900 for (int i = 0; i < m.height(); i++)
1902 DoubleVector row = new DoubleVector();
1903 for (int j = 0; j < m.width(); j++)
1905 row.getV().add(m.getValue(i, j));
1907 xmlMatrix.getRow().add(row);
1909 if (m.getD() != null)
1911 DoubleVector dVector = new DoubleVector();
1912 for (double d : m.getD())
1914 dVector.getV().add(d);
1916 xmlMatrix.setD(dVector);
1918 if (m.getE() != null)
1920 DoubleVector eVector = new DoubleVector();
1921 for (double e : m.getE())
1923 eVector.getV().add(e);
1925 xmlMatrix.setE(eVector);
1930 * Loads XML matrix data into a new Matrix object, including the D and/or E
1931 * vectors (if present)
1935 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1937 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1939 int rows = mData.getRows();
1940 double[][] vals = new double[rows][];
1942 for (int i = 0; i < rows; i++)
1944 List<Double> dVector = mData.getRow().get(i).getV();
1945 vals[i] = new double[dVector.size()];
1947 for (Double d : dVector)
1953 MatrixI m = new Matrix(vals);
1955 if (mData.getD() != null)
1957 List<Double> dVector = mData.getD().getV();
1958 double[] vec = new double[dVector.size()];
1960 for (Double d : dVector)
1966 if (mData.getE() != null)
1968 List<Double> dVector = mData.getE().getV();
1969 double[] vec = new double[dVector.size()];
1971 for (Double d : dVector)
1982 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1983 * for each viewer, with
1985 * <li>viewer geometry (position, size, split pane divider location)</li>
1986 * <li>index of the selected structure in the viewer (currently shows gapped
1988 * <li>the id of the annotation holding RNA secondary structure</li>
1989 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1991 * Varna viewer state is also written out (in native Varna XML) to separate
1992 * project jar entries. A separate entry is written for each RNA structure
1993 * displayed, with the naming convention
1995 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2003 * @param storeDataset
2005 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2006 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2007 boolean storeDataset)
2009 if (Desktop.desktop == null)
2013 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2014 for (int f = frames.length - 1; f > -1; f--)
2016 if (frames[f] instanceof AppVarna)
2018 AppVarna varna = (AppVarna) frames[f];
2020 * link the sequence to every viewer that is showing it and is linked to
2021 * its alignment panel
2023 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2025 String viewId = varna.getViewId();
2026 RnaViewer rna = new RnaViewer();
2027 rna.setViewId(viewId);
2028 rna.setTitle(varna.getTitle());
2029 rna.setXpos(varna.getX());
2030 rna.setYpos(varna.getY());
2031 rna.setWidth(varna.getWidth());
2032 rna.setHeight(varna.getHeight());
2033 rna.setDividerLocation(varna.getDividerLocation());
2034 rna.setSelectedRna(varna.getSelectedIndex());
2035 // jseq.addRnaViewer(rna);
2036 jseq.getRnaViewer().add(rna);
2039 * Store each Varna panel's state once in the project per sequence.
2040 * First time through only (storeDataset==false)
2042 // boolean storeSessions = false;
2043 // String sequenceViewId = viewId + seqsToIds.get(jds);
2044 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2046 // viewIds.add(sequenceViewId);
2047 // storeSessions = true;
2049 for (RnaModel model : varna.getModels())
2051 if (model.seq == jds)
2054 * VARNA saves each view (sequence or alignment secondary
2055 * structure, gapped or trimmed) as a separate XML file
2057 String jarEntryName = rnaSessions.get(model);
2058 if (jarEntryName == null)
2061 String varnaStateFile = varna.getStateInfo(model.rna);
2062 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2063 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2064 rnaSessions.put(model, jarEntryName);
2066 SecondaryStructure ss = new SecondaryStructure();
2067 String annotationId = varna.getAnnotation(jds).annotationId;
2068 ss.setAnnotationId(annotationId);
2069 ss.setViewerState(jarEntryName);
2070 ss.setGapped(model.gapped);
2071 ss.setTitle(model.title);
2072 // rna.addSecondaryStructure(ss);
2073 rna.getSecondaryStructure().add(ss);
2082 * Copy the contents of a file to a new entry added to the output jar
2086 * @param jarEntryName
2088 * additional identifying info to log to the console
2090 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2091 String jarEntryName, String msg)
2093 try (InputStream is = new FileInputStream(infilePath))
2095 File file = new File(infilePath);
2096 if (file.exists() && jout != null)
2099 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2100 jout.putNextEntry(new JarEntry(jarEntryName));
2103 // dis = new DataInputStream(new FileInputStream(file));
2104 // byte[] data = new byte[(int) file.length()];
2105 // dis.readFully(data);
2106 // writeJarEntry(jout, jarEntryName, data);
2108 } catch (Exception ex)
2110 ex.printStackTrace();
2115 * Copies input to output, in 4K buffers; handles any data (text or binary)
2119 * @throws IOException
2121 protected void copyAll(InputStream in, OutputStream out)
2124 byte[] buffer = new byte[4096];
2126 while ((bytesRead = in.read(buffer)) != -1)
2128 out.write(buffer, 0, bytesRead);
2133 * Save the state of a structure viewer
2138 * the archive XML element under which to save the state
2141 * @param matchedFile
2145 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2146 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2147 String matchedFile, StructureViewerBase viewFrame)
2149 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2152 * Look for any bindings for this viewer to the PDB file of interest
2153 * (including part matches excluding chain id)
2155 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2157 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2158 final String pdbId = pdbentry.getId();
2159 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2160 && entry.getId().toLowerCase(Locale.ROOT)
2161 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2164 * not interested in a binding to a different PDB entry here
2168 if (matchedFile == null)
2170 matchedFile = pdbentry.getFile();
2172 else if (!matchedFile.equals(pdbentry.getFile()))
2175 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2176 + pdbentry.getFile());
2180 // can get at it if the ID
2181 // match is ambiguous (e.g.
2184 for (int smap = 0; smap < viewFrame.getBinding()
2185 .getSequence()[peid].length; smap++)
2187 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2188 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2190 StructureState state = new StructureState();
2191 state.setVisible(true);
2192 state.setXpos(viewFrame.getX());
2193 state.setYpos(viewFrame.getY());
2194 state.setWidth(viewFrame.getWidth());
2195 state.setHeight(viewFrame.getHeight());
2196 final String viewId = viewFrame.getViewId();
2197 state.setViewId(viewId);
2198 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2199 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2200 state.setColourByJmol(viewFrame.isColouredByViewer());
2201 state.setType(viewFrame.getViewerType().toString());
2202 // pdb.addStructureState(state);
2203 pdb.getStructureState().add(state);
2211 * Populates the AnnotationColourScheme xml for save. This captures the
2212 * settings of the options in the 'Colour by Annotation' dialog.
2215 * @param userColours
2219 private AnnotationColourScheme constructAnnotationColours(
2220 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2223 AnnotationColourScheme ac = new AnnotationColourScheme();
2224 ac.setAboveThreshold(acg.getAboveThreshold());
2225 ac.setThreshold(acg.getAnnotationThreshold());
2226 // 2.10.2 save annotationId (unique) not annotation label
2227 ac.setAnnotation(acg.getAnnotation().annotationId);
2228 if (acg.getBaseColour() instanceof UserColourScheme)
2231 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2236 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2239 ac.setMaxColour(acg.getMaxColour().getRGB());
2240 ac.setMinColour(acg.getMinColour().getRGB());
2241 ac.setPerSequence(acg.isSeqAssociated());
2242 ac.setPredefinedColours(acg.isPredefinedColours());
2246 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2247 IdentityHashMap<SequenceGroup, String> groupRefs,
2248 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2249 SequenceSet vamsasSet)
2252 for (int i = 0; i < aa.length; i++)
2254 Annotation an = new Annotation();
2256 AlignmentAnnotation annotation = aa[i];
2257 if (annotation.annotationId != null)
2259 annotationIds.put(annotation.annotationId, annotation);
2262 an.setId(annotation.annotationId);
2264 an.setVisible(annotation.visible);
2266 an.setDescription(annotation.description);
2268 if (annotation.sequenceRef != null)
2270 // 2.9 JAL-1781 xref on sequence id rather than name
2271 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2273 if (annotation.groupRef != null)
2275 String groupIdr = groupRefs.get(annotation.groupRef);
2276 if (groupIdr == null)
2278 // make a locally unique String
2279 groupRefs.put(annotation.groupRef,
2280 groupIdr = ("" + System.currentTimeMillis()
2281 + annotation.groupRef.getName()
2282 + groupRefs.size()));
2284 an.setGroupRef(groupIdr.toString());
2287 // store all visualization attributes for annotation
2288 an.setGraphHeight(annotation.graphHeight);
2289 an.setCentreColLabels(annotation.centreColLabels);
2290 an.setScaleColLabels(annotation.scaleColLabel);
2291 an.setShowAllColLabels(annotation.showAllColLabels);
2292 an.setBelowAlignment(annotation.belowAlignment);
2294 if (annotation.graph > 0)
2297 an.setGraphType(annotation.graph);
2298 an.setGraphGroup(annotation.graphGroup);
2299 if (annotation.getThreshold() != null)
2301 ThresholdLine line = new ThresholdLine();
2302 line.setLabel(annotation.getThreshold().label);
2303 line.setValue(annotation.getThreshold().value);
2304 line.setColour(annotation.getThreshold().colour.getRGB());
2305 an.setThresholdLine(line);
2307 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2309 if (annotation.sequenceRef.getContactMaps() != null)
2311 ContactMatrixI cm = annotation.sequenceRef
2312 .getContactMatrixFor(annotation);
2315 MatrixType xmlmat = new MatrixType();
2316 xmlmat.setType(cm.getType());
2317 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2318 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2319 // consider using an opaque to/from -> allow instance to control
2320 // its representation ?
2321 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2324 for (BitSet gp : cm.getGroups())
2326 BigInteger val = new BigInteger(gp.toByteArray());
2327 xmlmat.getGroups().add(val.toString());
2332 // provenance object for tree ?
2333 xmlmat.getNewick().add(cm.getNewick());
2334 xmlmat.setTreeMethod(cm.getTreeMethod());
2336 if (cm.hasCutHeight())
2338 xmlmat.setCutHeight(cm.getCutHeight());
2341 // set/get properties
2342 an.getContactmatrix().add(xmlmat);
2352 an.setLabel(annotation.label);
2354 if (annotation == av.getAlignmentQualityAnnot()
2355 || annotation == av.getAlignmentConservationAnnotation()
2356 || annotation == av.getAlignmentConsensusAnnotation()
2357 || annotation.autoCalculated)
2359 // new way of indicating autocalculated annotation -
2360 an.setAutoCalculated(annotation.autoCalculated);
2362 if (annotation.hasScore())
2364 an.setScore(annotation.getScore());
2367 if (annotation.getCalcId() != null)
2369 calcIdSet.add(annotation.getCalcId());
2370 an.setCalcId(annotation.getCalcId());
2372 if (annotation.hasProperties())
2374 for (String pr : annotation.getProperties())
2376 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2378 prop.setValue(annotation.getProperty(pr));
2379 an.getProperty().add(prop);
2383 AnnotationElement ae;
2384 if (annotation.annotations != null)
2386 an.setScoreOnly(false);
2387 for (int a = 0; a < annotation.annotations.length; a++)
2389 if ((annotation == null) || (annotation.annotations[a] == null))
2394 ae = new AnnotationElement();
2395 if (annotation.annotations[a].description != null)
2397 ae.setDescription(annotation.annotations[a].description);
2399 if (annotation.annotations[a].displayCharacter != null)
2401 ae.setDisplayCharacter(
2402 annotation.annotations[a].displayCharacter);
2405 if (!Float.isNaN(annotation.annotations[a].value))
2407 ae.setValue(annotation.annotations[a].value);
2411 if (annotation.annotations[a].secondaryStructure > ' ')
2413 ae.setSecondaryStructure(
2414 annotation.annotations[a].secondaryStructure + "");
2417 if (annotation.annotations[a].colour != null
2418 && annotation.annotations[a].colour != java.awt.Color.black)
2420 ae.setColour(annotation.annotations[a].colour.getRGB());
2423 // an.addAnnotationElement(ae);
2424 an.getAnnotationElement().add(ae);
2425 if (annotation.autoCalculated)
2427 // only write one non-null entry into the annotation row -
2428 // sufficient to get the visualization attributes necessary to
2436 an.setScoreOnly(true);
2438 if (!storeDS || (storeDS && !annotation.autoCalculated))
2440 // skip autocalculated annotation - these are only provided for
2442 // vamsasSet.addAnnotation(an);
2443 vamsasSet.getAnnotation().add(an);
2449 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2451 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2452 if (settings != null)
2454 CalcIdParam vCalcIdParam = new CalcIdParam();
2455 vCalcIdParam.setCalcId(calcId);
2456 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2457 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2458 // generic URI allowing a third party to resolve another instance of the
2459 // service used for this calculation
2460 for (String url : settings.getServiceURLs())
2462 // vCalcIdParam.addServiceURL(urls);
2463 vCalcIdParam.getServiceURL().add(url);
2465 vCalcIdParam.setVersion("1.0");
2466 if (settings.getPreset() != null)
2468 WsParamSetI setting = settings.getPreset();
2469 vCalcIdParam.setName(setting.getName());
2470 vCalcIdParam.setDescription(setting.getDescription());
2474 vCalcIdParam.setName("");
2475 vCalcIdParam.setDescription("Last used parameters");
2477 // need to be able to recover 1) settings 2) user-defined presets or
2478 // recreate settings from preset 3) predefined settings provided by
2479 // service - or settings that can be transferred (or discarded)
2480 vCalcIdParam.setParameters(
2481 settings.getWsParamFile().replace("\n", "|\\n|"));
2482 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2483 // todo - decide if updateImmediately is needed for any projects.
2485 return vCalcIdParam;
2490 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2493 if (calcIdParam.getVersion().equals("1.0"))
2495 final String[] calcIds = calcIdParam.getServiceURL()
2496 .toArray(new String[0]);
2497 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2498 .getPreferredServiceFor(calcIds);
2499 if (service != null)
2501 WsParamSetI parmSet = null;
2504 parmSet = service.getParamStore().parseServiceParameterFile(
2505 calcIdParam.getName(), calcIdParam.getDescription(),
2507 calcIdParam.getParameters().replace("|\\n|", "\n"));
2508 } catch (IOException x)
2510 Console.warn("Couldn't parse parameter data for "
2511 + calcIdParam.getCalcId(), x);
2514 List<ArgumentI> argList = null;
2515 if (calcIdParam.getName().length() > 0)
2517 parmSet = service.getParamStore()
2518 .getPreset(calcIdParam.getName());
2519 if (parmSet != null)
2521 // TODO : check we have a good match with settings in AACon -
2522 // otherwise we'll need to create a new preset
2527 argList = parmSet.getArguments();
2530 AAConSettings settings = new AAConSettings(
2531 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2532 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2533 calcIdParam.isNeedsUpdate());
2539 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2543 throw new Error(MessageManager.formatMessage(
2544 "error.unsupported_version_calcIdparam", new Object[]
2545 { calcIdParam.toString() }));
2549 * External mapping between jalview objects and objects yielding a valid and
2550 * unique object ID string. This is null for normal Jalview project IO, but
2551 * non-null when a jalview project is being read or written as part of a
2554 IdentityHashMap jv2vobj = null;
2557 * Construct a unique ID for jvobj using either existing bindings or if none
2558 * exist, the result of the hashcode call for the object.
2561 * jalview data object
2562 * @return unique ID for referring to jvobj
2564 private String makeHashCode(Object jvobj, String altCode)
2566 if (jv2vobj != null)
2568 Object id = jv2vobj.get(jvobj);
2571 return id.toString();
2573 // check string ID mappings
2574 if (jvids2vobj != null && jvobj instanceof String)
2576 id = jvids2vobj.get(jvobj);
2580 return id.toString();
2582 // give up and warn that something has gone wrong
2584 "Cannot find ID for object in external mapping : " + jvobj);
2590 * return local jalview object mapped to ID, if it exists
2594 * @return null or object bound to idcode
2596 private Object retrieveExistingObj(String idcode)
2598 if (idcode != null && vobj2jv != null)
2600 return vobj2jv.get(idcode);
2606 * binding from ID strings from external mapping table to jalview data model
2609 private Hashtable vobj2jv;
2611 private Sequence createVamsasSequence(String id, SequenceI jds)
2613 return createVamsasSequence(true, id, jds, null);
2616 private Sequence createVamsasSequence(boolean recurse, String id,
2617 SequenceI jds, SequenceI parentseq)
2619 Sequence vamsasSeq = new Sequence();
2620 vamsasSeq.setId(id);
2621 vamsasSeq.setName(jds.getName());
2622 vamsasSeq.setSequence(jds.getSequenceAsString());
2623 vamsasSeq.setDescription(jds.getDescription());
2624 List<DBRefEntry> dbrefs = null;
2625 if (jds.getDatasetSequence() != null)
2627 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2631 // seqId==dsseqid so we can tell which sequences really are
2632 // dataset sequences only
2633 vamsasSeq.setDsseqid(id);
2634 dbrefs = jds.getDBRefs();
2635 if (parentseq == null)
2642 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2646 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2648 DBRef dbref = new DBRef();
2649 DBRefEntry ref = dbrefs.get(d);
2650 dbref.setSource(ref.getSource());
2651 dbref.setVersion(ref.getVersion());
2652 dbref.setAccessionId(ref.getAccessionId());
2653 dbref.setCanonical(ref.isCanonical());
2654 if (ref instanceof GeneLocus)
2656 dbref.setLocus(true);
2660 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2662 dbref.setMapping(mp);
2664 vamsasSeq.getDBRef().add(dbref);
2670 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2671 SequenceI parentseq, SequenceI jds, boolean recurse)
2674 if (jmp.getMap() != null)
2678 jalview.util.MapList mlst = jmp.getMap();
2679 List<int[]> r = mlst.getFromRanges();
2680 for (int[] range : r)
2682 MapListFrom mfrom = new MapListFrom();
2683 mfrom.setStart(range[0]);
2684 mfrom.setEnd(range[1]);
2685 // mp.addMapListFrom(mfrom);
2686 mp.getMapListFrom().add(mfrom);
2688 r = mlst.getToRanges();
2689 for (int[] range : r)
2691 MapListTo mto = new MapListTo();
2692 mto.setStart(range[0]);
2693 mto.setEnd(range[1]);
2694 // mp.addMapListTo(mto);
2695 mp.getMapListTo().add(mto);
2697 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2698 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2699 if (jmp.getTo() != null)
2701 // MappingChoice mpc = new MappingChoice();
2703 // check/create ID for the sequence referenced by getTo()
2706 SequenceI ps = null;
2707 if (parentseq != jmp.getTo()
2708 && parentseq.getDatasetSequence() != jmp.getTo())
2710 // chaining dbref rather than a handshaking one
2711 jmpid = seqHash(ps = jmp.getTo());
2715 jmpid = seqHash(ps = parentseq);
2717 // mpc.setDseqFor(jmpid);
2718 mp.setDseqFor(jmpid);
2719 if (!seqRefIds.containsKey(jmpid))
2721 Console.debug("creatign new DseqFor ID");
2722 seqRefIds.put(jmpid, ps);
2726 Console.debug("reusing DseqFor ID");
2729 // mp.setMappingChoice(mpc);
2735 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2736 List<UserColourScheme> userColours, JalviewModel jm)
2739 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2740 boolean newucs = false;
2741 if (!userColours.contains(ucs))
2743 userColours.add(ucs);
2746 id = "ucs" + userColours.indexOf(ucs);
2749 // actually create the scheme's entry in the XML model
2750 java.awt.Color[] colours = ucs.getColours();
2751 UserColours uc = new UserColours();
2752 // UserColourScheme jbucs = new UserColourScheme();
2753 JalviewUserColours jbucs = new JalviewUserColours();
2755 for (int i = 0; i < colours.length; i++)
2757 Colour col = new Colour();
2758 col.setName(ResidueProperties.aa[i]);
2759 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2760 // jbucs.addColour(col);
2761 jbucs.getColour().add(col);
2763 if (ucs.getLowerCaseColours() != null)
2765 colours = ucs.getLowerCaseColours();
2766 for (int i = 0; i < colours.length; i++)
2768 Colour col = new Colour();
2769 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2770 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2771 // jbucs.addColour(col);
2772 jbucs.getColour().add(col);
2777 uc.setUserColourScheme(jbucs);
2778 // jm.addUserColours(uc);
2779 jm.getUserColours().add(uc);
2785 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2788 List<UserColours> uc = jm.getUserColours();
2789 UserColours colours = null;
2791 for (int i = 0; i < uc.length; i++)
2793 if (uc[i].getId().equals(id))
2800 for (UserColours c : uc)
2802 if (c.getId().equals(id))
2809 java.awt.Color[] newColours = new java.awt.Color[24];
2811 for (int i = 0; i < 24; i++)
2813 newColours[i] = new java.awt.Color(Integer.parseInt(
2814 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2815 colours.getUserColourScheme().getColour().get(i).getRGB(),
2819 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2822 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2824 newColours = new java.awt.Color[23];
2825 for (int i = 0; i < 23; i++)
2827 newColours[i] = new java.awt.Color(
2828 Integer.parseInt(colours.getUserColourScheme().getColour()
2829 .get(i + 24).getRGB(), 16));
2831 ucs.setLowerCaseColours(newColours);
2838 * contains last error message (if any) encountered by XML loader.
2840 String errorMessage = null;
2843 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2844 * exceptions are raised during project XML parsing
2846 public boolean attemptversion1parse = false;
2849 * Load a jalview project archive from a jar file
2852 * - HTTP URL or filename
2854 public AlignFrame loadJalviewAlign(final Object file)
2857 jalview.gui.AlignFrame af = null;
2861 // create list to store references for any new Jmol viewers created
2862 newStructureViewers = new Vector<>();
2863 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2864 // Workaround is to make sure caller implements the JarInputStreamProvider
2866 // so we can re-open the jar input stream for each entry.
2868 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2869 af = loadJalviewAlign(jprovider);
2872 af.setMenusForViewport();
2874 } catch (MalformedURLException e)
2876 errorMessage = "Invalid URL format for '" + file + "'";
2882 SwingUtilities.invokeAndWait(new Runnable()
2887 setLoadingFinishedForNewStructureViewers();
2890 } catch (Exception x)
2892 System.err.println("Error loading alignment: " + x.getMessage());
2898 @SuppressWarnings("unused")
2899 private jarInputStreamProvider createjarInputStreamProvider(
2900 final Object ofile) throws MalformedURLException
2903 // BH 2018 allow for bytes already attached to File object
2906 String file = (ofile instanceof File
2907 ? ((File) ofile).getCanonicalPath()
2908 : ofile.toString());
2909 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2912 errorMessage = null;
2913 uniqueSetSuffix = null;
2915 viewportsAdded.clear();
2916 frefedSequence = null;
2918 if (HttpUtils.startsWithHttpOrHttps(file))
2920 url = new URL(file);
2922 final URL _url = url;
2923 return new jarInputStreamProvider()
2927 public JarInputStream getJarInputStream() throws IOException
2931 // System.out.println("Jalview2XML: opening byte jarInputStream for
2932 // bytes.length=" + bytes.length);
2933 return new JarInputStream(new ByteArrayInputStream(bytes));
2937 // System.out.println("Jalview2XML: opening url jarInputStream for "
2939 return new JarInputStream(_url.openStream());
2943 // System.out.println("Jalview2XML: opening file jarInputStream for
2945 return new JarInputStream(new FileInputStream(file));
2950 public String getFilename()
2955 } catch (IOException e)
2957 e.printStackTrace();
2963 * Recover jalview session from a jalview project archive. Caller may
2964 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2965 * themselves. Any null fields will be initialised with default values,
2966 * non-null fields are left alone.
2971 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2973 errorMessage = null;
2974 if (uniqueSetSuffix == null)
2976 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2978 if (seqRefIds == null)
2982 AlignFrame af = null, _af = null;
2983 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2984 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2985 final String file = jprovider.getFilename();
2988 JarInputStream jin = null;
2989 JarEntry jarentry = null;
2994 jin = jprovider.getJarInputStream();
2995 for (int i = 0; i < entryCount; i++)
2997 jarentry = jin.getNextJarEntry();
3000 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3002 JAXBContext jc = JAXBContext
3003 .newInstance("jalview.xml.binding.jalview");
3004 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3005 .createXMLStreamReader(jin);
3006 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3007 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3008 JalviewModel.class);
3009 JalviewModel object = jbe.getValue();
3011 if (true) // !skipViewport(object))
3013 _af = loadFromObject(object, file, true, jprovider);
3014 if (_af != null && object.getViewport().size() > 0)
3015 // getJalviewModelSequence().getViewportCount() > 0)
3019 // store a reference to the first view
3022 if (_af.getViewport().isGatherViewsHere())
3024 // if this is a gathered view, keep its reference since
3025 // after gathering views, only this frame will remain
3027 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3030 // Save dataset to register mappings once all resolved
3031 importedDatasets.put(
3032 af.getViewport().getAlignment().getDataset(),
3033 af.getViewport().getAlignment().getDataset());
3038 else if (jarentry != null)
3040 // Some other file here.
3043 } while (jarentry != null);
3045 resolveFrefedSequences();
3046 } catch (IOException ex)
3048 ex.printStackTrace();
3049 errorMessage = "Couldn't locate Jalview XML file : " + file;
3051 "Exception whilst loading jalview XML file : " + ex + "\n");
3052 } catch (Exception ex)
3054 System.err.println("Parsing as Jalview Version 2 file failed.");
3055 ex.printStackTrace(System.err);
3056 if (attemptversion1parse)
3058 // used to attempt to parse as V1 castor-generated xml
3060 if (Desktop.instance != null)
3062 Desktop.instance.stopLoading();
3066 System.out.println("Successfully loaded archive file");
3069 ex.printStackTrace();
3072 "Exception whilst loading jalview XML file : " + ex + "\n");
3073 } catch (OutOfMemoryError e)
3075 // Don't use the OOM Window here
3076 errorMessage = "Out of memory loading jalview XML file";
3077 System.err.println("Out of memory whilst loading jalview XML file");
3078 e.printStackTrace();
3082 * Regather multiple views (with the same sequence set id) to the frame (if
3083 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3084 * views instead of separate frames. Note this doesn't restore a state where
3085 * some expanded views in turn have tabbed views - the last "first tab" read
3086 * in will play the role of gatherer for all.
3088 for (AlignFrame fr : gatherToThisFrame.values())
3090 Desktop.instance.gatherViews(fr);
3093 restoreSplitFrames();
3094 for (AlignmentI ds : importedDatasets.keySet())
3096 if (ds.getCodonFrames() != null)
3098 StructureSelectionManager
3099 .getStructureSelectionManager(Desktop.instance)
3100 .registerMappings(ds.getCodonFrames());
3103 if (errorMessage != null)
3108 if (Desktop.instance != null)
3110 Desktop.instance.stopLoading();
3117 * Try to reconstruct and display SplitFrame windows, where each contains
3118 * complementary dna and protein alignments. Done by pairing up AlignFrame
3119 * objects (created earlier) which have complementary viewport ids associated.
3121 protected void restoreSplitFrames()
3123 List<SplitFrame> gatherTo = new ArrayList<>();
3124 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3125 Map<String, AlignFrame> dna = new HashMap<>();
3128 * Identify the DNA alignments
3130 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3133 AlignFrame af = candidate.getValue();
3134 if (af.getViewport().getAlignment().isNucleotide())
3136 dna.put(candidate.getKey().getId(), af);
3141 * Try to match up the protein complements
3143 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3146 AlignFrame af = candidate.getValue();
3147 if (!af.getViewport().getAlignment().isNucleotide())
3149 String complementId = candidate.getKey().getComplementId();
3150 // only non-null complements should be in the Map
3151 if (complementId != null && dna.containsKey(complementId))
3153 final AlignFrame dnaFrame = dna.get(complementId);
3154 SplitFrame sf = createSplitFrame(dnaFrame, af);
3155 addedToSplitFrames.add(dnaFrame);
3156 addedToSplitFrames.add(af);
3157 dnaFrame.setMenusForViewport();
3158 af.setMenusForViewport();
3159 if (af.getViewport().isGatherViewsHere())
3168 * Open any that we failed to pair up (which shouldn't happen!) as
3169 * standalone AlignFrame's.
3171 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3174 AlignFrame af = candidate.getValue();
3175 if (!addedToSplitFrames.contains(af))
3177 Viewport view = candidate.getKey();
3178 Desktop.addInternalFrame(af, view.getTitle(),
3179 safeInt(view.getWidth()), safeInt(view.getHeight()));
3180 af.setMenusForViewport();
3181 System.err.println("Failed to restore view " + view.getTitle()
3182 + " to split frame");
3187 * Gather back into tabbed views as flagged.
3189 for (SplitFrame sf : gatherTo)
3191 Desktop.instance.gatherViews(sf);
3194 splitFrameCandidates.clear();
3198 * Construct and display one SplitFrame holding DNA and protein alignments.
3201 * @param proteinFrame
3204 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3205 AlignFrame proteinFrame)
3207 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3208 String title = MessageManager.getString("label.linked_view_title");
3209 int width = (int) dnaFrame.getBounds().getWidth();
3210 int height = (int) (dnaFrame.getBounds().getHeight()
3211 + proteinFrame.getBounds().getHeight() + 50);
3214 * SplitFrame location is saved to both enclosed frames
3216 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3217 Desktop.addInternalFrame(splitFrame, title, width, height);
3220 * And compute cDNA consensus (couldn't do earlier with consensus as
3221 * mappings were not yet present)
3223 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3229 * check errorMessage for a valid error message and raise an error box in the
3230 * GUI or write the current errorMessage to stderr and then clear the error
3233 protected void reportErrors()
3235 reportErrors(false);
3238 protected void reportErrors(final boolean saving)
3240 if (errorMessage != null)
3242 final String finalErrorMessage = errorMessage;
3245 javax.swing.SwingUtilities.invokeLater(new Runnable()
3250 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3252 "Error " + (saving ? "saving" : "loading")
3254 JvOptionPane.WARNING_MESSAGE);
3260 System.err.println("Problem loading Jalview file: " + errorMessage);
3263 errorMessage = null;
3266 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3269 * when set, local views will be updated from view stored in JalviewXML
3270 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3271 * sync if this is set to true.
3273 private final boolean updateLocalViews = false;
3276 * Returns the path to a temporary file holding the PDB file for the given PDB
3277 * id. The first time of asking, searches for a file of that name in the
3278 * Jalview project jar, and copies it to a new temporary file. Any repeat
3279 * requests just return the path to the file previously created.
3285 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3288 if (alreadyLoadedPDB.containsKey(pdbId))
3290 return alreadyLoadedPDB.get(pdbId).toString();
3293 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3295 if (tempFile != null)
3297 alreadyLoadedPDB.put(pdbId, tempFile);
3303 * Copies the jar entry of given name to a new temporary file and returns the
3304 * path to the file, or null if the entry is not found.
3307 * @param jarEntryName
3309 * a prefix for the temporary file name, must be at least three
3311 * @param suffixModel
3312 * null or original file - so new file can be given the same suffix
3316 protected String copyJarEntry(jarInputStreamProvider jprovider,
3317 String jarEntryName, String prefix, String suffixModel)
3319 String suffix = ".tmp";
3320 if (suffixModel == null)
3322 suffixModel = jarEntryName;
3324 int sfpos = suffixModel.lastIndexOf(".");
3325 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3327 suffix = "." + suffixModel.substring(sfpos + 1);
3330 try (JarInputStream jin = jprovider.getJarInputStream())
3332 JarEntry entry = null;
3335 entry = jin.getNextJarEntry();
3336 } while (entry != null && !entry.getName().equals(jarEntryName));
3340 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3341 File outFile = File.createTempFile(prefix, suffix);
3342 outFile.deleteOnExit();
3343 try (OutputStream os = new FileOutputStream(outFile))
3347 String t = outFile.getAbsolutePath();
3353 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3355 } catch (Exception ex)
3357 ex.printStackTrace();
3363 private class JvAnnotRow
3365 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3372 * persisted version of annotation row from which to take vis properties
3374 public jalview.datamodel.AlignmentAnnotation template;
3377 * original position of the annotation row in the alignment
3383 * Load alignment frame from jalview XML DOM object
3385 * @param jalviewModel
3388 * filename source string
3389 * @param loadTreesAndStructures
3390 * when false only create Viewport
3392 * data source provider
3393 * @return alignment frame created from view stored in DOM
3395 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3396 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3398 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3400 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3402 // JalviewModelSequence jms = object.getJalviewModelSequence();
3404 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3406 Viewport view = (jalviewModel.getViewport().size() > 0)
3407 ? jalviewModel.getViewport().get(0)
3410 // ////////////////////////////////
3411 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3414 // If we just load in the same jar file again, the sequenceSetId
3415 // will be the same, and we end up with multiple references
3416 // to the same sequenceSet. We must modify this id on load
3417 // so that each load of the file gives a unique id
3420 * used to resolve correct alignment dataset for alignments with multiple
3423 String uniqueSeqSetId = null;
3424 String viewId = null;
3427 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3428 viewId = (view.getId() == null ? null
3429 : view.getId() + uniqueSetSuffix);
3432 // ////////////////////////////////
3435 List<SequenceI> hiddenSeqs = null;
3437 List<SequenceI> tmpseqs = new ArrayList<>();
3439 boolean multipleView = false;
3440 SequenceI referenceseqForView = null;
3441 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3442 List<JSeq> jseqs = jalviewModel.getJSeq();
3443 int vi = 0; // counter in vamsasSeq array
3444 for (int i = 0; i < jseqs.size(); i++)
3446 JSeq jseq = jseqs.get(i);
3447 String seqId = jseq.getId();
3449 SequenceI tmpSeq = seqRefIds.get(seqId);
3452 if (!incompleteSeqs.containsKey(seqId))
3454 // may not need this check, but keep it for at least 2.9,1 release
3455 if (tmpSeq.getStart() != jseq.getStart()
3456 || tmpSeq.getEnd() != jseq.getEnd())
3458 System.err.println(String.format(
3459 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3460 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3461 jseq.getStart(), jseq.getEnd()));
3466 incompleteSeqs.remove(seqId);
3468 if (vamsasSeqs.size() > vi
3469 && vamsasSeqs.get(vi).getId().equals(seqId))
3471 // most likely we are reading a dataset XML document so
3472 // update from vamsasSeq section of XML for this sequence
3473 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3474 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3475 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3480 // reading multiple views, so vamsasSeq set is a subset of JSeq
3481 multipleView = true;
3483 tmpSeq.setStart(jseq.getStart());
3484 tmpSeq.setEnd(jseq.getEnd());
3485 tmpseqs.add(tmpSeq);
3489 Sequence vamsasSeq = vamsasSeqs.get(vi);
3490 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3491 vamsasSeq.getSequence());
3492 tmpSeq.setDescription(vamsasSeq.getDescription());
3493 tmpSeq.setStart(jseq.getStart());
3494 tmpSeq.setEnd(jseq.getEnd());
3495 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3496 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3497 tmpseqs.add(tmpSeq);
3501 if (safeBoolean(jseq.isViewreference()))
3503 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3506 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3508 if (hiddenSeqs == null)
3510 hiddenSeqs = new ArrayList<>();
3513 hiddenSeqs.add(tmpSeq);
3518 // Create the alignment object from the sequence set
3519 // ///////////////////////////////
3520 SequenceI[] orderedSeqs = tmpseqs
3521 .toArray(new SequenceI[tmpseqs.size()]);
3523 AlignmentI al = null;
3524 // so we must create or recover the dataset alignment before going further
3525 // ///////////////////////////////
3526 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3528 // older jalview projects do not have a dataset - so creat alignment and
3530 al = new Alignment(orderedSeqs);
3531 al.setDataset(null);
3535 boolean isdsal = jalviewModel.getViewport().isEmpty();
3538 // we are importing a dataset record, so
3539 // recover reference to an alignment already materialsed as dataset
3540 al = getDatasetFor(vamsasSet.getDatasetId());
3544 // materialse the alignment
3545 al = new Alignment(orderedSeqs);
3549 addDatasetRef(vamsasSet.getDatasetId(), al);
3552 // finally, verify all data in vamsasSet is actually present in al
3553 // passing on flag indicating if it is actually a stored dataset
3554 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3557 if (referenceseqForView != null)
3559 al.setSeqrep(referenceseqForView);
3561 // / Add the alignment properties
3562 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3564 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3566 al.setProperty(ssp.getKey(), ssp.getValue());
3569 // ///////////////////////////////
3571 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3574 // load sequence features, database references and any associated PDB
3575 // structures for the alignment
3577 // prior to 2.10, this part would only be executed the first time a
3578 // sequence was encountered, but not afterwards.
3579 // now, for 2.10 projects, this is also done if the xml doc includes
3580 // dataset sequences not actually present in any particular view.
3582 for (int i = 0; i < vamsasSeqs.size(); i++)
3584 JSeq jseq = jseqs.get(i);
3585 if (jseq.getFeatures().size() > 0)
3587 List<Feature> features = jseq.getFeatures();
3588 for (int f = 0; f < features.size(); f++)
3590 Feature feat = features.get(f);
3591 SequenceFeature sf = new SequenceFeature(feat.getType(),
3592 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3593 safeFloat(feat.getScore()), feat.getFeatureGroup());
3594 sf.setStatus(feat.getStatus());
3597 * load any feature attributes - include map-valued attributes
3599 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3600 for (int od = 0; od < feat.getOtherData().size(); od++)
3602 OtherData keyValue = feat.getOtherData().get(od);
3603 String attributeName = keyValue.getKey();
3604 String attributeValue = keyValue.getValue();
3605 if (attributeName.startsWith("LINK"))
3607 sf.addLink(attributeValue);
3611 String subAttribute = keyValue.getKey2();
3612 if (subAttribute == null)
3614 // simple string-valued attribute
3615 sf.setValue(attributeName, attributeValue);
3619 // attribute 'key' has sub-attribute 'key2'
3620 if (!mapAttributes.containsKey(attributeName))
3622 mapAttributes.put(attributeName, new HashMap<>());
3624 mapAttributes.get(attributeName).put(subAttribute,
3629 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3632 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3635 // adds feature to datasequence's feature set (since Jalview 2.10)
3636 al.getSequenceAt(i).addSequenceFeature(sf);
3639 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3641 // adds dbrefs to datasequence's set (since Jalview 2.10)
3643 al.getSequenceAt(i).getDatasetSequence() == null
3644 ? al.getSequenceAt(i)
3645 : al.getSequenceAt(i).getDatasetSequence(),
3648 if (jseq.getPdbids().size() > 0)
3650 List<Pdbids> ids = jseq.getPdbids();
3651 for (int p = 0; p < ids.size(); p++)
3653 Pdbids pdbid = ids.get(p);
3654 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3655 entry.setId(pdbid.getId());
3656 if (pdbid.getType() != null)
3658 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3660 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3664 entry.setType(PDBEntry.Type.FILE);
3667 // jprovider is null when executing 'New View'
3668 if (pdbid.getFile() != null && jprovider != null)
3670 if (!pdbloaded.containsKey(pdbid.getFile()))
3672 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3677 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3681 if (pdbid.getPdbentryItem() != null)
3683 for (PdbentryItem item : pdbid.getPdbentryItem())
3685 for (Property pr : item.getProperty())
3687 entry.setProperty(pr.getName(), pr.getValue());
3692 for (Property prop : pdbid.getProperty())
3694 entry.setProperty(prop.getName(), prop.getValue());
3696 StructureSelectionManager
3697 .getStructureSelectionManager(Desktop.instance)
3698 .registerPDBEntry(entry);
3699 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3700 if (al.getSequenceAt(i).getDatasetSequence() != null)
3702 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3706 al.getSequenceAt(i).addPDBId(entry);
3711 } // end !multipleview
3713 // ///////////////////////////////
3714 // LOAD SEQUENCE MAPPINGS
3716 if (vamsasSet.getAlcodonFrame().size() > 0)
3718 // TODO Potentially this should only be done once for all views of an
3720 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3721 for (int i = 0; i < alc.size(); i++)
3723 AlignedCodonFrame cf = new AlignedCodonFrame();
3724 if (alc.get(i).getAlcodMap().size() > 0)
3726 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3727 for (int m = 0; m < maps.size(); m++)
3729 AlcodMap map = maps.get(m);
3730 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3732 jalview.datamodel.Mapping mapping = null;
3733 // attach to dna sequence reference.
3734 if (map.getMapping() != null)
3736 mapping = addMapping(map.getMapping());
3737 if (dnaseq != null && mapping.getTo() != null)
3739 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3745 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3749 al.addCodonFrame(cf);
3754 // ////////////////////////////////
3756 List<JvAnnotRow> autoAlan = new ArrayList<>();
3759 * store any annotations which forward reference a group's ID
3761 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3763 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3765 List<Annotation> an = vamsasSet.getAnnotation();
3767 for (int i = 0; i < an.size(); i++)
3769 Annotation annotation = an.get(i);
3772 * test if annotation is automatically calculated for this view only
3774 boolean autoForView = false;
3775 if (annotation.getLabel().equals("Quality")
3776 || annotation.getLabel().equals("Conservation")
3777 || annotation.getLabel().equals("Consensus"))
3779 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3781 // JAXB has no has() test; schema defaults value to false
3782 // if (!annotation.hasAutoCalculated())
3784 // annotation.setAutoCalculated(true);
3787 if (autoForView || annotation.isAutoCalculated())
3789 // remove ID - we don't recover annotation from other views for
3790 // view-specific annotation
3791 annotation.setId(null);
3794 // set visibility for other annotation in this view
3795 String annotationId = annotation.getId();
3796 if (annotationId != null && annotationIds.containsKey(annotationId))
3798 AlignmentAnnotation jda = annotationIds.get(annotationId);
3799 // in principle Visible should always be true for annotation displayed
3800 // in multiple views
3801 if (annotation.isVisible() != null)
3803 jda.visible = annotation.isVisible();
3806 al.addAnnotation(jda);
3810 // Construct new annotation from model.
3811 List<AnnotationElement> ae = annotation.getAnnotationElement();
3812 jalview.datamodel.Annotation[] anot = null;
3813 java.awt.Color firstColour = null;
3815 if (!annotation.isScoreOnly())
3817 anot = new jalview.datamodel.Annotation[al.getWidth()];
3818 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3820 AnnotationElement annElement = ae.get(aa);
3821 anpos = annElement.getPosition();
3823 if (anpos >= anot.length)
3828 float value = safeFloat(annElement.getValue());
3829 anot[anpos] = new jalview.datamodel.Annotation(
3830 annElement.getDisplayCharacter(),
3831 annElement.getDescription(),
3832 (annElement.getSecondaryStructure() == null
3833 || annElement.getSecondaryStructure()
3837 .getSecondaryStructure()
3840 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3841 if (firstColour == null)
3843 firstColour = anot[anpos].colour;
3847 jalview.datamodel.AlignmentAnnotation jaa = null;
3849 if (annotation.isGraph())
3851 float llim = 0, hlim = 0;
3852 // if (autoForView || an[i].isAutoCalculated()) {
3855 jaa = new jalview.datamodel.AlignmentAnnotation(
3856 annotation.getLabel(), annotation.getDescription(), anot,
3857 llim, hlim, safeInt(annotation.getGraphType()));
3859 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3860 jaa._linecolour = firstColour;
3861 if (annotation.getThresholdLine() != null)
3863 jaa.setThreshold(new jalview.datamodel.GraphLine(
3864 safeFloat(annotation.getThresholdLine().getValue()),
3865 annotation.getThresholdLine().getLabel(),
3866 new java.awt.Color(safeInt(
3867 annotation.getThresholdLine().getColour()))));
3869 if (autoForView || annotation.isAutoCalculated())
3871 // Hardwire the symbol display line to ensure that labels for
3872 // histograms are displayed
3878 jaa = new jalview.datamodel.AlignmentAnnotation(
3879 annotation.getLabel(), annotation.getDescription(), anot);
3880 jaa._linecolour = firstColour;
3882 // register new annotation
3883 if (annotation.getId() != null)
3885 annotationIds.put(annotation.getId(), jaa);
3886 jaa.annotationId = annotation.getId();
3888 // recover sequence association
3889 String sequenceRef = annotation.getSequenceRef();
3890 if (sequenceRef != null)
3892 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3893 SequenceI sequence = seqRefIds.get(sequenceRef);
3894 if (sequence == null)
3896 // in pre-2.9 projects sequence ref is to sequence name
3897 sequence = al.findName(sequenceRef);
3899 if (sequence != null)
3901 jaa.createSequenceMapping(sequence, 1, true);
3902 sequence.addAlignmentAnnotation(jaa);
3905 // and make a note of any group association
3906 if (annotation.getGroupRef() != null
3907 && annotation.getGroupRef().length() > 0)
3909 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3910 .get(annotation.getGroupRef());
3913 aal = new ArrayList<>();
3914 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3919 if (annotation.getScore() != null)
3921 jaa.setScore(annotation.getScore().doubleValue());
3923 if (annotation.isVisible() != null)
3925 jaa.visible = annotation.isVisible().booleanValue();
3928 if (annotation.isCentreColLabels() != null)
3930 jaa.centreColLabels = annotation.isCentreColLabels()
3934 if (annotation.isScaleColLabels() != null)
3936 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3938 if (annotation.isAutoCalculated())
3940 // newer files have an 'autoCalculated' flag and store calculation
3941 // state in viewport properties
3942 jaa.autoCalculated = true; // means annotation will be marked for
3943 // update at end of load.
3945 if (annotation.getGraphHeight() != null)
3947 jaa.graphHeight = annotation.getGraphHeight().intValue();
3949 jaa.belowAlignment = annotation.isBelowAlignment();
3950 jaa.setCalcId(annotation.getCalcId());
3951 if (annotation.getProperty().size() > 0)
3953 for (jalview.xml.binding.jalview.Property prop : annotation
3956 jaa.setProperty(prop.getName(), prop.getValue());
3959 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
3961 if (annotation.getContactmatrix() != null
3962 && annotation.getContactmatrix().size() > 0)
3964 for (MatrixType xmlmat : annotation.getContactmatrix())
3966 if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
3968 if (!xmlmat.getRows().equals(xmlmat.getCols()))
3970 Console.error("Can't handle non square PAE Matrices");
3974 float[][] elements = ContactMatrix
3975 .fromFloatStringToContacts(xmlmat.getElements(),
3976 xmlmat.getCols().intValue(),
3977 xmlmat.getRows().intValue());
3979 PAEContactMatrix newpae = new PAEContactMatrix(
3980 jaa.sequenceRef, elements);
3981 List<BitSet> newgroups = new ArrayList<BitSet>();
3982 if (xmlmat.getGroups().size() > 0)
3984 for (String sgroup : xmlmat.getGroups())
3988 BigInteger group = new BigInteger(sgroup);
3989 newgroups.add(BitSet.valueOf(group.toByteArray()));
3990 } catch (NumberFormatException nfe)
3993 "Problem parsing groups for a contact matrix (\""
3999 String nwk = xmlmat.getNewick().size() > 0
4000 ? xmlmat.getNewick().get(0)
4002 if (xmlmat.getNewick().size() > 1)
4005 "Ignoring additional clusterings for contact matrix");
4008 String treeMethod = xmlmat.getTreeMethod();
4009 double thresh = xmlmat.getCutHeight() != null
4010 ? xmlmat.getCutHeight()
4012 newpae.restoreGroups(newgroups, treeMethod, nwk, thresh);
4013 jaa.sequenceRef.addContactListFor(jaa, newpae);
4018 Console.error("Ignoring CONTACT_MAP annotation with type "
4019 + xmlmat.getType());
4025 if (jaa.autoCalculated)
4027 autoAlan.add(new JvAnnotRow(i, jaa));
4030 // if (!autoForView)
4032 // add autocalculated group annotation and any user created annotation
4034 al.addAnnotation(jaa);
4038 // ///////////////////////
4040 // Create alignment markup and styles for this view
4041 if (jalviewModel.getJGroup().size() > 0)
4043 List<JGroup> groups = jalviewModel.getJGroup();
4044 boolean addAnnotSchemeGroup = false;
4045 for (int i = 0; i < groups.size(); i++)
4047 JGroup jGroup = groups.get(i);
4048 ColourSchemeI cs = null;
4049 if (jGroup.getColour() != null)
4051 if (jGroup.getColour().startsWith("ucs"))
4053 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4055 else if (jGroup.getColour().equals("AnnotationColourGradient")
4056 && jGroup.getAnnotationColours() != null)
4058 addAnnotSchemeGroup = true;
4062 cs = ColourSchemeProperty.getColourScheme(null, al,
4063 jGroup.getColour());
4066 int pidThreshold = safeInt(jGroup.getPidThreshold());
4068 Vector<SequenceI> seqs = new Vector<>();
4070 for (int s = 0; s < jGroup.getSeq().size(); s++)
4072 String seqId = jGroup.getSeq().get(s);
4073 SequenceI ts = seqRefIds.get(seqId);
4077 seqs.addElement(ts);
4081 if (seqs.size() < 1)
4086 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4087 safeBoolean(jGroup.isDisplayBoxes()),
4088 safeBoolean(jGroup.isDisplayText()),
4089 safeBoolean(jGroup.isColourText()),
4090 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4091 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4092 sg.getGroupColourScheme()
4093 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4094 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4096 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4097 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4098 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4099 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4100 // attributes with a default in the schema are never null
4101 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4102 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4103 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4104 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4105 if (jGroup.getConsThreshold() != null
4106 && jGroup.getConsThreshold().intValue() != 0)
4108 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4111 c.verdict(false, 25);
4112 sg.cs.setConservation(c);
4115 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4117 // re-instate unique group/annotation row reference
4118 List<AlignmentAnnotation> jaal = groupAnnotRefs
4119 .get(jGroup.getId());
4122 for (AlignmentAnnotation jaa : jaal)
4125 if (jaa.autoCalculated)
4127 // match up and try to set group autocalc alignment row for this
4129 if (jaa.label.startsWith("Consensus for "))
4131 sg.setConsensus(jaa);
4133 // match up and try to set group autocalc alignment row for this
4135 if (jaa.label.startsWith("Conservation for "))
4137 sg.setConservationRow(jaa);
4144 if (addAnnotSchemeGroup)
4146 // reconstruct the annotation colourscheme
4148 constructAnnotationColour(jGroup.getAnnotationColours(),
4149 null, al, jalviewModel, false));
4155 // only dataset in this model, so just return.
4158 // ///////////////////////////////
4161 AlignFrame af = null;
4162 AlignViewport av = null;
4163 // now check to see if we really need to create a new viewport.
4164 if (multipleView && viewportsAdded.size() == 0)
4166 // We recovered an alignment for which a viewport already exists.
4167 // TODO: fix up any settings necessary for overlaying stored state onto
4168 // state recovered from another document. (may not be necessary).
4169 // we may need a binding from a viewport in memory to one recovered from
4171 // and then recover its containing af to allow the settings to be applied.
4172 // TODO: fix for vamsas demo
4174 "About to recover a viewport for existing alignment: Sequence set ID is "
4176 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4177 if (seqsetobj != null)
4179 if (seqsetobj instanceof String)
4181 uniqueSeqSetId = (String) seqsetobj;
4183 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4189 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4195 * indicate that annotation colours are applied across all groups (pre
4196 * Jalview 2.8.1 behaviour)
4198 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4199 jalviewModel.getVersion());
4201 AlignmentPanel ap = null;
4202 boolean isnewview = true;
4205 // Check to see if this alignment already has a view id == viewId
4206 jalview.gui.AlignmentPanel views[] = Desktop
4207 .getAlignmentPanels(uniqueSeqSetId);
4208 if (views != null && views.length > 0)
4210 for (int v = 0; v < views.length; v++)
4212 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4214 // recover the existing alignpanel, alignframe, viewport
4215 af = views[v].alignFrame;
4218 // TODO: could even skip resetting view settings if we don't want to
4219 // change the local settings from other jalview processes
4228 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4229 uniqueSeqSetId, viewId, autoAlan);
4230 av = af.getViewport();
4235 * Load any trees, PDB structures and viewers, Overview
4237 * Not done if flag is false (when this method is used for New View)
4239 if (loadTreesAndStructures)
4241 loadTrees(jalviewModel, view, af, av, ap);
4242 loadPCAViewers(jalviewModel, ap);
4243 loadPDBStructures(jprovider, jseqs, af, ap);
4244 loadRnaViewers(jprovider, jseqs, ap);
4245 loadOverview(view, jalviewModel.getVersion(), af);
4247 // and finally return.
4252 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4253 * and geometry as saved
4258 protected void loadOverview(Viewport view, String version, AlignFrame af)
4260 if (!isVersionStringLaterThan("2.11.3", version)
4261 && view.getOverview() == null)
4266 * first close any Overview that was opened automatically
4267 * (if so configured in Preferences) so that the view is
4268 * restored in the same state as saved
4270 af.alignPanel.closeOverviewPanel();
4272 Overview overview = view.getOverview();
4273 if (overview != null)
4275 OverviewPanel overviewPanel = af
4276 .openOverviewPanel(overview.isShowHidden());
4277 overviewPanel.setTitle(overview.getTitle());
4278 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4279 overview.getWidth(), overview.getHeight());
4280 Color gap = new Color(overview.getGapColour());
4281 Color residue = new Color(overview.getResidueColour());
4282 Color hidden = new Color(overview.getHiddenColour());
4283 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4288 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4289 * panel is restored from separate jar entries, two (gapped and trimmed) per
4290 * sequence and secondary structure.
4292 * Currently each viewer shows just one sequence and structure (gapped and
4293 * trimmed), however this method is designed to support multiple sequences or
4294 * structures in viewers if wanted in future.
4300 private void loadRnaViewers(jarInputStreamProvider jprovider,
4301 List<JSeq> jseqs, AlignmentPanel ap)
4304 * scan the sequences for references to viewers; create each one the first
4305 * time it is referenced, add Rna models to existing viewers
4307 for (JSeq jseq : jseqs)
4309 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4311 RnaViewer viewer = jseq.getRnaViewer().get(i);
4312 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4315 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4317 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4318 SequenceI seq = seqRefIds.get(jseq.getId());
4319 AlignmentAnnotation ann = this.annotationIds
4320 .get(ss.getAnnotationId());
4323 * add the structure to the Varna display (with session state copied
4324 * from the jar to a temporary file)
4326 boolean gapped = safeBoolean(ss.isGapped());
4327 String rnaTitle = ss.getTitle();
4328 String sessionState = ss.getViewerState();
4329 String tempStateFile = copyJarEntry(jprovider, sessionState,
4331 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4332 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4334 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4340 * Locate and return an already instantiated matching AppVarna, or create one
4344 * @param viewIdSuffix
4348 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4349 String viewIdSuffix, AlignmentPanel ap)
4352 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4353 * if load is repeated
4355 String postLoadId = viewer.getViewId() + viewIdSuffix;
4356 for (JInternalFrame frame : getAllFrames())
4358 if (frame instanceof AppVarna)
4360 AppVarna varna = (AppVarna) frame;
4361 if (postLoadId.equals(varna.getViewId()))
4363 // this viewer is already instantiated
4364 // could in future here add ap as another 'parent' of the
4365 // AppVarna window; currently just 1-to-many
4372 * viewer not found - make it
4374 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4375 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4376 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4377 safeInt(viewer.getDividerLocation()));
4378 AppVarna varna = new AppVarna(model, ap);
4384 * Load any saved trees
4392 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4393 AlignViewport av, AlignmentPanel ap)
4395 // TODO result of automated refactoring - are all these parameters needed?
4398 for (int t = 0; t < jm.getTree().size(); t++)
4401 Tree tree = jm.getTree().get(t);
4403 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4406 if (tree.isColumnWise())
4408 AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds
4409 .get(tree.getColumnReference());
4413 "Null alignment annotation when restoring columnwise tree");
4415 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4416 tree.getTitle(), safeInt(tree.getWidth()),
4417 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4418 safeInt(tree.getYpos()));
4423 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4424 tree.getTitle(), safeInt(tree.getWidth()),
4425 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4426 safeInt(tree.getYpos()));
4428 if (tree.getId() != null)
4430 // perhaps bind the tree id to something ?
4435 // update local tree attributes ?
4436 // TODO: should check if tp has been manipulated by user - if so its
4437 // settings shouldn't be modified
4438 tp.setTitle(tree.getTitle());
4439 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4440 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4441 safeInt(tree.getHeight())));
4442 tp.setViewport(av); // af.viewport;
4443 // TODO: verify 'associate with all views' works still
4444 tp.getTreeCanvas().setViewport(av); // af.viewport;
4445 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4447 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4451 "There was a problem recovering stored Newick tree: \n"
4452 + tree.getNewick());
4456 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4457 tp.fitToWindow_actionPerformed(null);
4459 if (tree.getFontName() != null)
4462 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4463 safeInt(tree.getFontSize())));
4468 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4469 safeInt(view.getFontSize())));
4472 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4473 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4474 tp.showDistances(safeBoolean(tree.isShowDistances()));
4476 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4478 if (safeBoolean(tree.isCurrentTree()))
4480 af.getViewport().setCurrentTree(tp.getTree());
4484 } catch (Exception ex)
4486 ex.printStackTrace();
4491 * Load and link any saved structure viewers.
4498 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4499 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4502 * Run through all PDB ids on the alignment, and collect mappings between
4503 * distinct view ids and all sequences referring to that view.
4505 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4507 for (int i = 0; i < jseqs.size(); i++)
4509 JSeq jseq = jseqs.get(i);
4510 if (jseq.getPdbids().size() > 0)
4512 List<Pdbids> ids = jseq.getPdbids();
4513 for (int p = 0; p < ids.size(); p++)
4515 Pdbids pdbid = ids.get(p);
4516 final int structureStateCount = pdbid.getStructureState().size();
4517 for (int s = 0; s < structureStateCount; s++)
4519 // check to see if we haven't already created this structure view
4520 final StructureState structureState = pdbid.getStructureState()
4522 String sviewid = (structureState.getViewId() == null) ? null
4523 : structureState.getViewId() + uniqueSetSuffix;
4524 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4525 // Originally : pdbid.getFile()
4526 // : TODO: verify external PDB file recovery still works in normal
4527 // jalview project load
4529 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4530 jpdb.setId(pdbid.getId());
4532 int x = safeInt(structureState.getXpos());
4533 int y = safeInt(structureState.getYpos());
4534 int width = safeInt(structureState.getWidth());
4535 int height = safeInt(structureState.getHeight());
4537 // Probably don't need to do this anymore...
4538 // Desktop.desktop.getComponentAt(x, y);
4539 // TODO: NOW: check that this recovers the PDB file correctly.
4540 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4542 jalview.datamodel.SequenceI seq = seqRefIds
4543 .get(jseq.getId() + "");
4544 if (sviewid == null)
4546 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4549 if (!structureViewers.containsKey(sviewid))
4551 String viewerType = structureState.getType();
4552 if (viewerType == null) // pre Jalview 2.9
4554 viewerType = ViewerType.JMOL.toString();
4556 structureViewers.put(sviewid,
4557 new StructureViewerModel(x, y, width, height, false,
4558 false, true, structureState.getViewId(),
4560 // Legacy pre-2.7 conversion JAL-823 :
4561 // do not assume any view has to be linked for colour by
4565 // assemble String[] { pdb files }, String[] { id for each
4566 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4567 // seqs_file 2}, boolean[] {
4568 // linkAlignPanel,superposeWithAlignpanel}} from hash
4569 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4570 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4571 || structureState.isAlignwithAlignPanel());
4574 * Default colour by linked panel to false if not specified (e.g.
4575 * for pre-2.7 projects)
4577 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4578 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4579 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4582 * Default colour by viewer to true if not specified (e.g. for
4585 boolean colourByViewer = jmoldat.isColourByViewer();
4586 colourByViewer &= structureState.isColourByJmol();
4587 jmoldat.setColourByViewer(colourByViewer);
4589 if (jmoldat.getStateData().length() < structureState.getValue()
4590 /*Content()*/.length())
4592 jmoldat.setStateData(structureState.getValue());// Content());
4594 if (pdbid.getFile() != null)
4596 File mapkey = new File(pdbid.getFile());
4597 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4598 if (seqstrmaps == null)
4600 jmoldat.getFileData().put(mapkey,
4601 seqstrmaps = jmoldat.new StructureData(pdbFile,
4604 if (!seqstrmaps.getSeqList().contains(seq))
4606 seqstrmaps.getSeqList().add(seq);
4612 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");
4613 Console.warn(errorMessage);
4619 // Instantiate the associated structure views
4620 for (Entry<String, StructureViewerModel> entry : structureViewers
4625 createOrLinkStructureViewer(entry, af, ap, jprovider);
4626 } catch (Exception e)
4629 "Error loading structure viewer: " + e.getMessage());
4630 // failed - try the next one
4642 protected void createOrLinkStructureViewer(
4643 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4644 AlignmentPanel ap, jarInputStreamProvider jprovider)
4646 final StructureViewerModel stateData = viewerData.getValue();
4649 * Search for any viewer windows already open from other alignment views
4650 * that exactly match the stored structure state
4652 StructureViewerBase comp = findMatchingViewer(viewerData);
4656 linkStructureViewer(ap, comp, stateData);
4660 String type = stateData.getType();
4663 ViewerType viewerType = ViewerType.valueOf(type);
4664 createStructureViewer(viewerType, viewerData, af, jprovider);
4665 } catch (IllegalArgumentException | NullPointerException e)
4667 // TODO JAL-3619 show error dialog / offer an alternative viewer
4668 Console.error("Invalid structure viewer type: " + type);
4673 * Generates a name for the entry in the project jar file to hold state
4674 * information for a structure viewer
4679 protected String getViewerJarEntryName(String viewId)
4681 return VIEWER_PREFIX + viewId;
4685 * Returns any open frame that matches given structure viewer data. The match
4686 * is based on the unique viewId, or (for older project versions) the frame's
4692 protected StructureViewerBase findMatchingViewer(
4693 Entry<String, StructureViewerModel> viewerData)
4695 final String sviewid = viewerData.getKey();
4696 final StructureViewerModel svattrib = viewerData.getValue();
4697 StructureViewerBase comp = null;
4698 JInternalFrame[] frames = getAllFrames();
4699 for (JInternalFrame frame : frames)
4701 if (frame instanceof StructureViewerBase)
4704 * Post jalview 2.4 schema includes structure view id
4706 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4709 comp = (StructureViewerBase) frame;
4710 break; // break added in 2.9
4713 * Otherwise test for matching position and size of viewer frame
4715 else if (frame.getX() == svattrib.getX()
4716 && frame.getY() == svattrib.getY()
4717 && frame.getHeight() == svattrib.getHeight()
4718 && frame.getWidth() == svattrib.getWidth())
4720 comp = (StructureViewerBase) frame;
4721 // no break in faint hope of an exact match on viewId
4729 * Link an AlignmentPanel to an existing structure viewer.
4734 * @param useinViewerSuperpos
4735 * @param usetoColourbyseq
4736 * @param viewerColouring
4738 protected void linkStructureViewer(AlignmentPanel ap,
4739 StructureViewerBase viewer, StructureViewerModel stateData)
4741 // NOTE: if the jalview project is part of a shared session then
4742 // view synchronization should/could be done here.
4744 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4745 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4746 final boolean viewerColouring = stateData.isColourByViewer();
4747 Map<File, StructureData> oldFiles = stateData.getFileData();
4750 * Add mapping for sequences in this view to an already open viewer
4752 final AAStructureBindingModel binding = viewer.getBinding();
4753 for (File id : oldFiles.keySet())
4755 // add this and any other pdb files that should be present in the
4757 StructureData filedat = oldFiles.get(id);
4758 String pdbFile = filedat.getFilePath();
4759 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4760 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4762 binding.addSequenceForStructFile(pdbFile, seq);
4764 // and add the AlignmentPanel's reference to the view panel
4765 viewer.addAlignmentPanel(ap);
4766 if (useinViewerSuperpos)
4768 viewer.useAlignmentPanelForSuperposition(ap);
4772 viewer.excludeAlignmentPanelForSuperposition(ap);
4774 if (usetoColourbyseq)
4776 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4780 viewer.excludeAlignmentPanelForColourbyseq(ap);
4785 * Get all frames within the Desktop.
4789 protected JInternalFrame[] getAllFrames()
4791 JInternalFrame[] frames = null;
4792 // TODO is this necessary - is it safe - risk of hanging?
4797 frames = Desktop.desktop.getAllFrames();
4798 } catch (ArrayIndexOutOfBoundsException e)
4800 // occasional No such child exceptions are thrown here...
4804 } catch (InterruptedException f)
4808 } while (frames == null);
4813 * Answers true if 'version' is equal to or later than 'supported', where each
4814 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4815 * changes. Development and test values for 'version' are leniently treated
4819 * - minimum version we are comparing against
4821 * - version of data being processsed
4822 * @return true if version is equal to or later than supported
4824 public static boolean isVersionStringLaterThan(String supported,
4827 if (supported == null || version == null
4828 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4829 || version.equalsIgnoreCase("Test")
4830 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4832 System.err.println("Assuming project file with "
4833 + (version == null ? "null" : version)
4834 + " is compatible with Jalview version " + supported);
4839 return StringUtils.compareVersions(version, supported, "b") >= 0;
4843 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4845 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4847 if (newStructureViewers != null)
4849 sview.getBinding().setFinishedLoadingFromArchive(false);
4850 newStructureViewers.add(sview);
4854 protected void setLoadingFinishedForNewStructureViewers()
4856 if (newStructureViewers != null)
4858 for (JalviewStructureDisplayI sview : newStructureViewers)
4860 sview.getBinding().setFinishedLoadingFromArchive(true);
4862 newStructureViewers.clear();
4863 newStructureViewers = null;
4867 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4868 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4869 Viewport view, String uniqueSeqSetId, String viewId,
4870 List<JvAnnotRow> autoAlan)
4872 AlignFrame af = null;
4873 af = new AlignFrame(al, safeInt(view.getWidth()),
4874 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4878 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4879 // System.out.println("Jalview2XML AF " + e);
4880 // super.processKeyEvent(e);
4887 af.setFileName(file, FileFormat.Jalview);
4889 final AlignViewport viewport = af.getViewport();
4890 for (int i = 0; i < JSEQ.size(); i++)
4892 int colour = safeInt(JSEQ.get(i).getColour());
4893 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4899 viewport.setColourByReferenceSeq(true);
4900 viewport.setDisplayReferenceSeq(true);
4903 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4905 if (view.getSequenceSetId() != null)
4907 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4909 viewport.setSequenceSetId(uniqueSeqSetId);
4912 // propagate shared settings to this new view
4913 viewport.setHistoryList(av.getHistoryList());
4914 viewport.setRedoList(av.getRedoList());
4918 viewportsAdded.put(uniqueSeqSetId, viewport);
4920 // TODO: check if this method can be called repeatedly without
4921 // side-effects if alignpanel already registered.
4922 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4924 // apply Hidden regions to view.
4925 if (hiddenSeqs != null)
4927 for (int s = 0; s < JSEQ.size(); s++)
4929 SequenceGroup hidden = new SequenceGroup();
4930 boolean isRepresentative = false;
4931 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4933 isRepresentative = true;
4934 SequenceI sequenceToHide = al
4935 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4936 hidden.addSequence(sequenceToHide, false);
4937 // remove from hiddenSeqs list so we don't try to hide it twice
4938 hiddenSeqs.remove(sequenceToHide);
4940 if (isRepresentative)
4942 SequenceI representativeSequence = al.getSequenceAt(s);
4943 hidden.addSequence(representativeSequence, false);
4944 viewport.hideRepSequences(representativeSequence, hidden);
4948 SequenceI[] hseqs = hiddenSeqs
4949 .toArray(new SequenceI[hiddenSeqs.size()]);
4950 viewport.hideSequence(hseqs);
4953 // recover view properties and display parameters
4955 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4956 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4957 final int pidThreshold = safeInt(view.getPidThreshold());
4958 viewport.setThreshold(pidThreshold);
4960 viewport.setColourText(safeBoolean(view.isShowColourText()));
4962 viewport.setConservationSelected(
4963 safeBoolean(view.isConservationSelected()));
4964 viewport.setIncrement(safeInt(view.getConsThreshold()));
4965 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4966 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4968 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4969 safeInt(view.getFontSize())),
4970 (view.getCharWidth() != null) ? false : true);
4971 if (view.getCharWidth() != null)
4973 viewport.setCharWidth(view.getCharWidth());
4974 viewport.setCharHeight(view.getCharHeight());
4976 ViewStyleI vs = viewport.getViewStyle();
4977 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4978 viewport.setViewStyle(vs);
4979 // TODO: allow custom charWidth/Heights to be restored by updating them
4980 // after setting font - which means set above to false
4981 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4982 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4983 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4985 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4987 viewport.setShowText(safeBoolean(view.isShowText()));
4989 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4990 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4991 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4992 viewport.setShowUnconserved(view.isShowUnconserved());
4993 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4995 if (view.getViewName() != null)
4997 viewport.setViewName(view.getViewName());
4998 af.setInitialTabVisible();
5000 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5001 safeInt(view.getWidth()), safeInt(view.getHeight()));
5002 // startSeq set in af.alignPanel.updateLayout below
5003 af.alignPanel.updateLayout();
5004 ColourSchemeI cs = null;
5005 // apply colourschemes
5006 if (view.getBgColour() != null)
5008 if (view.getBgColour().startsWith("ucs"))
5010 cs = getUserColourScheme(jm, view.getBgColour());
5012 else if (view.getBgColour().startsWith("Annotation"))
5014 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5015 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5022 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5023 view.getBgColour());
5028 * turn off 'alignment colour applies to all groups'
5029 * while restoring global colour scheme
5031 viewport.setColourAppliesToAllGroups(false);
5032 viewport.setGlobalColourScheme(cs);
5033 viewport.getResidueShading().setThreshold(pidThreshold,
5034 view.isIgnoreGapsinConsensus());
5035 viewport.getResidueShading()
5036 .setConsensus(viewport.getSequenceConsensusHash());
5037 if (safeBoolean(view.isConservationSelected()) && cs != null)
5039 viewport.getResidueShading()
5040 .setConservationInc(safeInt(view.getConsThreshold()));
5042 af.changeColour(cs);
5043 viewport.setColourAppliesToAllGroups(true);
5045 viewport.setShowSequenceFeatures(
5046 safeBoolean(view.isShowSequenceFeatures()));
5048 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5049 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5050 viewport.setFollowHighlight(view.isFollowHighlight());
5051 viewport.followSelection = view.isFollowSelection();
5052 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5053 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5054 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5055 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5056 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5057 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5058 viewport.setShowGroupConservation(view.isShowGroupConservation());
5059 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5060 viewport.setShowComplementFeaturesOnTop(
5061 view.isShowComplementFeaturesOnTop());
5063 // recover feature settings
5064 if (jm.getFeatureSettings() != null)
5066 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5067 .getFeatureRenderer();
5068 FeaturesDisplayed fdi;
5069 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5070 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5072 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5073 Map<String, Float> featureOrder = new Hashtable<>();
5075 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5078 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5079 String featureType = setting.getType();
5082 * restore feature filters (if any)
5084 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5086 if (filters != null)
5088 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5090 if (!filter.isEmpty())
5092 fr.setFeatureFilter(featureType, filter);
5097 * restore feature colour scheme
5099 Color maxColour = new Color(setting.getColour());
5100 if (setting.getMincolour() != null)
5103 * minColour is always set unless a simple colour
5104 * (including for colour by label though it doesn't use it)
5106 Color minColour = new Color(setting.getMincolour().intValue());
5107 Color noValueColour = minColour;
5108 NoValueColour noColour = setting.getNoValueColour();
5109 if (noColour == NoValueColour.NONE)
5111 noValueColour = null;
5113 else if (noColour == NoValueColour.MAX)
5115 noValueColour = maxColour;
5117 float min = safeFloat(safeFloat(setting.getMin()));
5118 float max = setting.getMax() == null ? 1f
5119 : setting.getMax().floatValue();
5120 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5121 maxColour, noValueColour, min, max);
5122 if (setting.getAttributeName().size() > 0)
5124 gc.setAttributeName(setting.getAttributeName().toArray(
5125 new String[setting.getAttributeName().size()]));
5127 if (setting.getThreshold() != null)
5129 gc.setThreshold(setting.getThreshold().floatValue());
5130 int threshstate = safeInt(setting.getThreshstate());
5131 // -1 = None, 0 = Below, 1 = Above threshold
5132 if (threshstate == 0)
5134 gc.setBelowThreshold(true);
5136 else if (threshstate == 1)
5138 gc.setAboveThreshold(true);
5141 gc.setAutoScaled(true); // default
5142 if (setting.isAutoScale() != null)
5144 gc.setAutoScaled(setting.isAutoScale());
5146 if (setting.isColourByLabel() != null)
5148 gc.setColourByLabel(setting.isColourByLabel());
5150 // and put in the feature colour table.
5151 featureColours.put(featureType, gc);
5155 featureColours.put(featureType, new FeatureColour(maxColour));
5157 renderOrder[fs] = featureType;
5158 if (setting.getOrder() != null)
5160 featureOrder.put(featureType, setting.getOrder().floatValue());
5164 featureOrder.put(featureType, Float.valueOf(
5165 fs / jm.getFeatureSettings().getSetting().size()));
5167 if (safeBoolean(setting.isDisplay()))
5169 fdi.setVisible(featureType);
5172 Map<String, Boolean> fgtable = new Hashtable<>();
5173 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5175 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5176 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5178 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5179 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5180 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5181 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5182 fgtable, featureColours, 1.0f, featureOrder);
5183 fr.transferSettings(frs);
5186 if (view.getHiddenColumns().size() > 0)
5188 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5190 final HiddenColumns hc = view.getHiddenColumns().get(c);
5191 viewport.hideColumns(safeInt(hc.getStart()),
5192 safeInt(hc.getEnd()) /* +1 */);
5195 if (view.getCalcIdParam() != null)
5197 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5199 if (calcIdParam != null)
5201 if (recoverCalcIdParam(calcIdParam, viewport))
5206 Console.warn("Couldn't recover parameters for "
5207 + calcIdParam.getCalcId());
5212 af.setMenusFromViewport(viewport);
5213 af.setTitle(view.getTitle());
5214 // TODO: we don't need to do this if the viewport is aready visible.
5216 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5217 * has a 'cdna/protein complement' view, in which case save it in order to
5218 * populate a SplitFrame once all views have been read in.
5220 String complementaryViewId = view.getComplementId();
5221 if (complementaryViewId == null)
5223 Desktop.addInternalFrame(af, view.getTitle(),
5224 safeInt(view.getWidth()), safeInt(view.getHeight()));
5225 // recompute any autoannotation
5226 af.alignPanel.updateAnnotation(false, true);
5227 reorderAutoannotation(af, al, autoAlan);
5228 af.alignPanel.alignmentChanged();
5232 splitFrameCandidates.put(view, af);
5239 * Reads saved data to restore Colour by Annotation settings
5241 * @param viewAnnColour
5245 * @param checkGroupAnnColour
5248 private ColourSchemeI constructAnnotationColour(
5249 AnnotationColourScheme viewAnnColour, AlignFrame af,
5250 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5252 boolean propagateAnnColour = false;
5253 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5255 if (checkGroupAnnColour && al.getGroups() != null
5256 && al.getGroups().size() > 0)
5258 // pre 2.8.1 behaviour
5259 // check to see if we should transfer annotation colours
5260 propagateAnnColour = true;
5261 for (SequenceGroup sg : al.getGroups())
5263 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5265 propagateAnnColour = false;
5271 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5273 String annotationId = viewAnnColour.getAnnotation();
5274 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5277 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5279 if (matchedAnnotation == null
5280 && annAlignment.getAlignmentAnnotation() != null)
5282 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5285 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5287 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5292 if (matchedAnnotation == null)
5294 System.err.println("Failed to match annotation colour scheme for "
5298 // belt-and-braces create a threshold line if the
5299 // colourscheme needs one but the matchedAnnotation doesn't have one
5300 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5301 && matchedAnnotation.getThreshold() == null)
5303 matchedAnnotation.setThreshold(
5304 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5305 "Threshold", Color.black));
5308 AnnotationColourGradient cs = null;
5309 if (viewAnnColour.getColourScheme().equals("None"))
5311 cs = new AnnotationColourGradient(matchedAnnotation,
5312 new Color(safeInt(viewAnnColour.getMinColour())),
5313 new Color(safeInt(viewAnnColour.getMaxColour())),
5314 safeInt(viewAnnColour.getAboveThreshold()));
5316 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5318 cs = new AnnotationColourGradient(matchedAnnotation,
5319 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5320 safeInt(viewAnnColour.getAboveThreshold()));
5324 cs = new AnnotationColourGradient(matchedAnnotation,
5325 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5326 viewAnnColour.getColourScheme()),
5327 safeInt(viewAnnColour.getAboveThreshold()));
5330 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5331 boolean useOriginalColours = safeBoolean(
5332 viewAnnColour.isPredefinedColours());
5333 cs.setSeqAssociated(perSequenceOnly);
5334 cs.setPredefinedColours(useOriginalColours);
5336 if (propagateAnnColour && al.getGroups() != null)
5338 // Also use these settings for all the groups
5339 for (int g = 0; g < al.getGroups().size(); g++)
5341 SequenceGroup sg = al.getGroups().get(g);
5342 if (sg.getGroupColourScheme() == null)
5347 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5348 matchedAnnotation, sg.getColourScheme(),
5349 safeInt(viewAnnColour.getAboveThreshold()));
5350 sg.setColourScheme(groupScheme);
5351 groupScheme.setSeqAssociated(perSequenceOnly);
5352 groupScheme.setPredefinedColours(useOriginalColours);
5358 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5359 List<JvAnnotRow> autoAlan)
5361 // copy over visualization settings for autocalculated annotation in the
5363 if (al.getAlignmentAnnotation() != null)
5366 * Kludge for magic autoannotation names (see JAL-811)
5368 String[] magicNames = new String[] { "Consensus", "Quality",
5370 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5371 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5372 for (String nm : magicNames)
5374 visan.put(nm, nullAnnot);
5376 for (JvAnnotRow auan : autoAlan)
5378 visan.put(auan.template.label
5379 + (auan.template.getCalcId() == null ? ""
5380 : "\t" + auan.template.getCalcId()),
5383 int hSize = al.getAlignmentAnnotation().length;
5384 List<JvAnnotRow> reorder = new ArrayList<>();
5385 // work through any autoCalculated annotation already on the view
5386 // removing it if it should be placed in a different location on the
5387 // annotation panel.
5388 List<String> remains = new ArrayList<>(visan.keySet());
5389 for (int h = 0; h < hSize; h++)
5391 jalview.datamodel.AlignmentAnnotation jalan = al
5392 .getAlignmentAnnotation()[h];
5393 if (jalan.autoCalculated)
5396 JvAnnotRow valan = visan.get(k = jalan.label);
5397 if (jalan.getCalcId() != null)
5399 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5404 // delete the auto calculated row from the alignment
5405 al.deleteAnnotation(jalan, false);
5409 if (valan != nullAnnot)
5411 if (jalan != valan.template)
5413 // newly created autoannotation row instance
5414 // so keep a reference to the visible annotation row
5415 // and copy over all relevant attributes
5416 if (valan.template.graphHeight >= 0)
5419 jalan.graphHeight = valan.template.graphHeight;
5421 jalan.visible = valan.template.visible;
5423 reorder.add(new JvAnnotRow(valan.order, jalan));
5428 // Add any (possibly stale) autocalculated rows that were not appended to
5429 // the view during construction
5430 for (String other : remains)
5432 JvAnnotRow othera = visan.get(other);
5433 if (othera != nullAnnot && othera.template.getCalcId() != null
5434 && othera.template.getCalcId().length() > 0)
5436 reorder.add(othera);
5439 // now put the automatic annotation in its correct place
5440 int s = 0, srt[] = new int[reorder.size()];
5441 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5442 for (JvAnnotRow jvar : reorder)
5445 srt[s++] = jvar.order;
5448 jalview.util.QuickSort.sort(srt, rws);
5449 // and re-insert the annotation at its correct position
5450 for (JvAnnotRow jvar : rws)
5452 al.addAnnotation(jvar.template, jvar.order);
5454 af.alignPanel.adjustAnnotationHeight();
5458 Hashtable skipList = null;
5461 * TODO remove this method
5464 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5465 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5466 * throw new Error("Implementation Error. No skipList defined for this
5467 * Jalview2XML instance."); } return (AlignFrame)
5468 * skipList.get(view.getSequenceSetId()); }
5472 * Check if the Jalview view contained in object should be skipped or not.
5475 * @return true if view's sequenceSetId is a key in skipList
5477 private boolean skipViewport(JalviewModel object)
5479 if (skipList == null)
5483 String id = object.getViewport().get(0).getSequenceSetId();
5484 if (skipList.containsKey(id))
5486 Console.debug("Skipping seuqence set id " + id);
5492 public void addToSkipList(AlignFrame af)
5494 if (skipList == null)
5496 skipList = new Hashtable();
5498 skipList.put(af.getViewport().getSequenceSetId(), af);
5501 public void clearSkipList()
5503 if (skipList != null)
5510 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5511 boolean ignoreUnrefed, String uniqueSeqSetId)
5513 jalview.datamodel.AlignmentI ds = getDatasetFor(
5514 vamsasSet.getDatasetId());
5515 AlignmentI xtant_ds = ds;
5516 if (xtant_ds == null)
5518 // good chance we are about to create a new dataset, but check if we've
5519 // seen some of the dataset sequence IDs before.
5520 // TODO: skip this check if we are working with project generated by
5521 // version 2.11 or later
5522 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5523 if (xtant_ds != null)
5526 addDatasetRef(vamsasSet.getDatasetId(), ds);
5529 Vector<SequenceI> dseqs = null;
5532 // recovering an alignment View
5533 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5534 if (seqSetDS != null)
5536 if (ds != null && ds != seqSetDS)
5539 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5540 + " - CDS/Protein crossreference data may be lost");
5541 if (xtant_ds != null)
5543 // This can only happen if the unique sequence set ID was bound to a
5544 // dataset that did not contain any of the sequences in the view
5545 // currently being restored.
5547 "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.");
5551 addDatasetRef(vamsasSet.getDatasetId(), ds);
5556 // try even harder to restore dataset
5557 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5558 // create a list of new dataset sequences
5559 dseqs = new Vector<>();
5561 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5563 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5564 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5566 // create a new dataset
5569 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5570 dseqs.copyInto(dsseqs);
5571 ds = new jalview.datamodel.Alignment(dsseqs);
5572 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5573 + " for alignment " + System.identityHashCode(al));
5574 addDatasetRef(vamsasSet.getDatasetId(), ds);
5576 // set the dataset for the newly imported alignment.
5577 if (al.getDataset() == null && !ignoreUnrefed)
5580 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5581 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5583 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5587 * XML dataset sequence ID to materialised dataset reference
5589 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5592 * @return the first materialised dataset reference containing a dataset
5593 * sequence referenced in the given view
5595 * - sequences from the view
5597 AlignmentI checkIfHasDataset(List<Sequence> list)
5599 for (Sequence restoredSeq : list)
5601 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5602 if (datasetFor != null)
5611 * Register ds as the containing dataset for the dataset sequences referenced
5612 * by sequences in list
5615 * - sequences in a view
5618 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5620 for (Sequence restoredSeq : list)
5622 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5623 if (prevDS != null && prevDS != ds)
5625 Console.warn("Dataset sequence appears in many datasets: "
5626 + restoredSeq.getDsseqid());
5627 // TODO: try to merge!
5635 * sequence definition to create/merge dataset sequence for
5639 * vector to add new dataset sequence to
5640 * @param ignoreUnrefed
5641 * - when true, don't create new sequences from vamsasSeq if it's id
5642 * doesn't already have an asssociated Jalview sequence.
5644 * - used to reorder the sequence in the alignment according to the
5645 * vamsasSeq array ordering, to preserve ordering of dataset
5647 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5648 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5651 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5653 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5654 boolean reorder = false;
5655 SequenceI dsq = null;
5656 if (sq != null && sq.getDatasetSequence() != null)
5658 dsq = sq.getDatasetSequence();
5664 if (sq == null && ignoreUnrefed)
5668 String sqid = vamsasSeq.getDsseqid();
5671 // need to create or add a new dataset sequence reference to this sequence
5674 dsq = seqRefIds.get(sqid);
5679 // make a new dataset sequence
5680 dsq = sq.createDatasetSequence();
5683 // make up a new dataset reference for this sequence
5684 sqid = seqHash(dsq);
5686 dsq.setVamsasId(uniqueSetSuffix + sqid);
5687 seqRefIds.put(sqid, dsq);
5692 dseqs.addElement(dsq);
5697 ds.addSequence(dsq);
5703 { // make this dataset sequence sq's dataset sequence
5704 sq.setDatasetSequence(dsq);
5705 // and update the current dataset alignment
5710 if (!dseqs.contains(dsq))
5717 if (ds.findIndex(dsq) < 0)
5719 ds.addSequence(dsq);
5726 // TODO: refactor this as a merge dataset sequence function
5727 // now check that sq (the dataset sequence) sequence really is the union of
5728 // all references to it
5729 // boolean pre = sq.getStart() < dsq.getStart();
5730 // boolean post = sq.getEnd() > dsq.getEnd();
5734 // StringBuffer sb = new StringBuffer();
5735 String newres = jalview.analysis.AlignSeq.extractGaps(
5736 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5737 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5738 && newres.length() > dsq.getLength())
5740 // Update with the longer sequence.
5744 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5745 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5746 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5747 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5749 dsq.setSequence(newres);
5751 // TODO: merges will never happen if we 'know' we have the real dataset
5752 // sequence - this should be detected when id==dssid
5754 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5755 // + (pre ? "prepended" : "") + " "
5756 // + (post ? "appended" : ""));
5761 // sequence refs are identical. We may need to update the existing dataset
5762 // alignment with this one, though.
5763 if (ds != null && dseqs == null)
5765 int opos = ds.findIndex(dsq);
5766 SequenceI tseq = null;
5767 if (opos != -1 && vseqpos != opos)
5769 // remove from old position
5770 ds.deleteSequence(dsq);
5772 if (vseqpos < ds.getHeight())
5774 if (vseqpos != opos)
5776 // save sequence at destination position
5777 tseq = ds.getSequenceAt(vseqpos);
5778 ds.replaceSequenceAt(vseqpos, dsq);
5779 ds.addSequence(tseq);
5784 ds.addSequence(dsq);
5791 * TODO use AlignmentI here and in related methods - needs
5792 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5794 Hashtable<String, AlignmentI> datasetIds = null;
5796 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5798 private AlignmentI getDatasetFor(String datasetId)
5800 if (datasetIds == null)
5802 datasetIds = new Hashtable<>();
5805 if (datasetIds.containsKey(datasetId))
5807 return datasetIds.get(datasetId);
5812 private void addDatasetRef(String datasetId, AlignmentI dataset)
5814 if (datasetIds == null)
5816 datasetIds = new Hashtable<>();
5818 datasetIds.put(datasetId, dataset);
5822 * make a new dataset ID for this jalview dataset alignment
5827 private String getDatasetIdRef(AlignmentI dataset)
5829 if (dataset.getDataset() != null)
5832 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5834 String datasetId = makeHashCode(dataset, null);
5835 if (datasetId == null)
5837 // make a new datasetId and record it
5838 if (dataset2Ids == null)
5840 dataset2Ids = new IdentityHashMap<>();
5844 datasetId = dataset2Ids.get(dataset);
5846 if (datasetId == null)
5848 datasetId = "ds" + dataset2Ids.size() + 1;
5849 dataset2Ids.put(dataset, datasetId);
5856 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5857 * constructed as a special subclass GeneLocus.
5859 * @param datasetSequence
5862 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5864 for (int d = 0; d < sequence.getDBRef().size(); d++)
5866 DBRef dr = sequence.getDBRef().get(d);
5870 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5871 dr.getAccessionId());
5875 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5876 dr.getAccessionId());
5878 if (dr.getMapping() != null)
5880 entry.setMap(addMapping(dr.getMapping()));
5882 entry.setCanonical(dr.isCanonical());
5883 datasetSequence.addDBRef(entry);
5887 private jalview.datamodel.Mapping addMapping(Mapping m)
5889 SequenceI dsto = null;
5890 // Mapping m = dr.getMapping();
5891 int fr[] = new int[m.getMapListFrom().size() * 2];
5892 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5893 for (int _i = 0; from.hasNext(); _i += 2)
5895 MapListFrom mf = from.next();
5896 fr[_i] = mf.getStart();
5897 fr[_i + 1] = mf.getEnd();
5899 int fto[] = new int[m.getMapListTo().size() * 2];
5900 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5901 for (int _i = 0; to.hasNext(); _i += 2)
5903 MapListTo mf = to.next();
5904 fto[_i] = mf.getStart();
5905 fto[_i + 1] = mf.getEnd();
5907 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5908 fto, m.getMapFromUnit().intValue(),
5909 m.getMapToUnit().intValue());
5912 * (optional) choice of dseqFor or Sequence
5914 if (m.getDseqFor() != null)
5916 String dsfor = m.getDseqFor();
5917 if (seqRefIds.containsKey(dsfor))
5922 jmap.setTo(seqRefIds.get(dsfor));
5926 frefedSequence.add(newMappingRef(dsfor, jmap));
5929 else if (m.getSequence() != null)
5932 * local sequence definition
5934 Sequence ms = m.getSequence();
5935 SequenceI djs = null;
5936 String sqid = ms.getDsseqid();
5937 if (sqid != null && sqid.length() > 0)
5940 * recover dataset sequence
5942 djs = seqRefIds.get(sqid);
5947 "Warning - making up dataset sequence id for DbRef sequence map reference");
5948 sqid = ((Object) ms).toString(); // make up a new hascode for
5949 // undefined dataset sequence hash
5950 // (unlikely to happen)
5956 * make a new dataset sequence and add it to refIds hash
5958 djs = new jalview.datamodel.Sequence(ms.getName(),
5960 djs.setStart(jmap.getMap().getToLowest());
5961 djs.setEnd(jmap.getMap().getToHighest());
5962 djs.setVamsasId(uniqueSetSuffix + sqid);
5964 incompleteSeqs.put(sqid, djs);
5965 seqRefIds.put(sqid, djs);
5968 Console.debug("about to recurse on addDBRefs.");
5977 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5978 * view as XML (but not to file), and then reloading it
5983 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5986 JalviewModel jm = saveState(ap, null, null, null);
5989 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5990 ap.getAlignment().getDataset());
5992 uniqueSetSuffix = "";
5993 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5994 jm.getViewport().get(0).setId(null);
5995 // we don't overwrite the view we just copied
5997 if (this.frefedSequence == null)
5999 frefedSequence = new Vector<>();
6002 viewportsAdded.clear();
6004 AlignFrame af = loadFromObject(jm, null, false, null);
6005 af.getAlignPanels().clear();
6006 af.closeMenuItem_actionPerformed(true);
6009 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6010 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6011 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6012 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6013 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6016 return af.alignPanel;
6019 private Hashtable jvids2vobj;
6022 * set the object to ID mapping tables used to write/recover objects and XML
6023 * ID strings for the jalview project. If external tables are provided then
6024 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6025 * object goes out of scope. - also populates the datasetIds hashtable with
6026 * alignment objects containing dataset sequences
6029 * Map from ID strings to jalview datamodel
6031 * Map from jalview datamodel to ID strings
6035 public void setObjectMappingTables(Hashtable vobj2jv,
6036 IdentityHashMap jv2vobj)
6038 this.jv2vobj = jv2vobj;
6039 this.vobj2jv = vobj2jv;
6040 Iterator ds = jv2vobj.keySet().iterator();
6042 while (ds.hasNext())
6044 Object jvobj = ds.next();
6045 id = jv2vobj.get(jvobj).toString();
6046 if (jvobj instanceof jalview.datamodel.Alignment)
6048 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6050 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6053 else if (jvobj instanceof jalview.datamodel.Sequence)
6055 // register sequence object so the XML parser can recover it.
6056 if (seqRefIds == null)
6058 seqRefIds = new HashMap<>();
6060 if (seqsToIds == null)
6062 seqsToIds = new IdentityHashMap<>();
6064 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6065 seqsToIds.put((SequenceI) jvobj, id);
6067 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6070 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6071 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6072 if (jvann.annotationId == null)
6074 jvann.annotationId = anid;
6076 if (!jvann.annotationId.equals(anid))
6078 // TODO verify that this is the correct behaviour
6079 Console.warn("Overriding Annotation ID for " + anid
6080 + " from different id : " + jvann.annotationId);
6081 jvann.annotationId = anid;
6084 else if (jvobj instanceof String)
6086 if (jvids2vobj == null)
6088 jvids2vobj = new Hashtable();
6089 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6094 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6100 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6101 * objects created from the project archive. If string is null (default for
6102 * construction) then suffix will be set automatically.
6106 public void setUniqueSetSuffix(String string)
6108 uniqueSetSuffix = string;
6113 * uses skipList2 as the skipList for skipping views on sequence sets
6114 * associated with keys in the skipList
6118 public void setSkipList(Hashtable skipList2)
6120 skipList = skipList2;
6124 * Reads the jar entry of given name and returns its contents, or null if the
6125 * entry is not found.
6128 * @param jarEntryName
6131 protected String readJarEntry(jarInputStreamProvider jprovider,
6132 String jarEntryName)
6134 String result = null;
6135 BufferedReader in = null;
6140 * Reopen the jar input stream and traverse its entries to find a matching
6143 JarInputStream jin = jprovider.getJarInputStream();
6144 JarEntry entry = null;
6147 entry = jin.getNextJarEntry();
6148 } while (entry != null && !entry.getName().equals(jarEntryName));
6152 StringBuilder out = new StringBuilder(256);
6153 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6156 while ((data = in.readLine()) != null)
6160 result = out.toString();
6165 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6167 } catch (Exception ex)
6169 ex.printStackTrace();
6177 } catch (IOException e)
6188 * Returns an incrementing counter (0, 1, 2...)
6192 private synchronized int nextCounter()
6198 * Loads any saved PCA viewers
6203 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6207 List<PcaViewer> pcaviewers = model.getPcaViewer();
6208 for (PcaViewer viewer : pcaviewers)
6210 String modelName = viewer.getScoreModelName();
6211 SimilarityParamsI params = new SimilarityParams(
6212 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6213 viewer.isIncludeGaps(),
6214 viewer.isDenominateByShortestLength());
6217 * create the panel (without computing the PCA)
6219 PCAPanel panel = new PCAPanel(ap, modelName, params);
6221 panel.setTitle(viewer.getTitle());
6222 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6223 viewer.getWidth(), viewer.getHeight()));
6225 boolean showLabels = viewer.isShowLabels();
6226 panel.setShowLabels(showLabels);
6227 panel.getRotatableCanvas().setShowLabels(showLabels);
6228 panel.getRotatableCanvas()
6229 .setBgColour(new Color(viewer.getBgColour()));
6230 panel.getRotatableCanvas()
6231 .setApplyToAllViews(viewer.isLinkToAllViews());
6234 * load PCA output data
6236 ScoreModelI scoreModel = ScoreModels.getInstance()
6237 .getScoreModel(modelName, ap);
6238 PCA pca = new PCA(null, scoreModel, params);
6239 PcaDataType pcaData = viewer.getPcaData();
6241 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6242 pca.setPairwiseScores(pairwise);
6244 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6245 pca.setTridiagonal(triDiag);
6247 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6248 pca.setEigenmatrix(result);
6250 panel.getPcaModel().setPCA(pca);
6253 * we haven't saved the input data! (JAL-2647 to do)
6255 panel.setInputData(null);
6258 * add the sequence points for the PCA display
6260 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6261 for (SequencePoint sp : viewer.getSequencePoint())
6263 String seqId = sp.getSequenceRef();
6264 SequenceI seq = seqRefIds.get(seqId);
6267 throw new IllegalStateException(
6268 "Unmatched seqref for PCA: " + seqId);
6270 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6271 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6273 seqPoints.add(seqPoint);
6275 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6278 * set min-max ranges and scale after setPoints (which recomputes them)
6280 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6281 SeqPointMin spMin = viewer.getSeqPointMin();
6282 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6284 SeqPointMax spMax = viewer.getSeqPointMax();
6285 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6287 panel.getRotatableCanvas().setSeqMinMax(min, max);
6289 // todo: hold points list in PCAModel only
6290 panel.getPcaModel().setSequencePoints(seqPoints);
6292 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6293 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6294 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6296 // is this duplication needed?
6297 panel.setTop(seqPoints.size() - 1);
6298 panel.getPcaModel().setTop(seqPoints.size() - 1);
6301 * add the axes' end points for the display
6303 for (int i = 0; i < 3; i++)
6305 Axis axis = viewer.getAxis().get(i);
6306 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6307 axis.getXPos(), axis.getYPos(), axis.getZPos());
6310 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6311 "label.calc_title", "PCA", modelName), 475, 450);
6313 } catch (Exception ex)
6315 Console.error("Error loading PCA: " + ex.toString());
6320 * Creates a new structure viewer window
6327 protected void createStructureViewer(ViewerType viewerType,
6328 final Entry<String, StructureViewerModel> viewerData,
6329 AlignFrame af, jarInputStreamProvider jprovider)
6331 final StructureViewerModel viewerModel = viewerData.getValue();
6332 String sessionFilePath = null;
6334 if (viewerType == ViewerType.JMOL)
6336 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6340 String viewerJarEntryName = getViewerJarEntryName(
6341 viewerModel.getViewId());
6342 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6343 "viewerSession", ".tmp");
6345 final String sessionPath = sessionFilePath;
6346 final String sviewid = viewerData.getKey();
6349 SwingUtilities.invokeAndWait(new Runnable()
6354 JalviewStructureDisplayI sview = null;
6357 sview = StructureViewer.createView(viewerType, af.alignPanel,
6358 viewerModel, sessionPath, sviewid);
6359 addNewStructureViewer(sview);
6360 } catch (OutOfMemoryError ex)
6362 new OOMWarning("Restoring structure view for " + viewerType,
6363 (OutOfMemoryError) ex.getCause());
6364 if (sview != null && sview.isVisible())
6366 sview.closeViewer(false);
6367 sview.setVisible(false);
6373 } catch (InvocationTargetException | InterruptedException ex)
6375 Console.warn("Unexpected error when opening " + viewerType
6376 + " structure viewer", ex);
6381 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6382 * the path of the file. "load file" commands are rewritten to change the
6383 * original PDB file names to those created as the Jalview project is loaded.
6389 private String rewriteJmolSession(StructureViewerModel svattrib,
6390 jarInputStreamProvider jprovider)
6392 String state = svattrib.getStateData(); // Jalview < 2.9
6393 if (state == null || state.isEmpty()) // Jalview >= 2.9
6395 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6396 state = readJarEntry(jprovider, jarEntryName);
6398 // TODO or simpler? for each key in oldFiles,
6399 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6400 // (allowing for different path escapings)
6401 StringBuilder rewritten = new StringBuilder(state.length());
6402 int cp = 0, ncp, ecp;
6403 Map<File, StructureData> oldFiles = svattrib.getFileData();
6404 while ((ncp = state.indexOf("load ", cp)) > -1)
6408 // look for next filename in load statement
6409 rewritten.append(state.substring(cp,
6410 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6411 String oldfilenam = state.substring(ncp,
6412 ecp = state.indexOf("\"", ncp));
6413 // recover the new mapping data for this old filename
6414 // have to normalize filename - since Jmol and jalview do
6415 // filename translation differently.
6416 StructureData filedat = oldFiles.get(new File(oldfilenam));
6417 if (filedat == null)
6419 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6420 filedat = oldFiles.get(new File(reformatedOldFilename));
6422 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6423 rewritten.append("\"");
6424 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6425 // look for next file statement.
6426 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6430 // just append rest of state
6431 rewritten.append(state.substring(cp));
6435 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6436 rewritten = new StringBuilder(state);
6437 rewritten.append("; load append ");
6438 for (File id : oldFiles.keySet())
6440 // add pdb files that should be present in the viewer
6441 StructureData filedat = oldFiles.get(id);
6442 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6444 rewritten.append(";");
6447 if (rewritten.length() == 0)
6451 final String history = "history = ";
6452 int historyIndex = rewritten.indexOf(history);
6453 if (historyIndex > -1)
6456 * change "history = [true|false];" to "history = [1|0];"
6458 historyIndex += history.length();
6459 String val = rewritten.substring(historyIndex, historyIndex + 5);
6460 if (val.startsWith("true"))
6462 rewritten.replace(historyIndex, historyIndex + 4, "1");
6464 else if (val.startsWith("false"))
6466 rewritten.replace(historyIndex, historyIndex + 5, "0");
6472 File tmp = File.createTempFile("viewerSession", ".tmp");
6473 try (OutputStream os = new FileOutputStream(tmp))
6475 InputStream is = new ByteArrayInputStream(
6476 rewritten.toString().getBytes());
6478 return tmp.getAbsolutePath();
6480 } catch (IOException e)
6482 Console.error("Error restoring Jmol session: " + e.toString());
6488 * Populates an XML model of the feature colour scheme for one feature type
6490 * @param featureType
6494 public static Colour marshalColour(String featureType,
6495 FeatureColourI fcol)
6497 Colour col = new Colour();
6498 if (fcol.isSimpleColour())
6500 col.setRGB(Format.getHexString(fcol.getColour()));
6504 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6505 col.setMin(fcol.getMin());
6506 col.setMax(fcol.getMax());
6507 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6508 col.setAutoScale(fcol.isAutoScaled());
6509 col.setThreshold(fcol.getThreshold());
6510 col.setColourByLabel(fcol.isColourByLabel());
6511 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6512 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6513 : ThresholdType.NONE));
6514 if (fcol.isColourByAttribute())
6516 final String[] attName = fcol.getAttributeName();
6517 col.getAttributeName().add(attName[0]);
6518 if (attName.length > 1)
6520 col.getAttributeName().add(attName[1]);
6523 Color noColour = fcol.getNoColour();
6524 if (noColour == null)
6526 col.setNoValueColour(NoValueColour.NONE);
6528 else if (noColour == fcol.getMaxColour())
6530 col.setNoValueColour(NoValueColour.MAX);
6534 col.setNoValueColour(NoValueColour.MIN);
6537 col.setName(featureType);
6542 * Populates an XML model of the feature filter(s) for one feature type
6544 * @param firstMatcher
6545 * the first (or only) match condition)
6547 * remaining match conditions (if any)
6549 * if true, conditions are and-ed, else or-ed
6551 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6552 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6555 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6557 if (filters.hasNext())
6562 CompoundMatcher compound = new CompoundMatcher();
6563 compound.setAnd(and);
6564 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6565 firstMatcher, Collections.emptyIterator(), and);
6566 // compound.addMatcherSet(matcher1);
6567 compound.getMatcherSet().add(matcher1);
6568 FeatureMatcherI nextMatcher = filters.next();
6569 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6570 nextMatcher, filters, and);
6571 // compound.addMatcherSet(matcher2);
6572 compound.getMatcherSet().add(matcher2);
6573 result.setCompoundMatcher(compound);
6578 * single condition matcher
6580 // MatchCondition matcherModel = new MatchCondition();
6581 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6582 matcherModel.setCondition(
6583 firstMatcher.getMatcher().getCondition().getStableName());
6584 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6585 if (firstMatcher.isByAttribute())
6587 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6588 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6589 String[] attName = firstMatcher.getAttribute();
6590 matcherModel.getAttributeName().add(attName[0]); // attribute
6591 if (attName.length > 1)
6593 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6596 else if (firstMatcher.isByLabel())
6598 matcherModel.setBy(FilterBy.BY_LABEL);
6600 else if (firstMatcher.isByScore())
6602 matcherModel.setBy(FilterBy.BY_SCORE);
6604 result.setMatchCondition(matcherModel);
6611 * Loads one XML model of a feature filter to a Jalview object
6613 * @param featureType
6614 * @param matcherSetModel
6617 public static FeatureMatcherSetI parseFilter(String featureType,
6618 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6620 FeatureMatcherSetI result = new FeatureMatcherSet();
6623 parseFilterConditions(result, matcherSetModel, true);
6624 } catch (IllegalStateException e)
6626 // mixing AND and OR conditions perhaps
6628 String.format("Error reading filter conditions for '%s': %s",
6629 featureType, e.getMessage()));
6630 // return as much as was parsed up to the error
6637 * Adds feature match conditions to matcherSet as unmarshalled from XML
6638 * (possibly recursively for compound conditions)
6641 * @param matcherSetModel
6643 * if true, multiple conditions are AND-ed, else they are OR-ed
6644 * @throws IllegalStateException
6645 * if AND and OR conditions are mixed
6647 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6648 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6651 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6652 .getMatchCondition();
6658 FilterBy filterBy = mc.getBy();
6659 Condition cond = Condition.fromString(mc.getCondition());
6660 String pattern = mc.getValue();
6661 FeatureMatcherI matchCondition = null;
6662 if (filterBy == FilterBy.BY_LABEL)
6664 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6666 else if (filterBy == FilterBy.BY_SCORE)
6668 matchCondition = FeatureMatcher.byScore(cond, pattern);
6671 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6673 final List<String> attributeName = mc.getAttributeName();
6674 String[] attNames = attributeName
6675 .toArray(new String[attributeName.size()]);
6676 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6681 * note this throws IllegalStateException if AND-ing to a
6682 * previously OR-ed compound condition, or vice versa
6686 matcherSet.and(matchCondition);
6690 matcherSet.or(matchCondition);
6696 * compound condition
6698 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6699 .getCompoundMatcher().getMatcherSet();
6700 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6701 if (matchers.size() == 2)
6703 parseFilterConditions(matcherSet, matchers.get(0), anded);
6704 parseFilterConditions(matcherSet, matchers.get(1), anded);
6708 System.err.println("Malformed compound filter condition");
6714 * Loads one XML model of a feature colour to a Jalview object
6716 * @param colourModel
6719 public static FeatureColourI parseColour(Colour colourModel)
6721 FeatureColourI colour = null;
6723 if (colourModel.getMax() != null)
6725 Color mincol = null;
6726 Color maxcol = null;
6727 Color noValueColour = null;
6731 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6732 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6733 } catch (Exception e)
6735 Console.warn("Couldn't parse out graduated feature color.", e);
6738 NoValueColour noCol = colourModel.getNoValueColour();
6739 if (noCol == NoValueColour.MIN)
6741 noValueColour = mincol;
6743 else if (noCol == NoValueColour.MAX)
6745 noValueColour = maxcol;
6748 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6749 safeFloat(colourModel.getMin()),
6750 safeFloat(colourModel.getMax()));
6751 final List<String> attributeName = colourModel.getAttributeName();
6752 String[] attributes = attributeName
6753 .toArray(new String[attributeName.size()]);
6754 if (attributes != null && attributes.length > 0)
6756 colour.setAttributeName(attributes);
6758 if (colourModel.isAutoScale() != null)
6760 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6762 if (colourModel.isColourByLabel() != null)
6764 colour.setColourByLabel(
6765 colourModel.isColourByLabel().booleanValue());
6767 if (colourModel.getThreshold() != null)
6769 colour.setThreshold(colourModel.getThreshold().floatValue());
6771 ThresholdType ttyp = colourModel.getThreshType();
6772 if (ttyp == ThresholdType.ABOVE)
6774 colour.setAboveThreshold(true);
6776 else if (ttyp == ThresholdType.BELOW)
6778 colour.setBelowThreshold(true);
6783 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6784 colour = new FeatureColour(color);
6790 public static void setStateSavedUpToDate(boolean s)
6792 Console.debug("Setting overall stateSavedUpToDate to " + s);
6793 stateSavedUpToDate = s;
6796 public static boolean stateSavedUpToDate()
6798 Console.debug("Returning overall stateSavedUpToDate value: "
6799 + stateSavedUpToDate);
6800 return stateSavedUpToDate;
6803 public static boolean allSavedUpToDate()
6805 if (stateSavedUpToDate()) // nothing happened since last project save
6808 AlignFrame[] frames = Desktop.getAlignFrames();
6811 for (int i = 0; i < frames.length; i++)
6813 if (frames[i] == null)
6815 if (!frames[i].getViewport().savedUpToDate())
6816 return false; // at least one alignment is not individually saved
6822 // used for debugging and tests
6823 private static int debugDelaySave = 20;
6825 public static void setDebugDelaySave(int n)