2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Enumeration;
49 import java.util.GregorianCalendar;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Hashtable;
53 import java.util.IdentityHashMap;
54 import java.util.Iterator;
55 import java.util.LinkedHashMap;
56 import java.util.List;
57 import java.util.Locale;
59 import java.util.Map.Entry;
61 import java.util.Vector;
62 import java.util.jar.JarEntry;
63 import java.util.jar.JarInputStream;
64 import java.util.jar.JarOutputStream;
66 import javax.swing.JInternalFrame;
67 import javax.swing.SwingUtilities;
68 import javax.xml.bind.JAXBContext;
69 import javax.xml.bind.JAXBElement;
70 import javax.xml.bind.Marshaller;
71 import javax.xml.datatype.DatatypeConfigurationException;
72 import javax.xml.datatype.DatatypeFactory;
73 import javax.xml.datatype.XMLGregorianCalendar;
74 import javax.xml.stream.XMLInputFactory;
75 import javax.xml.stream.XMLStreamReader;
77 import jalview.analysis.Conservation;
78 import jalview.analysis.PCA;
79 import jalview.analysis.scoremodels.ScoreModels;
80 import jalview.analysis.scoremodels.SimilarityParams;
81 import jalview.api.FeatureColourI;
82 import jalview.api.ViewStyleI;
83 import jalview.api.analysis.ScoreModelI;
84 import jalview.api.analysis.SimilarityParamsI;
85 import jalview.api.structures.JalviewStructureDisplayI;
86 import jalview.bin.Cache;
87 import jalview.datamodel.AlignedCodonFrame;
88 import jalview.datamodel.Alignment;
89 import jalview.datamodel.AlignmentAnnotation;
90 import jalview.datamodel.AlignmentI;
91 import jalview.datamodel.DBRefEntry;
92 import jalview.datamodel.GeneLocus;
93 import jalview.datamodel.GraphLine;
94 import jalview.datamodel.PDBEntry;
95 import jalview.datamodel.Point;
96 import jalview.datamodel.RnaViewerModel;
97 import jalview.datamodel.SequenceFeature;
98 import jalview.datamodel.SequenceGroup;
99 import jalview.datamodel.SequenceI;
100 import jalview.datamodel.StructureViewerModel;
101 import jalview.datamodel.StructureViewerModel.StructureData;
102 import jalview.datamodel.features.FeatureMatcher;
103 import jalview.datamodel.features.FeatureMatcherI;
104 import jalview.datamodel.features.FeatureMatcherSet;
105 import jalview.datamodel.features.FeatureMatcherSetI;
106 import jalview.ext.varna.RnaModel;
107 import jalview.gui.AlignFrame;
108 import jalview.gui.AlignViewport;
109 import jalview.gui.AlignmentPanel;
110 import jalview.gui.AppVarna;
111 import jalview.gui.Desktop;
112 import jalview.gui.JvOptionPane;
113 import jalview.gui.OOMWarning;
114 import jalview.gui.OverviewPanel;
115 import jalview.gui.PCAPanel;
116 import jalview.gui.PaintRefresher;
117 import jalview.gui.SplitFrame;
118 import jalview.gui.StructureViewer;
119 import jalview.gui.StructureViewer.ViewerType;
120 import jalview.gui.StructureViewerBase;
121 import jalview.gui.TreePanel;
122 import jalview.io.BackupFiles;
123 import jalview.io.DataSourceType;
124 import jalview.io.FileFormat;
125 import jalview.io.NewickFile;
126 import jalview.math.Matrix;
127 import jalview.math.MatrixI;
128 import jalview.renderer.ResidueShaderI;
129 import jalview.schemes.AnnotationColourGradient;
130 import jalview.schemes.ColourSchemeI;
131 import jalview.schemes.ColourSchemeProperty;
132 import jalview.schemes.FeatureColour;
133 import jalview.schemes.ResidueProperties;
134 import jalview.schemes.UserColourScheme;
135 import jalview.structure.StructureSelectionManager;
136 import jalview.structures.models.AAStructureBindingModel;
137 import jalview.util.Format;
138 import jalview.util.HttpUtils;
139 import jalview.util.MessageManager;
140 import jalview.util.Platform;
141 import jalview.util.StringUtils;
142 import jalview.util.jarInputStreamProvider;
143 import jalview.util.matcher.Condition;
144 import jalview.viewmodel.AlignmentViewport;
145 import jalview.viewmodel.PCAModel;
146 import jalview.viewmodel.ViewportRanges;
147 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
148 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
149 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
150 import jalview.ws.jws2.Jws2Discoverer;
151 import jalview.ws.jws2.dm.AAConSettings;
152 import jalview.ws.jws2.jabaws2.Jws2Instance;
153 import jalview.ws.params.ArgumentI;
154 import jalview.ws.params.AutoCalcSetting;
155 import jalview.ws.params.WsParamSetI;
156 import jalview.xml.binding.jalview.AlcodonFrame;
157 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
158 import jalview.xml.binding.jalview.Annotation;
159 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
160 import jalview.xml.binding.jalview.AnnotationColourScheme;
161 import jalview.xml.binding.jalview.AnnotationElement;
162 import jalview.xml.binding.jalview.DoubleMatrix;
163 import jalview.xml.binding.jalview.DoubleVector;
164 import jalview.xml.binding.jalview.Feature;
165 import jalview.xml.binding.jalview.Feature.OtherData;
166 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
167 import jalview.xml.binding.jalview.FilterBy;
168 import jalview.xml.binding.jalview.JalviewModel;
169 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
170 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
171 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
172 import jalview.xml.binding.jalview.JalviewModel.JGroup;
173 import jalview.xml.binding.jalview.JalviewModel.JSeq;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
176 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
177 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
178 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
181 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
182 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
183 import jalview.xml.binding.jalview.JalviewModel.Tree;
184 import jalview.xml.binding.jalview.JalviewModel.UserColours;
185 import jalview.xml.binding.jalview.JalviewModel.Viewport;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
187 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
188 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
189 import jalview.xml.binding.jalview.JalviewUserColours;
190 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
191 import jalview.xml.binding.jalview.MapListType.MapListFrom;
192 import jalview.xml.binding.jalview.MapListType.MapListTo;
193 import jalview.xml.binding.jalview.Mapping;
194 import jalview.xml.binding.jalview.NoValueColour;
195 import jalview.xml.binding.jalview.ObjectFactory;
196 import jalview.xml.binding.jalview.PcaDataType;
197 import jalview.xml.binding.jalview.Pdbentry.Property;
198 import jalview.xml.binding.jalview.Sequence;
199 import jalview.xml.binding.jalview.Sequence.DBRef;
200 import jalview.xml.binding.jalview.SequenceSet;
201 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
202 import jalview.xml.binding.jalview.ThresholdType;
203 import jalview.xml.binding.jalview.VAMSAS;
206 * Write out the current jalview desktop state as a Jalview XML stream.
208 * Note: the vamsas objects referred to here are primitive versions of the
209 * VAMSAS project schema elements - they are not the same and most likely never
213 * @version $Revision: 1.134 $
215 public class Jalview2XML
218 // BH 2018 we add the .jvp binary extension to J2S so that
219 // it will declare that binary when we do the file save from the browser
223 Platform.addJ2SBinaryType(".jvp?");
226 private static final String VIEWER_PREFIX = "viewer_";
228 private static final String RNA_PREFIX = "rna_";
230 private static final String UTF_8 = "UTF-8";
233 * prefix for recovering datasets for alignments with multiple views where
234 * non-existent dataset IDs were written for some views
236 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
238 // use this with nextCounter() to make unique names for entities
239 private int counter = 0;
242 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
243 * of sequence objects are created.
245 IdentityHashMap<SequenceI, String> seqsToIds = null;
248 * jalview XML Sequence ID to jalview sequence object reference (both dataset
249 * and alignment sequences. Populated as XML reps of sequence objects are
252 Map<String, SequenceI> seqRefIds = null;
254 Map<String, SequenceI> incompleteSeqs = null;
256 List<SeqFref> frefedSequence = null;
258 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
261 * Map of reconstructed AlignFrame objects that appear to have come from
262 * SplitFrame objects (have a dna/protein complement view).
264 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
267 * Map from displayed rna structure models to their saved session state jar
270 private Map<RnaModel, String> rnaSessions = new HashMap<>();
273 * A helper method for safely using the value of an optional attribute that
274 * may be null if not present in the XML. Answers the boolean value, or false
280 public static boolean safeBoolean(Boolean b)
282 return b == null ? false : b.booleanValue();
286 * A helper method for safely using the value of an optional attribute that
287 * may be null if not present in the XML. Answers the integer value, or zero
293 public static int safeInt(Integer i)
295 return i == null ? 0 : i.intValue();
299 * A helper method for safely using the value of an optional attribute that
300 * may be null if not present in the XML. Answers the float value, or zero if
306 public static float safeFloat(Float f)
308 return f == null ? 0f : f.floatValue();
312 * create/return unique hash string for sq
315 * @return new or existing unique string for sq
317 String seqHash(SequenceI sq)
319 if (seqsToIds == null)
323 if (seqsToIds.containsKey(sq))
325 return seqsToIds.get(sq);
329 // create sequential key
330 String key = "sq" + (seqsToIds.size() + 1);
331 key = makeHashCode(sq, key); // check we don't have an external reference
333 seqsToIds.put(sq, key);
340 if (seqsToIds == null)
342 seqsToIds = new IdentityHashMap<>();
344 if (seqRefIds == null)
346 seqRefIds = new HashMap<>();
348 if (incompleteSeqs == null)
350 incompleteSeqs = new HashMap<>();
352 if (frefedSequence == null)
354 frefedSequence = new ArrayList<>();
362 public Jalview2XML(boolean raiseGUI)
364 this.raiseGUI = raiseGUI;
368 * base class for resolving forward references to sequences by their ID
373 abstract class SeqFref
379 public SeqFref(String _sref, String type)
385 public String getSref()
390 public SequenceI getSrefSeq()
392 return seqRefIds.get(sref);
395 public boolean isResolvable()
397 return seqRefIds.get(sref) != null;
400 public SequenceI getSrefDatasetSeq()
402 SequenceI sq = seqRefIds.get(sref);
405 while (sq.getDatasetSequence() != null)
407 sq = sq.getDatasetSequence();
414 * @return true if the forward reference was fully resolved
416 abstract boolean resolve();
419 public String toString()
421 return type + " reference to " + sref;
426 * create forward reference for a mapping
432 public SeqFref newMappingRef(final String sref,
433 final jalview.datamodel.Mapping _jmap)
435 SeqFref fref = new SeqFref(sref, "Mapping")
437 public jalview.datamodel.Mapping jmap = _jmap;
442 SequenceI seq = getSrefDatasetSeq();
454 public SeqFref newAlcodMapRef(final String sref,
455 final AlignedCodonFrame _cf,
456 final jalview.datamodel.Mapping _jmap)
459 SeqFref fref = new SeqFref(sref, "Codon Frame")
461 AlignedCodonFrame cf = _cf;
463 public jalview.datamodel.Mapping mp = _jmap;
466 public boolean isResolvable()
468 return super.isResolvable() && mp.getTo() != null;
474 SequenceI seq = getSrefDatasetSeq();
479 cf.addMap(seq, mp.getTo(), mp.getMap());
486 public void resolveFrefedSequences()
488 Iterator<SeqFref> nextFref = frefedSequence.iterator();
489 int toresolve = frefedSequence.size();
490 int unresolved = 0, failedtoresolve = 0;
491 while (nextFref.hasNext())
493 SeqFref ref = nextFref.next();
494 if (ref.isResolvable())
506 } catch (Exception x)
509 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
522 System.err.println("Jalview Project Import: There were " + unresolved
523 + " forward references left unresolved on the stack.");
525 if (failedtoresolve > 0)
527 System.err.println("SERIOUS! " + failedtoresolve
528 + " resolvable forward references failed to resolve.");
530 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
533 "Jalview Project Import: There are " + incompleteSeqs.size()
534 + " sequences which may have incomplete metadata.");
535 if (incompleteSeqs.size() < 10)
537 for (SequenceI s : incompleteSeqs.values())
539 System.err.println(s.toString());
545 "Too many to report. Skipping output of incomplete sequences.");
551 * This maintains a map of viewports, the key being the seqSetId. Important to
552 * set historyItem and redoList for multiple views
554 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
556 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
558 String uniqueSetSuffix = "";
561 * List of pdbfiles added to Jar
563 List<String> pdbfiles = null;
565 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
566 public void saveState(File statefile)
568 FileOutputStream fos = null;
573 fos = new FileOutputStream(statefile);
575 JarOutputStream jout = new JarOutputStream(fos);
579 } catch (Exception e)
581 Cache.log.error("Couln't write Jalview state to " + statefile, e);
582 // TODO: inform user of the problem - they need to know if their data was
584 if (errorMessage == null)
586 errorMessage = "Did't write Jalview Archive to output file '"
587 + statefile + "' - See console error log for details";
591 errorMessage += "(Didn't write Jalview Archive to output file '"
602 } catch (IOException e)
612 * Writes a jalview project archive to the given Jar output stream.
616 public void saveState(JarOutputStream jout)
618 AlignFrame[] frames = Desktop.getAlignFrames();
624 saveAllFrames(Arrays.asList(frames), jout);
628 * core method for storing state for a set of AlignFrames.
631 * - frames involving all data to be exported (including containing
634 * - project output stream
636 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
638 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
641 * ensure cached data is clear before starting
643 // todo tidy up seqRefIds, seqsToIds initialisation / reset
645 splitFrameCandidates.clear();
650 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
651 // //////////////////////////////////////////////////
653 List<String> shortNames = new ArrayList<>();
654 List<String> viewIds = new ArrayList<>();
657 for (int i = frames.size() - 1; i > -1; i--)
659 AlignFrame af = frames.get(i);
661 if (skipList != null && skipList
662 .containsKey(af.getViewport().getSequenceSetId()))
667 String shortName = makeFilename(af, shortNames);
669 int apSize = af.getAlignPanels().size();
671 for (int ap = 0; ap < apSize; ap++)
673 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
675 String fileName = apSize == 1 ? shortName : ap + shortName;
676 if (!fileName.endsWith(".xml"))
678 fileName = fileName + ".xml";
681 saveState(apanel, fileName, jout, viewIds);
683 String dssid = getDatasetIdRef(
684 af.getViewport().getAlignment().getDataset());
685 if (!dsses.containsKey(dssid))
687 dsses.put(dssid, af);
692 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
698 } catch (Exception foo)
702 } catch (Exception ex)
704 // TODO: inform user of the problem - they need to know if their data was
706 if (errorMessage == null)
708 errorMessage = "Couldn't write Jalview Archive - see error output for details";
710 ex.printStackTrace();
715 * Generates a distinct file name, based on the title of the AlignFrame, by
716 * appending _n for increasing n until an unused name is generated. The new
717 * name (without its extension) is added to the list.
721 * @return the generated name, with .xml extension
723 protected String makeFilename(AlignFrame af, List<String> namesUsed)
725 String shortName = af.getTitle();
727 if (shortName.indexOf(File.separatorChar) > -1)
729 shortName = shortName
730 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
735 while (namesUsed.contains(shortName))
737 if (shortName.endsWith("_" + (count - 1)))
739 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
742 shortName = shortName.concat("_" + count);
746 namesUsed.add(shortName);
748 if (!shortName.endsWith(".xml"))
750 shortName = shortName + ".xml";
755 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
756 public boolean saveAlignment(AlignFrame af, String jarFile,
761 // create backupfiles object and get new temp filename destination
762 boolean doBackup = BackupFiles.getEnabled();
763 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
764 FileOutputStream fos = new FileOutputStream(
765 doBackup ? backupfiles.getTempFilePath() : jarFile);
767 JarOutputStream jout = new JarOutputStream(fos);
768 List<AlignFrame> frames = new ArrayList<>();
770 // resolve splitframes
771 if (af.getViewport().getCodingComplement() != null)
773 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
779 saveAllFrames(frames, jout);
783 } catch (Exception foo)
787 boolean success = true;
791 backupfiles.setWriteSuccess(success);
792 success = backupfiles.rollBackupsAndRenameTempFile();
796 } catch (Exception ex)
798 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
799 ex.printStackTrace();
804 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
805 String fileName, JarOutputStream jout)
808 for (String dssids : dsses.keySet())
810 AlignFrame _af = dsses.get(dssids);
811 String jfileName = fileName + " Dataset for " + _af.getTitle();
812 if (!jfileName.endsWith(".xml"))
814 jfileName = jfileName + ".xml";
816 saveState(_af.alignPanel, jfileName, true, jout, null);
821 * create a JalviewModel from an alignment view and marshall it to a
825 * panel to create jalview model for
827 * name of alignment panel written to output stream
834 public JalviewModel saveState(AlignmentPanel ap, String fileName,
835 JarOutputStream jout, List<String> viewIds)
837 return saveState(ap, fileName, false, jout, viewIds);
841 * create a JalviewModel from an alignment view and marshall it to a
845 * panel to create jalview model for
847 * name of alignment panel written to output stream
849 * when true, only write the dataset for the alignment, not the data
850 * associated with the view.
856 public JalviewModel saveState(AlignmentPanel ap, String fileName,
857 boolean storeDS, JarOutputStream jout, List<String> viewIds)
861 viewIds = new ArrayList<>();
866 List<UserColourScheme> userColours = new ArrayList<>();
868 AlignViewport av = ap.av;
869 ViewportRanges vpRanges = av.getRanges();
871 final ObjectFactory objectFactory = new ObjectFactory();
872 JalviewModel object = objectFactory.createJalviewModel();
873 object.setVamsasModel(new VAMSAS());
875 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
878 GregorianCalendar c = new GregorianCalendar();
879 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
880 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
881 object.setCreationDate(now);
882 } catch (DatatypeConfigurationException e)
884 System.err.println("error writing date: " + e.toString());
887 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
890 * rjal is full height alignment, jal is actual alignment with full metadata
891 * but excludes hidden sequences.
893 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
895 if (av.hasHiddenRows())
897 rjal = jal.getHiddenSequences().getFullAlignment();
900 SequenceSet vamsasSet = new SequenceSet();
902 // JalviewModelSequence jms = new JalviewModelSequence();
904 vamsasSet.setGapChar(jal.getGapCharacter() + "");
906 if (jal.getDataset() != null)
908 // dataset id is the dataset's hashcode
909 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
912 // switch jal and the dataset
913 jal = jal.getDataset();
917 if (jal.getProperties() != null)
919 Enumeration en = jal.getProperties().keys();
920 while (en.hasMoreElements())
922 String key = en.nextElement().toString();
923 SequenceSetProperties ssp = new SequenceSetProperties();
925 ssp.setValue(jal.getProperties().get(key).toString());
926 // vamsasSet.addSequenceSetProperties(ssp);
927 vamsasSet.getSequenceSetProperties().add(ssp);
932 Set<String> calcIdSet = new HashSet<>();
933 // record the set of vamsas sequence XML POJO we create.
934 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
936 for (final SequenceI jds : rjal.getSequences())
938 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
939 : jds.getDatasetSequence();
940 String id = seqHash(jds);
941 if (vamsasSetIds.get(id) == null)
943 if (seqRefIds.get(id) != null && !storeDS)
945 // This happens for two reasons: 1. multiple views are being
947 // 2. the hashCode has collided with another sequence's code. This
949 // HAPPEN! (PF00072.15.stk does this)
950 // JBPNote: Uncomment to debug writing out of files that do not read
951 // back in due to ArrayOutOfBoundExceptions.
952 // System.err.println("vamsasSeq backref: "+id+"");
953 // System.err.println(jds.getName()+"
954 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
955 // System.err.println("Hashcode: "+seqHash(jds));
956 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
957 // System.err.println(rsq.getName()+"
958 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
959 // System.err.println("Hashcode: "+seqHash(rsq));
963 vamsasSeq = createVamsasSequence(id, jds);
964 // vamsasSet.addSequence(vamsasSeq);
965 vamsasSet.getSequence().add(vamsasSeq);
966 vamsasSetIds.put(id, vamsasSeq);
967 seqRefIds.put(id, jds);
971 jseq.setStart(jds.getStart());
972 jseq.setEnd(jds.getEnd());
973 jseq.setColour(av.getSequenceColour(jds).getRGB());
975 jseq.setId(id); // jseq id should be a string not a number
978 // Store any sequences this sequence represents
979 if (av.hasHiddenRows())
981 // use rjal, contains the full height alignment
983 av.getAlignment().getHiddenSequences().isHidden(jds));
985 if (av.isHiddenRepSequence(jds))
987 jalview.datamodel.SequenceI[] reps = av
988 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
990 for (int h = 0; h < reps.length; h++)
994 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
995 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1000 // mark sequence as reference - if it is the reference for this view
1001 if (jal.hasSeqrep())
1003 jseq.setViewreference(jds == jal.getSeqrep());
1007 // TODO: omit sequence features from each alignment view's XML dump if we
1008 // are storing dataset
1009 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1010 for (SequenceFeature sf : sfs)
1012 // Features features = new Features();
1013 Feature features = new Feature();
1015 features.setBegin(sf.getBegin());
1016 features.setEnd(sf.getEnd());
1017 features.setDescription(sf.getDescription());
1018 features.setType(sf.getType());
1019 features.setFeatureGroup(sf.getFeatureGroup());
1020 features.setScore(sf.getScore());
1021 if (sf.links != null)
1023 for (int l = 0; l < sf.links.size(); l++)
1025 OtherData keyValue = new OtherData();
1026 keyValue.setKey("LINK_" + l);
1027 keyValue.setValue(sf.links.elementAt(l).toString());
1028 // features.addOtherData(keyValue);
1029 features.getOtherData().add(keyValue);
1032 if (sf.otherDetails != null)
1035 * save feature attributes, which may be simple strings or
1036 * map valued (have sub-attributes)
1038 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1040 String key = entry.getKey();
1041 Object value = entry.getValue();
1042 if (value instanceof Map<?, ?>)
1044 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1047 OtherData otherData = new OtherData();
1048 otherData.setKey(key);
1049 otherData.setKey2(subAttribute.getKey());
1050 otherData.setValue(subAttribute.getValue().toString());
1051 // features.addOtherData(otherData);
1052 features.getOtherData().add(otherData);
1057 OtherData otherData = new OtherData();
1058 otherData.setKey(key);
1059 otherData.setValue(value.toString());
1060 // features.addOtherData(otherData);
1061 features.getOtherData().add(otherData);
1066 // jseq.addFeatures(features);
1067 jseq.getFeatures().add(features);
1070 if (jdatasq.getAllPDBEntries() != null)
1072 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1073 while (en.hasMoreElements())
1075 Pdbids pdb = new Pdbids();
1076 jalview.datamodel.PDBEntry entry = en.nextElement();
1078 String pdbId = entry.getId();
1080 pdb.setType(entry.getType());
1083 * Store any structure views associated with this sequence. This
1084 * section copes with duplicate entries in the project, so a dataset
1085 * only view *should* be coped with sensibly.
1087 // This must have been loaded, is it still visible?
1088 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1089 String matchedFile = null;
1090 for (int f = frames.length - 1; f > -1; f--)
1092 if (frames[f] instanceof StructureViewerBase)
1094 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1095 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1096 viewIds, matchedFile, viewFrame);
1098 * Only store each structure viewer's state once in the project
1099 * jar. First time through only (storeDS==false)
1101 String viewId = viewFrame.getViewId();
1102 String viewerType = viewFrame.getViewerType().toString();
1103 if (!storeDS && !viewIds.contains(viewId))
1105 viewIds.add(viewId);
1106 File viewerState = viewFrame.saveSession();
1107 if (viewerState != null)
1109 copyFileToJar(jout, viewerState.getPath(),
1110 getViewerJarEntryName(viewId), viewerType);
1115 "Failed to save viewer state for " + viewerType);
1121 if (matchedFile != null || entry.getFile() != null)
1123 if (entry.getFile() != null)
1126 matchedFile = entry.getFile();
1128 pdb.setFile(matchedFile); // entry.getFile());
1129 if (pdbfiles == null)
1131 pdbfiles = new ArrayList<>();
1134 if (!pdbfiles.contains(pdbId))
1136 pdbfiles.add(pdbId);
1137 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1141 Enumeration<String> props = entry.getProperties();
1142 if (props.hasMoreElements())
1144 // PdbentryItem item = new PdbentryItem();
1145 while (props.hasMoreElements())
1147 Property prop = new Property();
1148 String key = props.nextElement();
1150 prop.setValue(entry.getProperty(key).toString());
1151 // item.addProperty(prop);
1152 pdb.getProperty().add(prop);
1154 // pdb.addPdbentryItem(item);
1157 // jseq.addPdbids(pdb);
1158 jseq.getPdbids().add(pdb);
1162 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1164 // jms.addJSeq(jseq);
1165 object.getJSeq().add(jseq);
1168 if (!storeDS && av.hasHiddenRows())
1170 jal = av.getAlignment();
1174 if (storeDS && jal.getCodonFrames() != null)
1176 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1177 for (AlignedCodonFrame acf : jac)
1179 AlcodonFrame alc = new AlcodonFrame();
1180 if (acf.getProtMappings() != null
1181 && acf.getProtMappings().length > 0)
1183 boolean hasMap = false;
1184 SequenceI[] dnas = acf.getdnaSeqs();
1185 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1186 for (int m = 0; m < pmaps.length; m++)
1188 AlcodMap alcmap = new AlcodMap();
1189 alcmap.setDnasq(seqHash(dnas[m]));
1191 createVamsasMapping(pmaps[m], dnas[m], null, false));
1192 // alc.addAlcodMap(alcmap);
1193 alc.getAlcodMap().add(alcmap);
1198 // vamsasSet.addAlcodonFrame(alc);
1199 vamsasSet.getAlcodonFrame().add(alc);
1202 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1204 // AlcodonFrame alc = new AlcodonFrame();
1205 // vamsasSet.addAlcodonFrame(alc);
1206 // for (int p = 0; p < acf.aaWidth; p++)
1208 // Alcodon cmap = new Alcodon();
1209 // if (acf.codons[p] != null)
1211 // // Null codons indicate a gapped column in the translated peptide
1213 // cmap.setPos1(acf.codons[p][0]);
1214 // cmap.setPos2(acf.codons[p][1]);
1215 // cmap.setPos3(acf.codons[p][2]);
1217 // alc.addAlcodon(cmap);
1219 // if (acf.getProtMappings() != null
1220 // && acf.getProtMappings().length > 0)
1222 // SequenceI[] dnas = acf.getdnaSeqs();
1223 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1224 // for (int m = 0; m < pmaps.length; m++)
1226 // AlcodMap alcmap = new AlcodMap();
1227 // alcmap.setDnasq(seqHash(dnas[m]));
1228 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1230 // alc.addAlcodMap(alcmap);
1237 // /////////////////////////////////
1238 if (!storeDS && av.getCurrentTree() != null)
1240 // FIND ANY ASSOCIATED TREES
1241 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1242 if (Desktop.desktop != null)
1244 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1246 for (int t = 0; t < frames.length; t++)
1248 if (frames[t] instanceof TreePanel)
1250 TreePanel tp = (TreePanel) frames[t];
1252 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1254 JalviewModel.Tree tree = new JalviewModel.Tree();
1255 tree.setTitle(tp.getTitle());
1256 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1257 tree.setNewick(tp.getTree().print());
1258 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1260 tree.setFitToWindow(tp.fitToWindow.getState());
1261 tree.setFontName(tp.getTreeFont().getName());
1262 tree.setFontSize(tp.getTreeFont().getSize());
1263 tree.setFontStyle(tp.getTreeFont().getStyle());
1264 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1266 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1267 tree.setShowDistances(tp.distanceMenu.getState());
1269 tree.setHeight(tp.getHeight());
1270 tree.setWidth(tp.getWidth());
1271 tree.setXpos(tp.getX());
1272 tree.setYpos(tp.getY());
1273 tree.setId(makeHashCode(tp, null));
1274 tree.setLinkToAllViews(
1275 tp.getTreeCanvas().isApplyToAllViews());
1277 // jms.addTree(tree);
1278 object.getTree().add(tree);
1288 if (!storeDS && Desktop.desktop != null)
1290 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1292 if (frame instanceof PCAPanel)
1294 PCAPanel panel = (PCAPanel) frame;
1295 if (panel.getAlignViewport().getAlignment() == jal)
1297 savePCA(panel, object);
1305 * store forward refs from an annotationRow to any groups
1307 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1310 for (SequenceI sq : jal.getSequences())
1312 // Store annotation on dataset sequences only
1313 AlignmentAnnotation[] aa = sq.getAnnotation();
1314 if (aa != null && aa.length > 0)
1316 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1323 if (jal.getAlignmentAnnotation() != null)
1325 // Store the annotation shown on the alignment.
1326 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1327 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1332 if (jal.getGroups() != null)
1334 JGroup[] groups = new JGroup[jal.getGroups().size()];
1336 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1338 JGroup jGroup = new JGroup();
1339 groups[++i] = jGroup;
1341 jGroup.setStart(sg.getStartRes());
1342 jGroup.setEnd(sg.getEndRes());
1343 jGroup.setName(sg.getName());
1344 if (groupRefs.containsKey(sg))
1346 // group has references so set its ID field
1347 jGroup.setId(groupRefs.get(sg));
1349 ColourSchemeI colourScheme = sg.getColourScheme();
1350 if (colourScheme != null)
1352 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1353 if (groupColourScheme.conservationApplied())
1355 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1357 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1359 jGroup.setColour(setUserColourScheme(colourScheme,
1360 userColours, object));
1364 jGroup.setColour(colourScheme.getSchemeName());
1367 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1369 jGroup.setColour("AnnotationColourGradient");
1370 jGroup.setAnnotationColours(constructAnnotationColours(
1371 (jalview.schemes.AnnotationColourGradient) colourScheme,
1372 userColours, object));
1374 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1377 setUserColourScheme(colourScheme, userColours, object));
1381 jGroup.setColour(colourScheme.getSchemeName());
1384 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1387 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1388 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1389 jGroup.setDisplayText(sg.getDisplayText());
1390 jGroup.setColourText(sg.getColourText());
1391 jGroup.setTextCol1(sg.textColour.getRGB());
1392 jGroup.setTextCol2(sg.textColour2.getRGB());
1393 jGroup.setTextColThreshold(sg.thresholdTextColour);
1394 jGroup.setShowUnconserved(sg.getShowNonconserved());
1395 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1396 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1397 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1398 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1399 for (SequenceI seq : sg.getSequences())
1401 // jGroup.addSeq(seqHash(seq));
1402 jGroup.getSeq().add(seqHash(seq));
1406 // jms.setJGroup(groups);
1408 for (JGroup grp : groups)
1410 object.getJGroup().add(grp);
1415 // /////////SAVE VIEWPORT
1416 Viewport view = new Viewport();
1417 view.setTitle(ap.alignFrame.getTitle());
1418 view.setSequenceSetId(
1419 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1420 view.setId(av.getViewId());
1421 if (av.getCodingComplement() != null)
1423 view.setComplementId(av.getCodingComplement().getViewId());
1425 view.setViewName(av.getViewName());
1426 view.setGatheredViews(av.isGatherViewsHere());
1428 Rectangle size = ap.av.getExplodedGeometry();
1429 Rectangle position = size;
1432 size = ap.alignFrame.getBounds();
1433 if (av.getCodingComplement() != null)
1435 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1443 view.setXpos(position.x);
1444 view.setYpos(position.y);
1446 view.setWidth(size.width);
1447 view.setHeight(size.height);
1449 view.setStartRes(vpRanges.getStartRes());
1450 view.setStartSeq(vpRanges.getStartSeq());
1452 OverviewPanel ov = ap.getOverviewPanel();
1455 Overview overview = new Overview();
1456 overview.setTitle(ov.getTitle());
1457 Rectangle bounds = ov.getFrameBounds();
1458 overview.setXpos(bounds.x);
1459 overview.setYpos(bounds.y);
1460 overview.setWidth(bounds.width);
1461 overview.setHeight(bounds.height);
1462 overview.setShowHidden(ov.isShowHiddenRegions());
1463 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1464 overview.setResidueColour(
1465 ov.getCanvas().getResidueColour().getRGB());
1466 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1467 view.setOverview(overview);
1469 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1471 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1472 userColours, object));
1475 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1477 AnnotationColourScheme ac = constructAnnotationColours(
1478 (jalview.schemes.AnnotationColourGradient) av
1479 .getGlobalColourScheme(),
1480 userColours, object);
1482 view.setAnnotationColours(ac);
1483 view.setBgColour("AnnotationColourGradient");
1487 view.setBgColour(ColourSchemeProperty
1488 .getColourName(av.getGlobalColourScheme()));
1491 ResidueShaderI vcs = av.getResidueShading();
1492 ColourSchemeI cs = av.getGlobalColourScheme();
1496 if (vcs.conservationApplied())
1498 view.setConsThreshold(vcs.getConservationInc());
1499 if (cs instanceof jalview.schemes.UserColourScheme)
1501 view.setBgColour(setUserColourScheme(cs, userColours, object));
1504 view.setPidThreshold(vcs.getThreshold());
1507 view.setConservationSelected(av.getConservationSelected());
1508 view.setPidSelected(av.getAbovePIDThreshold());
1509 final Font font = av.getFont();
1510 view.setFontName(font.getName());
1511 view.setFontSize(font.getSize());
1512 view.setFontStyle(font.getStyle());
1513 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1514 view.setRenderGaps(av.isRenderGaps());
1515 view.setShowAnnotation(av.isShowAnnotation());
1516 view.setShowBoxes(av.getShowBoxes());
1517 view.setShowColourText(av.getColourText());
1518 view.setShowFullId(av.getShowJVSuffix());
1519 view.setRightAlignIds(av.isRightAlignIds());
1520 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1521 view.setShowText(av.getShowText());
1522 view.setShowUnconserved(av.getShowUnconserved());
1523 view.setWrapAlignment(av.getWrapAlignment());
1524 view.setTextCol1(av.getTextColour().getRGB());
1525 view.setTextCol2(av.getTextColour2().getRGB());
1526 view.setTextColThreshold(av.getThresholdTextColour());
1527 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1528 view.setShowSequenceLogo(av.isShowSequenceLogo());
1529 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1530 view.setShowGroupConsensus(av.isShowGroupConsensus());
1531 view.setShowGroupConservation(av.isShowGroupConservation());
1532 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1533 view.setShowDbRefTooltip(av.isShowDBRefs());
1534 view.setFollowHighlight(av.isFollowHighlight());
1535 view.setFollowSelection(av.followSelection);
1536 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1537 view.setShowComplementFeatures(av.isShowComplementFeatures());
1538 view.setShowComplementFeaturesOnTop(
1539 av.isShowComplementFeaturesOnTop());
1540 if (av.getFeaturesDisplayed() != null)
1542 FeatureSettings fs = new FeatureSettings();
1544 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1545 .getFeatureRenderer();
1546 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1548 Vector<String> settingsAdded = new Vector<>();
1549 if (renderOrder != null)
1551 for (String featureType : renderOrder)
1553 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1554 setting.setType(featureType);
1557 * save any filter for the feature type
1559 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1562 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1564 FeatureMatcherI firstFilter = filters.next();
1565 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1566 filters, filter.isAnded()));
1570 * save colour scheme for the feature type
1572 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1573 if (!fcol.isSimpleColour())
1575 setting.setColour(fcol.getMaxColour().getRGB());
1576 setting.setMincolour(fcol.getMinColour().getRGB());
1577 setting.setMin(fcol.getMin());
1578 setting.setMax(fcol.getMax());
1579 setting.setColourByLabel(fcol.isColourByLabel());
1580 if (fcol.isColourByAttribute())
1582 String[] attName = fcol.getAttributeName();
1583 setting.getAttributeName().add(attName[0]);
1584 if (attName.length > 1)
1586 setting.getAttributeName().add(attName[1]);
1589 setting.setAutoScale(fcol.isAutoScaled());
1590 setting.setThreshold(fcol.getThreshold());
1591 Color noColour = fcol.getNoColour();
1592 if (noColour == null)
1594 setting.setNoValueColour(NoValueColour.NONE);
1596 else if (noColour.equals(fcol.getMaxColour()))
1598 setting.setNoValueColour(NoValueColour.MAX);
1602 setting.setNoValueColour(NoValueColour.MIN);
1604 // -1 = No threshold, 0 = Below, 1 = Above
1605 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1606 : (fcol.isBelowThreshold() ? 0 : -1));
1610 setting.setColour(fcol.getColour().getRGB());
1614 av.getFeaturesDisplayed().isVisible(featureType));
1615 float rorder = fr.getOrder(featureType);
1618 setting.setOrder(rorder);
1620 /// fs.addSetting(setting);
1621 fs.getSetting().add(setting);
1622 settingsAdded.addElement(featureType);
1626 // is groups actually supposed to be a map here ?
1627 Iterator<String> en = fr.getFeatureGroups().iterator();
1628 Vector<String> groupsAdded = new Vector<>();
1629 while (en.hasNext())
1631 String grp = en.next();
1632 if (groupsAdded.contains(grp))
1636 Group g = new Group();
1638 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1641 fs.getGroup().add(g);
1642 groupsAdded.addElement(grp);
1644 // jms.setFeatureSettings(fs);
1645 object.setFeatureSettings(fs);
1648 if (av.hasHiddenColumns())
1650 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1651 .getHiddenColumns();
1654 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1658 Iterator<int[]> hiddenRegions = hidden.iterator();
1659 while (hiddenRegions.hasNext())
1661 int[] region = hiddenRegions.next();
1662 HiddenColumns hc = new HiddenColumns();
1663 hc.setStart(region[0]);
1664 hc.setEnd(region[1]);
1665 // view.addHiddenColumns(hc);
1666 view.getHiddenColumns().add(hc);
1670 if (calcIdSet.size() > 0)
1672 for (String calcId : calcIdSet)
1674 if (calcId.trim().length() > 0)
1676 CalcIdParam cidp = createCalcIdParam(calcId, av);
1677 // Some calcIds have no parameters.
1680 // view.addCalcIdParam(cidp);
1681 view.getCalcIdParam().add(cidp);
1687 // jms.addViewport(view);
1688 object.getViewport().add(view);
1690 // object.setJalviewModelSequence(jms);
1691 // object.getVamsasModel().addSequenceSet(vamsasSet);
1692 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1694 if (jout != null && fileName != null)
1696 // We may not want to write the object to disk,
1697 // eg we can copy the alignViewport to a new view object
1698 // using save and then load
1701 fileName = fileName.replace('\\', '/');
1702 System.out.println("Writing jar entry " + fileName);
1703 JarEntry entry = new JarEntry(fileName);
1704 jout.putNextEntry(entry);
1705 PrintWriter pout = new PrintWriter(
1706 new OutputStreamWriter(jout, UTF_8));
1707 JAXBContext jaxbContext = JAXBContext
1708 .newInstance(JalviewModel.class);
1709 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1711 // output pretty printed
1712 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1713 jaxbMarshaller.marshal(
1714 new ObjectFactory().createJalviewModel(object), pout);
1716 // jaxbMarshaller.marshal(object, pout);
1717 // marshaller.marshal(object);
1720 } catch (Exception ex)
1722 // TODO: raise error in GUI if marshalling failed.
1723 System.err.println("Error writing Jalview project");
1724 ex.printStackTrace();
1731 * Writes PCA viewer attributes and computed values to an XML model object and
1732 * adds it to the JalviewModel. Any exceptions are reported by logging.
1734 protected void savePCA(PCAPanel panel, JalviewModel object)
1738 PcaViewer viewer = new PcaViewer();
1739 viewer.setHeight(panel.getHeight());
1740 viewer.setWidth(panel.getWidth());
1741 viewer.setXpos(panel.getX());
1742 viewer.setYpos(panel.getY());
1743 viewer.setTitle(panel.getTitle());
1744 PCAModel pcaModel = panel.getPcaModel();
1745 viewer.setScoreModelName(pcaModel.getScoreModelName());
1746 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1747 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1748 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1750 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1751 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1752 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1753 SeqPointMin spmin = new SeqPointMin();
1754 spmin.setXPos(spMin[0]);
1755 spmin.setYPos(spMin[1]);
1756 spmin.setZPos(spMin[2]);
1757 viewer.setSeqPointMin(spmin);
1758 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1759 SeqPointMax spmax = new SeqPointMax();
1760 spmax.setXPos(spMax[0]);
1761 spmax.setYPos(spMax[1]);
1762 spmax.setZPos(spMax[2]);
1763 viewer.setSeqPointMax(spmax);
1764 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1765 viewer.setLinkToAllViews(
1766 panel.getRotatableCanvas().isApplyToAllViews());
1767 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1768 viewer.setIncludeGaps(sp.includeGaps());
1769 viewer.setMatchGaps(sp.matchGaps());
1770 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1771 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1774 * sequence points on display
1776 for (jalview.datamodel.SequencePoint spt : pcaModel
1777 .getSequencePoints())
1779 SequencePoint point = new SequencePoint();
1780 point.setSequenceRef(seqHash(spt.getSequence()));
1781 point.setXPos(spt.coord.x);
1782 point.setYPos(spt.coord.y);
1783 point.setZPos(spt.coord.z);
1784 viewer.getSequencePoint().add(point);
1788 * (end points of) axes on display
1790 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1793 Axis axis = new Axis();
1797 viewer.getAxis().add(axis);
1801 * raw PCA data (note we are not restoring PCA inputs here -
1802 * alignment view, score model, similarity parameters)
1804 PcaDataType data = new PcaDataType();
1805 viewer.setPcaData(data);
1806 PCA pca = pcaModel.getPcaData();
1808 DoubleMatrix pm = new DoubleMatrix();
1809 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1810 data.setPairwiseMatrix(pm);
1812 DoubleMatrix tm = new DoubleMatrix();
1813 saveDoubleMatrix(pca.getTridiagonal(), tm);
1814 data.setTridiagonalMatrix(tm);
1816 DoubleMatrix eigenMatrix = new DoubleMatrix();
1817 data.setEigenMatrix(eigenMatrix);
1818 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1820 object.getPcaViewer().add(viewer);
1821 } catch (Throwable t)
1823 Cache.log.error("Error saving PCA: " + t.getMessage());
1828 * Stores values from a matrix into an XML element, including (if present) the
1833 * @see #loadDoubleMatrix(DoubleMatrix)
1835 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1837 xmlMatrix.setRows(m.height());
1838 xmlMatrix.setColumns(m.width());
1839 for (int i = 0; i < m.height(); i++)
1841 DoubleVector row = new DoubleVector();
1842 for (int j = 0; j < m.width(); j++)
1844 row.getV().add(m.getValue(i, j));
1846 xmlMatrix.getRow().add(row);
1848 if (m.getD() != null)
1850 DoubleVector dVector = new DoubleVector();
1851 for (double d : m.getD())
1853 dVector.getV().add(d);
1855 xmlMatrix.setD(dVector);
1857 if (m.getE() != null)
1859 DoubleVector eVector = new DoubleVector();
1860 for (double e : m.getE())
1862 eVector.getV().add(e);
1864 xmlMatrix.setE(eVector);
1869 * Loads XML matrix data into a new Matrix object, including the D and/or E
1870 * vectors (if present)
1874 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1876 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1878 int rows = mData.getRows();
1879 double[][] vals = new double[rows][];
1881 for (int i = 0; i < rows; i++)
1883 List<Double> dVector = mData.getRow().get(i).getV();
1884 vals[i] = new double[dVector.size()];
1886 for (Double d : dVector)
1892 MatrixI m = new Matrix(vals);
1894 if (mData.getD() != null)
1896 List<Double> dVector = mData.getD().getV();
1897 double[] vec = new double[dVector.size()];
1899 for (Double d : dVector)
1905 if (mData.getE() != null)
1907 List<Double> dVector = mData.getE().getV();
1908 double[] vec = new double[dVector.size()];
1910 for (Double d : dVector)
1921 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1922 * for each viewer, with
1924 * <li>viewer geometry (position, size, split pane divider location)</li>
1925 * <li>index of the selected structure in the viewer (currently shows gapped
1927 * <li>the id of the annotation holding RNA secondary structure</li>
1928 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1930 * Varna viewer state is also written out (in native Varna XML) to separate
1931 * project jar entries. A separate entry is written for each RNA structure
1932 * displayed, with the naming convention
1934 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1942 * @param storeDataset
1944 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1945 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1946 boolean storeDataset)
1948 if (Desktop.desktop == null)
1952 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1953 for (int f = frames.length - 1; f > -1; f--)
1955 if (frames[f] instanceof AppVarna)
1957 AppVarna varna = (AppVarna) frames[f];
1959 * link the sequence to every viewer that is showing it and is linked to
1960 * its alignment panel
1962 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1964 String viewId = varna.getViewId();
1965 RnaViewer rna = new RnaViewer();
1966 rna.setViewId(viewId);
1967 rna.setTitle(varna.getTitle());
1968 rna.setXpos(varna.getX());
1969 rna.setYpos(varna.getY());
1970 rna.setWidth(varna.getWidth());
1971 rna.setHeight(varna.getHeight());
1972 rna.setDividerLocation(varna.getDividerLocation());
1973 rna.setSelectedRna(varna.getSelectedIndex());
1974 // jseq.addRnaViewer(rna);
1975 jseq.getRnaViewer().add(rna);
1978 * Store each Varna panel's state once in the project per sequence.
1979 * First time through only (storeDataset==false)
1981 // boolean storeSessions = false;
1982 // String sequenceViewId = viewId + seqsToIds.get(jds);
1983 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1985 // viewIds.add(sequenceViewId);
1986 // storeSessions = true;
1988 for (RnaModel model : varna.getModels())
1990 if (model.seq == jds)
1993 * VARNA saves each view (sequence or alignment secondary
1994 * structure, gapped or trimmed) as a separate XML file
1996 String jarEntryName = rnaSessions.get(model);
1997 if (jarEntryName == null)
2000 String varnaStateFile = varna.getStateInfo(model.rna);
2001 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2002 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2003 rnaSessions.put(model, jarEntryName);
2005 SecondaryStructure ss = new SecondaryStructure();
2006 String annotationId = varna.getAnnotation(jds).annotationId;
2007 ss.setAnnotationId(annotationId);
2008 ss.setViewerState(jarEntryName);
2009 ss.setGapped(model.gapped);
2010 ss.setTitle(model.title);
2011 // rna.addSecondaryStructure(ss);
2012 rna.getSecondaryStructure().add(ss);
2021 * Copy the contents of a file to a new entry added to the output jar
2025 * @param jarEntryName
2027 * additional identifying info to log to the console
2029 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2030 String jarEntryName, String msg)
2032 try (InputStream is = new FileInputStream(infilePath))
2034 File file = new File(infilePath);
2035 if (file.exists() && jout != null)
2038 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2039 jout.putNextEntry(new JarEntry(jarEntryName));
2042 // dis = new DataInputStream(new FileInputStream(file));
2043 // byte[] data = new byte[(int) file.length()];
2044 // dis.readFully(data);
2045 // writeJarEntry(jout, jarEntryName, data);
2047 } catch (Exception ex)
2049 ex.printStackTrace();
2054 * Copies input to output, in 4K buffers; handles any data (text or binary)
2058 * @throws IOException
2060 protected void copyAll(InputStream in, OutputStream out)
2063 byte[] buffer = new byte[4096];
2065 while ((bytesRead = in.read(buffer)) != -1)
2067 out.write(buffer, 0, bytesRead);
2072 * Save the state of a structure viewer
2077 * the archive XML element under which to save the state
2080 * @param matchedFile
2084 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2085 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2086 String matchedFile, StructureViewerBase viewFrame)
2088 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2091 * Look for any bindings for this viewer to the PDB file of interest
2092 * (including part matches excluding chain id)
2094 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2096 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2097 final String pdbId = pdbentry.getId();
2098 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2099 && entry.getId().toLowerCase(Locale.ROOT)
2100 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2103 * not interested in a binding to a different PDB entry here
2107 if (matchedFile == null)
2109 matchedFile = pdbentry.getFile();
2111 else if (!matchedFile.equals(pdbentry.getFile()))
2114 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2115 + pdbentry.getFile());
2119 // can get at it if the ID
2120 // match is ambiguous (e.g.
2123 for (int smap = 0; smap < viewFrame.getBinding()
2124 .getSequence()[peid].length; smap++)
2126 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2127 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2129 StructureState state = new StructureState();
2130 state.setVisible(true);
2131 state.setXpos(viewFrame.getX());
2132 state.setYpos(viewFrame.getY());
2133 state.setWidth(viewFrame.getWidth());
2134 state.setHeight(viewFrame.getHeight());
2135 final String viewId = viewFrame.getViewId();
2136 state.setViewId(viewId);
2137 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2138 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2139 state.setColourByJmol(viewFrame.isColouredByViewer());
2140 state.setType(viewFrame.getViewerType().toString());
2141 // pdb.addStructureState(state);
2142 pdb.getStructureState().add(state);
2150 * Populates the AnnotationColourScheme xml for save. This captures the
2151 * settings of the options in the 'Colour by Annotation' dialog.
2154 * @param userColours
2158 private AnnotationColourScheme constructAnnotationColours(
2159 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2162 AnnotationColourScheme ac = new AnnotationColourScheme();
2163 ac.setAboveThreshold(acg.getAboveThreshold());
2164 ac.setThreshold(acg.getAnnotationThreshold());
2165 // 2.10.2 save annotationId (unique) not annotation label
2166 ac.setAnnotation(acg.getAnnotation().annotationId);
2167 if (acg.getBaseColour() instanceof UserColourScheme)
2170 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2175 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2178 ac.setMaxColour(acg.getMaxColour().getRGB());
2179 ac.setMinColour(acg.getMinColour().getRGB());
2180 ac.setPerSequence(acg.isSeqAssociated());
2181 ac.setPredefinedColours(acg.isPredefinedColours());
2185 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2186 IdentityHashMap<SequenceGroup, String> groupRefs,
2187 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2188 SequenceSet vamsasSet)
2191 for (int i = 0; i < aa.length; i++)
2193 Annotation an = new Annotation();
2195 AlignmentAnnotation annotation = aa[i];
2196 if (annotation.annotationId != null)
2198 annotationIds.put(annotation.annotationId, annotation);
2201 an.setId(annotation.annotationId);
2203 an.setVisible(annotation.visible);
2205 an.setDescription(annotation.description);
2207 if (annotation.sequenceRef != null)
2209 // 2.9 JAL-1781 xref on sequence id rather than name
2210 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2212 if (annotation.groupRef != null)
2214 String groupIdr = groupRefs.get(annotation.groupRef);
2215 if (groupIdr == null)
2217 // make a locally unique String
2218 groupRefs.put(annotation.groupRef,
2219 groupIdr = ("" + System.currentTimeMillis()
2220 + annotation.groupRef.getName()
2221 + groupRefs.size()));
2223 an.setGroupRef(groupIdr.toString());
2226 // store all visualization attributes for annotation
2227 an.setGraphHeight(annotation.graphHeight);
2228 an.setCentreColLabels(annotation.centreColLabels);
2229 an.setScaleColLabels(annotation.scaleColLabel);
2230 an.setShowAllColLabels(annotation.showAllColLabels);
2231 an.setBelowAlignment(annotation.belowAlignment);
2233 if (annotation.graph > 0)
2236 an.setGraphType(annotation.graph);
2237 an.setGraphGroup(annotation.graphGroup);
2238 if (annotation.getThreshold() != null)
2240 ThresholdLine line = new ThresholdLine();
2241 line.setLabel(annotation.getThreshold().label);
2242 line.setValue(annotation.getThreshold().value);
2243 line.setColour(annotation.getThreshold().colour.getRGB());
2244 an.setThresholdLine(line);
2252 an.setLabel(annotation.label);
2254 if (annotation == av.getAlignmentQualityAnnot()
2255 || annotation == av.getAlignmentConservationAnnotation()
2256 || annotation == av.getAlignmentConsensusAnnotation()
2257 || annotation.autoCalculated)
2259 // new way of indicating autocalculated annotation -
2260 an.setAutoCalculated(annotation.autoCalculated);
2262 if (annotation.hasScore())
2264 an.setScore(annotation.getScore());
2267 if (annotation.getCalcId() != null)
2269 calcIdSet.add(annotation.getCalcId());
2270 an.setCalcId(annotation.getCalcId());
2272 if (annotation.hasProperties())
2274 for (String pr : annotation.getProperties())
2276 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2278 prop.setValue(annotation.getProperty(pr));
2279 // an.addProperty(prop);
2280 an.getProperty().add(prop);
2284 AnnotationElement ae;
2285 if (annotation.annotations != null)
2287 an.setScoreOnly(false);
2288 for (int a = 0; a < annotation.annotations.length; a++)
2290 if ((annotation == null) || (annotation.annotations[a] == null))
2295 ae = new AnnotationElement();
2296 if (annotation.annotations[a].description != null)
2298 ae.setDescription(annotation.annotations[a].description);
2300 if (annotation.annotations[a].displayCharacter != null)
2302 ae.setDisplayCharacter(
2303 annotation.annotations[a].displayCharacter);
2306 if (!Float.isNaN(annotation.annotations[a].value))
2308 ae.setValue(annotation.annotations[a].value);
2312 if (annotation.annotations[a].secondaryStructure > ' ')
2314 ae.setSecondaryStructure(
2315 annotation.annotations[a].secondaryStructure + "");
2318 if (annotation.annotations[a].colour != null
2319 && annotation.annotations[a].colour != java.awt.Color.black)
2321 ae.setColour(annotation.annotations[a].colour.getRGB());
2324 // an.addAnnotationElement(ae);
2325 an.getAnnotationElement().add(ae);
2326 if (annotation.autoCalculated)
2328 // only write one non-null entry into the annotation row -
2329 // sufficient to get the visualization attributes necessary to
2337 an.setScoreOnly(true);
2339 if (!storeDS || (storeDS && !annotation.autoCalculated))
2341 // skip autocalculated annotation - these are only provided for
2343 // vamsasSet.addAnnotation(an);
2344 vamsasSet.getAnnotation().add(an);
2350 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2352 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2353 if (settings != null)
2355 CalcIdParam vCalcIdParam = new CalcIdParam();
2356 vCalcIdParam.setCalcId(calcId);
2357 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2358 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2359 // generic URI allowing a third party to resolve another instance of the
2360 // service used for this calculation
2361 for (String url : settings.getServiceURLs())
2363 // vCalcIdParam.addServiceURL(urls);
2364 vCalcIdParam.getServiceURL().add(url);
2366 vCalcIdParam.setVersion("1.0");
2367 if (settings.getPreset() != null)
2369 WsParamSetI setting = settings.getPreset();
2370 vCalcIdParam.setName(setting.getName());
2371 vCalcIdParam.setDescription(setting.getDescription());
2375 vCalcIdParam.setName("");
2376 vCalcIdParam.setDescription("Last used parameters");
2378 // need to be able to recover 1) settings 2) user-defined presets or
2379 // recreate settings from preset 3) predefined settings provided by
2380 // service - or settings that can be transferred (or discarded)
2381 vCalcIdParam.setParameters(
2382 settings.getWsParamFile().replace("\n", "|\\n|"));
2383 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2384 // todo - decide if updateImmediately is needed for any projects.
2386 return vCalcIdParam;
2391 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2394 if (calcIdParam.getVersion().equals("1.0"))
2396 final String[] calcIds = calcIdParam.getServiceURL()
2397 .toArray(new String[0]);
2398 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2399 .getPreferredServiceFor(calcIds);
2400 if (service != null)
2402 WsParamSetI parmSet = null;
2405 parmSet = service.getParamStore().parseServiceParameterFile(
2406 calcIdParam.getName(), calcIdParam.getDescription(),
2408 calcIdParam.getParameters().replace("|\\n|", "\n"));
2409 } catch (IOException x)
2411 warn("Couldn't parse parameter data for "
2412 + calcIdParam.getCalcId(), x);
2415 List<ArgumentI> argList = null;
2416 if (calcIdParam.getName().length() > 0)
2418 parmSet = service.getParamStore()
2419 .getPreset(calcIdParam.getName());
2420 if (parmSet != null)
2422 // TODO : check we have a good match with settings in AACon -
2423 // otherwise we'll need to create a new preset
2428 argList = parmSet.getArguments();
2431 AAConSettings settings = new AAConSettings(
2432 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2433 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2434 calcIdParam.isNeedsUpdate());
2439 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2443 throw new Error(MessageManager.formatMessage(
2444 "error.unsupported_version_calcIdparam", new Object[]
2445 { calcIdParam.toString() }));
2449 * External mapping between jalview objects and objects yielding a valid and
2450 * unique object ID string. This is null for normal Jalview project IO, but
2451 * non-null when a jalview project is being read or written as part of a
2454 IdentityHashMap jv2vobj = null;
2457 * Construct a unique ID for jvobj using either existing bindings or if none
2458 * exist, the result of the hashcode call for the object.
2461 * jalview data object
2462 * @return unique ID for referring to jvobj
2464 private String makeHashCode(Object jvobj, String altCode)
2466 if (jv2vobj != null)
2468 Object id = jv2vobj.get(jvobj);
2471 return id.toString();
2473 // check string ID mappings
2474 if (jvids2vobj != null && jvobj instanceof String)
2476 id = jvids2vobj.get(jvobj);
2480 return id.toString();
2482 // give up and warn that something has gone wrong
2483 warn("Cannot find ID for object in external mapping : " + jvobj);
2489 * return local jalview object mapped to ID, if it exists
2493 * @return null or object bound to idcode
2495 private Object retrieveExistingObj(String idcode)
2497 if (idcode != null && vobj2jv != null)
2499 return vobj2jv.get(idcode);
2505 * binding from ID strings from external mapping table to jalview data model
2508 private Hashtable vobj2jv;
2510 private Sequence createVamsasSequence(String id, SequenceI jds)
2512 return createVamsasSequence(true, id, jds, null);
2515 private Sequence createVamsasSequence(boolean recurse, String id,
2516 SequenceI jds, SequenceI parentseq)
2518 Sequence vamsasSeq = new Sequence();
2519 vamsasSeq.setId(id);
2520 vamsasSeq.setName(jds.getName());
2521 vamsasSeq.setSequence(jds.getSequenceAsString());
2522 vamsasSeq.setDescription(jds.getDescription());
2523 List<DBRefEntry> dbrefs = null;
2524 if (jds.getDatasetSequence() != null)
2526 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2530 // seqId==dsseqid so we can tell which sequences really are
2531 // dataset sequences only
2532 vamsasSeq.setDsseqid(id);
2533 dbrefs = jds.getDBRefs();
2534 if (parentseq == null)
2541 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2545 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2547 DBRef dbref = new DBRef();
2548 DBRefEntry ref = dbrefs.get(d);
2549 dbref.setSource(ref.getSource());
2550 dbref.setVersion(ref.getVersion());
2551 dbref.setAccessionId(ref.getAccessionId());
2552 dbref.setCanonical(ref.isCanonical());
2553 if (ref instanceof GeneLocus)
2555 dbref.setLocus(true);
2559 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2561 dbref.setMapping(mp);
2563 vamsasSeq.getDBRef().add(dbref);
2569 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2570 SequenceI parentseq, SequenceI jds, boolean recurse)
2573 if (jmp.getMap() != null)
2577 jalview.util.MapList mlst = jmp.getMap();
2578 List<int[]> r = mlst.getFromRanges();
2579 for (int[] range : r)
2581 MapListFrom mfrom = new MapListFrom();
2582 mfrom.setStart(range[0]);
2583 mfrom.setEnd(range[1]);
2584 // mp.addMapListFrom(mfrom);
2585 mp.getMapListFrom().add(mfrom);
2587 r = mlst.getToRanges();
2588 for (int[] range : r)
2590 MapListTo mto = new MapListTo();
2591 mto.setStart(range[0]);
2592 mto.setEnd(range[1]);
2593 // mp.addMapListTo(mto);
2594 mp.getMapListTo().add(mto);
2596 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2597 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2598 if (jmp.getTo() != null)
2600 // MappingChoice mpc = new MappingChoice();
2602 // check/create ID for the sequence referenced by getTo()
2605 SequenceI ps = null;
2606 if (parentseq != jmp.getTo()
2607 && parentseq.getDatasetSequence() != jmp.getTo())
2609 // chaining dbref rather than a handshaking one
2610 jmpid = seqHash(ps = jmp.getTo());
2614 jmpid = seqHash(ps = parentseq);
2616 // mpc.setDseqFor(jmpid);
2617 mp.setDseqFor(jmpid);
2618 if (!seqRefIds.containsKey(jmpid))
2620 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2621 seqRefIds.put(jmpid, ps);
2625 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2628 // mp.setMappingChoice(mpc);
2634 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2635 List<UserColourScheme> userColours, JalviewModel jm)
2638 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2639 boolean newucs = false;
2640 if (!userColours.contains(ucs))
2642 userColours.add(ucs);
2645 id = "ucs" + userColours.indexOf(ucs);
2648 // actually create the scheme's entry in the XML model
2649 java.awt.Color[] colours = ucs.getColours();
2650 UserColours uc = new UserColours();
2651 // UserColourScheme jbucs = new UserColourScheme();
2652 JalviewUserColours jbucs = new JalviewUserColours();
2654 for (int i = 0; i < colours.length; i++)
2656 Colour col = new Colour();
2657 col.setName(ResidueProperties.aa[i]);
2658 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2659 // jbucs.addColour(col);
2660 jbucs.getColour().add(col);
2662 if (ucs.getLowerCaseColours() != null)
2664 colours = ucs.getLowerCaseColours();
2665 for (int i = 0; i < colours.length; i++)
2667 Colour col = new Colour();
2668 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2669 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2670 // jbucs.addColour(col);
2671 jbucs.getColour().add(col);
2676 uc.setUserColourScheme(jbucs);
2677 // jm.addUserColours(uc);
2678 jm.getUserColours().add(uc);
2684 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2687 List<UserColours> uc = jm.getUserColours();
2688 UserColours colours = null;
2690 for (int i = 0; i < uc.length; i++)
2692 if (uc[i].getId().equals(id))
2699 for (UserColours c : uc)
2701 if (c.getId().equals(id))
2708 java.awt.Color[] newColours = new java.awt.Color[24];
2710 for (int i = 0; i < 24; i++)
2712 newColours[i] = new java.awt.Color(Integer.parseInt(
2713 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2714 colours.getUserColourScheme().getColour().get(i).getRGB(),
2718 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2721 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2723 newColours = new java.awt.Color[23];
2724 for (int i = 0; i < 23; i++)
2726 newColours[i] = new java.awt.Color(
2727 Integer.parseInt(colours.getUserColourScheme().getColour()
2728 .get(i + 24).getRGB(), 16));
2730 ucs.setLowerCaseColours(newColours);
2737 * contains last error message (if any) encountered by XML loader.
2739 String errorMessage = null;
2742 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2743 * exceptions are raised during project XML parsing
2745 public boolean attemptversion1parse = false;
2748 * Load a jalview project archive from a jar file
2751 * - HTTP URL or filename
2753 public AlignFrame loadJalviewAlign(final Object file)
2756 jalview.gui.AlignFrame af = null;
2760 // create list to store references for any new Jmol viewers created
2761 newStructureViewers = new Vector<>();
2762 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2763 // Workaround is to make sure caller implements the JarInputStreamProvider
2765 // so we can re-open the jar input stream for each entry.
2767 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2768 af = loadJalviewAlign(jprovider);
2771 af.setMenusForViewport();
2773 } catch (MalformedURLException e)
2775 errorMessage = "Invalid URL format for '" + file + "'";
2781 SwingUtilities.invokeAndWait(new Runnable()
2786 setLoadingFinishedForNewStructureViewers();
2789 } catch (Exception x)
2791 System.err.println("Error loading alignment: " + x.getMessage());
2797 @SuppressWarnings("unused")
2798 private jarInputStreamProvider createjarInputStreamProvider(
2799 final Object ofile) throws MalformedURLException
2802 // BH 2018 allow for bytes already attached to File object
2805 String file = (ofile instanceof File
2806 ? ((File) ofile).getCanonicalPath()
2807 : ofile.toString());
2808 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2811 errorMessage = null;
2812 uniqueSetSuffix = null;
2814 viewportsAdded.clear();
2815 frefedSequence = null;
2817 if (HttpUtils.startsWithHttpOrHttps(file))
2819 url = new URL(file);
2821 final URL _url = url;
2822 return new jarInputStreamProvider()
2826 public JarInputStream getJarInputStream() throws IOException
2830 // System.out.println("Jalview2XML: opening byte jarInputStream for
2831 // bytes.length=" + bytes.length);
2832 return new JarInputStream(new ByteArrayInputStream(bytes));
2836 // System.out.println("Jalview2XML: opening url jarInputStream for "
2838 return new JarInputStream(_url.openStream());
2842 // System.out.println("Jalview2XML: opening file jarInputStream for
2844 return new JarInputStream(new FileInputStream(file));
2849 public String getFilename()
2854 } catch (IOException e)
2856 e.printStackTrace();
2862 * Recover jalview session from a jalview project archive. Caller may
2863 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2864 * themselves. Any null fields will be initialised with default values,
2865 * non-null fields are left alone.
2870 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2872 errorMessage = null;
2873 if (uniqueSetSuffix == null)
2875 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2877 if (seqRefIds == null)
2881 AlignFrame af = null, _af = null;
2882 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2883 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2884 final String file = jprovider.getFilename();
2887 JarInputStream jin = null;
2888 JarEntry jarentry = null;
2893 jin = jprovider.getJarInputStream();
2894 for (int i = 0; i < entryCount; i++)
2896 jarentry = jin.getNextJarEntry();
2899 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2901 JAXBContext jc = JAXBContext
2902 .newInstance("jalview.xml.binding.jalview");
2903 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2904 .createXMLStreamReader(jin);
2905 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2906 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2907 JalviewModel.class);
2908 JalviewModel object = jbe.getValue();
2910 if (true) // !skipViewport(object))
2912 _af = loadFromObject(object, file, true, jprovider);
2913 if (_af != null && object.getViewport().size() > 0)
2914 // getJalviewModelSequence().getViewportCount() > 0)
2918 // store a reference to the first view
2921 if (_af.getViewport().isGatherViewsHere())
2923 // if this is a gathered view, keep its reference since
2924 // after gathering views, only this frame will remain
2926 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2929 // Save dataset to register mappings once all resolved
2930 importedDatasets.put(
2931 af.getViewport().getAlignment().getDataset(),
2932 af.getViewport().getAlignment().getDataset());
2937 else if (jarentry != null)
2939 // Some other file here.
2942 } while (jarentry != null);
2944 resolveFrefedSequences();
2945 } catch (IOException ex)
2947 ex.printStackTrace();
2948 errorMessage = "Couldn't locate Jalview XML file : " + file;
2950 "Exception whilst loading jalview XML file : " + ex + "\n");
2951 } catch (Exception ex)
2953 System.err.println("Parsing as Jalview Version 2 file failed.");
2954 ex.printStackTrace(System.err);
2955 if (attemptversion1parse)
2957 // used to attempt to parse as V1 castor-generated xml
2959 if (Desktop.instance != null)
2961 Desktop.instance.stopLoading();
2965 System.out.println("Successfully loaded archive file");
2968 ex.printStackTrace();
2971 "Exception whilst loading jalview XML file : " + ex + "\n");
2972 } catch (OutOfMemoryError e)
2974 // Don't use the OOM Window here
2975 errorMessage = "Out of memory loading jalview XML file";
2976 System.err.println("Out of memory whilst loading jalview XML file");
2977 e.printStackTrace();
2981 * Regather multiple views (with the same sequence set id) to the frame (if
2982 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2983 * views instead of separate frames. Note this doesn't restore a state where
2984 * some expanded views in turn have tabbed views - the last "first tab" read
2985 * in will play the role of gatherer for all.
2987 for (AlignFrame fr : gatherToThisFrame.values())
2989 Desktop.instance.gatherViews(fr);
2992 restoreSplitFrames();
2993 for (AlignmentI ds : importedDatasets.keySet())
2995 if (ds.getCodonFrames() != null)
2997 StructureSelectionManager
2998 .getStructureSelectionManager(Desktop.instance)
2999 .registerMappings(ds.getCodonFrames());
3002 if (errorMessage != null)
3007 if (Desktop.instance != null)
3009 Desktop.instance.stopLoading();
3016 * Try to reconstruct and display SplitFrame windows, where each contains
3017 * complementary dna and protein alignments. Done by pairing up AlignFrame
3018 * objects (created earlier) which have complementary viewport ids associated.
3020 protected void restoreSplitFrames()
3022 List<SplitFrame> gatherTo = new ArrayList<>();
3023 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3024 Map<String, AlignFrame> dna = new HashMap<>();
3027 * Identify the DNA alignments
3029 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3032 AlignFrame af = candidate.getValue();
3033 if (af.getViewport().getAlignment().isNucleotide())
3035 dna.put(candidate.getKey().getId(), af);
3040 * Try to match up the protein complements
3042 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3045 AlignFrame af = candidate.getValue();
3046 if (!af.getViewport().getAlignment().isNucleotide())
3048 String complementId = candidate.getKey().getComplementId();
3049 // only non-null complements should be in the Map
3050 if (complementId != null && dna.containsKey(complementId))
3052 final AlignFrame dnaFrame = dna.get(complementId);
3053 SplitFrame sf = createSplitFrame(dnaFrame, af);
3054 addedToSplitFrames.add(dnaFrame);
3055 addedToSplitFrames.add(af);
3056 dnaFrame.setMenusForViewport();
3057 af.setMenusForViewport();
3058 if (af.getViewport().isGatherViewsHere())
3067 * Open any that we failed to pair up (which shouldn't happen!) as
3068 * standalone AlignFrame's.
3070 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3073 AlignFrame af = candidate.getValue();
3074 if (!addedToSplitFrames.contains(af))
3076 Viewport view = candidate.getKey();
3077 Desktop.addInternalFrame(af, view.getTitle(),
3078 safeInt(view.getWidth()), safeInt(view.getHeight()));
3079 af.setMenusForViewport();
3080 System.err.println("Failed to restore view " + view.getTitle()
3081 + " to split frame");
3086 * Gather back into tabbed views as flagged.
3088 for (SplitFrame sf : gatherTo)
3090 Desktop.instance.gatherViews(sf);
3093 splitFrameCandidates.clear();
3097 * Construct and display one SplitFrame holding DNA and protein alignments.
3100 * @param proteinFrame
3103 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3104 AlignFrame proteinFrame)
3106 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3107 String title = MessageManager.getString("label.linked_view_title");
3108 int width = (int) dnaFrame.getBounds().getWidth();
3109 int height = (int) (dnaFrame.getBounds().getHeight()
3110 + proteinFrame.getBounds().getHeight() + 50);
3113 * SplitFrame location is saved to both enclosed frames
3115 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3116 Desktop.addInternalFrame(splitFrame, title, width, height);
3119 * And compute cDNA consensus (couldn't do earlier with consensus as
3120 * mappings were not yet present)
3122 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3128 * check errorMessage for a valid error message and raise an error box in the
3129 * GUI or write the current errorMessage to stderr and then clear the error
3132 protected void reportErrors()
3134 reportErrors(false);
3137 protected void reportErrors(final boolean saving)
3139 if (errorMessage != null)
3141 final String finalErrorMessage = errorMessage;
3144 javax.swing.SwingUtilities.invokeLater(new Runnable()
3149 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3151 "Error " + (saving ? "saving" : "loading")
3153 JvOptionPane.WARNING_MESSAGE);
3159 System.err.println("Problem loading Jalview file: " + errorMessage);
3162 errorMessage = null;
3165 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3168 * when set, local views will be updated from view stored in JalviewXML
3169 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3170 * sync if this is set to true.
3172 private final boolean updateLocalViews = false;
3175 * Returns the path to a temporary file holding the PDB file for the given PDB
3176 * id. The first time of asking, searches for a file of that name in the
3177 * Jalview project jar, and copies it to a new temporary file. Any repeat
3178 * requests just return the path to the file previously created.
3184 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3187 if (alreadyLoadedPDB.containsKey(pdbId))
3189 return alreadyLoadedPDB.get(pdbId).toString();
3192 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3194 if (tempFile != null)
3196 alreadyLoadedPDB.put(pdbId, tempFile);
3202 * Copies the jar entry of given name to a new temporary file and returns the
3203 * path to the file, or null if the entry is not found.
3206 * @param jarEntryName
3208 * a prefix for the temporary file name, must be at least three
3210 * @param suffixModel
3211 * null or original file - so new file can be given the same suffix
3215 protected String copyJarEntry(jarInputStreamProvider jprovider,
3216 String jarEntryName, String prefix, String suffixModel)
3218 String suffix = ".tmp";
3219 if (suffixModel == null)
3221 suffixModel = jarEntryName;
3223 int sfpos = suffixModel.lastIndexOf(".");
3224 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3226 suffix = "." + suffixModel.substring(sfpos + 1);
3229 try (JarInputStream jin = jprovider.getJarInputStream())
3231 JarEntry entry = null;
3234 entry = jin.getNextJarEntry();
3235 } while (entry != null && !entry.getName().equals(jarEntryName));
3239 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3240 File outFile = File.createTempFile(prefix, suffix);
3241 outFile.deleteOnExit();
3242 try (OutputStream os = new FileOutputStream(outFile))
3246 String t = outFile.getAbsolutePath();
3251 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3253 } catch (Exception ex)
3255 ex.printStackTrace();
3261 private class JvAnnotRow
3263 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3270 * persisted version of annotation row from which to take vis properties
3272 public jalview.datamodel.AlignmentAnnotation template;
3275 * original position of the annotation row in the alignment
3281 * Load alignment frame from jalview XML DOM object
3283 * @param jalviewModel
3286 * filename source string
3287 * @param loadTreesAndStructures
3288 * when false only create Viewport
3290 * data source provider
3291 * @return alignment frame created from view stored in DOM
3293 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3294 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3296 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3298 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3300 // JalviewModelSequence jms = object.getJalviewModelSequence();
3302 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3304 Viewport view = (jalviewModel.getViewport().size() > 0)
3305 ? jalviewModel.getViewport().get(0)
3308 // ////////////////////////////////
3309 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3312 // If we just load in the same jar file again, the sequenceSetId
3313 // will be the same, and we end up with multiple references
3314 // to the same sequenceSet. We must modify this id on load
3315 // so that each load of the file gives a unique id
3318 * used to resolve correct alignment dataset for alignments with multiple
3321 String uniqueSeqSetId = null;
3322 String viewId = null;
3325 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3326 viewId = (view.getId() == null ? null
3327 : view.getId() + uniqueSetSuffix);
3330 // ////////////////////////////////
3333 List<SequenceI> hiddenSeqs = null;
3335 List<SequenceI> tmpseqs = new ArrayList<>();
3337 boolean multipleView = false;
3338 SequenceI referenceseqForView = null;
3339 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3340 List<JSeq> jseqs = jalviewModel.getJSeq();
3341 int vi = 0; // counter in vamsasSeq array
3342 for (int i = 0; i < jseqs.size(); i++)
3344 JSeq jseq = jseqs.get(i);
3345 String seqId = jseq.getId();
3347 SequenceI tmpSeq = seqRefIds.get(seqId);
3350 if (!incompleteSeqs.containsKey(seqId))
3352 // may not need this check, but keep it for at least 2.9,1 release
3353 if (tmpSeq.getStart() != jseq.getStart()
3354 || tmpSeq.getEnd() != jseq.getEnd())
3356 System.err.println(String.format(
3357 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3358 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3359 jseq.getStart(), jseq.getEnd()));
3364 incompleteSeqs.remove(seqId);
3366 if (vamsasSeqs.size() > vi
3367 && vamsasSeqs.get(vi).getId().equals(seqId))
3369 // most likely we are reading a dataset XML document so
3370 // update from vamsasSeq section of XML for this sequence
3371 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3372 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3373 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3378 // reading multiple views, so vamsasSeq set is a subset of JSeq
3379 multipleView = true;
3381 tmpSeq.setStart(jseq.getStart());
3382 tmpSeq.setEnd(jseq.getEnd());
3383 tmpseqs.add(tmpSeq);
3387 Sequence vamsasSeq = vamsasSeqs.get(vi);
3388 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3389 vamsasSeq.getSequence());
3390 tmpSeq.setDescription(vamsasSeq.getDescription());
3391 tmpSeq.setStart(jseq.getStart());
3392 tmpSeq.setEnd(jseq.getEnd());
3393 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3394 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3395 tmpseqs.add(tmpSeq);
3399 if (safeBoolean(jseq.isViewreference()))
3401 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3404 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3406 if (hiddenSeqs == null)
3408 hiddenSeqs = new ArrayList<>();
3411 hiddenSeqs.add(tmpSeq);
3416 // Create the alignment object from the sequence set
3417 // ///////////////////////////////
3418 SequenceI[] orderedSeqs = tmpseqs
3419 .toArray(new SequenceI[tmpseqs.size()]);
3421 AlignmentI al = null;
3422 // so we must create or recover the dataset alignment before going further
3423 // ///////////////////////////////
3424 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3426 // older jalview projects do not have a dataset - so creat alignment and
3428 al = new Alignment(orderedSeqs);
3429 al.setDataset(null);
3433 boolean isdsal = jalviewModel.getViewport().isEmpty();
3436 // we are importing a dataset record, so
3437 // recover reference to an alignment already materialsed as dataset
3438 al = getDatasetFor(vamsasSet.getDatasetId());
3442 // materialse the alignment
3443 al = new Alignment(orderedSeqs);
3447 addDatasetRef(vamsasSet.getDatasetId(), al);
3450 // finally, verify all data in vamsasSet is actually present in al
3451 // passing on flag indicating if it is actually a stored dataset
3452 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3455 if (referenceseqForView != null)
3457 al.setSeqrep(referenceseqForView);
3459 // / Add the alignment properties
3460 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3462 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3464 al.setProperty(ssp.getKey(), ssp.getValue());
3467 // ///////////////////////////////
3469 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3472 // load sequence features, database references and any associated PDB
3473 // structures for the alignment
3475 // prior to 2.10, this part would only be executed the first time a
3476 // sequence was encountered, but not afterwards.
3477 // now, for 2.10 projects, this is also done if the xml doc includes
3478 // dataset sequences not actually present in any particular view.
3480 for (int i = 0; i < vamsasSeqs.size(); i++)
3482 JSeq jseq = jseqs.get(i);
3483 if (jseq.getFeatures().size() > 0)
3485 List<Feature> features = jseq.getFeatures();
3486 for (int f = 0; f < features.size(); f++)
3488 Feature feat = features.get(f);
3489 SequenceFeature sf = new SequenceFeature(feat.getType(),
3490 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3491 safeFloat(feat.getScore()), feat.getFeatureGroup());
3492 sf.setStatus(feat.getStatus());
3495 * load any feature attributes - include map-valued attributes
3497 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3498 for (int od = 0; od < feat.getOtherData().size(); od++)
3500 OtherData keyValue = feat.getOtherData().get(od);
3501 String attributeName = keyValue.getKey();
3502 String attributeValue = keyValue.getValue();
3503 if (attributeName.startsWith("LINK"))
3505 sf.addLink(attributeValue);
3509 String subAttribute = keyValue.getKey2();
3510 if (subAttribute == null)
3512 // simple string-valued attribute
3513 sf.setValue(attributeName, attributeValue);
3517 // attribute 'key' has sub-attribute 'key2'
3518 if (!mapAttributes.containsKey(attributeName))
3520 mapAttributes.put(attributeName, new HashMap<>());
3522 mapAttributes.get(attributeName).put(subAttribute,
3527 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3530 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3533 // adds feature to datasequence's feature set (since Jalview 2.10)
3534 al.getSequenceAt(i).addSequenceFeature(sf);
3537 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3539 // adds dbrefs to datasequence's set (since Jalview 2.10)
3541 al.getSequenceAt(i).getDatasetSequence() == null
3542 ? al.getSequenceAt(i)
3543 : al.getSequenceAt(i).getDatasetSequence(),
3546 if (jseq.getPdbids().size() > 0)
3548 List<Pdbids> ids = jseq.getPdbids();
3549 for (int p = 0; p < ids.size(); p++)
3551 Pdbids pdbid = ids.get(p);
3552 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3553 entry.setId(pdbid.getId());
3554 if (pdbid.getType() != null)
3556 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3558 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3562 entry.setType(PDBEntry.Type.FILE);
3565 // jprovider is null when executing 'New View'
3566 if (pdbid.getFile() != null && jprovider != null)
3568 if (!pdbloaded.containsKey(pdbid.getFile()))
3570 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3575 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3579 if (pdbid.getPdbentryItem() != null)
3581 for (PdbentryItem item : pdbid.getPdbentryItem())
3583 for (Property pr : item.getProperty())
3585 entry.setProperty(pr.getName(), pr.getValue());
3590 for (Property prop : pdbid.getProperty())
3592 entry.setProperty(prop.getName(), prop.getValue());
3594 StructureSelectionManager
3595 .getStructureSelectionManager(Desktop.instance)
3596 .registerPDBEntry(entry);
3597 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3598 if (al.getSequenceAt(i).getDatasetSequence() != null)
3600 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3604 al.getSequenceAt(i).addPDBId(entry);
3609 } // end !multipleview
3611 // ///////////////////////////////
3612 // LOAD SEQUENCE MAPPINGS
3614 if (vamsasSet.getAlcodonFrame().size() > 0)
3616 // TODO Potentially this should only be done once for all views of an
3618 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3619 for (int i = 0; i < alc.size(); i++)
3621 AlignedCodonFrame cf = new AlignedCodonFrame();
3622 if (alc.get(i).getAlcodMap().size() > 0)
3624 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3625 for (int m = 0; m < maps.size(); m++)
3627 AlcodMap map = maps.get(m);
3628 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3630 jalview.datamodel.Mapping mapping = null;
3631 // attach to dna sequence reference.
3632 if (map.getMapping() != null)
3634 mapping = addMapping(map.getMapping());
3635 if (dnaseq != null && mapping.getTo() != null)
3637 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3643 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3647 al.addCodonFrame(cf);
3652 // ////////////////////////////////
3654 List<JvAnnotRow> autoAlan = new ArrayList<>();
3657 * store any annotations which forward reference a group's ID
3659 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3661 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3663 List<Annotation> an = vamsasSet.getAnnotation();
3665 for (int i = 0; i < an.size(); i++)
3667 Annotation annotation = an.get(i);
3670 * test if annotation is automatically calculated for this view only
3672 boolean autoForView = false;
3673 if (annotation.getLabel().equals("Quality")
3674 || annotation.getLabel().equals("Conservation")
3675 || annotation.getLabel().equals("Consensus"))
3677 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3679 // JAXB has no has() test; schema defaults value to false
3680 // if (!annotation.hasAutoCalculated())
3682 // annotation.setAutoCalculated(true);
3685 if (autoForView || annotation.isAutoCalculated())
3687 // remove ID - we don't recover annotation from other views for
3688 // view-specific annotation
3689 annotation.setId(null);
3692 // set visibility for other annotation in this view
3693 String annotationId = annotation.getId();
3694 if (annotationId != null && annotationIds.containsKey(annotationId))
3696 AlignmentAnnotation jda = annotationIds.get(annotationId);
3697 // in principle Visible should always be true for annotation displayed
3698 // in multiple views
3699 if (annotation.isVisible() != null)
3701 jda.visible = annotation.isVisible();
3704 al.addAnnotation(jda);
3708 // Construct new annotation from model.
3709 List<AnnotationElement> ae = annotation.getAnnotationElement();
3710 jalview.datamodel.Annotation[] anot = null;
3711 java.awt.Color firstColour = null;
3713 if (!annotation.isScoreOnly())
3715 anot = new jalview.datamodel.Annotation[al.getWidth()];
3716 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3718 AnnotationElement annElement = ae.get(aa);
3719 anpos = annElement.getPosition();
3721 if (anpos >= anot.length)
3726 float value = safeFloat(annElement.getValue());
3727 anot[anpos] = new jalview.datamodel.Annotation(
3728 annElement.getDisplayCharacter(),
3729 annElement.getDescription(),
3730 (annElement.getSecondaryStructure() == null
3731 || annElement.getSecondaryStructure()
3735 .getSecondaryStructure()
3738 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3739 if (firstColour == null)
3741 firstColour = anot[anpos].colour;
3745 jalview.datamodel.AlignmentAnnotation jaa = null;
3747 if (annotation.isGraph())
3749 float llim = 0, hlim = 0;
3750 // if (autoForView || an[i].isAutoCalculated()) {
3753 jaa = new jalview.datamodel.AlignmentAnnotation(
3754 annotation.getLabel(), annotation.getDescription(), anot,
3755 llim, hlim, safeInt(annotation.getGraphType()));
3757 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3758 jaa._linecolour = firstColour;
3759 if (annotation.getThresholdLine() != null)
3761 jaa.setThreshold(new jalview.datamodel.GraphLine(
3762 safeFloat(annotation.getThresholdLine().getValue()),
3763 annotation.getThresholdLine().getLabel(),
3764 new java.awt.Color(safeInt(
3765 annotation.getThresholdLine().getColour()))));
3767 if (autoForView || annotation.isAutoCalculated())
3769 // Hardwire the symbol display line to ensure that labels for
3770 // histograms are displayed
3776 jaa = new jalview.datamodel.AlignmentAnnotation(
3777 annotation.getLabel(), annotation.getDescription(), anot);
3778 jaa._linecolour = firstColour;
3780 // register new annotation
3781 if (annotation.getId() != null)
3783 annotationIds.put(annotation.getId(), jaa);
3784 jaa.annotationId = annotation.getId();
3786 // recover sequence association
3787 String sequenceRef = annotation.getSequenceRef();
3788 if (sequenceRef != null)
3790 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3791 SequenceI sequence = seqRefIds.get(sequenceRef);
3792 if (sequence == null)
3794 // in pre-2.9 projects sequence ref is to sequence name
3795 sequence = al.findName(sequenceRef);
3797 if (sequence != null)
3799 jaa.createSequenceMapping(sequence, 1, true);
3800 sequence.addAlignmentAnnotation(jaa);
3803 // and make a note of any group association
3804 if (annotation.getGroupRef() != null
3805 && annotation.getGroupRef().length() > 0)
3807 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3808 .get(annotation.getGroupRef());
3811 aal = new ArrayList<>();
3812 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3817 if (annotation.getScore() != null)
3819 jaa.setScore(annotation.getScore().doubleValue());
3821 if (annotation.isVisible() != null)
3823 jaa.visible = annotation.isVisible().booleanValue();
3826 if (annotation.isCentreColLabels() != null)
3828 jaa.centreColLabels = annotation.isCentreColLabels()
3832 if (annotation.isScaleColLabels() != null)
3834 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3836 if (annotation.isAutoCalculated())
3838 // newer files have an 'autoCalculated' flag and store calculation
3839 // state in viewport properties
3840 jaa.autoCalculated = true; // means annotation will be marked for
3841 // update at end of load.
3843 if (annotation.getGraphHeight() != null)
3845 jaa.graphHeight = annotation.getGraphHeight().intValue();
3847 jaa.belowAlignment = annotation.isBelowAlignment();
3848 jaa.setCalcId(annotation.getCalcId());
3849 if (annotation.getProperty().size() > 0)
3851 for (Annotation.Property prop : annotation.getProperty())
3853 jaa.setProperty(prop.getName(), prop.getValue());
3856 if (jaa.autoCalculated)
3858 autoAlan.add(new JvAnnotRow(i, jaa));
3861 // if (!autoForView)
3863 // add autocalculated group annotation and any user created annotation
3865 al.addAnnotation(jaa);
3869 // ///////////////////////
3871 // Create alignment markup and styles for this view
3872 if (jalviewModel.getJGroup().size() > 0)
3874 List<JGroup> groups = jalviewModel.getJGroup();
3875 boolean addAnnotSchemeGroup = false;
3876 for (int i = 0; i < groups.size(); i++)
3878 JGroup jGroup = groups.get(i);
3879 ColourSchemeI cs = null;
3880 if (jGroup.getColour() != null)
3882 if (jGroup.getColour().startsWith("ucs"))
3884 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3886 else if (jGroup.getColour().equals("AnnotationColourGradient")
3887 && jGroup.getAnnotationColours() != null)
3889 addAnnotSchemeGroup = true;
3893 cs = ColourSchemeProperty.getColourScheme(null, al,
3894 jGroup.getColour());
3897 int pidThreshold = safeInt(jGroup.getPidThreshold());
3899 Vector<SequenceI> seqs = new Vector<>();
3901 for (int s = 0; s < jGroup.getSeq().size(); s++)
3903 String seqId = jGroup.getSeq().get(s);
3904 SequenceI ts = seqRefIds.get(seqId);
3908 seqs.addElement(ts);
3912 if (seqs.size() < 1)
3917 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3918 safeBoolean(jGroup.isDisplayBoxes()),
3919 safeBoolean(jGroup.isDisplayText()),
3920 safeBoolean(jGroup.isColourText()),
3921 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3922 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3923 sg.getGroupColourScheme()
3924 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3925 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3927 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3928 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3929 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3930 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3931 // attributes with a default in the schema are never null
3932 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3933 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3934 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3935 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3936 if (jGroup.getConsThreshold() != null
3937 && jGroup.getConsThreshold().intValue() != 0)
3939 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3942 c.verdict(false, 25);
3943 sg.cs.setConservation(c);
3946 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3948 // re-instate unique group/annotation row reference
3949 List<AlignmentAnnotation> jaal = groupAnnotRefs
3950 .get(jGroup.getId());
3953 for (AlignmentAnnotation jaa : jaal)
3956 if (jaa.autoCalculated)
3958 // match up and try to set group autocalc alignment row for this
3960 if (jaa.label.startsWith("Consensus for "))
3962 sg.setConsensus(jaa);
3964 // match up and try to set group autocalc alignment row for this
3966 if (jaa.label.startsWith("Conservation for "))
3968 sg.setConservationRow(jaa);
3975 if (addAnnotSchemeGroup)
3977 // reconstruct the annotation colourscheme
3979 constructAnnotationColour(jGroup.getAnnotationColours(),
3980 null, al, jalviewModel, false));
3986 // only dataset in this model, so just return.
3989 // ///////////////////////////////
3992 AlignFrame af = null;
3993 AlignViewport av = null;
3994 // now check to see if we really need to create a new viewport.
3995 if (multipleView && viewportsAdded.size() == 0)
3997 // We recovered an alignment for which a viewport already exists.
3998 // TODO: fix up any settings necessary for overlaying stored state onto
3999 // state recovered from another document. (may not be necessary).
4000 // we may need a binding from a viewport in memory to one recovered from
4002 // and then recover its containing af to allow the settings to be applied.
4003 // TODO: fix for vamsas demo
4005 "About to recover a viewport for existing alignment: Sequence set ID is "
4007 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4008 if (seqsetobj != null)
4010 if (seqsetobj instanceof String)
4012 uniqueSeqSetId = (String) seqsetobj;
4014 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4020 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4026 * indicate that annotation colours are applied across all groups (pre
4027 * Jalview 2.8.1 behaviour)
4029 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4030 jalviewModel.getVersion());
4032 AlignmentPanel ap = null;
4033 boolean isnewview = true;
4036 // Check to see if this alignment already has a view id == viewId
4037 jalview.gui.AlignmentPanel views[] = Desktop
4038 .getAlignmentPanels(uniqueSeqSetId);
4039 if (views != null && views.length > 0)
4041 for (int v = 0; v < views.length; v++)
4043 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4045 // recover the existing alignpanel, alignframe, viewport
4046 af = views[v].alignFrame;
4049 // TODO: could even skip resetting view settings if we don't want to
4050 // change the local settings from other jalview processes
4059 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4060 uniqueSeqSetId, viewId, autoAlan);
4061 av = af.getViewport();
4066 * Load any trees, PDB structures and viewers, Overview
4068 * Not done if flag is false (when this method is used for New View)
4070 if (loadTreesAndStructures)
4072 loadTrees(jalviewModel, view, af, av, ap);
4073 loadPCAViewers(jalviewModel, ap);
4074 loadPDBStructures(jprovider, jseqs, af, ap);
4075 loadRnaViewers(jprovider, jseqs, ap);
4076 loadOverview(view, af);
4078 // and finally return.
4083 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4084 * and geometry as saved
4089 protected void loadOverview(Viewport view, AlignFrame af)
4092 * first close any Overview that was opened automatically
4093 * (if so configured in Preferences) so that the view is
4094 * restored in the same state as saved
4096 af.alignPanel.closeOverviewPanel();
4098 Overview overview = view.getOverview();
4099 if (overview != null)
4101 OverviewPanel overviewPanel = af
4102 .openOverviewPanel(overview.isShowHidden());
4103 overviewPanel.setTitle(overview.getTitle());
4104 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4105 overview.getWidth(), overview.getHeight());
4106 Color gap = new Color(overview.getGapColour());
4107 Color residue = new Color(overview.getResidueColour());
4108 Color hidden = new Color(overview.getHiddenColour());
4109 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4114 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4115 * panel is restored from separate jar entries, two (gapped and trimmed) per
4116 * sequence and secondary structure.
4118 * Currently each viewer shows just one sequence and structure (gapped and
4119 * trimmed), however this method is designed to support multiple sequences or
4120 * structures in viewers if wanted in future.
4126 private void loadRnaViewers(jarInputStreamProvider jprovider,
4127 List<JSeq> jseqs, AlignmentPanel ap)
4130 * scan the sequences for references to viewers; create each one the first
4131 * time it is referenced, add Rna models to existing viewers
4133 for (JSeq jseq : jseqs)
4135 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4137 RnaViewer viewer = jseq.getRnaViewer().get(i);
4138 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4141 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4143 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4144 SequenceI seq = seqRefIds.get(jseq.getId());
4145 AlignmentAnnotation ann = this.annotationIds
4146 .get(ss.getAnnotationId());
4149 * add the structure to the Varna display (with session state copied
4150 * from the jar to a temporary file)
4152 boolean gapped = safeBoolean(ss.isGapped());
4153 String rnaTitle = ss.getTitle();
4154 String sessionState = ss.getViewerState();
4155 String tempStateFile = copyJarEntry(jprovider, sessionState,
4157 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4158 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4160 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4166 * Locate and return an already instantiated matching AppVarna, or create one
4170 * @param viewIdSuffix
4174 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4175 String viewIdSuffix, AlignmentPanel ap)
4178 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4179 * if load is repeated
4181 String postLoadId = viewer.getViewId() + viewIdSuffix;
4182 for (JInternalFrame frame : getAllFrames())
4184 if (frame instanceof AppVarna)
4186 AppVarna varna = (AppVarna) frame;
4187 if (postLoadId.equals(varna.getViewId()))
4189 // this viewer is already instantiated
4190 // could in future here add ap as another 'parent' of the
4191 // AppVarna window; currently just 1-to-many
4198 * viewer not found - make it
4200 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4201 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4202 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4203 safeInt(viewer.getDividerLocation()));
4204 AppVarna varna = new AppVarna(model, ap);
4210 * Load any saved trees
4218 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4219 AlignViewport av, AlignmentPanel ap)
4221 // TODO result of automated refactoring - are all these parameters needed?
4224 for (int t = 0; t < jm.getTree().size(); t++)
4227 Tree tree = jm.getTree().get(t);
4229 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4232 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4233 tree.getTitle(), safeInt(tree.getWidth()),
4234 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4235 safeInt(tree.getYpos()));
4236 if (tree.getId() != null)
4238 // perhaps bind the tree id to something ?
4243 // update local tree attributes ?
4244 // TODO: should check if tp has been manipulated by user - if so its
4245 // settings shouldn't be modified
4246 tp.setTitle(tree.getTitle());
4247 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4248 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4249 safeInt(tree.getHeight())));
4250 tp.setViewport(av); // af.viewport;
4251 // TODO: verify 'associate with all views' works still
4252 tp.getTreeCanvas().setViewport(av); // af.viewport;
4253 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4255 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4258 warn("There was a problem recovering stored Newick tree: \n"
4259 + tree.getNewick());
4263 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4264 tp.fitToWindow_actionPerformed(null);
4266 if (tree.getFontName() != null)
4269 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4270 safeInt(tree.getFontSize())));
4275 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4276 safeInt(view.getFontSize())));
4279 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4280 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4281 tp.showDistances(safeBoolean(tree.isShowDistances()));
4283 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4285 if (safeBoolean(tree.isCurrentTree()))
4287 af.getViewport().setCurrentTree(tp.getTree());
4291 } catch (Exception ex)
4293 ex.printStackTrace();
4298 * Load and link any saved structure viewers.
4305 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4306 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4309 * Run through all PDB ids on the alignment, and collect mappings between
4310 * distinct view ids and all sequences referring to that view.
4312 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4314 for (int i = 0; i < jseqs.size(); i++)
4316 JSeq jseq = jseqs.get(i);
4317 if (jseq.getPdbids().size() > 0)
4319 List<Pdbids> ids = jseq.getPdbids();
4320 for (int p = 0; p < ids.size(); p++)
4322 Pdbids pdbid = ids.get(p);
4323 final int structureStateCount = pdbid.getStructureState().size();
4324 for (int s = 0; s < structureStateCount; s++)
4326 // check to see if we haven't already created this structure view
4327 final StructureState structureState = pdbid.getStructureState()
4329 String sviewid = (structureState.getViewId() == null) ? null
4330 : structureState.getViewId() + uniqueSetSuffix;
4331 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4332 // Originally : pdbid.getFile()
4333 // : TODO: verify external PDB file recovery still works in normal
4334 // jalview project load
4336 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4337 jpdb.setId(pdbid.getId());
4339 int x = safeInt(structureState.getXpos());
4340 int y = safeInt(structureState.getYpos());
4341 int width = safeInt(structureState.getWidth());
4342 int height = safeInt(structureState.getHeight());
4344 // Probably don't need to do this anymore...
4345 // Desktop.desktop.getComponentAt(x, y);
4346 // TODO: NOW: check that this recovers the PDB file correctly.
4347 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4349 jalview.datamodel.SequenceI seq = seqRefIds
4350 .get(jseq.getId() + "");
4351 if (sviewid == null)
4353 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4356 if (!structureViewers.containsKey(sviewid))
4358 String viewerType = structureState.getType();
4359 if (viewerType == null) // pre Jalview 2.9
4361 viewerType = ViewerType.JMOL.toString();
4363 structureViewers.put(sviewid,
4364 new StructureViewerModel(x, y, width, height, false,
4365 false, true, structureState.getViewId(),
4367 // Legacy pre-2.7 conversion JAL-823 :
4368 // do not assume any view has to be linked for colour by
4372 // assemble String[] { pdb files }, String[] { id for each
4373 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4374 // seqs_file 2}, boolean[] {
4375 // linkAlignPanel,superposeWithAlignpanel}} from hash
4376 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4377 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4378 || structureState.isAlignwithAlignPanel());
4381 * Default colour by linked panel to false if not specified (e.g.
4382 * for pre-2.7 projects)
4384 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4385 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4386 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4389 * Default colour by viewer to true if not specified (e.g. for
4392 boolean colourByViewer = jmoldat.isColourByViewer();
4393 colourByViewer &= structureState.isColourByJmol();
4394 jmoldat.setColourByViewer(colourByViewer);
4396 if (jmoldat.getStateData().length() < structureState.getValue()
4397 /*Content()*/.length())
4399 jmoldat.setStateData(structureState.getValue());// Content());
4401 if (pdbid.getFile() != null)
4403 File mapkey = new File(pdbid.getFile());
4404 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4405 if (seqstrmaps == null)
4407 jmoldat.getFileData().put(mapkey,
4408 seqstrmaps = jmoldat.new StructureData(pdbFile,
4411 if (!seqstrmaps.getSeqList().contains(seq))
4413 seqstrmaps.getSeqList().add(seq);
4419 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");
4426 // Instantiate the associated structure views
4427 for (Entry<String, StructureViewerModel> entry : structureViewers
4432 createOrLinkStructureViewer(entry, af, ap, jprovider);
4433 } catch (Exception e)
4436 "Error loading structure viewer: " + e.getMessage());
4437 // failed - try the next one
4449 protected void createOrLinkStructureViewer(
4450 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4451 AlignmentPanel ap, jarInputStreamProvider jprovider)
4453 final StructureViewerModel stateData = viewerData.getValue();
4456 * Search for any viewer windows already open from other alignment views
4457 * that exactly match the stored structure state
4459 StructureViewerBase comp = findMatchingViewer(viewerData);
4463 linkStructureViewer(ap, comp, stateData);
4467 String type = stateData.getType();
4470 ViewerType viewerType = ViewerType.valueOf(type);
4471 createStructureViewer(viewerType, viewerData, af, jprovider);
4472 } catch (IllegalArgumentException | NullPointerException e)
4474 // TODO JAL-3619 show error dialog / offer an alternative viewer
4475 Cache.log.error("Invalid structure viewer type: " + type);
4480 * Generates a name for the entry in the project jar file to hold state
4481 * information for a structure viewer
4486 protected String getViewerJarEntryName(String viewId)
4488 return VIEWER_PREFIX + viewId;
4492 * Returns any open frame that matches given structure viewer data. The match
4493 * is based on the unique viewId, or (for older project versions) the frame's
4499 protected StructureViewerBase findMatchingViewer(
4500 Entry<String, StructureViewerModel> viewerData)
4502 final String sviewid = viewerData.getKey();
4503 final StructureViewerModel svattrib = viewerData.getValue();
4504 StructureViewerBase comp = null;
4505 JInternalFrame[] frames = getAllFrames();
4506 for (JInternalFrame frame : frames)
4508 if (frame instanceof StructureViewerBase)
4511 * Post jalview 2.4 schema includes structure view id
4513 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4516 comp = (StructureViewerBase) frame;
4517 break; // break added in 2.9
4520 * Otherwise test for matching position and size of viewer frame
4522 else if (frame.getX() == svattrib.getX()
4523 && frame.getY() == svattrib.getY()
4524 && frame.getHeight() == svattrib.getHeight()
4525 && frame.getWidth() == svattrib.getWidth())
4527 comp = (StructureViewerBase) frame;
4528 // no break in faint hope of an exact match on viewId
4536 * Link an AlignmentPanel to an existing structure viewer.
4541 * @param useinViewerSuperpos
4542 * @param usetoColourbyseq
4543 * @param viewerColouring
4545 protected void linkStructureViewer(AlignmentPanel ap,
4546 StructureViewerBase viewer, StructureViewerModel stateData)
4548 // NOTE: if the jalview project is part of a shared session then
4549 // view synchronization should/could be done here.
4551 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4552 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4553 final boolean viewerColouring = stateData.isColourByViewer();
4554 Map<File, StructureData> oldFiles = stateData.getFileData();
4557 * Add mapping for sequences in this view to an already open viewer
4559 final AAStructureBindingModel binding = viewer.getBinding();
4560 for (File id : oldFiles.keySet())
4562 // add this and any other pdb files that should be present in the
4564 StructureData filedat = oldFiles.get(id);
4565 String pdbFile = filedat.getFilePath();
4566 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4567 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4569 binding.addSequenceForStructFile(pdbFile, seq);
4571 // and add the AlignmentPanel's reference to the view panel
4572 viewer.addAlignmentPanel(ap);
4573 if (useinViewerSuperpos)
4575 viewer.useAlignmentPanelForSuperposition(ap);
4579 viewer.excludeAlignmentPanelForSuperposition(ap);
4581 if (usetoColourbyseq)
4583 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4587 viewer.excludeAlignmentPanelForColourbyseq(ap);
4592 * Get all frames within the Desktop.
4596 protected JInternalFrame[] getAllFrames()
4598 JInternalFrame[] frames = null;
4599 // TODO is this necessary - is it safe - risk of hanging?
4604 frames = Desktop.desktop.getAllFrames();
4605 } catch (ArrayIndexOutOfBoundsException e)
4607 // occasional No such child exceptions are thrown here...
4611 } catch (InterruptedException f)
4615 } while (frames == null);
4620 * Answers true if 'version' is equal to or later than 'supported', where each
4621 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4622 * changes. Development and test values for 'version' are leniently treated
4626 * - minimum version we are comparing against
4628 * - version of data being processsed
4631 public static boolean isVersionStringLaterThan(String supported,
4634 if (supported == null || version == null
4635 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4636 || version.equalsIgnoreCase("Test")
4637 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4639 System.err.println("Assuming project file with "
4640 + (version == null ? "null" : version)
4641 + " is compatible with Jalview version " + supported);
4646 return StringUtils.compareVersions(version, supported, "b") >= 0;
4650 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4652 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4654 if (newStructureViewers != null)
4656 sview.getBinding().setFinishedLoadingFromArchive(false);
4657 newStructureViewers.add(sview);
4661 protected void setLoadingFinishedForNewStructureViewers()
4663 if (newStructureViewers != null)
4665 for (JalviewStructureDisplayI sview : newStructureViewers)
4667 sview.getBinding().setFinishedLoadingFromArchive(true);
4669 newStructureViewers.clear();
4670 newStructureViewers = null;
4674 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4675 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4676 Viewport view, String uniqueSeqSetId, String viewId,
4677 List<JvAnnotRow> autoAlan)
4679 AlignFrame af = null;
4680 af = new AlignFrame(al, safeInt(view.getWidth()),
4681 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4685 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4686 // System.out.println("Jalview2XML AF " + e);
4687 // super.processKeyEvent(e);
4694 af.setFileName(file, FileFormat.Jalview);
4696 final AlignViewport viewport = af.getViewport();
4697 for (int i = 0; i < JSEQ.size(); i++)
4699 int colour = safeInt(JSEQ.get(i).getColour());
4700 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4706 viewport.setColourByReferenceSeq(true);
4707 viewport.setDisplayReferenceSeq(true);
4710 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4712 if (view.getSequenceSetId() != null)
4714 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4716 viewport.setSequenceSetId(uniqueSeqSetId);
4719 // propagate shared settings to this new view
4720 viewport.setHistoryList(av.getHistoryList());
4721 viewport.setRedoList(av.getRedoList());
4725 viewportsAdded.put(uniqueSeqSetId, viewport);
4727 // TODO: check if this method can be called repeatedly without
4728 // side-effects if alignpanel already registered.
4729 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4731 // apply Hidden regions to view.
4732 if (hiddenSeqs != null)
4734 for (int s = 0; s < JSEQ.size(); s++)
4736 SequenceGroup hidden = new SequenceGroup();
4737 boolean isRepresentative = false;
4738 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4740 isRepresentative = true;
4741 SequenceI sequenceToHide = al
4742 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4743 hidden.addSequence(sequenceToHide, false);
4744 // remove from hiddenSeqs list so we don't try to hide it twice
4745 hiddenSeqs.remove(sequenceToHide);
4747 if (isRepresentative)
4749 SequenceI representativeSequence = al.getSequenceAt(s);
4750 hidden.addSequence(representativeSequence, false);
4751 viewport.hideRepSequences(representativeSequence, hidden);
4755 SequenceI[] hseqs = hiddenSeqs
4756 .toArray(new SequenceI[hiddenSeqs.size()]);
4757 viewport.hideSequence(hseqs);
4760 // recover view properties and display parameters
4762 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4763 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4764 final int pidThreshold = safeInt(view.getPidThreshold());
4765 viewport.setThreshold(pidThreshold);
4767 viewport.setColourText(safeBoolean(view.isShowColourText()));
4769 viewport.setConservationSelected(
4770 safeBoolean(view.isConservationSelected()));
4771 viewport.setIncrement(safeInt(view.getConsThreshold()));
4772 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4773 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4774 viewport.setFont(new Font(view.getFontName(),
4775 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4777 ViewStyleI vs = viewport.getViewStyle();
4778 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4779 viewport.setViewStyle(vs);
4780 // TODO: allow custom charWidth/Heights to be restored by updating them
4781 // after setting font - which means set above to false
4782 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4783 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4784 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4786 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4788 viewport.setShowText(safeBoolean(view.isShowText()));
4790 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4791 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4792 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4793 viewport.setShowUnconserved(view.isShowUnconserved());
4794 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4796 if (view.getViewName() != null)
4798 viewport.setViewName(view.getViewName());
4799 af.setInitialTabVisible();
4801 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4802 safeInt(view.getWidth()), safeInt(view.getHeight()));
4803 // startSeq set in af.alignPanel.updateLayout below
4804 af.alignPanel.updateLayout();
4805 ColourSchemeI cs = null;
4806 // apply colourschemes
4807 if (view.getBgColour() != null)
4809 if (view.getBgColour().startsWith("ucs"))
4811 cs = getUserColourScheme(jm, view.getBgColour());
4813 else if (view.getBgColour().startsWith("Annotation"))
4815 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4816 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4823 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4824 view.getBgColour());
4829 * turn off 'alignment colour applies to all groups'
4830 * while restoring global colour scheme
4832 viewport.setColourAppliesToAllGroups(false);
4833 viewport.setGlobalColourScheme(cs);
4834 viewport.getResidueShading().setThreshold(pidThreshold,
4835 view.isIgnoreGapsinConsensus());
4836 viewport.getResidueShading()
4837 .setConsensus(viewport.getSequenceConsensusHash());
4838 if (safeBoolean(view.isConservationSelected()) && cs != null)
4840 viewport.getResidueShading()
4841 .setConservationInc(safeInt(view.getConsThreshold()));
4843 af.changeColour(cs);
4844 viewport.setColourAppliesToAllGroups(true);
4846 viewport.setShowSequenceFeatures(
4847 safeBoolean(view.isShowSequenceFeatures()));
4849 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4850 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4851 viewport.setFollowHighlight(view.isFollowHighlight());
4852 viewport.followSelection = view.isFollowSelection();
4853 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4854 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4855 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4856 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4857 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4858 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4859 viewport.setShowGroupConservation(view.isShowGroupConservation());
4860 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4861 viewport.setShowComplementFeaturesOnTop(
4862 view.isShowComplementFeaturesOnTop());
4864 // recover feature settings
4865 if (jm.getFeatureSettings() != null)
4867 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4868 .getFeatureRenderer();
4869 FeaturesDisplayed fdi;
4870 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4871 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
4873 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4874 Map<String, Float> featureOrder = new Hashtable<>();
4876 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
4879 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4880 String featureType = setting.getType();
4883 * restore feature filters (if any)
4885 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4887 if (filters != null)
4889 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
4891 if (!filter.isEmpty())
4893 fr.setFeatureFilter(featureType, filter);
4898 * restore feature colour scheme
4900 Color maxColour = new Color(setting.getColour());
4901 if (setting.getMincolour() != null)
4904 * minColour is always set unless a simple colour
4905 * (including for colour by label though it doesn't use it)
4907 Color minColour = new Color(setting.getMincolour().intValue());
4908 Color noValueColour = minColour;
4909 NoValueColour noColour = setting.getNoValueColour();
4910 if (noColour == NoValueColour.NONE)
4912 noValueColour = null;
4914 else if (noColour == NoValueColour.MAX)
4916 noValueColour = maxColour;
4918 float min = safeFloat(safeFloat(setting.getMin()));
4919 float max = setting.getMax() == null ? 1f
4920 : setting.getMax().floatValue();
4921 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4922 maxColour, noValueColour, min, max);
4923 if (setting.getAttributeName().size() > 0)
4925 gc.setAttributeName(setting.getAttributeName().toArray(
4926 new String[setting.getAttributeName().size()]));
4928 if (setting.getThreshold() != null)
4930 gc.setThreshold(setting.getThreshold().floatValue());
4931 int threshstate = safeInt(setting.getThreshstate());
4932 // -1 = None, 0 = Below, 1 = Above threshold
4933 if (threshstate == 0)
4935 gc.setBelowThreshold(true);
4937 else if (threshstate == 1)
4939 gc.setAboveThreshold(true);
4942 gc.setAutoScaled(true); // default
4943 if (setting.isAutoScale() != null)
4945 gc.setAutoScaled(setting.isAutoScale());
4947 if (setting.isColourByLabel() != null)
4949 gc.setColourByLabel(setting.isColourByLabel());
4951 // and put in the feature colour table.
4952 featureColours.put(featureType, gc);
4956 featureColours.put(featureType, new FeatureColour(maxColour));
4958 renderOrder[fs] = featureType;
4959 if (setting.getOrder() != null)
4961 featureOrder.put(featureType, setting.getOrder().floatValue());
4965 featureOrder.put(featureType, Float.valueOf(
4966 fs / jm.getFeatureSettings().getSetting().size()));
4968 if (safeBoolean(setting.isDisplay()))
4970 fdi.setVisible(featureType);
4973 Map<String, Boolean> fgtable = new Hashtable<>();
4974 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4976 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4977 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4979 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4980 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4981 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4982 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4983 fgtable, featureColours, 1.0f, featureOrder);
4984 fr.transferSettings(frs);
4987 if (view.getHiddenColumns().size() > 0)
4989 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4991 final HiddenColumns hc = view.getHiddenColumns().get(c);
4992 viewport.hideColumns(safeInt(hc.getStart()),
4993 safeInt(hc.getEnd()) /* +1 */);
4996 if (view.getCalcIdParam() != null)
4998 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5000 if (calcIdParam != null)
5002 if (recoverCalcIdParam(calcIdParam, viewport))
5007 warn("Couldn't recover parameters for "
5008 + calcIdParam.getCalcId());
5013 af.setMenusFromViewport(viewport);
5014 af.setTitle(view.getTitle());
5015 // TODO: we don't need to do this if the viewport is aready visible.
5017 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5018 * has a 'cdna/protein complement' view, in which case save it in order to
5019 * populate a SplitFrame once all views have been read in.
5021 String complementaryViewId = view.getComplementId();
5022 if (complementaryViewId == null)
5024 Desktop.addInternalFrame(af, view.getTitle(),
5025 safeInt(view.getWidth()), safeInt(view.getHeight()));
5026 // recompute any autoannotation
5027 af.alignPanel.updateAnnotation(false, true);
5028 reorderAutoannotation(af, al, autoAlan);
5029 af.alignPanel.alignmentChanged();
5033 splitFrameCandidates.put(view, af);
5040 * Reads saved data to restore Colour by Annotation settings
5042 * @param viewAnnColour
5046 * @param checkGroupAnnColour
5049 private ColourSchemeI constructAnnotationColour(
5050 AnnotationColourScheme viewAnnColour, AlignFrame af,
5051 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5053 boolean propagateAnnColour = false;
5054 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5056 if (checkGroupAnnColour && al.getGroups() != null
5057 && al.getGroups().size() > 0)
5059 // pre 2.8.1 behaviour
5060 // check to see if we should transfer annotation colours
5061 propagateAnnColour = true;
5062 for (SequenceGroup sg : al.getGroups())
5064 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5066 propagateAnnColour = false;
5072 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5074 String annotationId = viewAnnColour.getAnnotation();
5075 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5078 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5080 if (matchedAnnotation == null
5081 && annAlignment.getAlignmentAnnotation() != null)
5083 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5086 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5088 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5093 if (matchedAnnotation == null)
5095 System.err.println("Failed to match annotation colour scheme for "
5099 if (matchedAnnotation.getThreshold() == null)
5101 matchedAnnotation.setThreshold(
5102 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5103 "Threshold", Color.black));
5106 AnnotationColourGradient cs = null;
5107 if (viewAnnColour.getColourScheme().equals("None"))
5109 cs = new AnnotationColourGradient(matchedAnnotation,
5110 new Color(safeInt(viewAnnColour.getMinColour())),
5111 new Color(safeInt(viewAnnColour.getMaxColour())),
5112 safeInt(viewAnnColour.getAboveThreshold()));
5114 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5116 cs = new AnnotationColourGradient(matchedAnnotation,
5117 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5118 safeInt(viewAnnColour.getAboveThreshold()));
5122 cs = new AnnotationColourGradient(matchedAnnotation,
5123 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5124 viewAnnColour.getColourScheme()),
5125 safeInt(viewAnnColour.getAboveThreshold()));
5128 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5129 boolean useOriginalColours = safeBoolean(
5130 viewAnnColour.isPredefinedColours());
5131 cs.setSeqAssociated(perSequenceOnly);
5132 cs.setPredefinedColours(useOriginalColours);
5134 if (propagateAnnColour && al.getGroups() != null)
5136 // Also use these settings for all the groups
5137 for (int g = 0; g < al.getGroups().size(); g++)
5139 SequenceGroup sg = al.getGroups().get(g);
5140 if (sg.getGroupColourScheme() == null)
5145 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5146 matchedAnnotation, sg.getColourScheme(),
5147 safeInt(viewAnnColour.getAboveThreshold()));
5148 sg.setColourScheme(groupScheme);
5149 groupScheme.setSeqAssociated(perSequenceOnly);
5150 groupScheme.setPredefinedColours(useOriginalColours);
5156 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5157 List<JvAnnotRow> autoAlan)
5159 // copy over visualization settings for autocalculated annotation in the
5161 if (al.getAlignmentAnnotation() != null)
5164 * Kludge for magic autoannotation names (see JAL-811)
5166 String[] magicNames = new String[] { "Consensus", "Quality",
5168 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5169 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5170 for (String nm : magicNames)
5172 visan.put(nm, nullAnnot);
5174 for (JvAnnotRow auan : autoAlan)
5176 visan.put(auan.template.label
5177 + (auan.template.getCalcId() == null ? ""
5178 : "\t" + auan.template.getCalcId()),
5181 int hSize = al.getAlignmentAnnotation().length;
5182 List<JvAnnotRow> reorder = new ArrayList<>();
5183 // work through any autoCalculated annotation already on the view
5184 // removing it if it should be placed in a different location on the
5185 // annotation panel.
5186 List<String> remains = new ArrayList<>(visan.keySet());
5187 for (int h = 0; h < hSize; h++)
5189 jalview.datamodel.AlignmentAnnotation jalan = al
5190 .getAlignmentAnnotation()[h];
5191 if (jalan.autoCalculated)
5194 JvAnnotRow valan = visan.get(k = jalan.label);
5195 if (jalan.getCalcId() != null)
5197 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5202 // delete the auto calculated row from the alignment
5203 al.deleteAnnotation(jalan, false);
5207 if (valan != nullAnnot)
5209 if (jalan != valan.template)
5211 // newly created autoannotation row instance
5212 // so keep a reference to the visible annotation row
5213 // and copy over all relevant attributes
5214 if (valan.template.graphHeight >= 0)
5217 jalan.graphHeight = valan.template.graphHeight;
5219 jalan.visible = valan.template.visible;
5221 reorder.add(new JvAnnotRow(valan.order, jalan));
5226 // Add any (possibly stale) autocalculated rows that were not appended to
5227 // the view during construction
5228 for (String other : remains)
5230 JvAnnotRow othera = visan.get(other);
5231 if (othera != nullAnnot && othera.template.getCalcId() != null
5232 && othera.template.getCalcId().length() > 0)
5234 reorder.add(othera);
5237 // now put the automatic annotation in its correct place
5238 int s = 0, srt[] = new int[reorder.size()];
5239 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5240 for (JvAnnotRow jvar : reorder)
5243 srt[s++] = jvar.order;
5246 jalview.util.QuickSort.sort(srt, rws);
5247 // and re-insert the annotation at its correct position
5248 for (JvAnnotRow jvar : rws)
5250 al.addAnnotation(jvar.template, jvar.order);
5252 af.alignPanel.adjustAnnotationHeight();
5256 Hashtable skipList = null;
5259 * TODO remove this method
5262 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5263 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5264 * throw new Error("Implementation Error. No skipList defined for this
5265 * Jalview2XML instance."); } return (AlignFrame)
5266 * skipList.get(view.getSequenceSetId()); }
5270 * Check if the Jalview view contained in object should be skipped or not.
5273 * @return true if view's sequenceSetId is a key in skipList
5275 private boolean skipViewport(JalviewModel object)
5277 if (skipList == null)
5281 String id = object.getViewport().get(0).getSequenceSetId();
5282 if (skipList.containsKey(id))
5284 if (Cache.log != null && Cache.log.isDebugEnabled())
5286 Cache.log.debug("Skipping seuqence set id " + id);
5293 public void addToSkipList(AlignFrame af)
5295 if (skipList == null)
5297 skipList = new Hashtable();
5299 skipList.put(af.getViewport().getSequenceSetId(), af);
5302 public void clearSkipList()
5304 if (skipList != null)
5311 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5312 boolean ignoreUnrefed, String uniqueSeqSetId)
5314 jalview.datamodel.AlignmentI ds = getDatasetFor(
5315 vamsasSet.getDatasetId());
5316 AlignmentI xtant_ds = ds;
5317 if (xtant_ds == null)
5319 // good chance we are about to create a new dataset, but check if we've
5320 // seen some of the dataset sequence IDs before.
5321 // TODO: skip this check if we are working with project generated by
5322 // version 2.11 or later
5323 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5324 if (xtant_ds != null)
5327 addDatasetRef(vamsasSet.getDatasetId(), ds);
5330 Vector<SequenceI> dseqs = null;
5333 // recovering an alignment View
5334 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5335 if (seqSetDS != null)
5337 if (ds != null && ds != seqSetDS)
5339 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5340 + " - CDS/Protein crossreference data may be lost");
5341 if (xtant_ds != null)
5343 // This can only happen if the unique sequence set ID was bound to a
5344 // dataset that did not contain any of the sequences in the view
5345 // currently being restored.
5346 warn("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.");
5350 addDatasetRef(vamsasSet.getDatasetId(), ds);
5355 // try even harder to restore dataset
5356 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5357 // create a list of new dataset sequences
5358 dseqs = new Vector<>();
5360 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5362 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5363 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5365 // create a new dataset
5368 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5369 dseqs.copyInto(dsseqs);
5370 ds = new jalview.datamodel.Alignment(dsseqs);
5371 debug("Created new dataset " + vamsasSet.getDatasetId()
5372 + " for alignment " + System.identityHashCode(al));
5373 addDatasetRef(vamsasSet.getDatasetId(), ds);
5375 // set the dataset for the newly imported alignment.
5376 if (al.getDataset() == null && !ignoreUnrefed)
5379 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5380 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5382 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5386 * XML dataset sequence ID to materialised dataset reference
5388 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5391 * @return the first materialised dataset reference containing a dataset
5392 * sequence referenced in the given view
5394 * - sequences from the view
5396 AlignmentI checkIfHasDataset(List<Sequence> list)
5398 for (Sequence restoredSeq : list)
5400 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5401 if (datasetFor != null)
5410 * Register ds as the containing dataset for the dataset sequences referenced
5411 * by sequences in list
5414 * - sequences in a view
5417 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5419 for (Sequence restoredSeq : list)
5421 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5422 if (prevDS != null && prevDS != ds)
5424 warn("Dataset sequence appears in many datasets: "
5425 + restoredSeq.getDsseqid());
5426 // TODO: try to merge!
5434 * sequence definition to create/merge dataset sequence for
5438 * vector to add new dataset sequence to
5439 * @param ignoreUnrefed
5440 * - when true, don't create new sequences from vamsasSeq if it's id
5441 * doesn't already have an asssociated Jalview sequence.
5443 * - used to reorder the sequence in the alignment according to the
5444 * vamsasSeq array ordering, to preserve ordering of dataset
5446 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5447 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5450 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5452 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5453 boolean reorder = false;
5454 SequenceI dsq = null;
5455 if (sq != null && sq.getDatasetSequence() != null)
5457 dsq = sq.getDatasetSequence();
5463 if (sq == null && ignoreUnrefed)
5467 String sqid = vamsasSeq.getDsseqid();
5470 // need to create or add a new dataset sequence reference to this sequence
5473 dsq = seqRefIds.get(sqid);
5478 // make a new dataset sequence
5479 dsq = sq.createDatasetSequence();
5482 // make up a new dataset reference for this sequence
5483 sqid = seqHash(dsq);
5485 dsq.setVamsasId(uniqueSetSuffix + sqid);
5486 seqRefIds.put(sqid, dsq);
5491 dseqs.addElement(dsq);
5496 ds.addSequence(dsq);
5502 { // make this dataset sequence sq's dataset sequence
5503 sq.setDatasetSequence(dsq);
5504 // and update the current dataset alignment
5509 if (!dseqs.contains(dsq))
5516 if (ds.findIndex(dsq) < 0)
5518 ds.addSequence(dsq);
5525 // TODO: refactor this as a merge dataset sequence function
5526 // now check that sq (the dataset sequence) sequence really is the union of
5527 // all references to it
5528 // boolean pre = sq.getStart() < dsq.getStart();
5529 // boolean post = sq.getEnd() > dsq.getEnd();
5533 // StringBuffer sb = new StringBuffer();
5534 String newres = jalview.analysis.AlignSeq.extractGaps(
5535 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5536 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5537 && newres.length() > dsq.getLength())
5539 // Update with the longer sequence.
5543 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5544 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5545 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5546 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5548 dsq.setSequence(newres);
5550 // TODO: merges will never happen if we 'know' we have the real dataset
5551 // sequence - this should be detected when id==dssid
5553 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5554 // + (pre ? "prepended" : "") + " "
5555 // + (post ? "appended" : ""));
5560 // sequence refs are identical. We may need to update the existing dataset
5561 // alignment with this one, though.
5562 if (ds != null && dseqs == null)
5564 int opos = ds.findIndex(dsq);
5565 SequenceI tseq = null;
5566 if (opos != -1 && vseqpos != opos)
5568 // remove from old position
5569 ds.deleteSequence(dsq);
5571 if (vseqpos < ds.getHeight())
5573 if (vseqpos != opos)
5575 // save sequence at destination position
5576 tseq = ds.getSequenceAt(vseqpos);
5577 ds.replaceSequenceAt(vseqpos, dsq);
5578 ds.addSequence(tseq);
5583 ds.addSequence(dsq);
5590 * TODO use AlignmentI here and in related methods - needs
5591 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5593 Hashtable<String, AlignmentI> datasetIds = null;
5595 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5597 private AlignmentI getDatasetFor(String datasetId)
5599 if (datasetIds == null)
5601 datasetIds = new Hashtable<>();
5604 if (datasetIds.containsKey(datasetId))
5606 return datasetIds.get(datasetId);
5611 private void addDatasetRef(String datasetId, AlignmentI dataset)
5613 if (datasetIds == null)
5615 datasetIds = new Hashtable<>();
5617 datasetIds.put(datasetId, dataset);
5621 * make a new dataset ID for this jalview dataset alignment
5626 private String getDatasetIdRef(AlignmentI dataset)
5628 if (dataset.getDataset() != null)
5630 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5632 String datasetId = makeHashCode(dataset, null);
5633 if (datasetId == null)
5635 // make a new datasetId and record it
5636 if (dataset2Ids == null)
5638 dataset2Ids = new IdentityHashMap<>();
5642 datasetId = dataset2Ids.get(dataset);
5644 if (datasetId == null)
5646 datasetId = "ds" + dataset2Ids.size() + 1;
5647 dataset2Ids.put(dataset, datasetId);
5654 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5655 * constructed as a special subclass GeneLocus.
5657 * @param datasetSequence
5660 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5662 for (int d = 0; d < sequence.getDBRef().size(); d++)
5664 DBRef dr = sequence.getDBRef().get(d);
5668 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5669 dr.getAccessionId());
5673 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5674 dr.getAccessionId());
5676 if (dr.getMapping() != null)
5678 entry.setMap(addMapping(dr.getMapping()));
5680 entry.setCanonical(dr.isCanonical());
5681 datasetSequence.addDBRef(entry);
5685 private jalview.datamodel.Mapping addMapping(Mapping m)
5687 SequenceI dsto = null;
5688 // Mapping m = dr.getMapping();
5689 int fr[] = new int[m.getMapListFrom().size() * 2];
5690 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5691 for (int _i = 0; from.hasNext(); _i += 2)
5693 MapListFrom mf = from.next();
5694 fr[_i] = mf.getStart();
5695 fr[_i + 1] = mf.getEnd();
5697 int fto[] = new int[m.getMapListTo().size() * 2];
5698 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5699 for (int _i = 0; to.hasNext(); _i += 2)
5701 MapListTo mf = to.next();
5702 fto[_i] = mf.getStart();
5703 fto[_i + 1] = mf.getEnd();
5705 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5706 fto, m.getMapFromUnit().intValue(),
5707 m.getMapToUnit().intValue());
5710 * (optional) choice of dseqFor or Sequence
5712 if (m.getDseqFor() != null)
5714 String dsfor = m.getDseqFor();
5715 if (seqRefIds.containsKey(dsfor))
5720 jmap.setTo(seqRefIds.get(dsfor));
5724 frefedSequence.add(newMappingRef(dsfor, jmap));
5727 else if (m.getSequence() != null)
5730 * local sequence definition
5732 Sequence ms = m.getSequence();
5733 SequenceI djs = null;
5734 String sqid = ms.getDsseqid();
5735 if (sqid != null && sqid.length() > 0)
5738 * recover dataset sequence
5740 djs = seqRefIds.get(sqid);
5745 "Warning - making up dataset sequence id for DbRef sequence map reference");
5746 sqid = ((Object) ms).toString(); // make up a new hascode for
5747 // undefined dataset sequence hash
5748 // (unlikely to happen)
5754 * make a new dataset sequence and add it to refIds hash
5756 djs = new jalview.datamodel.Sequence(ms.getName(),
5758 djs.setStart(jmap.getMap().getToLowest());
5759 djs.setEnd(jmap.getMap().getToHighest());
5760 djs.setVamsasId(uniqueSetSuffix + sqid);
5762 incompleteSeqs.put(sqid, djs);
5763 seqRefIds.put(sqid, djs);
5766 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5775 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5776 * view as XML (but not to file), and then reloading it
5781 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5784 JalviewModel jm = saveState(ap, null, null, null);
5787 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5788 ap.getAlignment().getDataset());
5790 uniqueSetSuffix = "";
5791 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5792 jm.getViewport().get(0).setId(null);
5793 // we don't overwrite the view we just copied
5795 if (this.frefedSequence == null)
5797 frefedSequence = new Vector<>();
5800 viewportsAdded.clear();
5802 AlignFrame af = loadFromObject(jm, null, false, null);
5803 af.getAlignPanels().clear();
5804 af.closeMenuItem_actionPerformed(true);
5807 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5808 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5809 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5810 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5811 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5814 return af.alignPanel;
5817 private Hashtable jvids2vobj;
5819 private void warn(String msg)
5824 private void warn(String msg, Exception e)
5826 if (Cache.log != null)
5830 Cache.log.warn(msg, e);
5834 Cache.log.warn(msg);
5839 System.err.println("Warning: " + msg);
5842 e.printStackTrace();
5847 private void debug(String string)
5849 debug(string, null);
5852 private void debug(String msg, Exception e)
5854 if (Cache.log != null)
5858 Cache.log.debug(msg, e);
5862 Cache.log.debug(msg);
5867 System.err.println("Warning: " + msg);
5870 e.printStackTrace();
5876 * set the object to ID mapping tables used to write/recover objects and XML
5877 * ID strings for the jalview project. If external tables are provided then
5878 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5879 * object goes out of scope. - also populates the datasetIds hashtable with
5880 * alignment objects containing dataset sequences
5883 * Map from ID strings to jalview datamodel
5885 * Map from jalview datamodel to ID strings
5889 public void setObjectMappingTables(Hashtable vobj2jv,
5890 IdentityHashMap jv2vobj)
5892 this.jv2vobj = jv2vobj;
5893 this.vobj2jv = vobj2jv;
5894 Iterator ds = jv2vobj.keySet().iterator();
5896 while (ds.hasNext())
5898 Object jvobj = ds.next();
5899 id = jv2vobj.get(jvobj).toString();
5900 if (jvobj instanceof jalview.datamodel.Alignment)
5902 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5904 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5907 else if (jvobj instanceof jalview.datamodel.Sequence)
5909 // register sequence object so the XML parser can recover it.
5910 if (seqRefIds == null)
5912 seqRefIds = new HashMap<>();
5914 if (seqsToIds == null)
5916 seqsToIds = new IdentityHashMap<>();
5918 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5919 seqsToIds.put((SequenceI) jvobj, id);
5921 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5924 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5925 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5926 if (jvann.annotationId == null)
5928 jvann.annotationId = anid;
5930 if (!jvann.annotationId.equals(anid))
5932 // TODO verify that this is the correct behaviour
5933 this.warn("Overriding Annotation ID for " + anid
5934 + " from different id : " + jvann.annotationId);
5935 jvann.annotationId = anid;
5938 else if (jvobj instanceof String)
5940 if (jvids2vobj == null)
5942 jvids2vobj = new Hashtable();
5943 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5948 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5954 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5955 * objects created from the project archive. If string is null (default for
5956 * construction) then suffix will be set automatically.
5960 public void setUniqueSetSuffix(String string)
5962 uniqueSetSuffix = string;
5967 * uses skipList2 as the skipList for skipping views on sequence sets
5968 * associated with keys in the skipList
5972 public void setSkipList(Hashtable skipList2)
5974 skipList = skipList2;
5978 * Reads the jar entry of given name and returns its contents, or null if the
5979 * entry is not found.
5982 * @param jarEntryName
5985 protected String readJarEntry(jarInputStreamProvider jprovider,
5986 String jarEntryName)
5988 String result = null;
5989 BufferedReader in = null;
5994 * Reopen the jar input stream and traverse its entries to find a matching
5997 JarInputStream jin = jprovider.getJarInputStream();
5998 JarEntry entry = null;
6001 entry = jin.getNextJarEntry();
6002 } while (entry != null && !entry.getName().equals(jarEntryName));
6006 StringBuilder out = new StringBuilder(256);
6007 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6010 while ((data = in.readLine()) != null)
6014 result = out.toString();
6018 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6020 } catch (Exception ex)
6022 ex.printStackTrace();
6030 } catch (IOException e)
6041 * Returns an incrementing counter (0, 1, 2...)
6045 private synchronized int nextCounter()
6051 * Loads any saved PCA viewers
6056 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6060 List<PcaViewer> pcaviewers = model.getPcaViewer();
6061 for (PcaViewer viewer : pcaviewers)
6063 String modelName = viewer.getScoreModelName();
6064 SimilarityParamsI params = new SimilarityParams(
6065 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6066 viewer.isIncludeGaps(),
6067 viewer.isDenominateByShortestLength());
6070 * create the panel (without computing the PCA)
6072 PCAPanel panel = new PCAPanel(ap, modelName, params);
6074 panel.setTitle(viewer.getTitle());
6075 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6076 viewer.getWidth(), viewer.getHeight()));
6078 boolean showLabels = viewer.isShowLabels();
6079 panel.setShowLabels(showLabels);
6080 panel.getRotatableCanvas().setShowLabels(showLabels);
6081 panel.getRotatableCanvas()
6082 .setBgColour(new Color(viewer.getBgColour()));
6083 panel.getRotatableCanvas()
6084 .setApplyToAllViews(viewer.isLinkToAllViews());
6087 * load PCA output data
6089 ScoreModelI scoreModel = ScoreModels.getInstance()
6090 .getScoreModel(modelName, ap);
6091 PCA pca = new PCA(null, scoreModel, params);
6092 PcaDataType pcaData = viewer.getPcaData();
6094 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6095 pca.setPairwiseScores(pairwise);
6097 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6098 pca.setTridiagonal(triDiag);
6100 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6101 pca.setEigenmatrix(result);
6103 panel.getPcaModel().setPCA(pca);
6106 * we haven't saved the input data! (JAL-2647 to do)
6108 panel.setInputData(null);
6111 * add the sequence points for the PCA display
6113 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6114 for (SequencePoint sp : viewer.getSequencePoint())
6116 String seqId = sp.getSequenceRef();
6117 SequenceI seq = seqRefIds.get(seqId);
6120 throw new IllegalStateException(
6121 "Unmatched seqref for PCA: " + seqId);
6123 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6124 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6126 seqPoints.add(seqPoint);
6128 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6131 * set min-max ranges and scale after setPoints (which recomputes them)
6133 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6134 SeqPointMin spMin = viewer.getSeqPointMin();
6135 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6137 SeqPointMax spMax = viewer.getSeqPointMax();
6138 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6140 panel.getRotatableCanvas().setSeqMinMax(min, max);
6142 // todo: hold points list in PCAModel only
6143 panel.getPcaModel().setSequencePoints(seqPoints);
6145 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6146 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6147 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6149 // is this duplication needed?
6150 panel.setTop(seqPoints.size() - 1);
6151 panel.getPcaModel().setTop(seqPoints.size() - 1);
6154 * add the axes' end points for the display
6156 for (int i = 0; i < 3; i++)
6158 Axis axis = viewer.getAxis().get(i);
6159 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6160 axis.getXPos(), axis.getYPos(), axis.getZPos());
6163 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6164 "label.calc_title", "PCA", modelName), 475, 450);
6166 } catch (Exception ex)
6168 Cache.log.error("Error loading PCA: " + ex.toString());
6173 * Creates a new structure viewer window
6180 protected void createStructureViewer(ViewerType viewerType,
6181 final Entry<String, StructureViewerModel> viewerData,
6182 AlignFrame af, jarInputStreamProvider jprovider)
6184 final StructureViewerModel viewerModel = viewerData.getValue();
6185 String sessionFilePath = null;
6187 if (viewerType == ViewerType.JMOL)
6189 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6193 String viewerJarEntryName = getViewerJarEntryName(
6194 viewerModel.getViewId());
6195 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6196 "viewerSession", ".tmp");
6198 final String sessionPath = sessionFilePath;
6199 final String sviewid = viewerData.getKey();
6202 SwingUtilities.invokeAndWait(new Runnable()
6207 JalviewStructureDisplayI sview = null;
6210 sview = StructureViewer.createView(viewerType, af.alignPanel,
6211 viewerModel, sessionPath, sviewid);
6212 addNewStructureViewer(sview);
6213 } catch (OutOfMemoryError ex)
6215 new OOMWarning("Restoring structure view for " + viewerType,
6216 (OutOfMemoryError) ex.getCause());
6217 if (sview != null && sview.isVisible())
6219 sview.closeViewer(false);
6220 sview.setVisible(false);
6226 } catch (InvocationTargetException | InterruptedException ex)
6228 warn("Unexpected error when opening " + viewerType
6229 + " structure viewer", ex);
6234 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6235 * the path of the file. "load file" commands are rewritten to change the
6236 * original PDB file names to those created as the Jalview project is loaded.
6242 private String rewriteJmolSession(StructureViewerModel svattrib,
6243 jarInputStreamProvider jprovider)
6245 String state = svattrib.getStateData(); // Jalview < 2.9
6246 if (state == null || state.isEmpty()) // Jalview >= 2.9
6248 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6249 state = readJarEntry(jprovider, jarEntryName);
6251 // TODO or simpler? for each key in oldFiles,
6252 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6253 // (allowing for different path escapings)
6254 StringBuilder rewritten = new StringBuilder(state.length());
6255 int cp = 0, ncp, ecp;
6256 Map<File, StructureData> oldFiles = svattrib.getFileData();
6257 while ((ncp = state.indexOf("load ", cp)) > -1)
6261 // look for next filename in load statement
6262 rewritten.append(state.substring(cp,
6263 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6264 String oldfilenam = state.substring(ncp,
6265 ecp = state.indexOf("\"", ncp));
6266 // recover the new mapping data for this old filename
6267 // have to normalize filename - since Jmol and jalview do
6268 // filename translation differently.
6269 StructureData filedat = oldFiles.get(new File(oldfilenam));
6270 if (filedat == null)
6272 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6273 filedat = oldFiles.get(new File(reformatedOldFilename));
6275 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6276 rewritten.append("\"");
6277 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6278 // look for next file statement.
6279 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6283 // just append rest of state
6284 rewritten.append(state.substring(cp));
6288 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6289 rewritten = new StringBuilder(state);
6290 rewritten.append("; load append ");
6291 for (File id : oldFiles.keySet())
6293 // add pdb files that should be present in the viewer
6294 StructureData filedat = oldFiles.get(id);
6295 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6297 rewritten.append(";");
6300 if (rewritten.length() == 0)
6304 final String history = "history = ";
6305 int historyIndex = rewritten.indexOf(history);
6306 if (historyIndex > -1)
6309 * change "history = [true|false];" to "history = [1|0];"
6311 historyIndex += history.length();
6312 String val = rewritten.substring(historyIndex, historyIndex + 5);
6313 if (val.startsWith("true"))
6315 rewritten.replace(historyIndex, historyIndex + 4, "1");
6317 else if (val.startsWith("false"))
6319 rewritten.replace(historyIndex, historyIndex + 5, "0");
6325 File tmp = File.createTempFile("viewerSession", ".tmp");
6326 try (OutputStream os = new FileOutputStream(tmp))
6328 InputStream is = new ByteArrayInputStream(
6329 rewritten.toString().getBytes());
6331 return tmp.getAbsolutePath();
6333 } catch (IOException e)
6335 Cache.log.error("Error restoring Jmol session: " + e.toString());
6341 * Populates an XML model of the feature colour scheme for one feature type
6343 * @param featureType
6347 public static Colour marshalColour(String featureType,
6348 FeatureColourI fcol)
6350 Colour col = new Colour();
6351 if (fcol.isSimpleColour())
6353 col.setRGB(Format.getHexString(fcol.getColour()));
6357 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6358 col.setMin(fcol.getMin());
6359 col.setMax(fcol.getMax());
6360 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6361 col.setAutoScale(fcol.isAutoScaled());
6362 col.setThreshold(fcol.getThreshold());
6363 col.setColourByLabel(fcol.isColourByLabel());
6364 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6365 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6366 : ThresholdType.NONE));
6367 if (fcol.isColourByAttribute())
6369 final String[] attName = fcol.getAttributeName();
6370 col.getAttributeName().add(attName[0]);
6371 if (attName.length > 1)
6373 col.getAttributeName().add(attName[1]);
6376 Color noColour = fcol.getNoColour();
6377 if (noColour == null)
6379 col.setNoValueColour(NoValueColour.NONE);
6381 else if (noColour == fcol.getMaxColour())
6383 col.setNoValueColour(NoValueColour.MAX);
6387 col.setNoValueColour(NoValueColour.MIN);
6390 col.setName(featureType);
6395 * Populates an XML model of the feature filter(s) for one feature type
6397 * @param firstMatcher
6398 * the first (or only) match condition)
6400 * remaining match conditions (if any)
6402 * if true, conditions are and-ed, else or-ed
6404 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6405 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6408 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6410 if (filters.hasNext())
6415 CompoundMatcher compound = new CompoundMatcher();
6416 compound.setAnd(and);
6417 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6418 firstMatcher, Collections.emptyIterator(), and);
6419 // compound.addMatcherSet(matcher1);
6420 compound.getMatcherSet().add(matcher1);
6421 FeatureMatcherI nextMatcher = filters.next();
6422 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6423 nextMatcher, filters, and);
6424 // compound.addMatcherSet(matcher2);
6425 compound.getMatcherSet().add(matcher2);
6426 result.setCompoundMatcher(compound);
6431 * single condition matcher
6433 // MatchCondition matcherModel = new MatchCondition();
6434 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6435 matcherModel.setCondition(
6436 firstMatcher.getMatcher().getCondition().getStableName());
6437 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6438 if (firstMatcher.isByAttribute())
6440 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6441 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6442 String[] attName = firstMatcher.getAttribute();
6443 matcherModel.getAttributeName().add(attName[0]); // attribute
6444 if (attName.length > 1)
6446 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6449 else if (firstMatcher.isByLabel())
6451 matcherModel.setBy(FilterBy.BY_LABEL);
6453 else if (firstMatcher.isByScore())
6455 matcherModel.setBy(FilterBy.BY_SCORE);
6457 result.setMatchCondition(matcherModel);
6464 * Loads one XML model of a feature filter to a Jalview object
6466 * @param featureType
6467 * @param matcherSetModel
6470 public static FeatureMatcherSetI parseFilter(String featureType,
6471 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6473 FeatureMatcherSetI result = new FeatureMatcherSet();
6476 parseFilterConditions(result, matcherSetModel, true);
6477 } catch (IllegalStateException e)
6479 // mixing AND and OR conditions perhaps
6481 String.format("Error reading filter conditions for '%s': %s",
6482 featureType, e.getMessage()));
6483 // return as much as was parsed up to the error
6490 * Adds feature match conditions to matcherSet as unmarshalled from XML
6491 * (possibly recursively for compound conditions)
6494 * @param matcherSetModel
6496 * if true, multiple conditions are AND-ed, else they are OR-ed
6497 * @throws IllegalStateException
6498 * if AND and OR conditions are mixed
6500 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6501 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6504 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6505 .getMatchCondition();
6511 FilterBy filterBy = mc.getBy();
6512 Condition cond = Condition.fromString(mc.getCondition());
6513 String pattern = mc.getValue();
6514 FeatureMatcherI matchCondition = null;
6515 if (filterBy == FilterBy.BY_LABEL)
6517 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6519 else if (filterBy == FilterBy.BY_SCORE)
6521 matchCondition = FeatureMatcher.byScore(cond, pattern);
6524 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6526 final List<String> attributeName = mc.getAttributeName();
6527 String[] attNames = attributeName
6528 .toArray(new String[attributeName.size()]);
6529 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6534 * note this throws IllegalStateException if AND-ing to a
6535 * previously OR-ed compound condition, or vice versa
6539 matcherSet.and(matchCondition);
6543 matcherSet.or(matchCondition);
6549 * compound condition
6551 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6552 .getCompoundMatcher().getMatcherSet();
6553 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6554 if (matchers.size() == 2)
6556 parseFilterConditions(matcherSet, matchers.get(0), anded);
6557 parseFilterConditions(matcherSet, matchers.get(1), anded);
6561 System.err.println("Malformed compound filter condition");
6567 * Loads one XML model of a feature colour to a Jalview object
6569 * @param colourModel
6572 public static FeatureColourI parseColour(Colour colourModel)
6574 FeatureColourI colour = null;
6576 if (colourModel.getMax() != null)
6578 Color mincol = null;
6579 Color maxcol = null;
6580 Color noValueColour = null;
6584 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6585 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6586 } catch (Exception e)
6588 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6591 NoValueColour noCol = colourModel.getNoValueColour();
6592 if (noCol == NoValueColour.MIN)
6594 noValueColour = mincol;
6596 else if (noCol == NoValueColour.MAX)
6598 noValueColour = maxcol;
6601 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6602 safeFloat(colourModel.getMin()),
6603 safeFloat(colourModel.getMax()));
6604 final List<String> attributeName = colourModel.getAttributeName();
6605 String[] attributes = attributeName
6606 .toArray(new String[attributeName.size()]);
6607 if (attributes != null && attributes.length > 0)
6609 colour.setAttributeName(attributes);
6611 if (colourModel.isAutoScale() != null)
6613 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6615 if (colourModel.isColourByLabel() != null)
6617 colour.setColourByLabel(
6618 colourModel.isColourByLabel().booleanValue());
6620 if (colourModel.getThreshold() != null)
6622 colour.setThreshold(colourModel.getThreshold().floatValue());
6624 ThresholdType ttyp = colourModel.getThreshType();
6625 if (ttyp == ThresholdType.ABOVE)
6627 colour.setAboveThreshold(true);
6629 else if (ttyp == ThresholdType.BELOW)
6631 colour.setBelowThreshold(true);
6636 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6637 colour = new FeatureColour(color);