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.getContactMatrixFor(annotation);
2314 MatrixType xmlmat = new MatrixType();
2315 xmlmat.setType(cm.getType());
2316 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2317 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2318 // consider using an opaque to/from -> allow instance to control its representation ?
2319 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2322 for (BitSet gp: cm.getGroups())
2324 BigInteger val = new BigInteger(gp.toByteArray());
2325 xmlmat.getGroups().add(val.toString());
2330 // provenance object for tree ?
2331 xmlmat.getNewick().add(cm.getNewick());
2332 xmlmat.setTreeMethod(cm.getTreeMethod());
2334 if (cm.hasCutHeight())
2336 xmlmat.setCutHeight(cm.getCutHeight());
2339 // set/get properties
2340 an.getContactmatrix().add(xmlmat);
2350 an.setLabel(annotation.label);
2352 if (annotation == av.getAlignmentQualityAnnot()
2353 || annotation == av.getAlignmentConservationAnnotation()
2354 || annotation == av.getAlignmentConsensusAnnotation()
2355 || annotation.autoCalculated)
2357 // new way of indicating autocalculated annotation -
2358 an.setAutoCalculated(annotation.autoCalculated);
2360 if (annotation.hasScore())
2362 an.setScore(annotation.getScore());
2365 if (annotation.getCalcId() != null)
2367 calcIdSet.add(annotation.getCalcId());
2368 an.setCalcId(annotation.getCalcId());
2370 if (annotation.hasProperties())
2372 for (String pr : annotation.getProperties())
2374 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2376 prop.setValue(annotation.getProperty(pr));
2377 an.getProperty().add(prop);
2381 AnnotationElement ae;
2382 if (annotation.annotations != null)
2384 an.setScoreOnly(false);
2385 for (int a = 0; a < annotation.annotations.length; a++)
2387 if ((annotation == null) || (annotation.annotations[a] == null))
2392 ae = new AnnotationElement();
2393 if (annotation.annotations[a].description != null)
2395 ae.setDescription(annotation.annotations[a].description);
2397 if (annotation.annotations[a].displayCharacter != null)
2399 ae.setDisplayCharacter(
2400 annotation.annotations[a].displayCharacter);
2403 if (!Float.isNaN(annotation.annotations[a].value))
2405 ae.setValue(annotation.annotations[a].value);
2409 if (annotation.annotations[a].secondaryStructure > ' ')
2411 ae.setSecondaryStructure(
2412 annotation.annotations[a].secondaryStructure + "");
2415 if (annotation.annotations[a].colour != null
2416 && annotation.annotations[a].colour != java.awt.Color.black)
2418 ae.setColour(annotation.annotations[a].colour.getRGB());
2421 // an.addAnnotationElement(ae);
2422 an.getAnnotationElement().add(ae);
2423 if (annotation.autoCalculated)
2425 // only write one non-null entry into the annotation row -
2426 // sufficient to get the visualization attributes necessary to
2434 an.setScoreOnly(true);
2436 if (!storeDS || (storeDS && !annotation.autoCalculated))
2438 // skip autocalculated annotation - these are only provided for
2440 // vamsasSet.addAnnotation(an);
2441 vamsasSet.getAnnotation().add(an);
2447 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2449 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2450 if (settings != null)
2452 CalcIdParam vCalcIdParam = new CalcIdParam();
2453 vCalcIdParam.setCalcId(calcId);
2454 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2455 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2456 // generic URI allowing a third party to resolve another instance of the
2457 // service used for this calculation
2458 for (String url : settings.getServiceURLs())
2460 // vCalcIdParam.addServiceURL(urls);
2461 vCalcIdParam.getServiceURL().add(url);
2463 vCalcIdParam.setVersion("1.0");
2464 if (settings.getPreset() != null)
2466 WsParamSetI setting = settings.getPreset();
2467 vCalcIdParam.setName(setting.getName());
2468 vCalcIdParam.setDescription(setting.getDescription());
2472 vCalcIdParam.setName("");
2473 vCalcIdParam.setDescription("Last used parameters");
2475 // need to be able to recover 1) settings 2) user-defined presets or
2476 // recreate settings from preset 3) predefined settings provided by
2477 // service - or settings that can be transferred (or discarded)
2478 vCalcIdParam.setParameters(
2479 settings.getWsParamFile().replace("\n", "|\\n|"));
2480 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2481 // todo - decide if updateImmediately is needed for any projects.
2483 return vCalcIdParam;
2488 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2491 if (calcIdParam.getVersion().equals("1.0"))
2493 final String[] calcIds = calcIdParam.getServiceURL()
2494 .toArray(new String[0]);
2495 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2496 .getPreferredServiceFor(calcIds);
2497 if (service != null)
2499 WsParamSetI parmSet = null;
2502 parmSet = service.getParamStore().parseServiceParameterFile(
2503 calcIdParam.getName(), calcIdParam.getDescription(),
2505 calcIdParam.getParameters().replace("|\\n|", "\n"));
2506 } catch (IOException x)
2508 Console.warn("Couldn't parse parameter data for "
2509 + calcIdParam.getCalcId(), x);
2512 List<ArgumentI> argList = null;
2513 if (calcIdParam.getName().length() > 0)
2515 parmSet = service.getParamStore()
2516 .getPreset(calcIdParam.getName());
2517 if (parmSet != null)
2519 // TODO : check we have a good match with settings in AACon -
2520 // otherwise we'll need to create a new preset
2525 argList = parmSet.getArguments();
2528 AAConSettings settings = new AAConSettings(
2529 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2530 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2531 calcIdParam.isNeedsUpdate());
2537 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2541 throw new Error(MessageManager.formatMessage(
2542 "error.unsupported_version_calcIdparam", new Object[]
2543 { calcIdParam.toString() }));
2547 * External mapping between jalview objects and objects yielding a valid and
2548 * unique object ID string. This is null for normal Jalview project IO, but
2549 * non-null when a jalview project is being read or written as part of a
2552 IdentityHashMap jv2vobj = null;
2555 * Construct a unique ID for jvobj using either existing bindings or if none
2556 * exist, the result of the hashcode call for the object.
2559 * jalview data object
2560 * @return unique ID for referring to jvobj
2562 private String makeHashCode(Object jvobj, String altCode)
2564 if (jv2vobj != null)
2566 Object id = jv2vobj.get(jvobj);
2569 return id.toString();
2571 // check string ID mappings
2572 if (jvids2vobj != null && jvobj instanceof String)
2574 id = jvids2vobj.get(jvobj);
2578 return id.toString();
2580 // give up and warn that something has gone wrong
2582 "Cannot find ID for object in external mapping : " + jvobj);
2588 * return local jalview object mapped to ID, if it exists
2592 * @return null or object bound to idcode
2594 private Object retrieveExistingObj(String idcode)
2596 if (idcode != null && vobj2jv != null)
2598 return vobj2jv.get(idcode);
2604 * binding from ID strings from external mapping table to jalview data model
2607 private Hashtable vobj2jv;
2609 private Sequence createVamsasSequence(String id, SequenceI jds)
2611 return createVamsasSequence(true, id, jds, null);
2614 private Sequence createVamsasSequence(boolean recurse, String id,
2615 SequenceI jds, SequenceI parentseq)
2617 Sequence vamsasSeq = new Sequence();
2618 vamsasSeq.setId(id);
2619 vamsasSeq.setName(jds.getName());
2620 vamsasSeq.setSequence(jds.getSequenceAsString());
2621 vamsasSeq.setDescription(jds.getDescription());
2622 List<DBRefEntry> dbrefs = null;
2623 if (jds.getDatasetSequence() != null)
2625 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2629 // seqId==dsseqid so we can tell which sequences really are
2630 // dataset sequences only
2631 vamsasSeq.setDsseqid(id);
2632 dbrefs = jds.getDBRefs();
2633 if (parentseq == null)
2640 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2644 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2646 DBRef dbref = new DBRef();
2647 DBRefEntry ref = dbrefs.get(d);
2648 dbref.setSource(ref.getSource());
2649 dbref.setVersion(ref.getVersion());
2650 dbref.setAccessionId(ref.getAccessionId());
2651 dbref.setCanonical(ref.isCanonical());
2652 if (ref instanceof GeneLocus)
2654 dbref.setLocus(true);
2658 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2660 dbref.setMapping(mp);
2662 vamsasSeq.getDBRef().add(dbref);
2668 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2669 SequenceI parentseq, SequenceI jds, boolean recurse)
2672 if (jmp.getMap() != null)
2676 jalview.util.MapList mlst = jmp.getMap();
2677 List<int[]> r = mlst.getFromRanges();
2678 for (int[] range : r)
2680 MapListFrom mfrom = new MapListFrom();
2681 mfrom.setStart(range[0]);
2682 mfrom.setEnd(range[1]);
2683 // mp.addMapListFrom(mfrom);
2684 mp.getMapListFrom().add(mfrom);
2686 r = mlst.getToRanges();
2687 for (int[] range : r)
2689 MapListTo mto = new MapListTo();
2690 mto.setStart(range[0]);
2691 mto.setEnd(range[1]);
2692 // mp.addMapListTo(mto);
2693 mp.getMapListTo().add(mto);
2695 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2696 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2697 if (jmp.getTo() != null)
2699 // MappingChoice mpc = new MappingChoice();
2701 // check/create ID for the sequence referenced by getTo()
2704 SequenceI ps = null;
2705 if (parentseq != jmp.getTo()
2706 && parentseq.getDatasetSequence() != jmp.getTo())
2708 // chaining dbref rather than a handshaking one
2709 jmpid = seqHash(ps = jmp.getTo());
2713 jmpid = seqHash(ps = parentseq);
2715 // mpc.setDseqFor(jmpid);
2716 mp.setDseqFor(jmpid);
2717 if (!seqRefIds.containsKey(jmpid))
2719 Console.debug("creatign new DseqFor ID");
2720 seqRefIds.put(jmpid, ps);
2724 Console.debug("reusing DseqFor ID");
2727 // mp.setMappingChoice(mpc);
2733 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2734 List<UserColourScheme> userColours, JalviewModel jm)
2737 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2738 boolean newucs = false;
2739 if (!userColours.contains(ucs))
2741 userColours.add(ucs);
2744 id = "ucs" + userColours.indexOf(ucs);
2747 // actually create the scheme's entry in the XML model
2748 java.awt.Color[] colours = ucs.getColours();
2749 UserColours uc = new UserColours();
2750 // UserColourScheme jbucs = new UserColourScheme();
2751 JalviewUserColours jbucs = new JalviewUserColours();
2753 for (int i = 0; i < colours.length; i++)
2755 Colour col = new Colour();
2756 col.setName(ResidueProperties.aa[i]);
2757 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2758 // jbucs.addColour(col);
2759 jbucs.getColour().add(col);
2761 if (ucs.getLowerCaseColours() != null)
2763 colours = ucs.getLowerCaseColours();
2764 for (int i = 0; i < colours.length; i++)
2766 Colour col = new Colour();
2767 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2768 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2769 // jbucs.addColour(col);
2770 jbucs.getColour().add(col);
2775 uc.setUserColourScheme(jbucs);
2776 // jm.addUserColours(uc);
2777 jm.getUserColours().add(uc);
2783 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2786 List<UserColours> uc = jm.getUserColours();
2787 UserColours colours = null;
2789 for (int i = 0; i < uc.length; i++)
2791 if (uc[i].getId().equals(id))
2798 for (UserColours c : uc)
2800 if (c.getId().equals(id))
2807 java.awt.Color[] newColours = new java.awt.Color[24];
2809 for (int i = 0; i < 24; i++)
2811 newColours[i] = new java.awt.Color(Integer.parseInt(
2812 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2813 colours.getUserColourScheme().getColour().get(i).getRGB(),
2817 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2820 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2822 newColours = new java.awt.Color[23];
2823 for (int i = 0; i < 23; i++)
2825 newColours[i] = new java.awt.Color(
2826 Integer.parseInt(colours.getUserColourScheme().getColour()
2827 .get(i + 24).getRGB(), 16));
2829 ucs.setLowerCaseColours(newColours);
2836 * contains last error message (if any) encountered by XML loader.
2838 String errorMessage = null;
2841 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2842 * exceptions are raised during project XML parsing
2844 public boolean attemptversion1parse = false;
2847 * Load a jalview project archive from a jar file
2850 * - HTTP URL or filename
2852 public AlignFrame loadJalviewAlign(final Object file)
2855 jalview.gui.AlignFrame af = null;
2859 // create list to store references for any new Jmol viewers created
2860 newStructureViewers = new Vector<>();
2861 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2862 // Workaround is to make sure caller implements the JarInputStreamProvider
2864 // so we can re-open the jar input stream for each entry.
2866 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2867 af = loadJalviewAlign(jprovider);
2870 af.setMenusForViewport();
2872 } catch (MalformedURLException e)
2874 errorMessage = "Invalid URL format for '" + file + "'";
2880 SwingUtilities.invokeAndWait(new Runnable()
2885 setLoadingFinishedForNewStructureViewers();
2888 } catch (Exception x)
2890 System.err.println("Error loading alignment: " + x.getMessage());
2896 @SuppressWarnings("unused")
2897 private jarInputStreamProvider createjarInputStreamProvider(
2898 final Object ofile) throws MalformedURLException
2901 // BH 2018 allow for bytes already attached to File object
2904 String file = (ofile instanceof File
2905 ? ((File) ofile).getCanonicalPath()
2906 : ofile.toString());
2907 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2910 errorMessage = null;
2911 uniqueSetSuffix = null;
2913 viewportsAdded.clear();
2914 frefedSequence = null;
2916 if (HttpUtils.startsWithHttpOrHttps(file))
2918 url = new URL(file);
2920 final URL _url = url;
2921 return new jarInputStreamProvider()
2925 public JarInputStream getJarInputStream() throws IOException
2929 // System.out.println("Jalview2XML: opening byte jarInputStream for
2930 // bytes.length=" + bytes.length);
2931 return new JarInputStream(new ByteArrayInputStream(bytes));
2935 // System.out.println("Jalview2XML: opening url jarInputStream for "
2937 return new JarInputStream(_url.openStream());
2941 // System.out.println("Jalview2XML: opening file jarInputStream for
2943 return new JarInputStream(new FileInputStream(file));
2948 public String getFilename()
2953 } catch (IOException e)
2955 e.printStackTrace();
2961 * Recover jalview session from a jalview project archive. Caller may
2962 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2963 * themselves. Any null fields will be initialised with default values,
2964 * non-null fields are left alone.
2969 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2971 errorMessage = null;
2972 if (uniqueSetSuffix == null)
2974 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2976 if (seqRefIds == null)
2980 AlignFrame af = null, _af = null;
2981 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2982 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2983 final String file = jprovider.getFilename();
2986 JarInputStream jin = null;
2987 JarEntry jarentry = null;
2992 jin = jprovider.getJarInputStream();
2993 for (int i = 0; i < entryCount; i++)
2995 jarentry = jin.getNextJarEntry();
2998 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3000 JAXBContext jc = JAXBContext
3001 .newInstance("jalview.xml.binding.jalview");
3002 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3003 .createXMLStreamReader(jin);
3004 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3005 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3006 JalviewModel.class);
3007 JalviewModel object = jbe.getValue();
3009 if (true) // !skipViewport(object))
3011 _af = loadFromObject(object, file, true, jprovider);
3012 if (_af != null && object.getViewport().size() > 0)
3013 // getJalviewModelSequence().getViewportCount() > 0)
3017 // store a reference to the first view
3020 if (_af.getViewport().isGatherViewsHere())
3022 // if this is a gathered view, keep its reference since
3023 // after gathering views, only this frame will remain
3025 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3028 // Save dataset to register mappings once all resolved
3029 importedDatasets.put(
3030 af.getViewport().getAlignment().getDataset(),
3031 af.getViewport().getAlignment().getDataset());
3036 else if (jarentry != null)
3038 // Some other file here.
3041 } while (jarentry != null);
3043 resolveFrefedSequences();
3044 } catch (IOException ex)
3046 ex.printStackTrace();
3047 errorMessage = "Couldn't locate Jalview XML file : " + file;
3049 "Exception whilst loading jalview XML file : " + ex + "\n");
3050 } catch (Exception ex)
3052 System.err.println("Parsing as Jalview Version 2 file failed.");
3053 ex.printStackTrace(System.err);
3054 if (attemptversion1parse)
3056 // used to attempt to parse as V1 castor-generated xml
3058 if (Desktop.instance != null)
3060 Desktop.instance.stopLoading();
3064 System.out.println("Successfully loaded archive file");
3067 ex.printStackTrace();
3070 "Exception whilst loading jalview XML file : " + ex + "\n");
3071 } catch (OutOfMemoryError e)
3073 // Don't use the OOM Window here
3074 errorMessage = "Out of memory loading jalview XML file";
3075 System.err.println("Out of memory whilst loading jalview XML file");
3076 e.printStackTrace();
3080 * Regather multiple views (with the same sequence set id) to the frame (if
3081 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3082 * views instead of separate frames. Note this doesn't restore a state where
3083 * some expanded views in turn have tabbed views - the last "first tab" read
3084 * in will play the role of gatherer for all.
3086 for (AlignFrame fr : gatherToThisFrame.values())
3088 Desktop.instance.gatherViews(fr);
3091 restoreSplitFrames();
3092 for (AlignmentI ds : importedDatasets.keySet())
3094 if (ds.getCodonFrames() != null)
3096 StructureSelectionManager
3097 .getStructureSelectionManager(Desktop.instance)
3098 .registerMappings(ds.getCodonFrames());
3101 if (errorMessage != null)
3106 if (Desktop.instance != null)
3108 Desktop.instance.stopLoading();
3115 * Try to reconstruct and display SplitFrame windows, where each contains
3116 * complementary dna and protein alignments. Done by pairing up AlignFrame
3117 * objects (created earlier) which have complementary viewport ids associated.
3119 protected void restoreSplitFrames()
3121 List<SplitFrame> gatherTo = new ArrayList<>();
3122 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3123 Map<String, AlignFrame> dna = new HashMap<>();
3126 * Identify the DNA alignments
3128 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3131 AlignFrame af = candidate.getValue();
3132 if (af.getViewport().getAlignment().isNucleotide())
3134 dna.put(candidate.getKey().getId(), af);
3139 * Try to match up the protein complements
3141 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3144 AlignFrame af = candidate.getValue();
3145 if (!af.getViewport().getAlignment().isNucleotide())
3147 String complementId = candidate.getKey().getComplementId();
3148 // only non-null complements should be in the Map
3149 if (complementId != null && dna.containsKey(complementId))
3151 final AlignFrame dnaFrame = dna.get(complementId);
3152 SplitFrame sf = createSplitFrame(dnaFrame, af);
3153 addedToSplitFrames.add(dnaFrame);
3154 addedToSplitFrames.add(af);
3155 dnaFrame.setMenusForViewport();
3156 af.setMenusForViewport();
3157 if (af.getViewport().isGatherViewsHere())
3166 * Open any that we failed to pair up (which shouldn't happen!) as
3167 * standalone AlignFrame's.
3169 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3172 AlignFrame af = candidate.getValue();
3173 if (!addedToSplitFrames.contains(af))
3175 Viewport view = candidate.getKey();
3176 Desktop.addInternalFrame(af, view.getTitle(),
3177 safeInt(view.getWidth()), safeInt(view.getHeight()));
3178 af.setMenusForViewport();
3179 System.err.println("Failed to restore view " + view.getTitle()
3180 + " to split frame");
3185 * Gather back into tabbed views as flagged.
3187 for (SplitFrame sf : gatherTo)
3189 Desktop.instance.gatherViews(sf);
3192 splitFrameCandidates.clear();
3196 * Construct and display one SplitFrame holding DNA and protein alignments.
3199 * @param proteinFrame
3202 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3203 AlignFrame proteinFrame)
3205 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3206 String title = MessageManager.getString("label.linked_view_title");
3207 int width = (int) dnaFrame.getBounds().getWidth();
3208 int height = (int) (dnaFrame.getBounds().getHeight()
3209 + proteinFrame.getBounds().getHeight() + 50);
3212 * SplitFrame location is saved to both enclosed frames
3214 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3215 Desktop.addInternalFrame(splitFrame, title, width, height);
3218 * And compute cDNA consensus (couldn't do earlier with consensus as
3219 * mappings were not yet present)
3221 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3227 * check errorMessage for a valid error message and raise an error box in the
3228 * GUI or write the current errorMessage to stderr and then clear the error
3231 protected void reportErrors()
3233 reportErrors(false);
3236 protected void reportErrors(final boolean saving)
3238 if (errorMessage != null)
3240 final String finalErrorMessage = errorMessage;
3243 javax.swing.SwingUtilities.invokeLater(new Runnable()
3248 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3250 "Error " + (saving ? "saving" : "loading")
3252 JvOptionPane.WARNING_MESSAGE);
3258 System.err.println("Problem loading Jalview file: " + errorMessage);
3261 errorMessage = null;
3264 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3267 * when set, local views will be updated from view stored in JalviewXML
3268 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3269 * sync if this is set to true.
3271 private final boolean updateLocalViews = false;
3274 * Returns the path to a temporary file holding the PDB file for the given PDB
3275 * id. The first time of asking, searches for a file of that name in the
3276 * Jalview project jar, and copies it to a new temporary file. Any repeat
3277 * requests just return the path to the file previously created.
3283 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3286 if (alreadyLoadedPDB.containsKey(pdbId))
3288 return alreadyLoadedPDB.get(pdbId).toString();
3291 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3293 if (tempFile != null)
3295 alreadyLoadedPDB.put(pdbId, tempFile);
3301 * Copies the jar entry of given name to a new temporary file and returns the
3302 * path to the file, or null if the entry is not found.
3305 * @param jarEntryName
3307 * a prefix for the temporary file name, must be at least three
3309 * @param suffixModel
3310 * null or original file - so new file can be given the same suffix
3314 protected String copyJarEntry(jarInputStreamProvider jprovider,
3315 String jarEntryName, String prefix, String suffixModel)
3317 String suffix = ".tmp";
3318 if (suffixModel == null)
3320 suffixModel = jarEntryName;
3322 int sfpos = suffixModel.lastIndexOf(".");
3323 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3325 suffix = "." + suffixModel.substring(sfpos + 1);
3328 try (JarInputStream jin = jprovider.getJarInputStream())
3330 JarEntry entry = null;
3333 entry = jin.getNextJarEntry();
3334 } while (entry != null && !entry.getName().equals(jarEntryName));
3338 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3339 File outFile = File.createTempFile(prefix, suffix);
3340 outFile.deleteOnExit();
3341 try (OutputStream os = new FileOutputStream(outFile))
3345 String t = outFile.getAbsolutePath();
3351 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3353 } catch (Exception ex)
3355 ex.printStackTrace();
3361 private class JvAnnotRow
3363 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3370 * persisted version of annotation row from which to take vis properties
3372 public jalview.datamodel.AlignmentAnnotation template;
3375 * original position of the annotation row in the alignment
3381 * Load alignment frame from jalview XML DOM object
3383 * @param jalviewModel
3386 * filename source string
3387 * @param loadTreesAndStructures
3388 * when false only create Viewport
3390 * data source provider
3391 * @return alignment frame created from view stored in DOM
3393 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3394 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3396 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3398 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3400 // JalviewModelSequence jms = object.getJalviewModelSequence();
3402 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3404 Viewport view = (jalviewModel.getViewport().size() > 0)
3405 ? jalviewModel.getViewport().get(0)
3408 // ////////////////////////////////
3409 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3412 // If we just load in the same jar file again, the sequenceSetId
3413 // will be the same, and we end up with multiple references
3414 // to the same sequenceSet. We must modify this id on load
3415 // so that each load of the file gives a unique id
3418 * used to resolve correct alignment dataset for alignments with multiple
3421 String uniqueSeqSetId = null;
3422 String viewId = null;
3425 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3426 viewId = (view.getId() == null ? null
3427 : view.getId() + uniqueSetSuffix);
3430 // ////////////////////////////////
3433 List<SequenceI> hiddenSeqs = null;
3435 List<SequenceI> tmpseqs = new ArrayList<>();
3437 boolean multipleView = false;
3438 SequenceI referenceseqForView = null;
3439 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3440 List<JSeq> jseqs = jalviewModel.getJSeq();
3441 int vi = 0; // counter in vamsasSeq array
3442 for (int i = 0; i < jseqs.size(); i++)
3444 JSeq jseq = jseqs.get(i);
3445 String seqId = jseq.getId();
3447 SequenceI tmpSeq = seqRefIds.get(seqId);
3450 if (!incompleteSeqs.containsKey(seqId))
3452 // may not need this check, but keep it for at least 2.9,1 release
3453 if (tmpSeq.getStart() != jseq.getStart()
3454 || tmpSeq.getEnd() != jseq.getEnd())
3456 System.err.println(String.format(
3457 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3458 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3459 jseq.getStart(), jseq.getEnd()));
3464 incompleteSeqs.remove(seqId);
3466 if (vamsasSeqs.size() > vi
3467 && vamsasSeqs.get(vi).getId().equals(seqId))
3469 // most likely we are reading a dataset XML document so
3470 // update from vamsasSeq section of XML for this sequence
3471 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3472 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3473 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3478 // reading multiple views, so vamsasSeq set is a subset of JSeq
3479 multipleView = true;
3481 tmpSeq.setStart(jseq.getStart());
3482 tmpSeq.setEnd(jseq.getEnd());
3483 tmpseqs.add(tmpSeq);
3487 Sequence vamsasSeq = vamsasSeqs.get(vi);
3488 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3489 vamsasSeq.getSequence());
3490 tmpSeq.setDescription(vamsasSeq.getDescription());
3491 tmpSeq.setStart(jseq.getStart());
3492 tmpSeq.setEnd(jseq.getEnd());
3493 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3494 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3495 tmpseqs.add(tmpSeq);
3499 if (safeBoolean(jseq.isViewreference()))
3501 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3504 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3506 if (hiddenSeqs == null)
3508 hiddenSeqs = new ArrayList<>();
3511 hiddenSeqs.add(tmpSeq);
3516 // Create the alignment object from the sequence set
3517 // ///////////////////////////////
3518 SequenceI[] orderedSeqs = tmpseqs
3519 .toArray(new SequenceI[tmpseqs.size()]);
3521 AlignmentI al = null;
3522 // so we must create or recover the dataset alignment before going further
3523 // ///////////////////////////////
3524 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3526 // older jalview projects do not have a dataset - so creat alignment and
3528 al = new Alignment(orderedSeqs);
3529 al.setDataset(null);
3533 boolean isdsal = jalviewModel.getViewport().isEmpty();
3536 // we are importing a dataset record, so
3537 // recover reference to an alignment already materialsed as dataset
3538 al = getDatasetFor(vamsasSet.getDatasetId());
3542 // materialse the alignment
3543 al = new Alignment(orderedSeqs);
3547 addDatasetRef(vamsasSet.getDatasetId(), al);
3550 // finally, verify all data in vamsasSet is actually present in al
3551 // passing on flag indicating if it is actually a stored dataset
3552 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3555 if (referenceseqForView != null)
3557 al.setSeqrep(referenceseqForView);
3559 // / Add the alignment properties
3560 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3562 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3564 al.setProperty(ssp.getKey(), ssp.getValue());
3567 // ///////////////////////////////
3569 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3572 // load sequence features, database references and any associated PDB
3573 // structures for the alignment
3575 // prior to 2.10, this part would only be executed the first time a
3576 // sequence was encountered, but not afterwards.
3577 // now, for 2.10 projects, this is also done if the xml doc includes
3578 // dataset sequences not actually present in any particular view.
3580 for (int i = 0; i < vamsasSeqs.size(); i++)
3582 JSeq jseq = jseqs.get(i);
3583 if (jseq.getFeatures().size() > 0)
3585 List<Feature> features = jseq.getFeatures();
3586 for (int f = 0; f < features.size(); f++)
3588 Feature feat = features.get(f);
3589 SequenceFeature sf = new SequenceFeature(feat.getType(),
3590 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3591 safeFloat(feat.getScore()), feat.getFeatureGroup());
3592 sf.setStatus(feat.getStatus());
3595 * load any feature attributes - include map-valued attributes
3597 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3598 for (int od = 0; od < feat.getOtherData().size(); od++)
3600 OtherData keyValue = feat.getOtherData().get(od);
3601 String attributeName = keyValue.getKey();
3602 String attributeValue = keyValue.getValue();
3603 if (attributeName.startsWith("LINK"))
3605 sf.addLink(attributeValue);
3609 String subAttribute = keyValue.getKey2();
3610 if (subAttribute == null)
3612 // simple string-valued attribute
3613 sf.setValue(attributeName, attributeValue);
3617 // attribute 'key' has sub-attribute 'key2'
3618 if (!mapAttributes.containsKey(attributeName))
3620 mapAttributes.put(attributeName, new HashMap<>());
3622 mapAttributes.get(attributeName).put(subAttribute,
3627 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3630 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3633 // adds feature to datasequence's feature set (since Jalview 2.10)
3634 al.getSequenceAt(i).addSequenceFeature(sf);
3637 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3639 // adds dbrefs to datasequence's set (since Jalview 2.10)
3641 al.getSequenceAt(i).getDatasetSequence() == null
3642 ? al.getSequenceAt(i)
3643 : al.getSequenceAt(i).getDatasetSequence(),
3646 if (jseq.getPdbids().size() > 0)
3648 List<Pdbids> ids = jseq.getPdbids();
3649 for (int p = 0; p < ids.size(); p++)
3651 Pdbids pdbid = ids.get(p);
3652 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3653 entry.setId(pdbid.getId());
3654 if (pdbid.getType() != null)
3656 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3658 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3662 entry.setType(PDBEntry.Type.FILE);
3665 // jprovider is null when executing 'New View'
3666 if (pdbid.getFile() != null && jprovider != null)
3668 if (!pdbloaded.containsKey(pdbid.getFile()))
3670 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3675 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3679 if (pdbid.getPdbentryItem() != null)
3681 for (PdbentryItem item : pdbid.getPdbentryItem())
3683 for (Property pr : item.getProperty())
3685 entry.setProperty(pr.getName(), pr.getValue());
3690 for (Property prop : pdbid.getProperty())
3692 entry.setProperty(prop.getName(), prop.getValue());
3694 StructureSelectionManager
3695 .getStructureSelectionManager(Desktop.instance)
3696 .registerPDBEntry(entry);
3697 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3698 if (al.getSequenceAt(i).getDatasetSequence() != null)
3700 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3704 al.getSequenceAt(i).addPDBId(entry);
3709 } // end !multipleview
3711 // ///////////////////////////////
3712 // LOAD SEQUENCE MAPPINGS
3714 if (vamsasSet.getAlcodonFrame().size() > 0)
3716 // TODO Potentially this should only be done once for all views of an
3718 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3719 for (int i = 0; i < alc.size(); i++)
3721 AlignedCodonFrame cf = new AlignedCodonFrame();
3722 if (alc.get(i).getAlcodMap().size() > 0)
3724 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3725 for (int m = 0; m < maps.size(); m++)
3727 AlcodMap map = maps.get(m);
3728 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3730 jalview.datamodel.Mapping mapping = null;
3731 // attach to dna sequence reference.
3732 if (map.getMapping() != null)
3734 mapping = addMapping(map.getMapping());
3735 if (dnaseq != null && mapping.getTo() != null)
3737 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3743 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3747 al.addCodonFrame(cf);
3752 // ////////////////////////////////
3754 List<JvAnnotRow> autoAlan = new ArrayList<>();
3757 * store any annotations which forward reference a group's ID
3759 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3761 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3763 List<Annotation> an = vamsasSet.getAnnotation();
3765 for (int i = 0; i < an.size(); i++)
3767 Annotation annotation = an.get(i);
3770 * test if annotation is automatically calculated for this view only
3772 boolean autoForView = false;
3773 if (annotation.getLabel().equals("Quality")
3774 || annotation.getLabel().equals("Conservation")
3775 || annotation.getLabel().equals("Consensus"))
3777 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3779 // JAXB has no has() test; schema defaults value to false
3780 // if (!annotation.hasAutoCalculated())
3782 // annotation.setAutoCalculated(true);
3785 if (autoForView || annotation.isAutoCalculated())
3787 // remove ID - we don't recover annotation from other views for
3788 // view-specific annotation
3789 annotation.setId(null);
3792 // set visibility for other annotation in this view
3793 String annotationId = annotation.getId();
3794 if (annotationId != null && annotationIds.containsKey(annotationId))
3796 AlignmentAnnotation jda = annotationIds.get(annotationId);
3797 // in principle Visible should always be true for annotation displayed
3798 // in multiple views
3799 if (annotation.isVisible() != null)
3801 jda.visible = annotation.isVisible();
3804 al.addAnnotation(jda);
3808 // Construct new annotation from model.
3809 List<AnnotationElement> ae = annotation.getAnnotationElement();
3810 jalview.datamodel.Annotation[] anot = null;
3811 java.awt.Color firstColour = null;
3813 if (!annotation.isScoreOnly())
3815 anot = new jalview.datamodel.Annotation[al.getWidth()];
3816 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3818 AnnotationElement annElement = ae.get(aa);
3819 anpos = annElement.getPosition();
3821 if (anpos >= anot.length)
3826 float value = safeFloat(annElement.getValue());
3827 anot[anpos] = new jalview.datamodel.Annotation(
3828 annElement.getDisplayCharacter(),
3829 annElement.getDescription(),
3830 (annElement.getSecondaryStructure() == null
3831 || annElement.getSecondaryStructure()
3835 .getSecondaryStructure()
3838 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3839 if (firstColour == null)
3841 firstColour = anot[anpos].colour;
3845 jalview.datamodel.AlignmentAnnotation jaa = null;
3847 if (annotation.isGraph())
3849 float llim = 0, hlim = 0;
3850 // if (autoForView || an[i].isAutoCalculated()) {
3853 jaa = new jalview.datamodel.AlignmentAnnotation(
3854 annotation.getLabel(), annotation.getDescription(), anot,
3855 llim, hlim, safeInt(annotation.getGraphType()));
3857 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3858 jaa._linecolour = firstColour;
3859 if (annotation.getThresholdLine() != null)
3861 jaa.setThreshold(new jalview.datamodel.GraphLine(
3862 safeFloat(annotation.getThresholdLine().getValue()),
3863 annotation.getThresholdLine().getLabel(),
3864 new java.awt.Color(safeInt(
3865 annotation.getThresholdLine().getColour()))));
3867 if (autoForView || annotation.isAutoCalculated())
3869 // Hardwire the symbol display line to ensure that labels for
3870 // histograms are displayed
3876 jaa = new jalview.datamodel.AlignmentAnnotation(
3877 annotation.getLabel(), annotation.getDescription(), anot);
3878 jaa._linecolour = firstColour;
3880 // register new annotation
3881 if (annotation.getId() != null)
3883 annotationIds.put(annotation.getId(), jaa);
3884 jaa.annotationId = annotation.getId();
3886 // recover sequence association
3887 String sequenceRef = annotation.getSequenceRef();
3888 if (sequenceRef != null)
3890 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3891 SequenceI sequence = seqRefIds.get(sequenceRef);
3892 if (sequence == null)
3894 // in pre-2.9 projects sequence ref is to sequence name
3895 sequence = al.findName(sequenceRef);
3897 if (sequence != null)
3899 jaa.createSequenceMapping(sequence, 1, true);
3900 sequence.addAlignmentAnnotation(jaa);
3903 // and make a note of any group association
3904 if (annotation.getGroupRef() != null
3905 && annotation.getGroupRef().length() > 0)
3907 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3908 .get(annotation.getGroupRef());
3911 aal = new ArrayList<>();
3912 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3917 if (annotation.getScore() != null)
3919 jaa.setScore(annotation.getScore().doubleValue());
3921 if (annotation.isVisible() != null)
3923 jaa.visible = annotation.isVisible().booleanValue();
3926 if (annotation.isCentreColLabels() != null)
3928 jaa.centreColLabels = annotation.isCentreColLabels()
3932 if (annotation.isScaleColLabels() != null)
3934 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3936 if (annotation.isAutoCalculated())
3938 // newer files have an 'autoCalculated' flag and store calculation
3939 // state in viewport properties
3940 jaa.autoCalculated = true; // means annotation will be marked for
3941 // update at end of load.
3943 if (annotation.getGraphHeight() != null)
3945 jaa.graphHeight = annotation.getGraphHeight().intValue();
3947 jaa.belowAlignment = annotation.isBelowAlignment();
3948 jaa.setCalcId(annotation.getCalcId());
3949 if (annotation.getProperty().size() > 0)
3951 for (jalview.xml.binding.jalview.Property prop : annotation.getProperty())
3953 jaa.setProperty(prop.getName(), prop.getValue());
3956 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
3958 if (annotation.getContactmatrix() != null
3959 && annotation.getContactmatrix().size() > 0)
3961 for (MatrixType xmlmat : annotation.getContactmatrix())
3963 if (PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
3965 if (!xmlmat.getRows().equals(xmlmat.getCols()))
3967 Console.error("Can't handle non square PAE Matrices");
3971 float[][] elements = ContactMatrix
3972 .fromFloatStringToContacts(xmlmat.getElements(),
3973 xmlmat.getCols().intValue(),
3974 xmlmat.getRows().intValue());
3976 PAEContactMatrix newpae = new PAEContactMatrix(
3977 jaa.sequenceRef, elements);
3978 List<BitSet> newgroups=new ArrayList<BitSet>();
3979 if (xmlmat.getGroups().size()>0)
3981 for (String sgroup:xmlmat.getGroups())
3984 BigInteger group = new BigInteger(sgroup);
3985 newgroups.add(BitSet.valueOf(group.toByteArray()));
3986 } catch (NumberFormatException nfe)
3988 Console.error("Problem parsing groups for a contact matrix (\""+sgroup+"\"",nfe);
3992 String nwk=xmlmat.getNewick().size()>0 ? xmlmat.getNewick().get(0):null;
3993 if (xmlmat.getNewick().size()>1)
3996 "Ignoring additional clusterings for contact matrix");
3999 String treeMethod = xmlmat.getTreeMethod();
4000 double thresh = xmlmat.getCutHeight()!=null ? xmlmat.getCutHeight() : 0;
4001 newpae.restoreGroups(newgroups, treeMethod, nwk, thresh);
4002 jaa.sequenceRef.addContactListFor(jaa, newpae);
4007 Console.error("Ignoring CONTACT_MAP annotation with type "
4008 + xmlmat.getType());
4014 if (jaa.autoCalculated)
4016 autoAlan.add(new JvAnnotRow(i, jaa));
4019 // if (!autoForView)
4021 // add autocalculated group annotation and any user created annotation
4023 al.addAnnotation(jaa);
4027 // ///////////////////////
4029 // Create alignment markup and styles for this view
4030 if (jalviewModel.getJGroup().size() > 0)
4032 List<JGroup> groups = jalviewModel.getJGroup();
4033 boolean addAnnotSchemeGroup = false;
4034 for (int i = 0; i < groups.size(); i++)
4036 JGroup jGroup = groups.get(i);
4037 ColourSchemeI cs = null;
4038 if (jGroup.getColour() != null)
4040 if (jGroup.getColour().startsWith("ucs"))
4042 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4044 else if (jGroup.getColour().equals("AnnotationColourGradient")
4045 && jGroup.getAnnotationColours() != null)
4047 addAnnotSchemeGroup = true;
4051 cs = ColourSchemeProperty.getColourScheme(null, al,
4052 jGroup.getColour());
4055 int pidThreshold = safeInt(jGroup.getPidThreshold());
4057 Vector<SequenceI> seqs = new Vector<>();
4059 for (int s = 0; s < jGroup.getSeq().size(); s++)
4061 String seqId = jGroup.getSeq().get(s);
4062 SequenceI ts = seqRefIds.get(seqId);
4066 seqs.addElement(ts);
4070 if (seqs.size() < 1)
4075 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4076 safeBoolean(jGroup.isDisplayBoxes()),
4077 safeBoolean(jGroup.isDisplayText()),
4078 safeBoolean(jGroup.isColourText()),
4079 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4080 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4081 sg.getGroupColourScheme()
4082 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4083 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4085 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4086 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4087 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4088 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4089 // attributes with a default in the schema are never null
4090 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4091 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4092 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4093 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4094 if (jGroup.getConsThreshold() != null
4095 && jGroup.getConsThreshold().intValue() != 0)
4097 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4100 c.verdict(false, 25);
4101 sg.cs.setConservation(c);
4104 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4106 // re-instate unique group/annotation row reference
4107 List<AlignmentAnnotation> jaal = groupAnnotRefs
4108 .get(jGroup.getId());
4111 for (AlignmentAnnotation jaa : jaal)
4114 if (jaa.autoCalculated)
4116 // match up and try to set group autocalc alignment row for this
4118 if (jaa.label.startsWith("Consensus for "))
4120 sg.setConsensus(jaa);
4122 // match up and try to set group autocalc alignment row for this
4124 if (jaa.label.startsWith("Conservation for "))
4126 sg.setConservationRow(jaa);
4133 if (addAnnotSchemeGroup)
4135 // reconstruct the annotation colourscheme
4137 constructAnnotationColour(jGroup.getAnnotationColours(),
4138 null, al, jalviewModel, false));
4144 // only dataset in this model, so just return.
4147 // ///////////////////////////////
4150 AlignFrame af = null;
4151 AlignViewport av = null;
4152 // now check to see if we really need to create a new viewport.
4153 if (multipleView && viewportsAdded.size() == 0)
4155 // We recovered an alignment for which a viewport already exists.
4156 // TODO: fix up any settings necessary for overlaying stored state onto
4157 // state recovered from another document. (may not be necessary).
4158 // we may need a binding from a viewport in memory to one recovered from
4160 // and then recover its containing af to allow the settings to be applied.
4161 // TODO: fix for vamsas demo
4163 "About to recover a viewport for existing alignment: Sequence set ID is "
4165 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4166 if (seqsetobj != null)
4168 if (seqsetobj instanceof String)
4170 uniqueSeqSetId = (String) seqsetobj;
4172 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4178 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4184 * indicate that annotation colours are applied across all groups (pre
4185 * Jalview 2.8.1 behaviour)
4187 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4188 jalviewModel.getVersion());
4190 AlignmentPanel ap = null;
4191 boolean isnewview = true;
4194 // Check to see if this alignment already has a view id == viewId
4195 jalview.gui.AlignmentPanel views[] = Desktop
4196 .getAlignmentPanels(uniqueSeqSetId);
4197 if (views != null && views.length > 0)
4199 for (int v = 0; v < views.length; v++)
4201 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4203 // recover the existing alignpanel, alignframe, viewport
4204 af = views[v].alignFrame;
4207 // TODO: could even skip resetting view settings if we don't want to
4208 // change the local settings from other jalview processes
4217 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4218 uniqueSeqSetId, viewId, autoAlan);
4219 av = af.getViewport();
4224 * Load any trees, PDB structures and viewers, Overview
4226 * Not done if flag is false (when this method is used for New View)
4228 if (loadTreesAndStructures)
4230 loadTrees(jalviewModel, view, af, av, ap);
4231 loadPCAViewers(jalviewModel, ap);
4232 loadPDBStructures(jprovider, jseqs, af, ap);
4233 loadRnaViewers(jprovider, jseqs, ap);
4234 loadOverview(view, jalviewModel.getVersion(), af);
4236 // and finally return.
4241 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4242 * and geometry as saved
4247 protected void loadOverview(Viewport view, String version, AlignFrame af)
4249 if (!isVersionStringLaterThan("2.11.3",
4250 version) && view.getOverview()==null)
4255 * first close any Overview that was opened automatically
4256 * (if so configured in Preferences) so that the view is
4257 * restored in the same state as saved
4259 af.alignPanel.closeOverviewPanel();
4261 Overview overview = view.getOverview();
4262 if (overview != null)
4264 OverviewPanel overviewPanel = af
4265 .openOverviewPanel(overview.isShowHidden());
4266 overviewPanel.setTitle(overview.getTitle());
4267 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4268 overview.getWidth(), overview.getHeight());
4269 Color gap = new Color(overview.getGapColour());
4270 Color residue = new Color(overview.getResidueColour());
4271 Color hidden = new Color(overview.getHiddenColour());
4272 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4277 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4278 * panel is restored from separate jar entries, two (gapped and trimmed) per
4279 * sequence and secondary structure.
4281 * Currently each viewer shows just one sequence and structure (gapped and
4282 * trimmed), however this method is designed to support multiple sequences or
4283 * structures in viewers if wanted in future.
4289 private void loadRnaViewers(jarInputStreamProvider jprovider,
4290 List<JSeq> jseqs, AlignmentPanel ap)
4293 * scan the sequences for references to viewers; create each one the first
4294 * time it is referenced, add Rna models to existing viewers
4296 for (JSeq jseq : jseqs)
4298 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4300 RnaViewer viewer = jseq.getRnaViewer().get(i);
4301 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4304 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4306 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4307 SequenceI seq = seqRefIds.get(jseq.getId());
4308 AlignmentAnnotation ann = this.annotationIds
4309 .get(ss.getAnnotationId());
4312 * add the structure to the Varna display (with session state copied
4313 * from the jar to a temporary file)
4315 boolean gapped = safeBoolean(ss.isGapped());
4316 String rnaTitle = ss.getTitle();
4317 String sessionState = ss.getViewerState();
4318 String tempStateFile = copyJarEntry(jprovider, sessionState,
4320 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4321 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4323 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4329 * Locate and return an already instantiated matching AppVarna, or create one
4333 * @param viewIdSuffix
4337 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4338 String viewIdSuffix, AlignmentPanel ap)
4341 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4342 * if load is repeated
4344 String postLoadId = viewer.getViewId() + viewIdSuffix;
4345 for (JInternalFrame frame : getAllFrames())
4347 if (frame instanceof AppVarna)
4349 AppVarna varna = (AppVarna) frame;
4350 if (postLoadId.equals(varna.getViewId()))
4352 // this viewer is already instantiated
4353 // could in future here add ap as another 'parent' of the
4354 // AppVarna window; currently just 1-to-many
4361 * viewer not found - make it
4363 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4364 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4365 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4366 safeInt(viewer.getDividerLocation()));
4367 AppVarna varna = new AppVarna(model, ap);
4373 * Load any saved trees
4381 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4382 AlignViewport av, AlignmentPanel ap)
4384 // TODO result of automated refactoring - are all these parameters needed?
4387 for (int t = 0; t < jm.getTree().size(); t++)
4390 Tree tree = jm.getTree().get(t);
4392 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4395 if (tree.isColumnWise())
4397 AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds.get(tree
4398 .getColumnReference());
4402 "Null alignment annotation when restoring columnwise tree");
4404 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4405 tree.getTitle(), safeInt(tree.getWidth()),
4406 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4407 safeInt(tree.getYpos()));
4412 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4413 tree.getTitle(), safeInt(tree.getWidth()),
4414 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4415 safeInt(tree.getYpos()));
4417 if (tree.getId() != null)
4419 // perhaps bind the tree id to something ?
4424 // update local tree attributes ?
4425 // TODO: should check if tp has been manipulated by user - if so its
4426 // settings shouldn't be modified
4427 tp.setTitle(tree.getTitle());
4428 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4429 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4430 safeInt(tree.getHeight())));
4431 tp.setViewport(av); // af.viewport;
4432 // TODO: verify 'associate with all views' works still
4433 tp.getTreeCanvas().setViewport(av); // af.viewport;
4434 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4436 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4440 "There was a problem recovering stored Newick tree: \n"
4441 + tree.getNewick());
4445 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4446 tp.fitToWindow_actionPerformed(null);
4448 if (tree.getFontName() != null)
4451 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4452 safeInt(tree.getFontSize())));
4457 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4458 safeInt(view.getFontSize())));
4461 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4462 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4463 tp.showDistances(safeBoolean(tree.isShowDistances()));
4465 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4467 if (safeBoolean(tree.isCurrentTree()))
4469 af.getViewport().setCurrentTree(tp.getTree());
4473 } catch (Exception ex)
4475 ex.printStackTrace();
4480 * Load and link any saved structure viewers.
4487 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4488 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4491 * Run through all PDB ids on the alignment, and collect mappings between
4492 * distinct view ids and all sequences referring to that view.
4494 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4496 for (int i = 0; i < jseqs.size(); i++)
4498 JSeq jseq = jseqs.get(i);
4499 if (jseq.getPdbids().size() > 0)
4501 List<Pdbids> ids = jseq.getPdbids();
4502 for (int p = 0; p < ids.size(); p++)
4504 Pdbids pdbid = ids.get(p);
4505 final int structureStateCount = pdbid.getStructureState().size();
4506 for (int s = 0; s < structureStateCount; s++)
4508 // check to see if we haven't already created this structure view
4509 final StructureState structureState = pdbid.getStructureState()
4511 String sviewid = (structureState.getViewId() == null) ? null
4512 : structureState.getViewId() + uniqueSetSuffix;
4513 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4514 // Originally : pdbid.getFile()
4515 // : TODO: verify external PDB file recovery still works in normal
4516 // jalview project load
4518 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4519 jpdb.setId(pdbid.getId());
4521 int x = safeInt(structureState.getXpos());
4522 int y = safeInt(structureState.getYpos());
4523 int width = safeInt(structureState.getWidth());
4524 int height = safeInt(structureState.getHeight());
4526 // Probably don't need to do this anymore...
4527 // Desktop.desktop.getComponentAt(x, y);
4528 // TODO: NOW: check that this recovers the PDB file correctly.
4529 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4531 jalview.datamodel.SequenceI seq = seqRefIds
4532 .get(jseq.getId() + "");
4533 if (sviewid == null)
4535 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4538 if (!structureViewers.containsKey(sviewid))
4540 String viewerType = structureState.getType();
4541 if (viewerType == null) // pre Jalview 2.9
4543 viewerType = ViewerType.JMOL.toString();
4545 structureViewers.put(sviewid,
4546 new StructureViewerModel(x, y, width, height, false,
4547 false, true, structureState.getViewId(),
4549 // Legacy pre-2.7 conversion JAL-823 :
4550 // do not assume any view has to be linked for colour by
4554 // assemble String[] { pdb files }, String[] { id for each
4555 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4556 // seqs_file 2}, boolean[] {
4557 // linkAlignPanel,superposeWithAlignpanel}} from hash
4558 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4559 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4560 || structureState.isAlignwithAlignPanel());
4563 * Default colour by linked panel to false if not specified (e.g.
4564 * for pre-2.7 projects)
4566 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4567 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4568 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4571 * Default colour by viewer to true if not specified (e.g. for
4574 boolean colourByViewer = jmoldat.isColourByViewer();
4575 colourByViewer &= structureState.isColourByJmol();
4576 jmoldat.setColourByViewer(colourByViewer);
4578 if (jmoldat.getStateData().length() < structureState.getValue()
4579 /*Content()*/.length())
4581 jmoldat.setStateData(structureState.getValue());// Content());
4583 if (pdbid.getFile() != null)
4585 File mapkey = new File(pdbid.getFile());
4586 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4587 if (seqstrmaps == null)
4589 jmoldat.getFileData().put(mapkey,
4590 seqstrmaps = jmoldat.new StructureData(pdbFile,
4593 if (!seqstrmaps.getSeqList().contains(seq))
4595 seqstrmaps.getSeqList().add(seq);
4601 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");
4602 Console.warn(errorMessage);
4608 // Instantiate the associated structure views
4609 for (Entry<String, StructureViewerModel> entry : structureViewers
4614 createOrLinkStructureViewer(entry, af, ap, jprovider);
4615 } catch (Exception e)
4618 "Error loading structure viewer: " + e.getMessage());
4619 // failed - try the next one
4631 protected void createOrLinkStructureViewer(
4632 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4633 AlignmentPanel ap, jarInputStreamProvider jprovider)
4635 final StructureViewerModel stateData = viewerData.getValue();
4638 * Search for any viewer windows already open from other alignment views
4639 * that exactly match the stored structure state
4641 StructureViewerBase comp = findMatchingViewer(viewerData);
4645 linkStructureViewer(ap, comp, stateData);
4649 String type = stateData.getType();
4652 ViewerType viewerType = ViewerType.valueOf(type);
4653 createStructureViewer(viewerType, viewerData, af, jprovider);
4654 } catch (IllegalArgumentException | NullPointerException e)
4656 // TODO JAL-3619 show error dialog / offer an alternative viewer
4657 Console.error("Invalid structure viewer type: " + type);
4662 * Generates a name for the entry in the project jar file to hold state
4663 * information for a structure viewer
4668 protected String getViewerJarEntryName(String viewId)
4670 return VIEWER_PREFIX + viewId;
4674 * Returns any open frame that matches given structure viewer data. The match
4675 * is based on the unique viewId, or (for older project versions) the frame's
4681 protected StructureViewerBase findMatchingViewer(
4682 Entry<String, StructureViewerModel> viewerData)
4684 final String sviewid = viewerData.getKey();
4685 final StructureViewerModel svattrib = viewerData.getValue();
4686 StructureViewerBase comp = null;
4687 JInternalFrame[] frames = getAllFrames();
4688 for (JInternalFrame frame : frames)
4690 if (frame instanceof StructureViewerBase)
4693 * Post jalview 2.4 schema includes structure view id
4695 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4698 comp = (StructureViewerBase) frame;
4699 break; // break added in 2.9
4702 * Otherwise test for matching position and size of viewer frame
4704 else if (frame.getX() == svattrib.getX()
4705 && frame.getY() == svattrib.getY()
4706 && frame.getHeight() == svattrib.getHeight()
4707 && frame.getWidth() == svattrib.getWidth())
4709 comp = (StructureViewerBase) frame;
4710 // no break in faint hope of an exact match on viewId
4718 * Link an AlignmentPanel to an existing structure viewer.
4723 * @param useinViewerSuperpos
4724 * @param usetoColourbyseq
4725 * @param viewerColouring
4727 protected void linkStructureViewer(AlignmentPanel ap,
4728 StructureViewerBase viewer, StructureViewerModel stateData)
4730 // NOTE: if the jalview project is part of a shared session then
4731 // view synchronization should/could be done here.
4733 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4734 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4735 final boolean viewerColouring = stateData.isColourByViewer();
4736 Map<File, StructureData> oldFiles = stateData.getFileData();
4739 * Add mapping for sequences in this view to an already open viewer
4741 final AAStructureBindingModel binding = viewer.getBinding();
4742 for (File id : oldFiles.keySet())
4744 // add this and any other pdb files that should be present in the
4746 StructureData filedat = oldFiles.get(id);
4747 String pdbFile = filedat.getFilePath();
4748 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4749 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4751 binding.addSequenceForStructFile(pdbFile, seq);
4753 // and add the AlignmentPanel's reference to the view panel
4754 viewer.addAlignmentPanel(ap);
4755 if (useinViewerSuperpos)
4757 viewer.useAlignmentPanelForSuperposition(ap);
4761 viewer.excludeAlignmentPanelForSuperposition(ap);
4763 if (usetoColourbyseq)
4765 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4769 viewer.excludeAlignmentPanelForColourbyseq(ap);
4774 * Get all frames within the Desktop.
4778 protected JInternalFrame[] getAllFrames()
4780 JInternalFrame[] frames = null;
4781 // TODO is this necessary - is it safe - risk of hanging?
4786 frames = Desktop.desktop.getAllFrames();
4787 } catch (ArrayIndexOutOfBoundsException e)
4789 // occasional No such child exceptions are thrown here...
4793 } catch (InterruptedException f)
4797 } while (frames == null);
4802 * Answers true if 'version' is equal to or later than 'supported', where each
4803 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4804 * changes. Development and test values for 'version' are leniently treated
4808 * - minimum version we are comparing against
4810 * - version of data being processsed
4811 * @return true if version is equal to or later than supported
4813 public static boolean isVersionStringLaterThan(String supported,
4816 if (supported == null || version == null
4817 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4818 || version.equalsIgnoreCase("Test")
4819 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4821 System.err.println("Assuming project file with "
4822 + (version == null ? "null" : version)
4823 + " is compatible with Jalview version " + supported);
4828 return StringUtils.compareVersions(version, supported, "b") >= 0;
4832 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4834 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4836 if (newStructureViewers != null)
4838 sview.getBinding().setFinishedLoadingFromArchive(false);
4839 newStructureViewers.add(sview);
4843 protected void setLoadingFinishedForNewStructureViewers()
4845 if (newStructureViewers != null)
4847 for (JalviewStructureDisplayI sview : newStructureViewers)
4849 sview.getBinding().setFinishedLoadingFromArchive(true);
4851 newStructureViewers.clear();
4852 newStructureViewers = null;
4856 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4857 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4858 Viewport view, String uniqueSeqSetId, String viewId,
4859 List<JvAnnotRow> autoAlan)
4861 AlignFrame af = null;
4862 af = new AlignFrame(al, safeInt(view.getWidth()),
4863 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4867 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4868 // System.out.println("Jalview2XML AF " + e);
4869 // super.processKeyEvent(e);
4876 af.setFileName(file, FileFormat.Jalview);
4878 final AlignViewport viewport = af.getViewport();
4879 for (int i = 0; i < JSEQ.size(); i++)
4881 int colour = safeInt(JSEQ.get(i).getColour());
4882 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4888 viewport.setColourByReferenceSeq(true);
4889 viewport.setDisplayReferenceSeq(true);
4892 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4894 if (view.getSequenceSetId() != null)
4896 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4898 viewport.setSequenceSetId(uniqueSeqSetId);
4901 // propagate shared settings to this new view
4902 viewport.setHistoryList(av.getHistoryList());
4903 viewport.setRedoList(av.getRedoList());
4907 viewportsAdded.put(uniqueSeqSetId, viewport);
4909 // TODO: check if this method can be called repeatedly without
4910 // side-effects if alignpanel already registered.
4911 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4913 // apply Hidden regions to view.
4914 if (hiddenSeqs != null)
4916 for (int s = 0; s < JSEQ.size(); s++)
4918 SequenceGroup hidden = new SequenceGroup();
4919 boolean isRepresentative = false;
4920 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4922 isRepresentative = true;
4923 SequenceI sequenceToHide = al
4924 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4925 hidden.addSequence(sequenceToHide, false);
4926 // remove from hiddenSeqs list so we don't try to hide it twice
4927 hiddenSeqs.remove(sequenceToHide);
4929 if (isRepresentative)
4931 SequenceI representativeSequence = al.getSequenceAt(s);
4932 hidden.addSequence(representativeSequence, false);
4933 viewport.hideRepSequences(representativeSequence, hidden);
4937 SequenceI[] hseqs = hiddenSeqs
4938 .toArray(new SequenceI[hiddenSeqs.size()]);
4939 viewport.hideSequence(hseqs);
4942 // recover view properties and display parameters
4944 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4945 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4946 final int pidThreshold = safeInt(view.getPidThreshold());
4947 viewport.setThreshold(pidThreshold);
4949 viewport.setColourText(safeBoolean(view.isShowColourText()));
4951 viewport.setConservationSelected(
4952 safeBoolean(view.isConservationSelected()));
4953 viewport.setIncrement(safeInt(view.getConsThreshold()));
4954 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4955 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4956 viewport.setFont(new Font(view.getFontName(),
4957 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4958 (view.getCharWidth()!=null) ? false : true);
4959 if (view.getCharWidth()!=null)
4961 viewport.setCharWidth(view.getCharWidth());
4962 viewport.setCharHeight(view.getCharHeight());
4964 ViewStyleI vs = viewport.getViewStyle();
4965 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4966 viewport.setViewStyle(vs);
4967 // TODO: allow custom charWidth/Heights to be restored by updating them
4968 // after setting font - which means set above to false
4969 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4970 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4971 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4973 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4975 viewport.setShowText(safeBoolean(view.isShowText()));
4977 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4978 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4979 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4980 viewport.setShowUnconserved(view.isShowUnconserved());
4981 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4983 if (view.getViewName() != null)
4985 viewport.setViewName(view.getViewName());
4986 af.setInitialTabVisible();
4988 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4989 safeInt(view.getWidth()), safeInt(view.getHeight()));
4990 // startSeq set in af.alignPanel.updateLayout below
4991 af.alignPanel.updateLayout();
4992 ColourSchemeI cs = null;
4993 // apply colourschemes
4994 if (view.getBgColour() != null)
4996 if (view.getBgColour().startsWith("ucs"))
4998 cs = getUserColourScheme(jm, view.getBgColour());
5000 else if (view.getBgColour().startsWith("Annotation"))
5002 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5003 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5010 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5011 view.getBgColour());
5016 * turn off 'alignment colour applies to all groups'
5017 * while restoring global colour scheme
5019 viewport.setColourAppliesToAllGroups(false);
5020 viewport.setGlobalColourScheme(cs);
5021 viewport.getResidueShading().setThreshold(pidThreshold,
5022 view.isIgnoreGapsinConsensus());
5023 viewport.getResidueShading()
5024 .setConsensus(viewport.getSequenceConsensusHash());
5025 if (safeBoolean(view.isConservationSelected()) && cs != null)
5027 viewport.getResidueShading()
5028 .setConservationInc(safeInt(view.getConsThreshold()));
5030 af.changeColour(cs);
5031 viewport.setColourAppliesToAllGroups(true);
5033 viewport.setShowSequenceFeatures(
5034 safeBoolean(view.isShowSequenceFeatures()));
5036 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5037 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5038 viewport.setFollowHighlight(view.isFollowHighlight());
5039 viewport.followSelection = view.isFollowSelection();
5040 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5041 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5042 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5043 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5044 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5045 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5046 viewport.setShowGroupConservation(view.isShowGroupConservation());
5047 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5048 viewport.setShowComplementFeaturesOnTop(
5049 view.isShowComplementFeaturesOnTop());
5051 // recover feature settings
5052 if (jm.getFeatureSettings() != null)
5054 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5055 .getFeatureRenderer();
5056 FeaturesDisplayed fdi;
5057 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5058 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5060 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5061 Map<String, Float> featureOrder = new Hashtable<>();
5063 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5066 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5067 String featureType = setting.getType();
5070 * restore feature filters (if any)
5072 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5074 if (filters != null)
5076 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5078 if (!filter.isEmpty())
5080 fr.setFeatureFilter(featureType, filter);
5085 * restore feature colour scheme
5087 Color maxColour = new Color(setting.getColour());
5088 if (setting.getMincolour() != null)
5091 * minColour is always set unless a simple colour
5092 * (including for colour by label though it doesn't use it)
5094 Color minColour = new Color(setting.getMincolour().intValue());
5095 Color noValueColour = minColour;
5096 NoValueColour noColour = setting.getNoValueColour();
5097 if (noColour == NoValueColour.NONE)
5099 noValueColour = null;
5101 else if (noColour == NoValueColour.MAX)
5103 noValueColour = maxColour;
5105 float min = safeFloat(safeFloat(setting.getMin()));
5106 float max = setting.getMax() == null ? 1f
5107 : setting.getMax().floatValue();
5108 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5109 maxColour, noValueColour, min, max);
5110 if (setting.getAttributeName().size() > 0)
5112 gc.setAttributeName(setting.getAttributeName().toArray(
5113 new String[setting.getAttributeName().size()]));
5115 if (setting.getThreshold() != null)
5117 gc.setThreshold(setting.getThreshold().floatValue());
5118 int threshstate = safeInt(setting.getThreshstate());
5119 // -1 = None, 0 = Below, 1 = Above threshold
5120 if (threshstate == 0)
5122 gc.setBelowThreshold(true);
5124 else if (threshstate == 1)
5126 gc.setAboveThreshold(true);
5129 gc.setAutoScaled(true); // default
5130 if (setting.isAutoScale() != null)
5132 gc.setAutoScaled(setting.isAutoScale());
5134 if (setting.isColourByLabel() != null)
5136 gc.setColourByLabel(setting.isColourByLabel());
5138 // and put in the feature colour table.
5139 featureColours.put(featureType, gc);
5143 featureColours.put(featureType, new FeatureColour(maxColour));
5145 renderOrder[fs] = featureType;
5146 if (setting.getOrder() != null)
5148 featureOrder.put(featureType, setting.getOrder().floatValue());
5152 featureOrder.put(featureType, Float.valueOf(
5153 fs / jm.getFeatureSettings().getSetting().size()));
5155 if (safeBoolean(setting.isDisplay()))
5157 fdi.setVisible(featureType);
5160 Map<String, Boolean> fgtable = new Hashtable<>();
5161 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5163 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5164 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5166 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5167 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5168 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5169 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5170 fgtable, featureColours, 1.0f, featureOrder);
5171 fr.transferSettings(frs);
5174 if (view.getHiddenColumns().size() > 0)
5176 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5178 final HiddenColumns hc = view.getHiddenColumns().get(c);
5179 viewport.hideColumns(safeInt(hc.getStart()),
5180 safeInt(hc.getEnd()) /* +1 */);
5183 if (view.getCalcIdParam() != null)
5185 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5187 if (calcIdParam != null)
5189 if (recoverCalcIdParam(calcIdParam, viewport))
5194 Console.warn("Couldn't recover parameters for "
5195 + calcIdParam.getCalcId());
5200 af.setMenusFromViewport(viewport);
5201 af.setTitle(view.getTitle());
5202 // TODO: we don't need to do this if the viewport is aready visible.
5204 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5205 * has a 'cdna/protein complement' view, in which case save it in order to
5206 * populate a SplitFrame once all views have been read in.
5208 String complementaryViewId = view.getComplementId();
5209 if (complementaryViewId == null)
5211 Desktop.addInternalFrame(af, view.getTitle(),
5212 safeInt(view.getWidth()), safeInt(view.getHeight()));
5213 // recompute any autoannotation
5214 af.alignPanel.updateAnnotation(false, true);
5215 reorderAutoannotation(af, al, autoAlan);
5216 af.alignPanel.alignmentChanged();
5220 splitFrameCandidates.put(view, af);
5227 * Reads saved data to restore Colour by Annotation settings
5229 * @param viewAnnColour
5233 * @param checkGroupAnnColour
5236 private ColourSchemeI constructAnnotationColour(
5237 AnnotationColourScheme viewAnnColour, AlignFrame af,
5238 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5240 boolean propagateAnnColour = false;
5241 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5243 if (checkGroupAnnColour && al.getGroups() != null
5244 && al.getGroups().size() > 0)
5246 // pre 2.8.1 behaviour
5247 // check to see if we should transfer annotation colours
5248 propagateAnnColour = true;
5249 for (SequenceGroup sg : al.getGroups())
5251 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5253 propagateAnnColour = false;
5259 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5261 String annotationId = viewAnnColour.getAnnotation();
5262 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5265 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5267 if (matchedAnnotation == null
5268 && annAlignment.getAlignmentAnnotation() != null)
5270 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5273 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5275 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5280 if (matchedAnnotation == null)
5282 System.err.println("Failed to match annotation colour scheme for "
5286 // belt-and-braces create a threshold line if the
5287 // colourscheme needs one but the matchedAnnotation doesn't have one
5288 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5289 && matchedAnnotation.getThreshold() == null)
5291 matchedAnnotation.setThreshold(
5292 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5293 "Threshold", Color.black));
5296 AnnotationColourGradient cs = null;
5297 if (viewAnnColour.getColourScheme().equals("None"))
5299 cs = new AnnotationColourGradient(matchedAnnotation,
5300 new Color(safeInt(viewAnnColour.getMinColour())),
5301 new Color(safeInt(viewAnnColour.getMaxColour())),
5302 safeInt(viewAnnColour.getAboveThreshold()));
5304 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5306 cs = new AnnotationColourGradient(matchedAnnotation,
5307 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5308 safeInt(viewAnnColour.getAboveThreshold()));
5312 cs = new AnnotationColourGradient(matchedAnnotation,
5313 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5314 viewAnnColour.getColourScheme()),
5315 safeInt(viewAnnColour.getAboveThreshold()));
5318 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5319 boolean useOriginalColours = safeBoolean(
5320 viewAnnColour.isPredefinedColours());
5321 cs.setSeqAssociated(perSequenceOnly);
5322 cs.setPredefinedColours(useOriginalColours);
5324 if (propagateAnnColour && al.getGroups() != null)
5326 // Also use these settings for all the groups
5327 for (int g = 0; g < al.getGroups().size(); g++)
5329 SequenceGroup sg = al.getGroups().get(g);
5330 if (sg.getGroupColourScheme() == null)
5335 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5336 matchedAnnotation, sg.getColourScheme(),
5337 safeInt(viewAnnColour.getAboveThreshold()));
5338 sg.setColourScheme(groupScheme);
5339 groupScheme.setSeqAssociated(perSequenceOnly);
5340 groupScheme.setPredefinedColours(useOriginalColours);
5346 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5347 List<JvAnnotRow> autoAlan)
5349 // copy over visualization settings for autocalculated annotation in the
5351 if (al.getAlignmentAnnotation() != null)
5354 * Kludge for magic autoannotation names (see JAL-811)
5356 String[] magicNames = new String[] { "Consensus", "Quality",
5358 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5359 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5360 for (String nm : magicNames)
5362 visan.put(nm, nullAnnot);
5364 for (JvAnnotRow auan : autoAlan)
5366 visan.put(auan.template.label
5367 + (auan.template.getCalcId() == null ? ""
5368 : "\t" + auan.template.getCalcId()),
5371 int hSize = al.getAlignmentAnnotation().length;
5372 List<JvAnnotRow> reorder = new ArrayList<>();
5373 // work through any autoCalculated annotation already on the view
5374 // removing it if it should be placed in a different location on the
5375 // annotation panel.
5376 List<String> remains = new ArrayList<>(visan.keySet());
5377 for (int h = 0; h < hSize; h++)
5379 jalview.datamodel.AlignmentAnnotation jalan = al
5380 .getAlignmentAnnotation()[h];
5381 if (jalan.autoCalculated)
5384 JvAnnotRow valan = visan.get(k = jalan.label);
5385 if (jalan.getCalcId() != null)
5387 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5392 // delete the auto calculated row from the alignment
5393 al.deleteAnnotation(jalan, false);
5397 if (valan != nullAnnot)
5399 if (jalan != valan.template)
5401 // newly created autoannotation row instance
5402 // so keep a reference to the visible annotation row
5403 // and copy over all relevant attributes
5404 if (valan.template.graphHeight >= 0)
5407 jalan.graphHeight = valan.template.graphHeight;
5409 jalan.visible = valan.template.visible;
5411 reorder.add(new JvAnnotRow(valan.order, jalan));
5416 // Add any (possibly stale) autocalculated rows that were not appended to
5417 // the view during construction
5418 for (String other : remains)
5420 JvAnnotRow othera = visan.get(other);
5421 if (othera != nullAnnot && othera.template.getCalcId() != null
5422 && othera.template.getCalcId().length() > 0)
5424 reorder.add(othera);
5427 // now put the automatic annotation in its correct place
5428 int s = 0, srt[] = new int[reorder.size()];
5429 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5430 for (JvAnnotRow jvar : reorder)
5433 srt[s++] = jvar.order;
5436 jalview.util.QuickSort.sort(srt, rws);
5437 // and re-insert the annotation at its correct position
5438 for (JvAnnotRow jvar : rws)
5440 al.addAnnotation(jvar.template, jvar.order);
5442 af.alignPanel.adjustAnnotationHeight();
5446 Hashtable skipList = null;
5449 * TODO remove this method
5452 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5453 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5454 * throw new Error("Implementation Error. No skipList defined for this
5455 * Jalview2XML instance."); } return (AlignFrame)
5456 * skipList.get(view.getSequenceSetId()); }
5460 * Check if the Jalview view contained in object should be skipped or not.
5463 * @return true if view's sequenceSetId is a key in skipList
5465 private boolean skipViewport(JalviewModel object)
5467 if (skipList == null)
5471 String id = object.getViewport().get(0).getSequenceSetId();
5472 if (skipList.containsKey(id))
5474 Console.debug("Skipping seuqence set id " + id);
5480 public void addToSkipList(AlignFrame af)
5482 if (skipList == null)
5484 skipList = new Hashtable();
5486 skipList.put(af.getViewport().getSequenceSetId(), af);
5489 public void clearSkipList()
5491 if (skipList != null)
5498 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5499 boolean ignoreUnrefed, String uniqueSeqSetId)
5501 jalview.datamodel.AlignmentI ds = getDatasetFor(
5502 vamsasSet.getDatasetId());
5503 AlignmentI xtant_ds = ds;
5504 if (xtant_ds == null)
5506 // good chance we are about to create a new dataset, but check if we've
5507 // seen some of the dataset sequence IDs before.
5508 // TODO: skip this check if we are working with project generated by
5509 // version 2.11 or later
5510 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5511 if (xtant_ds != null)
5514 addDatasetRef(vamsasSet.getDatasetId(), ds);
5517 Vector<SequenceI> dseqs = null;
5520 // recovering an alignment View
5521 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5522 if (seqSetDS != null)
5524 if (ds != null && ds != seqSetDS)
5527 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5528 + " - CDS/Protein crossreference data may be lost");
5529 if (xtant_ds != null)
5531 // This can only happen if the unique sequence set ID was bound to a
5532 // dataset that did not contain any of the sequences in the view
5533 // currently being restored.
5535 "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.");
5539 addDatasetRef(vamsasSet.getDatasetId(), ds);
5544 // try even harder to restore dataset
5545 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5546 // create a list of new dataset sequences
5547 dseqs = new Vector<>();
5549 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5551 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5552 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5554 // create a new dataset
5557 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5558 dseqs.copyInto(dsseqs);
5559 ds = new jalview.datamodel.Alignment(dsseqs);
5560 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5561 + " for alignment " + System.identityHashCode(al));
5562 addDatasetRef(vamsasSet.getDatasetId(), ds);
5564 // set the dataset for the newly imported alignment.
5565 if (al.getDataset() == null && !ignoreUnrefed)
5568 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5569 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5571 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5575 * XML dataset sequence ID to materialised dataset reference
5577 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5580 * @return the first materialised dataset reference containing a dataset
5581 * sequence referenced in the given view
5583 * - sequences from the view
5585 AlignmentI checkIfHasDataset(List<Sequence> list)
5587 for (Sequence restoredSeq : list)
5589 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5590 if (datasetFor != null)
5599 * Register ds as the containing dataset for the dataset sequences referenced
5600 * by sequences in list
5603 * - sequences in a view
5606 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5608 for (Sequence restoredSeq : list)
5610 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5611 if (prevDS != null && prevDS != ds)
5613 Console.warn("Dataset sequence appears in many datasets: "
5614 + restoredSeq.getDsseqid());
5615 // TODO: try to merge!
5623 * sequence definition to create/merge dataset sequence for
5627 * vector to add new dataset sequence to
5628 * @param ignoreUnrefed
5629 * - when true, don't create new sequences from vamsasSeq if it's id
5630 * doesn't already have an asssociated Jalview sequence.
5632 * - used to reorder the sequence in the alignment according to the
5633 * vamsasSeq array ordering, to preserve ordering of dataset
5635 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5636 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5639 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5641 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5642 boolean reorder = false;
5643 SequenceI dsq = null;
5644 if (sq != null && sq.getDatasetSequence() != null)
5646 dsq = sq.getDatasetSequence();
5652 if (sq == null && ignoreUnrefed)
5656 String sqid = vamsasSeq.getDsseqid();
5659 // need to create or add a new dataset sequence reference to this sequence
5662 dsq = seqRefIds.get(sqid);
5667 // make a new dataset sequence
5668 dsq = sq.createDatasetSequence();
5671 // make up a new dataset reference for this sequence
5672 sqid = seqHash(dsq);
5674 dsq.setVamsasId(uniqueSetSuffix + sqid);
5675 seqRefIds.put(sqid, dsq);
5680 dseqs.addElement(dsq);
5685 ds.addSequence(dsq);
5691 { // make this dataset sequence sq's dataset sequence
5692 sq.setDatasetSequence(dsq);
5693 // and update the current dataset alignment
5698 if (!dseqs.contains(dsq))
5705 if (ds.findIndex(dsq) < 0)
5707 ds.addSequence(dsq);
5714 // TODO: refactor this as a merge dataset sequence function
5715 // now check that sq (the dataset sequence) sequence really is the union of
5716 // all references to it
5717 // boolean pre = sq.getStart() < dsq.getStart();
5718 // boolean post = sq.getEnd() > dsq.getEnd();
5722 // StringBuffer sb = new StringBuffer();
5723 String newres = jalview.analysis.AlignSeq.extractGaps(
5724 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5725 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5726 && newres.length() > dsq.getLength())
5728 // Update with the longer sequence.
5732 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5733 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5734 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5735 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5737 dsq.setSequence(newres);
5739 // TODO: merges will never happen if we 'know' we have the real dataset
5740 // sequence - this should be detected when id==dssid
5742 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5743 // + (pre ? "prepended" : "") + " "
5744 // + (post ? "appended" : ""));
5749 // sequence refs are identical. We may need to update the existing dataset
5750 // alignment with this one, though.
5751 if (ds != null && dseqs == null)
5753 int opos = ds.findIndex(dsq);
5754 SequenceI tseq = null;
5755 if (opos != -1 && vseqpos != opos)
5757 // remove from old position
5758 ds.deleteSequence(dsq);
5760 if (vseqpos < ds.getHeight())
5762 if (vseqpos != opos)
5764 // save sequence at destination position
5765 tseq = ds.getSequenceAt(vseqpos);
5766 ds.replaceSequenceAt(vseqpos, dsq);
5767 ds.addSequence(tseq);
5772 ds.addSequence(dsq);
5779 * TODO use AlignmentI here and in related methods - needs
5780 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5782 Hashtable<String, AlignmentI> datasetIds = null;
5784 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5786 private AlignmentI getDatasetFor(String datasetId)
5788 if (datasetIds == null)
5790 datasetIds = new Hashtable<>();
5793 if (datasetIds.containsKey(datasetId))
5795 return datasetIds.get(datasetId);
5800 private void addDatasetRef(String datasetId, AlignmentI dataset)
5802 if (datasetIds == null)
5804 datasetIds = new Hashtable<>();
5806 datasetIds.put(datasetId, dataset);
5810 * make a new dataset ID for this jalview dataset alignment
5815 private String getDatasetIdRef(AlignmentI dataset)
5817 if (dataset.getDataset() != null)
5820 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5822 String datasetId = makeHashCode(dataset, null);
5823 if (datasetId == null)
5825 // make a new datasetId and record it
5826 if (dataset2Ids == null)
5828 dataset2Ids = new IdentityHashMap<>();
5832 datasetId = dataset2Ids.get(dataset);
5834 if (datasetId == null)
5836 datasetId = "ds" + dataset2Ids.size() + 1;
5837 dataset2Ids.put(dataset, datasetId);
5844 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5845 * constructed as a special subclass GeneLocus.
5847 * @param datasetSequence
5850 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5852 for (int d = 0; d < sequence.getDBRef().size(); d++)
5854 DBRef dr = sequence.getDBRef().get(d);
5858 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5859 dr.getAccessionId());
5863 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5864 dr.getAccessionId());
5866 if (dr.getMapping() != null)
5868 entry.setMap(addMapping(dr.getMapping()));
5870 entry.setCanonical(dr.isCanonical());
5871 datasetSequence.addDBRef(entry);
5875 private jalview.datamodel.Mapping addMapping(Mapping m)
5877 SequenceI dsto = null;
5878 // Mapping m = dr.getMapping();
5879 int fr[] = new int[m.getMapListFrom().size() * 2];
5880 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5881 for (int _i = 0; from.hasNext(); _i += 2)
5883 MapListFrom mf = from.next();
5884 fr[_i] = mf.getStart();
5885 fr[_i + 1] = mf.getEnd();
5887 int fto[] = new int[m.getMapListTo().size() * 2];
5888 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5889 for (int _i = 0; to.hasNext(); _i += 2)
5891 MapListTo mf = to.next();
5892 fto[_i] = mf.getStart();
5893 fto[_i + 1] = mf.getEnd();
5895 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5896 fto, m.getMapFromUnit().intValue(),
5897 m.getMapToUnit().intValue());
5900 * (optional) choice of dseqFor or Sequence
5902 if (m.getDseqFor() != null)
5904 String dsfor = m.getDseqFor();
5905 if (seqRefIds.containsKey(dsfor))
5910 jmap.setTo(seqRefIds.get(dsfor));
5914 frefedSequence.add(newMappingRef(dsfor, jmap));
5917 else if (m.getSequence() != null)
5920 * local sequence definition
5922 Sequence ms = m.getSequence();
5923 SequenceI djs = null;
5924 String sqid = ms.getDsseqid();
5925 if (sqid != null && sqid.length() > 0)
5928 * recover dataset sequence
5930 djs = seqRefIds.get(sqid);
5935 "Warning - making up dataset sequence id for DbRef sequence map reference");
5936 sqid = ((Object) ms).toString(); // make up a new hascode for
5937 // undefined dataset sequence hash
5938 // (unlikely to happen)
5944 * make a new dataset sequence and add it to refIds hash
5946 djs = new jalview.datamodel.Sequence(ms.getName(),
5948 djs.setStart(jmap.getMap().getToLowest());
5949 djs.setEnd(jmap.getMap().getToHighest());
5950 djs.setVamsasId(uniqueSetSuffix + sqid);
5952 incompleteSeqs.put(sqid, djs);
5953 seqRefIds.put(sqid, djs);
5956 Console.debug("about to recurse on addDBRefs.");
5965 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5966 * view as XML (but not to file), and then reloading it
5971 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5974 JalviewModel jm = saveState(ap, null, null, null);
5977 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5978 ap.getAlignment().getDataset());
5980 uniqueSetSuffix = "";
5981 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5982 jm.getViewport().get(0).setId(null);
5983 // we don't overwrite the view we just copied
5985 if (this.frefedSequence == null)
5987 frefedSequence = new Vector<>();
5990 viewportsAdded.clear();
5992 AlignFrame af = loadFromObject(jm, null, false, null);
5993 af.getAlignPanels().clear();
5994 af.closeMenuItem_actionPerformed(true);
5997 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5998 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5999 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6000 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6001 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6004 return af.alignPanel;
6007 private Hashtable jvids2vobj;
6010 * set the object to ID mapping tables used to write/recover objects and XML
6011 * ID strings for the jalview project. If external tables are provided then
6012 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6013 * object goes out of scope. - also populates the datasetIds hashtable with
6014 * alignment objects containing dataset sequences
6017 * Map from ID strings to jalview datamodel
6019 * Map from jalview datamodel to ID strings
6023 public void setObjectMappingTables(Hashtable vobj2jv,
6024 IdentityHashMap jv2vobj)
6026 this.jv2vobj = jv2vobj;
6027 this.vobj2jv = vobj2jv;
6028 Iterator ds = jv2vobj.keySet().iterator();
6030 while (ds.hasNext())
6032 Object jvobj = ds.next();
6033 id = jv2vobj.get(jvobj).toString();
6034 if (jvobj instanceof jalview.datamodel.Alignment)
6036 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6038 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6041 else if (jvobj instanceof jalview.datamodel.Sequence)
6043 // register sequence object so the XML parser can recover it.
6044 if (seqRefIds == null)
6046 seqRefIds = new HashMap<>();
6048 if (seqsToIds == null)
6050 seqsToIds = new IdentityHashMap<>();
6052 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6053 seqsToIds.put((SequenceI) jvobj, id);
6055 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6058 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6059 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6060 if (jvann.annotationId == null)
6062 jvann.annotationId = anid;
6064 if (!jvann.annotationId.equals(anid))
6066 // TODO verify that this is the correct behaviour
6067 Console.warn("Overriding Annotation ID for " + anid
6068 + " from different id : " + jvann.annotationId);
6069 jvann.annotationId = anid;
6072 else if (jvobj instanceof String)
6074 if (jvids2vobj == null)
6076 jvids2vobj = new Hashtable();
6077 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6082 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6088 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6089 * objects created from the project archive. If string is null (default for
6090 * construction) then suffix will be set automatically.
6094 public void setUniqueSetSuffix(String string)
6096 uniqueSetSuffix = string;
6101 * uses skipList2 as the skipList for skipping views on sequence sets
6102 * associated with keys in the skipList
6106 public void setSkipList(Hashtable skipList2)
6108 skipList = skipList2;
6112 * Reads the jar entry of given name and returns its contents, or null if the
6113 * entry is not found.
6116 * @param jarEntryName
6119 protected String readJarEntry(jarInputStreamProvider jprovider,
6120 String jarEntryName)
6122 String result = null;
6123 BufferedReader in = null;
6128 * Reopen the jar input stream and traverse its entries to find a matching
6131 JarInputStream jin = jprovider.getJarInputStream();
6132 JarEntry entry = null;
6135 entry = jin.getNextJarEntry();
6136 } while (entry != null && !entry.getName().equals(jarEntryName));
6140 StringBuilder out = new StringBuilder(256);
6141 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6144 while ((data = in.readLine()) != null)
6148 result = out.toString();
6153 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6155 } catch (Exception ex)
6157 ex.printStackTrace();
6165 } catch (IOException e)
6176 * Returns an incrementing counter (0, 1, 2...)
6180 private synchronized int nextCounter()
6186 * Loads any saved PCA viewers
6191 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6195 List<PcaViewer> pcaviewers = model.getPcaViewer();
6196 for (PcaViewer viewer : pcaviewers)
6198 String modelName = viewer.getScoreModelName();
6199 SimilarityParamsI params = new SimilarityParams(
6200 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6201 viewer.isIncludeGaps(),
6202 viewer.isDenominateByShortestLength());
6205 * create the panel (without computing the PCA)
6207 PCAPanel panel = new PCAPanel(ap, modelName, params);
6209 panel.setTitle(viewer.getTitle());
6210 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6211 viewer.getWidth(), viewer.getHeight()));
6213 boolean showLabels = viewer.isShowLabels();
6214 panel.setShowLabels(showLabels);
6215 panel.getRotatableCanvas().setShowLabels(showLabels);
6216 panel.getRotatableCanvas()
6217 .setBgColour(new Color(viewer.getBgColour()));
6218 panel.getRotatableCanvas()
6219 .setApplyToAllViews(viewer.isLinkToAllViews());
6222 * load PCA output data
6224 ScoreModelI scoreModel = ScoreModels.getInstance()
6225 .getScoreModel(modelName, ap);
6226 PCA pca = new PCA(null, scoreModel, params);
6227 PcaDataType pcaData = viewer.getPcaData();
6229 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6230 pca.setPairwiseScores(pairwise);
6232 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6233 pca.setTridiagonal(triDiag);
6235 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6236 pca.setEigenmatrix(result);
6238 panel.getPcaModel().setPCA(pca);
6241 * we haven't saved the input data! (JAL-2647 to do)
6243 panel.setInputData(null);
6246 * add the sequence points for the PCA display
6248 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6249 for (SequencePoint sp : viewer.getSequencePoint())
6251 String seqId = sp.getSequenceRef();
6252 SequenceI seq = seqRefIds.get(seqId);
6255 throw new IllegalStateException(
6256 "Unmatched seqref for PCA: " + seqId);
6258 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6259 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6261 seqPoints.add(seqPoint);
6263 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6266 * set min-max ranges and scale after setPoints (which recomputes them)
6268 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6269 SeqPointMin spMin = viewer.getSeqPointMin();
6270 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6272 SeqPointMax spMax = viewer.getSeqPointMax();
6273 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6275 panel.getRotatableCanvas().setSeqMinMax(min, max);
6277 // todo: hold points list in PCAModel only
6278 panel.getPcaModel().setSequencePoints(seqPoints);
6280 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6281 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6282 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6284 // is this duplication needed?
6285 panel.setTop(seqPoints.size() - 1);
6286 panel.getPcaModel().setTop(seqPoints.size() - 1);
6289 * add the axes' end points for the display
6291 for (int i = 0; i < 3; i++)
6293 Axis axis = viewer.getAxis().get(i);
6294 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6295 axis.getXPos(), axis.getYPos(), axis.getZPos());
6298 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6299 "label.calc_title", "PCA", modelName), 475, 450);
6301 } catch (Exception ex)
6303 Console.error("Error loading PCA: " + ex.toString());
6308 * Creates a new structure viewer window
6315 protected void createStructureViewer(ViewerType viewerType,
6316 final Entry<String, StructureViewerModel> viewerData,
6317 AlignFrame af, jarInputStreamProvider jprovider)
6319 final StructureViewerModel viewerModel = viewerData.getValue();
6320 String sessionFilePath = null;
6322 if (viewerType == ViewerType.JMOL)
6324 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6328 String viewerJarEntryName = getViewerJarEntryName(
6329 viewerModel.getViewId());
6330 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6331 "viewerSession", ".tmp");
6333 final String sessionPath = sessionFilePath;
6334 final String sviewid = viewerData.getKey();
6337 SwingUtilities.invokeAndWait(new Runnable()
6342 JalviewStructureDisplayI sview = null;
6345 sview = StructureViewer.createView(viewerType, af.alignPanel,
6346 viewerModel, sessionPath, sviewid);
6347 addNewStructureViewer(sview);
6348 } catch (OutOfMemoryError ex)
6350 new OOMWarning("Restoring structure view for " + viewerType,
6351 (OutOfMemoryError) ex.getCause());
6352 if (sview != null && sview.isVisible())
6354 sview.closeViewer(false);
6355 sview.setVisible(false);
6361 } catch (InvocationTargetException | InterruptedException ex)
6363 Console.warn("Unexpected error when opening " + viewerType
6364 + " structure viewer", ex);
6369 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6370 * the path of the file. "load file" commands are rewritten to change the
6371 * original PDB file names to those created as the Jalview project is loaded.
6377 private String rewriteJmolSession(StructureViewerModel svattrib,
6378 jarInputStreamProvider jprovider)
6380 String state = svattrib.getStateData(); // Jalview < 2.9
6381 if (state == null || state.isEmpty()) // Jalview >= 2.9
6383 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6384 state = readJarEntry(jprovider, jarEntryName);
6386 // TODO or simpler? for each key in oldFiles,
6387 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6388 // (allowing for different path escapings)
6389 StringBuilder rewritten = new StringBuilder(state.length());
6390 int cp = 0, ncp, ecp;
6391 Map<File, StructureData> oldFiles = svattrib.getFileData();
6392 while ((ncp = state.indexOf("load ", cp)) > -1)
6396 // look for next filename in load statement
6397 rewritten.append(state.substring(cp,
6398 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6399 String oldfilenam = state.substring(ncp,
6400 ecp = state.indexOf("\"", ncp));
6401 // recover the new mapping data for this old filename
6402 // have to normalize filename - since Jmol and jalview do
6403 // filename translation differently.
6404 StructureData filedat = oldFiles.get(new File(oldfilenam));
6405 if (filedat == null)
6407 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6408 filedat = oldFiles.get(new File(reformatedOldFilename));
6410 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6411 rewritten.append("\"");
6412 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6413 // look for next file statement.
6414 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6418 // just append rest of state
6419 rewritten.append(state.substring(cp));
6423 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6424 rewritten = new StringBuilder(state);
6425 rewritten.append("; load append ");
6426 for (File id : oldFiles.keySet())
6428 // add pdb files that should be present in the viewer
6429 StructureData filedat = oldFiles.get(id);
6430 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6432 rewritten.append(";");
6435 if (rewritten.length() == 0)
6439 final String history = "history = ";
6440 int historyIndex = rewritten.indexOf(history);
6441 if (historyIndex > -1)
6444 * change "history = [true|false];" to "history = [1|0];"
6446 historyIndex += history.length();
6447 String val = rewritten.substring(historyIndex, historyIndex + 5);
6448 if (val.startsWith("true"))
6450 rewritten.replace(historyIndex, historyIndex + 4, "1");
6452 else if (val.startsWith("false"))
6454 rewritten.replace(historyIndex, historyIndex + 5, "0");
6460 File tmp = File.createTempFile("viewerSession", ".tmp");
6461 try (OutputStream os = new FileOutputStream(tmp))
6463 InputStream is = new ByteArrayInputStream(
6464 rewritten.toString().getBytes());
6466 return tmp.getAbsolutePath();
6468 } catch (IOException e)
6470 Console.error("Error restoring Jmol session: " + e.toString());
6476 * Populates an XML model of the feature colour scheme for one feature type
6478 * @param featureType
6482 public static Colour marshalColour(String featureType,
6483 FeatureColourI fcol)
6485 Colour col = new Colour();
6486 if (fcol.isSimpleColour())
6488 col.setRGB(Format.getHexString(fcol.getColour()));
6492 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6493 col.setMin(fcol.getMin());
6494 col.setMax(fcol.getMax());
6495 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6496 col.setAutoScale(fcol.isAutoScaled());
6497 col.setThreshold(fcol.getThreshold());
6498 col.setColourByLabel(fcol.isColourByLabel());
6499 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6500 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6501 : ThresholdType.NONE));
6502 if (fcol.isColourByAttribute())
6504 final String[] attName = fcol.getAttributeName();
6505 col.getAttributeName().add(attName[0]);
6506 if (attName.length > 1)
6508 col.getAttributeName().add(attName[1]);
6511 Color noColour = fcol.getNoColour();
6512 if (noColour == null)
6514 col.setNoValueColour(NoValueColour.NONE);
6516 else if (noColour == fcol.getMaxColour())
6518 col.setNoValueColour(NoValueColour.MAX);
6522 col.setNoValueColour(NoValueColour.MIN);
6525 col.setName(featureType);
6530 * Populates an XML model of the feature filter(s) for one feature type
6532 * @param firstMatcher
6533 * the first (or only) match condition)
6535 * remaining match conditions (if any)
6537 * if true, conditions are and-ed, else or-ed
6539 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6540 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6543 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6545 if (filters.hasNext())
6550 CompoundMatcher compound = new CompoundMatcher();
6551 compound.setAnd(and);
6552 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6553 firstMatcher, Collections.emptyIterator(), and);
6554 // compound.addMatcherSet(matcher1);
6555 compound.getMatcherSet().add(matcher1);
6556 FeatureMatcherI nextMatcher = filters.next();
6557 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6558 nextMatcher, filters, and);
6559 // compound.addMatcherSet(matcher2);
6560 compound.getMatcherSet().add(matcher2);
6561 result.setCompoundMatcher(compound);
6566 * single condition matcher
6568 // MatchCondition matcherModel = new MatchCondition();
6569 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6570 matcherModel.setCondition(
6571 firstMatcher.getMatcher().getCondition().getStableName());
6572 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6573 if (firstMatcher.isByAttribute())
6575 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6576 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6577 String[] attName = firstMatcher.getAttribute();
6578 matcherModel.getAttributeName().add(attName[0]); // attribute
6579 if (attName.length > 1)
6581 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6584 else if (firstMatcher.isByLabel())
6586 matcherModel.setBy(FilterBy.BY_LABEL);
6588 else if (firstMatcher.isByScore())
6590 matcherModel.setBy(FilterBy.BY_SCORE);
6592 result.setMatchCondition(matcherModel);
6599 * Loads one XML model of a feature filter to a Jalview object
6601 * @param featureType
6602 * @param matcherSetModel
6605 public static FeatureMatcherSetI parseFilter(String featureType,
6606 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6608 FeatureMatcherSetI result = new FeatureMatcherSet();
6611 parseFilterConditions(result, matcherSetModel, true);
6612 } catch (IllegalStateException e)
6614 // mixing AND and OR conditions perhaps
6616 String.format("Error reading filter conditions for '%s': %s",
6617 featureType, e.getMessage()));
6618 // return as much as was parsed up to the error
6625 * Adds feature match conditions to matcherSet as unmarshalled from XML
6626 * (possibly recursively for compound conditions)
6629 * @param matcherSetModel
6631 * if true, multiple conditions are AND-ed, else they are OR-ed
6632 * @throws IllegalStateException
6633 * if AND and OR conditions are mixed
6635 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6636 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6639 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6640 .getMatchCondition();
6646 FilterBy filterBy = mc.getBy();
6647 Condition cond = Condition.fromString(mc.getCondition());
6648 String pattern = mc.getValue();
6649 FeatureMatcherI matchCondition = null;
6650 if (filterBy == FilterBy.BY_LABEL)
6652 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6654 else if (filterBy == FilterBy.BY_SCORE)
6656 matchCondition = FeatureMatcher.byScore(cond, pattern);
6659 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6661 final List<String> attributeName = mc.getAttributeName();
6662 String[] attNames = attributeName
6663 .toArray(new String[attributeName.size()]);
6664 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6669 * note this throws IllegalStateException if AND-ing to a
6670 * previously OR-ed compound condition, or vice versa
6674 matcherSet.and(matchCondition);
6678 matcherSet.or(matchCondition);
6684 * compound condition
6686 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6687 .getCompoundMatcher().getMatcherSet();
6688 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6689 if (matchers.size() == 2)
6691 parseFilterConditions(matcherSet, matchers.get(0), anded);
6692 parseFilterConditions(matcherSet, matchers.get(1), anded);
6696 System.err.println("Malformed compound filter condition");
6702 * Loads one XML model of a feature colour to a Jalview object
6704 * @param colourModel
6707 public static FeatureColourI parseColour(Colour colourModel)
6709 FeatureColourI colour = null;
6711 if (colourModel.getMax() != null)
6713 Color mincol = null;
6714 Color maxcol = null;
6715 Color noValueColour = null;
6719 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6720 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6721 } catch (Exception e)
6723 Console.warn("Couldn't parse out graduated feature color.", e);
6726 NoValueColour noCol = colourModel.getNoValueColour();
6727 if (noCol == NoValueColour.MIN)
6729 noValueColour = mincol;
6731 else if (noCol == NoValueColour.MAX)
6733 noValueColour = maxcol;
6736 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6737 safeFloat(colourModel.getMin()),
6738 safeFloat(colourModel.getMax()));
6739 final List<String> attributeName = colourModel.getAttributeName();
6740 String[] attributes = attributeName
6741 .toArray(new String[attributeName.size()]);
6742 if (attributes != null && attributes.length > 0)
6744 colour.setAttributeName(attributes);
6746 if (colourModel.isAutoScale() != null)
6748 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6750 if (colourModel.isColourByLabel() != null)
6752 colour.setColourByLabel(
6753 colourModel.isColourByLabel().booleanValue());
6755 if (colourModel.getThreshold() != null)
6757 colour.setThreshold(colourModel.getThreshold().floatValue());
6759 ThresholdType ttyp = colourModel.getThreshType();
6760 if (ttyp == ThresholdType.ABOVE)
6762 colour.setAboveThreshold(true);
6764 else if (ttyp == ThresholdType.BELOW)
6766 colour.setBelowThreshold(true);
6771 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6772 colour = new FeatureColour(color);
6778 public static void setStateSavedUpToDate(boolean s)
6780 Console.debug("Setting overall stateSavedUpToDate to " + s);
6781 stateSavedUpToDate = s;
6784 public static boolean stateSavedUpToDate()
6786 Console.debug("Returning overall stateSavedUpToDate value: "
6787 + stateSavedUpToDate);
6788 return stateSavedUpToDate;
6791 public static boolean allSavedUpToDate()
6793 if (stateSavedUpToDate()) // nothing happened since last project save
6796 AlignFrame[] frames = Desktop.getAlignFrames();
6799 for (int i = 0; i < frames.length; i++)
6801 if (frames[i] == null)
6803 if (!frames[i].getViewport().savedUpToDate())
6804 return false; // at least one alignment is not individually saved
6810 // used for debugging and tests
6811 private static int debugDelaySave = 20;
6813 public static void setDebugDelaySave(int n)