2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Enumeration;
49 import java.util.GregorianCalendar;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Hashtable;
53 import java.util.IdentityHashMap;
54 import java.util.Iterator;
55 import java.util.LinkedHashMap;
56 import java.util.List;
57 import java.util.Locale;
59 import java.util.Map.Entry;
61 import java.util.Vector;
62 import java.util.jar.JarEntry;
63 import java.util.jar.JarInputStream;
64 import java.util.jar.JarOutputStream;
66 import javax.swing.JInternalFrame;
67 import javax.swing.SwingUtilities;
68 import javax.xml.bind.JAXBContext;
69 import javax.xml.bind.JAXBElement;
70 import javax.xml.bind.Marshaller;
71 import javax.xml.datatype.DatatypeConfigurationException;
72 import javax.xml.datatype.DatatypeFactory;
73 import javax.xml.datatype.XMLGregorianCalendar;
74 import javax.xml.stream.XMLInputFactory;
75 import javax.xml.stream.XMLStreamReader;
77 import jalview.analysis.Conservation;
78 import jalview.analysis.PCA;
79 import jalview.analysis.scoremodels.ScoreModels;
80 import jalview.analysis.scoremodels.SimilarityParams;
81 import jalview.api.FeatureColourI;
82 import jalview.api.ViewStyleI;
83 import jalview.api.analysis.ScoreModelI;
84 import jalview.api.analysis.SimilarityParamsI;
85 import jalview.api.structures.JalviewStructureDisplayI;
86 import jalview.bin.Cache;
87 import jalview.bin.Console;
88 import jalview.datamodel.AlignedCodonFrame;
89 import jalview.datamodel.Alignment;
90 import jalview.datamodel.AlignmentAnnotation;
91 import jalview.datamodel.AlignmentI;
92 import jalview.datamodel.DBRefEntry;
93 import jalview.datamodel.GeneLocus;
94 import jalview.datamodel.GraphLine;
95 import jalview.datamodel.PDBEntry;
96 import jalview.datamodel.Point;
97 import jalview.datamodel.RnaViewerModel;
98 import jalview.datamodel.SequenceFeature;
99 import jalview.datamodel.SequenceGroup;
100 import jalview.datamodel.SequenceI;
101 import jalview.datamodel.StructureViewerModel;
102 import jalview.datamodel.StructureViewerModel.StructureData;
103 import jalview.datamodel.features.FeatureMatcher;
104 import jalview.datamodel.features.FeatureMatcherI;
105 import jalview.datamodel.features.FeatureMatcherSet;
106 import jalview.datamodel.features.FeatureMatcherSetI;
107 import jalview.ext.varna.RnaModel;
108 import jalview.gui.AlignFrame;
109 import jalview.gui.AlignViewport;
110 import jalview.gui.AlignmentPanel;
111 import jalview.gui.AppVarna;
112 import jalview.gui.Desktop;
113 import jalview.gui.JvOptionPane;
114 import jalview.gui.OOMWarning;
115 import jalview.gui.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.JalviewUserColours;
189 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
190 import jalview.xml.binding.jalview.MapListType.MapListFrom;
191 import jalview.xml.binding.jalview.MapListType.MapListTo;
192 import jalview.xml.binding.jalview.Mapping;
193 import jalview.xml.binding.jalview.NoValueColour;
194 import jalview.xml.binding.jalview.ObjectFactory;
195 import jalview.xml.binding.jalview.PcaDataType;
196 import jalview.xml.binding.jalview.Pdbentry.Property;
197 import jalview.xml.binding.jalview.Sequence;
198 import jalview.xml.binding.jalview.Sequence.DBRef;
199 import jalview.xml.binding.jalview.SequenceSet;
200 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
201 import jalview.xml.binding.jalview.ThresholdType;
202 import jalview.xml.binding.jalview.VAMSAS;
205 * Write out the current jalview desktop state as a Jalview XML stream.
207 * Note: the vamsas objects referred to here are primitive versions of the
208 * VAMSAS project schema elements - they are not the same and most likely never
212 * @version $Revision: 1.134 $
214 public class Jalview2XML
217 // BH 2018 we add the .jvp binary extension to J2S so that
218 // it will declare that binary when we do the file save from the browser
222 Platform.addJ2SBinaryType(".jvp?");
225 private static final String VIEWER_PREFIX = "viewer_";
227 private static final String RNA_PREFIX = "rna_";
229 private static final String UTF_8 = "UTF-8";
232 * prefix for recovering datasets for alignments with multiple views where
233 * non-existent dataset IDs were written for some views
235 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
237 // use this with nextCounter() to make unique names for entities
238 private int counter = 0;
241 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
242 * of sequence objects are created.
244 IdentityHashMap<SequenceI, String> seqsToIds = null;
247 * jalview XML Sequence ID to jalview sequence object reference (both dataset
248 * and alignment sequences. Populated as XML reps of sequence objects are
251 Map<String, SequenceI> seqRefIds = null;
253 Map<String, SequenceI> incompleteSeqs = null;
255 List<SeqFref> frefedSequence = null;
257 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
260 * Map of reconstructed AlignFrame objects that appear to have come from
261 * SplitFrame objects (have a dna/protein complement view).
263 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
266 * Map from displayed rna structure models to their saved session state jar
269 private Map<RnaModel, String> rnaSessions = new HashMap<>();
272 * A helper method for safely using the value of an optional attribute that
273 * may be null if not present in the XML. Answers the boolean value, or false
279 public static boolean safeBoolean(Boolean b)
281 return b == null ? false : b.booleanValue();
285 * A helper method for safely using the value of an optional attribute that
286 * may be null if not present in the XML. Answers the integer value, or zero
292 public static int safeInt(Integer i)
294 return i == null ? 0 : i.intValue();
298 * A helper method for safely using the value of an optional attribute that
299 * may be null if not present in the XML. Answers the float value, or zero if
305 public static float safeFloat(Float f)
307 return f == null ? 0f : f.floatValue();
311 * create/return unique hash string for sq
314 * @return new or existing unique string for sq
316 String seqHash(SequenceI sq)
318 if (seqsToIds == null)
322 if (seqsToIds.containsKey(sq))
324 return seqsToIds.get(sq);
328 // create sequential key
329 String key = "sq" + (seqsToIds.size() + 1);
330 key = makeHashCode(sq, key); // check we don't have an external reference
332 seqsToIds.put(sq, key);
339 if (seqsToIds == null)
341 seqsToIds = new IdentityHashMap<>();
343 if (seqRefIds == null)
345 seqRefIds = new HashMap<>();
347 if (incompleteSeqs == null)
349 incompleteSeqs = new HashMap<>();
351 if (frefedSequence == null)
353 frefedSequence = new ArrayList<>();
361 public Jalview2XML(boolean raiseGUI)
363 this.raiseGUI = raiseGUI;
367 * base class for resolving forward references to sequences by their ID
372 abstract class SeqFref
378 public SeqFref(String _sref, String type)
384 public String getSref()
389 public SequenceI getSrefSeq()
391 return seqRefIds.get(sref);
394 public boolean isResolvable()
396 return seqRefIds.get(sref) != null;
399 public SequenceI getSrefDatasetSeq()
401 SequenceI sq = seqRefIds.get(sref);
404 while (sq.getDatasetSequence() != null)
406 sq = sq.getDatasetSequence();
413 * @return true if the forward reference was fully resolved
415 abstract boolean resolve();
418 public String toString()
420 return type + " reference to " + sref;
425 * create forward reference for a mapping
431 public SeqFref newMappingRef(final String sref,
432 final jalview.datamodel.Mapping _jmap)
434 SeqFref fref = new SeqFref(sref, "Mapping")
436 public jalview.datamodel.Mapping jmap = _jmap;
441 SequenceI seq = getSrefDatasetSeq();
453 public SeqFref newAlcodMapRef(final String sref,
454 final AlignedCodonFrame _cf,
455 final jalview.datamodel.Mapping _jmap)
458 SeqFref fref = new SeqFref(sref, "Codon Frame")
460 AlignedCodonFrame cf = _cf;
462 public jalview.datamodel.Mapping mp = _jmap;
465 public boolean isResolvable()
467 return super.isResolvable() && mp.getTo() != null;
473 SequenceI seq = getSrefDatasetSeq();
478 cf.addMap(seq, mp.getTo(), mp.getMap());
485 public void resolveFrefedSequences()
487 Iterator<SeqFref> nextFref = frefedSequence.iterator();
488 int toresolve = frefedSequence.size();
489 int unresolved = 0, failedtoresolve = 0;
490 while (nextFref.hasNext())
492 SeqFref ref = nextFref.next();
493 if (ref.isResolvable())
505 } catch (Exception x)
508 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
521 System.err.println("Jalview Project Import: There were " + unresolved
522 + " forward references left unresolved on the stack.");
524 if (failedtoresolve > 0)
526 System.err.println("SERIOUS! " + failedtoresolve
527 + " resolvable forward references failed to resolve.");
529 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
532 "Jalview Project Import: There are " + incompleteSeqs.size()
533 + " sequences which may have incomplete metadata.");
534 if (incompleteSeqs.size() < 10)
536 for (SequenceI s : incompleteSeqs.values())
538 System.err.println(s.toString());
544 "Too many to report. Skipping output of incomplete sequences.");
550 * This maintains a map of viewports, the key being the seqSetId. Important to
551 * set historyItem and redoList for multiple views
553 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
555 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
557 String uniqueSetSuffix = "";
560 * List of pdbfiles added to Jar
562 List<String> pdbfiles = null;
564 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
565 public void saveState(File statefile)
567 FileOutputStream fos = null;
572 fos = new FileOutputStream(statefile);
574 JarOutputStream jout = new JarOutputStream(fos);
578 } catch (Exception e)
580 Console.error("Couln't write Jalview state to " + statefile, e);
581 // TODO: inform user of the problem - they need to know if their data was
583 if (errorMessage == null)
585 errorMessage = "Did't write Jalview Archive to output file '"
586 + statefile + "' - See console error log for details";
590 errorMessage += "(Didn't write Jalview Archive to output file '"
601 } catch (IOException e)
611 * Writes a jalview project archive to the given Jar output stream.
615 public void saveState(JarOutputStream jout)
617 AlignFrame[] frames = Desktop.getAlignFrames();
619 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
625 Console.debug("***** debugging save sleep " + i + "/" + n);
629 } catch (InterruptedException e)
631 // TODO Auto-generated catch block
642 saveAllFrames(Arrays.asList(frames), jout);
646 * core method for storing state for a set of AlignFrames.
649 * - frames involving all data to be exported (including containing
652 * - project output stream
654 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
656 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
659 * ensure cached data is clear before starting
661 // todo tidy up seqRefIds, seqsToIds initialisation / reset
663 splitFrameCandidates.clear();
668 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
669 // //////////////////////////////////////////////////
671 List<String> shortNames = new ArrayList<>();
672 List<String> viewIds = new ArrayList<>();
675 for (int i = frames.size() - 1; i > -1; i--)
677 AlignFrame af = frames.get(i);
679 if (skipList != null && skipList
680 .containsKey(af.getViewport().getSequenceSetId()))
685 String shortName = makeFilename(af, shortNames);
687 int apSize = af.getAlignPanels().size();
689 for (int ap = 0; ap < apSize; ap++)
691 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
693 String fileName = apSize == 1 ? shortName : ap + shortName;
694 if (!fileName.endsWith(".xml"))
696 fileName = fileName + ".xml";
699 saveState(apanel, fileName, jout, viewIds);
701 String dssid = getDatasetIdRef(
702 af.getViewport().getAlignment().getDataset());
703 if (!dsses.containsKey(dssid))
705 dsses.put(dssid, af);
710 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
716 } catch (Exception foo)
720 } catch (Exception ex)
722 // TODO: inform user of the problem - they need to know if their data was
724 if (errorMessage == null)
726 errorMessage = "Couldn't write Jalview Archive - see error output for details";
728 ex.printStackTrace();
733 * Generates a distinct file name, based on the title of the AlignFrame, by
734 * appending _n for increasing n until an unused name is generated. The new
735 * name (without its extension) is added to the list.
739 * @return the generated name, with .xml extension
741 protected String makeFilename(AlignFrame af, List<String> namesUsed)
743 String shortName = af.getTitle();
745 if (shortName.indexOf(File.separatorChar) > -1)
747 shortName = shortName
748 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
753 while (namesUsed.contains(shortName))
755 if (shortName.endsWith("_" + (count - 1)))
757 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
760 shortName = shortName.concat("_" + count);
764 namesUsed.add(shortName);
766 if (!shortName.endsWith(".xml"))
768 shortName = shortName + ".xml";
773 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
774 public boolean saveAlignment(AlignFrame af, String jarFile,
779 // create backupfiles object and get new temp filename destination
780 boolean doBackup = BackupFiles.getEnabled();
781 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
782 FileOutputStream fos = new FileOutputStream(
783 doBackup ? backupfiles.getTempFilePath() : jarFile);
785 JarOutputStream jout = new JarOutputStream(fos);
786 List<AlignFrame> frames = new ArrayList<>();
788 // resolve splitframes
789 if (af.getViewport().getCodingComplement() != null)
791 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
797 saveAllFrames(frames, jout);
801 } catch (Exception foo)
805 boolean success = true;
809 backupfiles.setWriteSuccess(success);
810 success = backupfiles.rollBackupsAndRenameTempFile();
814 } catch (Exception ex)
816 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
817 ex.printStackTrace();
822 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
823 String fileName, JarOutputStream jout)
826 for (String dssids : dsses.keySet())
828 AlignFrame _af = dsses.get(dssids);
829 String jfileName = fileName + " Dataset for " + _af.getTitle();
830 if (!jfileName.endsWith(".xml"))
832 jfileName = jfileName + ".xml";
834 saveState(_af.alignPanel, jfileName, true, jout, null);
839 * create a JalviewModel from an alignment view and marshall it to a
843 * panel to create jalview model for
845 * name of alignment panel written to output stream
852 public JalviewModel saveState(AlignmentPanel ap, String fileName,
853 JarOutputStream jout, List<String> viewIds)
855 return saveState(ap, fileName, false, jout, viewIds);
859 * create a JalviewModel from an alignment view and marshall it to a
863 * panel to create jalview model for
865 * name of alignment panel written to output stream
867 * when true, only write the dataset for the alignment, not the data
868 * associated with the view.
874 public JalviewModel saveState(AlignmentPanel ap, String fileName,
875 boolean storeDS, JarOutputStream jout, List<String> viewIds)
879 viewIds = new ArrayList<>();
884 List<UserColourScheme> userColours = new ArrayList<>();
886 AlignViewport av = ap.av;
887 ViewportRanges vpRanges = av.getRanges();
889 final ObjectFactory objectFactory = new ObjectFactory();
890 JalviewModel object = objectFactory.createJalviewModel();
891 object.setVamsasModel(new VAMSAS());
893 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
896 GregorianCalendar c = new GregorianCalendar();
897 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
898 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
899 object.setCreationDate(now);
900 } catch (DatatypeConfigurationException e)
902 System.err.println("error writing date: " + e.toString());
904 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
907 * rjal is full height alignment, jal is actual alignment with full metadata
908 * but excludes hidden sequences.
910 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
912 if (av.hasHiddenRows())
914 rjal = jal.getHiddenSequences().getFullAlignment();
917 SequenceSet vamsasSet = new SequenceSet();
919 // JalviewModelSequence jms = new JalviewModelSequence();
921 vamsasSet.setGapChar(jal.getGapCharacter() + "");
923 if (jal.getDataset() != null)
925 // dataset id is the dataset's hashcode
926 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
929 // switch jal and the dataset
930 jal = jal.getDataset();
934 if (jal.getProperties() != null)
936 Enumeration en = jal.getProperties().keys();
937 while (en.hasMoreElements())
939 String key = en.nextElement().toString();
940 SequenceSetProperties ssp = new SequenceSetProperties();
942 ssp.setValue(jal.getProperties().get(key).toString());
943 // vamsasSet.addSequenceSetProperties(ssp);
944 vamsasSet.getSequenceSetProperties().add(ssp);
949 Set<String> calcIdSet = new HashSet<>();
950 // record the set of vamsas sequence XML POJO we create.
951 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
953 for (final SequenceI jds : rjal.getSequences())
955 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
956 : jds.getDatasetSequence();
957 String id = seqHash(jds);
958 if (vamsasSetIds.get(id) == null)
960 if (seqRefIds.get(id) != null && !storeDS)
962 // This happens for two reasons: 1. multiple views are being
964 // 2. the hashCode has collided with another sequence's code. This
966 // HAPPEN! (PF00072.15.stk does this)
967 // JBPNote: Uncomment to debug writing out of files that do not read
968 // back in due to ArrayOutOfBoundExceptions.
969 // System.err.println("vamsasSeq backref: "+id+"");
970 // System.err.println(jds.getName()+"
971 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
972 // System.err.println("Hashcode: "+seqHash(jds));
973 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
974 // System.err.println(rsq.getName()+"
975 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
976 // System.err.println("Hashcode: "+seqHash(rsq));
980 vamsasSeq = createVamsasSequence(id, jds);
981 // vamsasSet.addSequence(vamsasSeq);
982 vamsasSet.getSequence().add(vamsasSeq);
983 vamsasSetIds.put(id, vamsasSeq);
984 seqRefIds.put(id, jds);
988 jseq.setStart(jds.getStart());
989 jseq.setEnd(jds.getEnd());
990 jseq.setColour(av.getSequenceColour(jds).getRGB());
992 jseq.setId(id); // jseq id should be a string not a number
995 // Store any sequences this sequence represents
996 if (av.hasHiddenRows())
998 // use rjal, contains the full height alignment
1000 av.getAlignment().getHiddenSequences().isHidden(jds));
1002 if (av.isHiddenRepSequence(jds))
1004 jalview.datamodel.SequenceI[] reps = av
1005 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1007 for (int h = 0; h < reps.length; h++)
1011 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1012 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1017 // mark sequence as reference - if it is the reference for this view
1018 if (jal.hasSeqrep())
1020 jseq.setViewreference(jds == jal.getSeqrep());
1024 // TODO: omit sequence features from each alignment view's XML dump if we
1025 // are storing dataset
1026 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1027 for (SequenceFeature sf : sfs)
1029 // Features features = new Features();
1030 Feature features = new Feature();
1032 features.setBegin(sf.getBegin());
1033 features.setEnd(sf.getEnd());
1034 features.setDescription(sf.getDescription());
1035 features.setType(sf.getType());
1036 features.setFeatureGroup(sf.getFeatureGroup());
1037 features.setScore(sf.getScore());
1038 if (sf.links != null)
1040 for (int l = 0; l < sf.links.size(); l++)
1042 OtherData keyValue = new OtherData();
1043 keyValue.setKey("LINK_" + l);
1044 keyValue.setValue(sf.links.elementAt(l).toString());
1045 // features.addOtherData(keyValue);
1046 features.getOtherData().add(keyValue);
1049 if (sf.otherDetails != null)
1052 * save feature attributes, which may be simple strings or
1053 * map valued (have sub-attributes)
1055 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1057 String key = entry.getKey();
1058 Object value = entry.getValue();
1059 if (value instanceof Map<?, ?>)
1061 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1064 OtherData otherData = new OtherData();
1065 otherData.setKey(key);
1066 otherData.setKey2(subAttribute.getKey());
1067 otherData.setValue(subAttribute.getValue().toString());
1068 // features.addOtherData(otherData);
1069 features.getOtherData().add(otherData);
1074 OtherData otherData = new OtherData();
1075 otherData.setKey(key);
1076 otherData.setValue(value.toString());
1077 // features.addOtherData(otherData);
1078 features.getOtherData().add(otherData);
1083 // jseq.addFeatures(features);
1084 jseq.getFeatures().add(features);
1087 if (jdatasq.getAllPDBEntries() != null)
1089 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1090 while (en.hasMoreElements())
1092 Pdbids pdb = new Pdbids();
1093 jalview.datamodel.PDBEntry entry = en.nextElement();
1095 String pdbId = entry.getId();
1097 pdb.setType(entry.getType());
1100 * Store any structure views associated with this sequence. This
1101 * section copes with duplicate entries in the project, so a dataset
1102 * only view *should* be coped with sensibly.
1104 // This must have been loaded, is it still visible?
1105 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1106 String matchedFile = null;
1107 for (int f = frames.length - 1; f > -1; f--)
1109 if (frames[f] instanceof StructureViewerBase)
1111 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1112 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1113 viewIds, matchedFile, viewFrame);
1115 * Only store each structure viewer's state once in the project
1116 * jar. First time through only (storeDS==false)
1118 String viewId = viewFrame.getViewId();
1119 String viewerType = viewFrame.getViewerType().toString();
1120 if (!storeDS && !viewIds.contains(viewId))
1122 viewIds.add(viewId);
1123 File viewerState = viewFrame.saveSession();
1124 if (viewerState != null)
1126 copyFileToJar(jout, viewerState.getPath(),
1127 getViewerJarEntryName(viewId), viewerType);
1132 "Failed to save viewer state for " + viewerType);
1138 if (matchedFile != null || entry.getFile() != null)
1140 if (entry.getFile() != null)
1143 matchedFile = entry.getFile();
1145 pdb.setFile(matchedFile); // entry.getFile());
1146 if (pdbfiles == null)
1148 pdbfiles = new ArrayList<>();
1151 if (!pdbfiles.contains(pdbId))
1153 pdbfiles.add(pdbId);
1154 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1158 Enumeration<String> props = entry.getProperties();
1159 if (props.hasMoreElements())
1161 // PdbentryItem item = new PdbentryItem();
1162 while (props.hasMoreElements())
1164 Property prop = new Property();
1165 String key = props.nextElement();
1167 prop.setValue(entry.getProperty(key).toString());
1168 // item.addProperty(prop);
1169 pdb.getProperty().add(prop);
1171 // pdb.addPdbentryItem(item);
1174 // jseq.addPdbids(pdb);
1175 jseq.getPdbids().add(pdb);
1179 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1181 // jms.addJSeq(jseq);
1182 object.getJSeq().add(jseq);
1185 if (!storeDS && av.hasHiddenRows())
1187 jal = av.getAlignment();
1191 if (storeDS && jal.getCodonFrames() != null)
1193 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1194 for (AlignedCodonFrame acf : jac)
1196 AlcodonFrame alc = new AlcodonFrame();
1197 if (acf.getProtMappings() != null
1198 && acf.getProtMappings().length > 0)
1200 boolean hasMap = false;
1201 SequenceI[] dnas = acf.getdnaSeqs();
1202 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1203 for (int m = 0; m < pmaps.length; m++)
1205 AlcodMap alcmap = new AlcodMap();
1206 alcmap.setDnasq(seqHash(dnas[m]));
1208 createVamsasMapping(pmaps[m], dnas[m], null, false));
1209 // alc.addAlcodMap(alcmap);
1210 alc.getAlcodMap().add(alcmap);
1215 // vamsasSet.addAlcodonFrame(alc);
1216 vamsasSet.getAlcodonFrame().add(alc);
1219 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1221 // AlcodonFrame alc = new AlcodonFrame();
1222 // vamsasSet.addAlcodonFrame(alc);
1223 // for (int p = 0; p < acf.aaWidth; p++)
1225 // Alcodon cmap = new Alcodon();
1226 // if (acf.codons[p] != null)
1228 // // Null codons indicate a gapped column in the translated peptide
1230 // cmap.setPos1(acf.codons[p][0]);
1231 // cmap.setPos2(acf.codons[p][1]);
1232 // cmap.setPos3(acf.codons[p][2]);
1234 // alc.addAlcodon(cmap);
1236 // if (acf.getProtMappings() != null
1237 // && acf.getProtMappings().length > 0)
1239 // SequenceI[] dnas = acf.getdnaSeqs();
1240 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1241 // for (int m = 0; m < pmaps.length; m++)
1243 // AlcodMap alcmap = new AlcodMap();
1244 // alcmap.setDnasq(seqHash(dnas[m]));
1245 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1247 // alc.addAlcodMap(alcmap);
1254 // /////////////////////////////////
1255 if (!storeDS && av.getCurrentTree() != null)
1257 // FIND ANY ASSOCIATED TREES
1258 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1259 if (Desktop.desktop != null)
1261 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1263 for (int t = 0; t < frames.length; t++)
1265 if (frames[t] instanceof TreePanel)
1267 TreePanel tp = (TreePanel) frames[t];
1269 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1271 JalviewModel.Tree tree = new JalviewModel.Tree();
1272 tree.setTitle(tp.getTitle());
1273 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1274 tree.setNewick(tp.getTree().print());
1275 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1277 tree.setFitToWindow(tp.fitToWindow.getState());
1278 tree.setFontName(tp.getTreeFont().getName());
1279 tree.setFontSize(tp.getTreeFont().getSize());
1280 tree.setFontStyle(tp.getTreeFont().getStyle());
1281 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1283 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1284 tree.setShowDistances(tp.distanceMenu.getState());
1286 tree.setHeight(tp.getHeight());
1287 tree.setWidth(tp.getWidth());
1288 tree.setXpos(tp.getX());
1289 tree.setYpos(tp.getY());
1290 tree.setId(makeHashCode(tp, null));
1291 tree.setLinkToAllViews(
1292 tp.getTreeCanvas().isApplyToAllViews());
1294 // jms.addTree(tree);
1295 object.getTree().add(tree);
1305 if (!storeDS && Desktop.desktop != null)
1307 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1309 if (frame instanceof PCAPanel)
1311 PCAPanel panel = (PCAPanel) frame;
1312 if (panel.getAlignViewport().getAlignment() == jal)
1314 savePCA(panel, object);
1322 * store forward refs from an annotationRow to any groups
1324 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1327 for (SequenceI sq : jal.getSequences())
1329 // Store annotation on dataset sequences only
1330 AlignmentAnnotation[] aa = sq.getAnnotation();
1331 if (aa != null && aa.length > 0)
1333 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1340 if (jal.getAlignmentAnnotation() != null)
1342 // Store the annotation shown on the alignment.
1343 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1344 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1349 if (jal.getGroups() != null)
1351 JGroup[] groups = new JGroup[jal.getGroups().size()];
1353 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1355 JGroup jGroup = new JGroup();
1356 groups[++i] = jGroup;
1358 jGroup.setStart(sg.getStartRes());
1359 jGroup.setEnd(sg.getEndRes());
1360 jGroup.setName(sg.getName());
1361 if (groupRefs.containsKey(sg))
1363 // group has references so set its ID field
1364 jGroup.setId(groupRefs.get(sg));
1366 ColourSchemeI colourScheme = sg.getColourScheme();
1367 if (colourScheme != null)
1369 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1370 if (groupColourScheme.conservationApplied())
1372 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1374 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1376 jGroup.setColour(setUserColourScheme(colourScheme,
1377 userColours, object));
1381 jGroup.setColour(colourScheme.getSchemeName());
1384 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1386 jGroup.setColour("AnnotationColourGradient");
1387 jGroup.setAnnotationColours(constructAnnotationColours(
1388 (jalview.schemes.AnnotationColourGradient) colourScheme,
1389 userColours, object));
1391 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1394 setUserColourScheme(colourScheme, userColours, object));
1398 jGroup.setColour(colourScheme.getSchemeName());
1401 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1404 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1405 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1406 jGroup.setDisplayText(sg.getDisplayText());
1407 jGroup.setColourText(sg.getColourText());
1408 jGroup.setTextCol1(sg.textColour.getRGB());
1409 jGroup.setTextCol2(sg.textColour2.getRGB());
1410 jGroup.setTextColThreshold(sg.thresholdTextColour);
1411 jGroup.setShowUnconserved(sg.getShowNonconserved());
1412 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1413 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1414 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1415 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1416 for (SequenceI seq : sg.getSequences())
1418 // jGroup.addSeq(seqHash(seq));
1419 jGroup.getSeq().add(seqHash(seq));
1423 // jms.setJGroup(groups);
1425 for (JGroup grp : groups)
1427 object.getJGroup().add(grp);
1432 // /////////SAVE VIEWPORT
1433 Viewport view = new Viewport();
1434 view.setTitle(ap.alignFrame.getTitle());
1435 view.setSequenceSetId(
1436 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1437 view.setId(av.getViewId());
1438 if (av.getCodingComplement() != null)
1440 view.setComplementId(av.getCodingComplement().getViewId());
1442 view.setViewName(av.getViewName());
1443 view.setGatheredViews(av.isGatherViewsHere());
1445 Rectangle size = ap.av.getExplodedGeometry();
1446 Rectangle position = size;
1449 size = ap.alignFrame.getBounds();
1450 if (av.getCodingComplement() != null)
1452 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1460 view.setXpos(position.x);
1461 view.setYpos(position.y);
1463 view.setWidth(size.width);
1464 view.setHeight(size.height);
1466 view.setStartRes(vpRanges.getStartRes());
1467 view.setStartSeq(vpRanges.getStartSeq());
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();
1655 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1659 Iterator<int[]> hiddenRegions = hidden.iterator();
1660 while (hiddenRegions.hasNext())
1662 int[] region = hiddenRegions.next();
1663 HiddenColumns hc = new HiddenColumns();
1664 hc.setStart(region[0]);
1665 hc.setEnd(region[1]);
1666 // view.addHiddenColumns(hc);
1667 view.getHiddenColumns().add(hc);
1671 if (calcIdSet.size() > 0)
1673 for (String calcId : calcIdSet)
1675 if (calcId.trim().length() > 0)
1677 CalcIdParam cidp = createCalcIdParam(calcId, av);
1678 // Some calcIds have no parameters.
1681 // view.addCalcIdParam(cidp);
1682 view.getCalcIdParam().add(cidp);
1688 // jms.addViewport(view);
1689 object.getViewport().add(view);
1691 // object.setJalviewModelSequence(jms);
1692 // object.getVamsasModel().addSequenceSet(vamsasSet);
1693 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1695 if (jout != null && fileName != null)
1697 // We may not want to write the object to disk,
1698 // eg we can copy the alignViewport to a new view object
1699 // using save and then load
1702 fileName = fileName.replace('\\', '/');
1703 System.out.println("Writing jar entry " + fileName);
1704 JarEntry entry = new JarEntry(fileName);
1705 jout.putNextEntry(entry);
1706 PrintWriter pout = new PrintWriter(
1707 new OutputStreamWriter(jout, UTF_8));
1708 JAXBContext jaxbContext = JAXBContext
1709 .newInstance(JalviewModel.class);
1710 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1712 // output pretty printed
1713 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1714 jaxbMarshaller.marshal(
1715 new ObjectFactory().createJalviewModel(object), pout);
1717 // jaxbMarshaller.marshal(object, pout);
1718 // marshaller.marshal(object);
1721 } catch (Exception ex)
1723 // TODO: raise error in GUI if marshalling failed.
1724 System.err.println("Error writing Jalview project");
1725 ex.printStackTrace();
1732 * Writes PCA viewer attributes and computed values to an XML model object and
1733 * adds it to the JalviewModel. Any exceptions are reported by logging.
1735 protected void savePCA(PCAPanel panel, JalviewModel object)
1739 PcaViewer viewer = new PcaViewer();
1740 viewer.setHeight(panel.getHeight());
1741 viewer.setWidth(panel.getWidth());
1742 viewer.setXpos(panel.getX());
1743 viewer.setYpos(panel.getY());
1744 viewer.setTitle(panel.getTitle());
1745 PCAModel pcaModel = panel.getPcaModel();
1746 viewer.setScoreModelName(pcaModel.getScoreModelName());
1747 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1748 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1749 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1751 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1752 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1753 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1754 SeqPointMin spmin = new SeqPointMin();
1755 spmin.setXPos(spMin[0]);
1756 spmin.setYPos(spMin[1]);
1757 spmin.setZPos(spMin[2]);
1758 viewer.setSeqPointMin(spmin);
1759 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1760 SeqPointMax spmax = new SeqPointMax();
1761 spmax.setXPos(spMax[0]);
1762 spmax.setYPos(spMax[1]);
1763 spmax.setZPos(spMax[2]);
1764 viewer.setSeqPointMax(spmax);
1765 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1766 viewer.setLinkToAllViews(
1767 panel.getRotatableCanvas().isApplyToAllViews());
1768 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1769 viewer.setIncludeGaps(sp.includeGaps());
1770 viewer.setMatchGaps(sp.matchGaps());
1771 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1772 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1775 * sequence points on display
1777 for (jalview.datamodel.SequencePoint spt : pcaModel
1778 .getSequencePoints())
1780 SequencePoint point = new SequencePoint();
1781 point.setSequenceRef(seqHash(spt.getSequence()));
1782 point.setXPos(spt.coord.x);
1783 point.setYPos(spt.coord.y);
1784 point.setZPos(spt.coord.z);
1785 viewer.getSequencePoint().add(point);
1789 * (end points of) axes on display
1791 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1794 Axis axis = new Axis();
1798 viewer.getAxis().add(axis);
1802 * raw PCA data (note we are not restoring PCA inputs here -
1803 * alignment view, score model, similarity parameters)
1805 PcaDataType data = new PcaDataType();
1806 viewer.setPcaData(data);
1807 PCA pca = pcaModel.getPcaData();
1809 DoubleMatrix pm = new DoubleMatrix();
1810 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1811 data.setPairwiseMatrix(pm);
1813 DoubleMatrix tm = new DoubleMatrix();
1814 saveDoubleMatrix(pca.getTridiagonal(), tm);
1815 data.setTridiagonalMatrix(tm);
1817 DoubleMatrix eigenMatrix = new DoubleMatrix();
1818 data.setEigenMatrix(eigenMatrix);
1819 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1821 object.getPcaViewer().add(viewer);
1822 } catch (Throwable t)
1824 Console.error("Error saving PCA: " + t.getMessage());
1829 * Stores values from a matrix into an XML element, including (if present) the
1834 * @see #loadDoubleMatrix(DoubleMatrix)
1836 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1838 xmlMatrix.setRows(m.height());
1839 xmlMatrix.setColumns(m.width());
1840 for (int i = 0; i < m.height(); i++)
1842 DoubleVector row = new DoubleVector();
1843 for (int j = 0; j < m.width(); j++)
1845 row.getV().add(m.getValue(i, j));
1847 xmlMatrix.getRow().add(row);
1849 if (m.getD() != null)
1851 DoubleVector dVector = new DoubleVector();
1852 for (double d : m.getD())
1854 dVector.getV().add(d);
1856 xmlMatrix.setD(dVector);
1858 if (m.getE() != null)
1860 DoubleVector eVector = new DoubleVector();
1861 for (double e : m.getE())
1863 eVector.getV().add(e);
1865 xmlMatrix.setE(eVector);
1870 * Loads XML matrix data into a new Matrix object, including the D and/or E
1871 * vectors (if present)
1875 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1877 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1879 int rows = mData.getRows();
1880 double[][] vals = new double[rows][];
1882 for (int i = 0; i < rows; i++)
1884 List<Double> dVector = mData.getRow().get(i).getV();
1885 vals[i] = new double[dVector.size()];
1887 for (Double d : dVector)
1893 MatrixI m = new Matrix(vals);
1895 if (mData.getD() != null)
1897 List<Double> dVector = mData.getD().getV();
1898 double[] vec = new double[dVector.size()];
1900 for (Double d : dVector)
1906 if (mData.getE() != null)
1908 List<Double> dVector = mData.getE().getV();
1909 double[] vec = new double[dVector.size()];
1911 for (Double d : dVector)
1922 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1923 * for each viewer, with
1925 * <li>viewer geometry (position, size, split pane divider location)</li>
1926 * <li>index of the selected structure in the viewer (currently shows gapped
1928 * <li>the id of the annotation holding RNA secondary structure</li>
1929 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1931 * Varna viewer state is also written out (in native Varna XML) to separate
1932 * project jar entries. A separate entry is written for each RNA structure
1933 * displayed, with the naming convention
1935 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1943 * @param storeDataset
1945 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1946 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1947 boolean storeDataset)
1949 if (Desktop.desktop == null)
1953 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1954 for (int f = frames.length - 1; f > -1; f--)
1956 if (frames[f] instanceof AppVarna)
1958 AppVarna varna = (AppVarna) frames[f];
1960 * link the sequence to every viewer that is showing it and is linked to
1961 * its alignment panel
1963 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1965 String viewId = varna.getViewId();
1966 RnaViewer rna = new RnaViewer();
1967 rna.setViewId(viewId);
1968 rna.setTitle(varna.getTitle());
1969 rna.setXpos(varna.getX());
1970 rna.setYpos(varna.getY());
1971 rna.setWidth(varna.getWidth());
1972 rna.setHeight(varna.getHeight());
1973 rna.setDividerLocation(varna.getDividerLocation());
1974 rna.setSelectedRna(varna.getSelectedIndex());
1975 // jseq.addRnaViewer(rna);
1976 jseq.getRnaViewer().add(rna);
1979 * Store each Varna panel's state once in the project per sequence.
1980 * First time through only (storeDataset==false)
1982 // boolean storeSessions = false;
1983 // String sequenceViewId = viewId + seqsToIds.get(jds);
1984 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1986 // viewIds.add(sequenceViewId);
1987 // storeSessions = true;
1989 for (RnaModel model : varna.getModels())
1991 if (model.seq == jds)
1994 * VARNA saves each view (sequence or alignment secondary
1995 * structure, gapped or trimmed) as a separate XML file
1997 String jarEntryName = rnaSessions.get(model);
1998 if (jarEntryName == null)
2001 String varnaStateFile = varna.getStateInfo(model.rna);
2002 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2003 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2004 rnaSessions.put(model, jarEntryName);
2006 SecondaryStructure ss = new SecondaryStructure();
2007 String annotationId = varna.getAnnotation(jds).annotationId;
2008 ss.setAnnotationId(annotationId);
2009 ss.setViewerState(jarEntryName);
2010 ss.setGapped(model.gapped);
2011 ss.setTitle(model.title);
2012 // rna.addSecondaryStructure(ss);
2013 rna.getSecondaryStructure().add(ss);
2022 * Copy the contents of a file to a new entry added to the output jar
2026 * @param jarEntryName
2028 * additional identifying info to log to the console
2030 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2031 String jarEntryName, String msg)
2033 try (InputStream is = new FileInputStream(infilePath))
2035 File file = new File(infilePath);
2036 if (file.exists() && jout != null)
2039 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2040 jout.putNextEntry(new JarEntry(jarEntryName));
2043 // dis = new DataInputStream(new FileInputStream(file));
2044 // byte[] data = new byte[(int) file.length()];
2045 // dis.readFully(data);
2046 // writeJarEntry(jout, jarEntryName, data);
2048 } catch (Exception ex)
2050 ex.printStackTrace();
2055 * Copies input to output, in 4K buffers; handles any data (text or binary)
2059 * @throws IOException
2061 protected void copyAll(InputStream in, OutputStream out)
2064 byte[] buffer = new byte[4096];
2066 while ((bytesRead = in.read(buffer)) != -1)
2068 out.write(buffer, 0, bytesRead);
2073 * Save the state of a structure viewer
2078 * the archive XML element under which to save the state
2081 * @param matchedFile
2085 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2086 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2087 String matchedFile, StructureViewerBase viewFrame)
2089 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2092 * Look for any bindings for this viewer to the PDB file of interest
2093 * (including part matches excluding chain id)
2095 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2097 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2098 final String pdbId = pdbentry.getId();
2099 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2100 && entry.getId().toLowerCase(Locale.ROOT)
2101 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2104 * not interested in a binding to a different PDB entry here
2108 if (matchedFile == null)
2110 matchedFile = pdbentry.getFile();
2112 else if (!matchedFile.equals(pdbentry.getFile()))
2115 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2116 + pdbentry.getFile());
2120 // can get at it if the ID
2121 // match is ambiguous (e.g.
2124 for (int smap = 0; smap < viewFrame.getBinding()
2125 .getSequence()[peid].length; smap++)
2127 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2128 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2130 StructureState state = new StructureState();
2131 state.setVisible(true);
2132 state.setXpos(viewFrame.getX());
2133 state.setYpos(viewFrame.getY());
2134 state.setWidth(viewFrame.getWidth());
2135 state.setHeight(viewFrame.getHeight());
2136 final String viewId = viewFrame.getViewId();
2137 state.setViewId(viewId);
2138 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2139 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2140 state.setColourByJmol(viewFrame.isColouredByViewer());
2141 state.setType(viewFrame.getViewerType().toString());
2142 // pdb.addStructureState(state);
2143 pdb.getStructureState().add(state);
2151 * Populates the AnnotationColourScheme xml for save. This captures the
2152 * settings of the options in the 'Colour by Annotation' dialog.
2155 * @param userColours
2159 private AnnotationColourScheme constructAnnotationColours(
2160 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2163 AnnotationColourScheme ac = new AnnotationColourScheme();
2164 ac.setAboveThreshold(acg.getAboveThreshold());
2165 ac.setThreshold(acg.getAnnotationThreshold());
2166 // 2.10.2 save annotationId (unique) not annotation label
2167 ac.setAnnotation(acg.getAnnotation().annotationId);
2168 if (acg.getBaseColour() instanceof UserColourScheme)
2171 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2176 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2179 ac.setMaxColour(acg.getMaxColour().getRGB());
2180 ac.setMinColour(acg.getMinColour().getRGB());
2181 ac.setPerSequence(acg.isSeqAssociated());
2182 ac.setPredefinedColours(acg.isPredefinedColours());
2186 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2187 IdentityHashMap<SequenceGroup, String> groupRefs,
2188 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2189 SequenceSet vamsasSet)
2192 for (int i = 0; i < aa.length; i++)
2194 Annotation an = new Annotation();
2196 AlignmentAnnotation annotation = aa[i];
2197 if (annotation.annotationId != null)
2199 annotationIds.put(annotation.annotationId, annotation);
2202 an.setId(annotation.annotationId);
2204 an.setVisible(annotation.visible);
2206 an.setDescription(annotation.description);
2208 if (annotation.sequenceRef != null)
2210 // 2.9 JAL-1781 xref on sequence id rather than name
2211 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2213 if (annotation.groupRef != null)
2215 String groupIdr = groupRefs.get(annotation.groupRef);
2216 if (groupIdr == null)
2218 // make a locally unique String
2219 groupRefs.put(annotation.groupRef,
2220 groupIdr = ("" + System.currentTimeMillis()
2221 + annotation.groupRef.getName()
2222 + groupRefs.size()));
2224 an.setGroupRef(groupIdr.toString());
2227 // store all visualization attributes for annotation
2228 an.setGraphHeight(annotation.graphHeight);
2229 an.setCentreColLabels(annotation.centreColLabels);
2230 an.setScaleColLabels(annotation.scaleColLabel);
2231 an.setShowAllColLabels(annotation.showAllColLabels);
2232 an.setBelowAlignment(annotation.belowAlignment);
2234 if (annotation.graph > 0)
2237 an.setGraphType(annotation.graph);
2238 an.setGraphGroup(annotation.graphGroup);
2239 if (annotation.getThreshold() != null)
2241 ThresholdLine line = new ThresholdLine();
2242 line.setLabel(annotation.getThreshold().label);
2243 line.setValue(annotation.getThreshold().value);
2244 line.setColour(annotation.getThreshold().colour.getRGB());
2245 an.setThresholdLine(line);
2253 an.setLabel(annotation.label);
2255 if (annotation == av.getAlignmentQualityAnnot()
2256 || annotation == av.getAlignmentConservationAnnotation()
2257 || annotation == av.getAlignmentConsensusAnnotation()
2258 || annotation.autoCalculated)
2260 // new way of indicating autocalculated annotation -
2261 an.setAutoCalculated(annotation.autoCalculated);
2263 if (annotation.hasScore())
2265 an.setScore(annotation.getScore());
2268 if (annotation.getCalcId() != null)
2270 calcIdSet.add(annotation.getCalcId());
2271 an.setCalcId(annotation.getCalcId());
2273 if (annotation.hasProperties())
2275 for (String pr : annotation.getProperties())
2277 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2279 prop.setValue(annotation.getProperty(pr));
2280 // an.addProperty(prop);
2281 an.getProperty().add(prop);
2285 AnnotationElement ae;
2286 if (annotation.annotations != null)
2288 an.setScoreOnly(false);
2289 for (int a = 0; a < annotation.annotations.length; a++)
2291 if ((annotation == null) || (annotation.annotations[a] == null))
2296 ae = new AnnotationElement();
2297 if (annotation.annotations[a].description != null)
2299 ae.setDescription(annotation.annotations[a].description);
2301 if (annotation.annotations[a].displayCharacter != null)
2303 ae.setDisplayCharacter(
2304 annotation.annotations[a].displayCharacter);
2307 if (!Float.isNaN(annotation.annotations[a].value))
2309 ae.setValue(annotation.annotations[a].value);
2313 if (annotation.annotations[a].secondaryStructure > ' ')
2315 ae.setSecondaryStructure(
2316 annotation.annotations[a].secondaryStructure + "");
2319 if (annotation.annotations[a].colour != null
2320 && annotation.annotations[a].colour != java.awt.Color.black)
2322 ae.setColour(annotation.annotations[a].colour.getRGB());
2325 // an.addAnnotationElement(ae);
2326 an.getAnnotationElement().add(ae);
2327 if (annotation.autoCalculated)
2329 // only write one non-null entry into the annotation row -
2330 // sufficient to get the visualization attributes necessary to
2338 an.setScoreOnly(true);
2340 if (!storeDS || (storeDS && !annotation.autoCalculated))
2342 // skip autocalculated annotation - these are only provided for
2344 // vamsasSet.addAnnotation(an);
2345 vamsasSet.getAnnotation().add(an);
2351 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2353 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2354 if (settings != null)
2356 CalcIdParam vCalcIdParam = new CalcIdParam();
2357 vCalcIdParam.setCalcId(calcId);
2358 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2359 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2360 // generic URI allowing a third party to resolve another instance of the
2361 // service used for this calculation
2362 for (String url : settings.getServiceURLs())
2364 // vCalcIdParam.addServiceURL(urls);
2365 vCalcIdParam.getServiceURL().add(url);
2367 vCalcIdParam.setVersion("1.0");
2368 if (settings.getPreset() != null)
2370 WsParamSetI setting = settings.getPreset();
2371 vCalcIdParam.setName(setting.getName());
2372 vCalcIdParam.setDescription(setting.getDescription());
2376 vCalcIdParam.setName("");
2377 vCalcIdParam.setDescription("Last used parameters");
2379 // need to be able to recover 1) settings 2) user-defined presets or
2380 // recreate settings from preset 3) predefined settings provided by
2381 // service - or settings that can be transferred (or discarded)
2382 vCalcIdParam.setParameters(
2383 settings.getWsParamFile().replace("\n", "|\\n|"));
2384 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2385 // todo - decide if updateImmediately is needed for any projects.
2387 return vCalcIdParam;
2392 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2395 if (calcIdParam.getVersion().equals("1.0"))
2397 final String[] calcIds = calcIdParam.getServiceURL()
2398 .toArray(new String[0]);
2399 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2400 .getPreferredServiceFor(calcIds);
2401 if (service != null)
2403 WsParamSetI parmSet = null;
2406 parmSet = service.getParamStore().parseServiceParameterFile(
2407 calcIdParam.getName(), calcIdParam.getDescription(),
2409 calcIdParam.getParameters().replace("|\\n|", "\n"));
2410 } catch (IOException x)
2412 Console.warn("Couldn't parse parameter data for "
2413 + calcIdParam.getCalcId(), x);
2416 List<ArgumentI> argList = null;
2417 if (calcIdParam.getName().length() > 0)
2419 parmSet = service.getParamStore()
2420 .getPreset(calcIdParam.getName());
2421 if (parmSet != null)
2423 // TODO : check we have a good match with settings in AACon -
2424 // otherwise we'll need to create a new preset
2429 argList = parmSet.getArguments();
2432 AAConSettings settings = new AAConSettings(
2433 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2434 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2435 calcIdParam.isNeedsUpdate());
2441 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2445 throw new Error(MessageManager.formatMessage(
2446 "error.unsupported_version_calcIdparam", new Object[]
2447 { calcIdParam.toString() }));
2451 * External mapping between jalview objects and objects yielding a valid and
2452 * unique object ID string. This is null for normal Jalview project IO, but
2453 * non-null when a jalview project is being read or written as part of a
2456 IdentityHashMap jv2vobj = null;
2459 * Construct a unique ID for jvobj using either existing bindings or if none
2460 * exist, the result of the hashcode call for the object.
2463 * jalview data object
2464 * @return unique ID for referring to jvobj
2466 private String makeHashCode(Object jvobj, String altCode)
2468 if (jv2vobj != null)
2470 Object id = jv2vobj.get(jvobj);
2473 return id.toString();
2475 // check string ID mappings
2476 if (jvids2vobj != null && jvobj instanceof String)
2478 id = jvids2vobj.get(jvobj);
2482 return id.toString();
2484 // give up and warn that something has gone wrong
2486 "Cannot find ID for object in external mapping : " + jvobj);
2492 * return local jalview object mapped to ID, if it exists
2496 * @return null or object bound to idcode
2498 private Object retrieveExistingObj(String idcode)
2500 if (idcode != null && vobj2jv != null)
2502 return vobj2jv.get(idcode);
2508 * binding from ID strings from external mapping table to jalview data model
2511 private Hashtable vobj2jv;
2513 private Sequence createVamsasSequence(String id, SequenceI jds)
2515 return createVamsasSequence(true, id, jds, null);
2518 private Sequence createVamsasSequence(boolean recurse, String id,
2519 SequenceI jds, SequenceI parentseq)
2521 Sequence vamsasSeq = new Sequence();
2522 vamsasSeq.setId(id);
2523 vamsasSeq.setName(jds.getName());
2524 vamsasSeq.setSequence(jds.getSequenceAsString());
2525 vamsasSeq.setDescription(jds.getDescription());
2526 List<DBRefEntry> dbrefs = null;
2527 if (jds.getDatasetSequence() != null)
2529 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2533 // seqId==dsseqid so we can tell which sequences really are
2534 // dataset sequences only
2535 vamsasSeq.setDsseqid(id);
2536 dbrefs = jds.getDBRefs();
2537 if (parentseq == null)
2544 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2548 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2550 DBRef dbref = new DBRef();
2551 DBRefEntry ref = dbrefs.get(d);
2552 dbref.setSource(ref.getSource());
2553 dbref.setVersion(ref.getVersion());
2554 dbref.setAccessionId(ref.getAccessionId());
2555 dbref.setCanonical(ref.isCanonical());
2556 if (ref instanceof GeneLocus)
2558 dbref.setLocus(true);
2562 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2564 dbref.setMapping(mp);
2566 vamsasSeq.getDBRef().add(dbref);
2572 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2573 SequenceI parentseq, SequenceI jds, boolean recurse)
2576 if (jmp.getMap() != null)
2580 jalview.util.MapList mlst = jmp.getMap();
2581 List<int[]> r = mlst.getFromRanges();
2582 for (int[] range : r)
2584 MapListFrom mfrom = new MapListFrom();
2585 mfrom.setStart(range[0]);
2586 mfrom.setEnd(range[1]);
2587 // mp.addMapListFrom(mfrom);
2588 mp.getMapListFrom().add(mfrom);
2590 r = mlst.getToRanges();
2591 for (int[] range : r)
2593 MapListTo mto = new MapListTo();
2594 mto.setStart(range[0]);
2595 mto.setEnd(range[1]);
2596 // mp.addMapListTo(mto);
2597 mp.getMapListTo().add(mto);
2599 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2600 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2601 if (jmp.getTo() != null)
2603 // MappingChoice mpc = new MappingChoice();
2605 // check/create ID for the sequence referenced by getTo()
2608 SequenceI ps = null;
2609 if (parentseq != jmp.getTo()
2610 && parentseq.getDatasetSequence() != jmp.getTo())
2612 // chaining dbref rather than a handshaking one
2613 jmpid = seqHash(ps = jmp.getTo());
2617 jmpid = seqHash(ps = parentseq);
2619 // mpc.setDseqFor(jmpid);
2620 mp.setDseqFor(jmpid);
2621 if (!seqRefIds.containsKey(jmpid))
2623 Console.debug("creatign new DseqFor ID");
2624 seqRefIds.put(jmpid, ps);
2628 Console.debug("reusing DseqFor ID");
2631 // mp.setMappingChoice(mpc);
2637 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2638 List<UserColourScheme> userColours, JalviewModel jm)
2641 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2642 boolean newucs = false;
2643 if (!userColours.contains(ucs))
2645 userColours.add(ucs);
2648 id = "ucs" + userColours.indexOf(ucs);
2651 // actually create the scheme's entry in the XML model
2652 java.awt.Color[] colours = ucs.getColours();
2653 UserColours uc = new UserColours();
2654 // UserColourScheme jbucs = new UserColourScheme();
2655 JalviewUserColours jbucs = new JalviewUserColours();
2657 for (int i = 0; i < colours.length; i++)
2659 Colour col = new Colour();
2660 col.setName(ResidueProperties.aa[i]);
2661 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2662 // jbucs.addColour(col);
2663 jbucs.getColour().add(col);
2665 if (ucs.getLowerCaseColours() != null)
2667 colours = ucs.getLowerCaseColours();
2668 for (int i = 0; i < colours.length; i++)
2670 Colour col = new Colour();
2671 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2672 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2673 // jbucs.addColour(col);
2674 jbucs.getColour().add(col);
2679 uc.setUserColourScheme(jbucs);
2680 // jm.addUserColours(uc);
2681 jm.getUserColours().add(uc);
2687 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2690 List<UserColours> uc = jm.getUserColours();
2691 UserColours colours = null;
2693 for (int i = 0; i < uc.length; i++)
2695 if (uc[i].getId().equals(id))
2702 for (UserColours c : uc)
2704 if (c.getId().equals(id))
2711 java.awt.Color[] newColours = new java.awt.Color[24];
2713 for (int i = 0; i < 24; i++)
2715 newColours[i] = new java.awt.Color(Integer.parseInt(
2716 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2717 colours.getUserColourScheme().getColour().get(i).getRGB(),
2721 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2724 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2726 newColours = new java.awt.Color[23];
2727 for (int i = 0; i < 23; i++)
2729 newColours[i] = new java.awt.Color(
2730 Integer.parseInt(colours.getUserColourScheme().getColour()
2731 .get(i + 24).getRGB(), 16));
2733 ucs.setLowerCaseColours(newColours);
2740 * contains last error message (if any) encountered by XML loader.
2742 String errorMessage = null;
2745 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2746 * exceptions are raised during project XML parsing
2748 public boolean attemptversion1parse = false;
2751 * Load a jalview project archive from a jar file
2754 * - HTTP URL or filename
2756 public AlignFrame loadJalviewAlign(final Object file)
2759 jalview.gui.AlignFrame af = null;
2763 // create list to store references for any new Jmol viewers created
2764 newStructureViewers = new Vector<>();
2765 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2766 // Workaround is to make sure caller implements the JarInputStreamProvider
2768 // so we can re-open the jar input stream for each entry.
2770 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2771 af = loadJalviewAlign(jprovider);
2774 af.setMenusForViewport();
2776 } catch (MalformedURLException e)
2778 errorMessage = "Invalid URL format for '" + file + "'";
2784 SwingUtilities.invokeAndWait(new Runnable()
2789 setLoadingFinishedForNewStructureViewers();
2792 } catch (Exception x)
2794 System.err.println("Error loading alignment: " + x.getMessage());
2800 @SuppressWarnings("unused")
2801 private jarInputStreamProvider createjarInputStreamProvider(
2802 final Object ofile) throws MalformedURLException
2805 // BH 2018 allow for bytes already attached to File object
2808 String file = (ofile instanceof File
2809 ? ((File) ofile).getCanonicalPath()
2810 : ofile.toString());
2811 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2814 errorMessage = null;
2815 uniqueSetSuffix = null;
2817 viewportsAdded.clear();
2818 frefedSequence = null;
2820 if (HttpUtils.startsWithHttpOrHttps(file))
2822 url = new URL(file);
2824 final URL _url = url;
2825 return new jarInputStreamProvider()
2829 public JarInputStream getJarInputStream() throws IOException
2833 // System.out.println("Jalview2XML: opening byte jarInputStream for
2834 // bytes.length=" + bytes.length);
2835 return new JarInputStream(new ByteArrayInputStream(bytes));
2839 // System.out.println("Jalview2XML: opening url jarInputStream for "
2841 return new JarInputStream(_url.openStream());
2845 // System.out.println("Jalview2XML: opening file jarInputStream for
2847 return new JarInputStream(new FileInputStream(file));
2852 public String getFilename()
2857 } catch (IOException e)
2859 e.printStackTrace();
2865 * Recover jalview session from a jalview project archive. Caller may
2866 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2867 * themselves. Any null fields will be initialised with default values,
2868 * non-null fields are left alone.
2873 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2875 errorMessage = null;
2876 if (uniqueSetSuffix == null)
2878 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2880 if (seqRefIds == null)
2884 AlignFrame af = null, _af = null;
2885 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2886 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2887 final String file = jprovider.getFilename();
2890 JarInputStream jin = null;
2891 JarEntry jarentry = null;
2896 jin = jprovider.getJarInputStream();
2897 for (int i = 0; i < entryCount; i++)
2899 jarentry = jin.getNextJarEntry();
2902 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2904 JAXBContext jc = JAXBContext
2905 .newInstance("jalview.xml.binding.jalview");
2906 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2907 .createXMLStreamReader(jin);
2908 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2909 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2910 JalviewModel.class);
2911 JalviewModel object = jbe.getValue();
2913 if (true) // !skipViewport(object))
2915 _af = loadFromObject(object, file, true, jprovider);
2916 if (_af != null && object.getViewport().size() > 0)
2917 // getJalviewModelSequence().getViewportCount() > 0)
2921 // store a reference to the first view
2924 if (_af.getViewport().isGatherViewsHere())
2926 // if this is a gathered view, keep its reference since
2927 // after gathering views, only this frame will remain
2929 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2932 // Save dataset to register mappings once all resolved
2933 importedDatasets.put(
2934 af.getViewport().getAlignment().getDataset(),
2935 af.getViewport().getAlignment().getDataset());
2940 else if (jarentry != null)
2942 // Some other file here.
2945 } while (jarentry != null);
2947 resolveFrefedSequences();
2948 } catch (IOException ex)
2950 ex.printStackTrace();
2951 errorMessage = "Couldn't locate Jalview XML file : " + file;
2953 "Exception whilst loading jalview XML file : " + ex + "\n");
2954 } catch (Exception ex)
2956 System.err.println("Parsing as Jalview Version 2 file failed.");
2957 ex.printStackTrace(System.err);
2958 if (attemptversion1parse)
2960 // used to attempt to parse as V1 castor-generated xml
2962 if (Desktop.instance != null)
2964 Desktop.instance.stopLoading();
2968 System.out.println("Successfully loaded archive file");
2971 ex.printStackTrace();
2974 "Exception whilst loading jalview XML file : " + ex + "\n");
2975 } catch (OutOfMemoryError e)
2977 // Don't use the OOM Window here
2978 errorMessage = "Out of memory loading jalview XML file";
2979 System.err.println("Out of memory whilst loading jalview XML file");
2980 e.printStackTrace();
2984 * Regather multiple views (with the same sequence set id) to the frame (if
2985 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2986 * views instead of separate frames. Note this doesn't restore a state where
2987 * some expanded views in turn have tabbed views - the last "first tab" read
2988 * in will play the role of gatherer for all.
2990 for (AlignFrame fr : gatherToThisFrame.values())
2992 Desktop.instance.gatherViews(fr);
2995 restoreSplitFrames();
2996 for (AlignmentI ds : importedDatasets.keySet())
2998 if (ds.getCodonFrames() != null)
3000 StructureSelectionManager
3001 .getStructureSelectionManager(Desktop.instance)
3002 .registerMappings(ds.getCodonFrames());
3005 if (errorMessage != null)
3010 if (Desktop.instance != null)
3012 Desktop.instance.stopLoading();
3019 * Try to reconstruct and display SplitFrame windows, where each contains
3020 * complementary dna and protein alignments. Done by pairing up AlignFrame
3021 * objects (created earlier) which have complementary viewport ids associated.
3023 protected void restoreSplitFrames()
3025 List<SplitFrame> gatherTo = new ArrayList<>();
3026 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3027 Map<String, AlignFrame> dna = new HashMap<>();
3030 * Identify the DNA alignments
3032 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3035 AlignFrame af = candidate.getValue();
3036 if (af.getViewport().getAlignment().isNucleotide())
3038 dna.put(candidate.getKey().getId(), af);
3043 * Try to match up the protein complements
3045 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3048 AlignFrame af = candidate.getValue();
3049 if (!af.getViewport().getAlignment().isNucleotide())
3051 String complementId = candidate.getKey().getComplementId();
3052 // only non-null complements should be in the Map
3053 if (complementId != null && dna.containsKey(complementId))
3055 final AlignFrame dnaFrame = dna.get(complementId);
3056 SplitFrame sf = createSplitFrame(dnaFrame, af);
3057 addedToSplitFrames.add(dnaFrame);
3058 addedToSplitFrames.add(af);
3059 dnaFrame.setMenusForViewport();
3060 af.setMenusForViewport();
3061 if (af.getViewport().isGatherViewsHere())
3070 * Open any that we failed to pair up (which shouldn't happen!) as
3071 * standalone AlignFrame's.
3073 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3076 AlignFrame af = candidate.getValue();
3077 if (!addedToSplitFrames.contains(af))
3079 Viewport view = candidate.getKey();
3080 Desktop.addInternalFrame(af, view.getTitle(),
3081 safeInt(view.getWidth()), safeInt(view.getHeight()));
3082 af.setMenusForViewport();
3083 System.err.println("Failed to restore view " + view.getTitle()
3084 + " to split frame");
3089 * Gather back into tabbed views as flagged.
3091 for (SplitFrame sf : gatherTo)
3093 Desktop.instance.gatherViews(sf);
3096 splitFrameCandidates.clear();
3100 * Construct and display one SplitFrame holding DNA and protein alignments.
3103 * @param proteinFrame
3106 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3107 AlignFrame proteinFrame)
3109 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3110 String title = MessageManager.getString("label.linked_view_title");
3111 int width = (int) dnaFrame.getBounds().getWidth();
3112 int height = (int) (dnaFrame.getBounds().getHeight()
3113 + proteinFrame.getBounds().getHeight() + 50);
3116 * SplitFrame location is saved to both enclosed frames
3118 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3119 Desktop.addInternalFrame(splitFrame, title, width, height);
3122 * And compute cDNA consensus (couldn't do earlier with consensus as
3123 * mappings were not yet present)
3125 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3131 * check errorMessage for a valid error message and raise an error box in the
3132 * GUI or write the current errorMessage to stderr and then clear the error
3135 protected void reportErrors()
3137 reportErrors(false);
3140 protected void reportErrors(final boolean saving)
3142 if (errorMessage != null)
3144 final String finalErrorMessage = errorMessage;
3147 javax.swing.SwingUtilities.invokeLater(new Runnable()
3152 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3154 "Error " + (saving ? "saving" : "loading")
3156 JvOptionPane.WARNING_MESSAGE);
3162 System.err.println("Problem loading Jalview file: " + errorMessage);
3165 errorMessage = null;
3168 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3171 * when set, local views will be updated from view stored in JalviewXML
3172 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3173 * sync if this is set to true.
3175 private final boolean updateLocalViews = false;
3178 * Returns the path to a temporary file holding the PDB file for the given PDB
3179 * id. The first time of asking, searches for a file of that name in the
3180 * Jalview project jar, and copies it to a new temporary file. Any repeat
3181 * requests just return the path to the file previously created.
3187 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3190 if (alreadyLoadedPDB.containsKey(pdbId))
3192 return alreadyLoadedPDB.get(pdbId).toString();
3195 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3197 if (tempFile != null)
3199 alreadyLoadedPDB.put(pdbId, tempFile);
3205 * Copies the jar entry of given name to a new temporary file and returns the
3206 * path to the file, or null if the entry is not found.
3209 * @param jarEntryName
3211 * a prefix for the temporary file name, must be at least three
3213 * @param suffixModel
3214 * null or original file - so new file can be given the same suffix
3218 protected String copyJarEntry(jarInputStreamProvider jprovider,
3219 String jarEntryName, String prefix, String suffixModel)
3221 String suffix = ".tmp";
3222 if (suffixModel == null)
3224 suffixModel = jarEntryName;
3226 int sfpos = suffixModel.lastIndexOf(".");
3227 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3229 suffix = "." + suffixModel.substring(sfpos + 1);
3232 try (JarInputStream jin = jprovider.getJarInputStream())
3234 JarEntry entry = null;
3237 entry = jin.getNextJarEntry();
3238 } while (entry != null && !entry.getName().equals(jarEntryName));
3242 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3243 File outFile = File.createTempFile(prefix, suffix);
3244 outFile.deleteOnExit();
3245 try (OutputStream os = new FileOutputStream(outFile))
3249 String t = outFile.getAbsolutePath();
3255 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3257 } catch (Exception ex)
3259 ex.printStackTrace();
3265 private class JvAnnotRow
3267 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3274 * persisted version of annotation row from which to take vis properties
3276 public jalview.datamodel.AlignmentAnnotation template;
3279 * original position of the annotation row in the alignment
3285 * Load alignment frame from jalview XML DOM object
3287 * @param jalviewModel
3290 * filename source string
3291 * @param loadTreesAndStructures
3292 * when false only create Viewport
3294 * data source provider
3295 * @return alignment frame created from view stored in DOM
3297 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3298 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3300 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3302 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3304 // JalviewModelSequence jms = object.getJalviewModelSequence();
3306 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3308 Viewport view = (jalviewModel.getViewport().size() > 0)
3309 ? jalviewModel.getViewport().get(0)
3312 // ////////////////////////////////
3313 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3316 // If we just load in the same jar file again, the sequenceSetId
3317 // will be the same, and we end up with multiple references
3318 // to the same sequenceSet. We must modify this id on load
3319 // so that each load of the file gives a unique id
3322 * used to resolve correct alignment dataset for alignments with multiple
3325 String uniqueSeqSetId = null;
3326 String viewId = null;
3329 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3330 viewId = (view.getId() == null ? null
3331 : view.getId() + uniqueSetSuffix);
3334 // ////////////////////////////////
3337 List<SequenceI> hiddenSeqs = null;
3339 List<SequenceI> tmpseqs = new ArrayList<>();
3341 boolean multipleView = false;
3342 SequenceI referenceseqForView = null;
3343 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3344 List<JSeq> jseqs = jalviewModel.getJSeq();
3345 int vi = 0; // counter in vamsasSeq array
3346 for (int i = 0; i < jseqs.size(); i++)
3348 JSeq jseq = jseqs.get(i);
3349 String seqId = jseq.getId();
3351 SequenceI tmpSeq = seqRefIds.get(seqId);
3354 if (!incompleteSeqs.containsKey(seqId))
3356 // may not need this check, but keep it for at least 2.9,1 release
3357 if (tmpSeq.getStart() != jseq.getStart()
3358 || tmpSeq.getEnd() != jseq.getEnd())
3360 System.err.println(String.format(
3361 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3362 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3363 jseq.getStart(), jseq.getEnd()));
3368 incompleteSeqs.remove(seqId);
3370 if (vamsasSeqs.size() > vi
3371 && vamsasSeqs.get(vi).getId().equals(seqId))
3373 // most likely we are reading a dataset XML document so
3374 // update from vamsasSeq section of XML for this sequence
3375 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3376 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3377 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3382 // reading multiple views, so vamsasSeq set is a subset of JSeq
3383 multipleView = true;
3385 tmpSeq.setStart(jseq.getStart());
3386 tmpSeq.setEnd(jseq.getEnd());
3387 tmpseqs.add(tmpSeq);
3391 Sequence vamsasSeq = vamsasSeqs.get(vi);
3392 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3393 vamsasSeq.getSequence());
3394 tmpSeq.setDescription(vamsasSeq.getDescription());
3395 tmpSeq.setStart(jseq.getStart());
3396 tmpSeq.setEnd(jseq.getEnd());
3397 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3398 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3399 tmpseqs.add(tmpSeq);
3403 if (safeBoolean(jseq.isViewreference()))
3405 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3408 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3410 if (hiddenSeqs == null)
3412 hiddenSeqs = new ArrayList<>();
3415 hiddenSeqs.add(tmpSeq);
3420 // Create the alignment object from the sequence set
3421 // ///////////////////////////////
3422 SequenceI[] orderedSeqs = tmpseqs
3423 .toArray(new SequenceI[tmpseqs.size()]);
3425 AlignmentI al = null;
3426 // so we must create or recover the dataset alignment before going further
3427 // ///////////////////////////////
3428 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3430 // older jalview projects do not have a dataset - so creat alignment and
3432 al = new Alignment(orderedSeqs);
3433 al.setDataset(null);
3437 boolean isdsal = jalviewModel.getViewport().isEmpty();
3440 // we are importing a dataset record, so
3441 // recover reference to an alignment already materialsed as dataset
3442 al = getDatasetFor(vamsasSet.getDatasetId());
3446 // materialse the alignment
3447 al = new Alignment(orderedSeqs);
3451 addDatasetRef(vamsasSet.getDatasetId(), al);
3454 // finally, verify all data in vamsasSet is actually present in al
3455 // passing on flag indicating if it is actually a stored dataset
3456 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3459 if (referenceseqForView != null)
3461 al.setSeqrep(referenceseqForView);
3463 // / Add the alignment properties
3464 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3466 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3468 al.setProperty(ssp.getKey(), ssp.getValue());
3471 // ///////////////////////////////
3473 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3476 // load sequence features, database references and any associated PDB
3477 // structures for the alignment
3479 // prior to 2.10, this part would only be executed the first time a
3480 // sequence was encountered, but not afterwards.
3481 // now, for 2.10 projects, this is also done if the xml doc includes
3482 // dataset sequences not actually present in any particular view.
3484 for (int i = 0; i < vamsasSeqs.size(); i++)
3486 JSeq jseq = jseqs.get(i);
3487 if (jseq.getFeatures().size() > 0)
3489 List<Feature> features = jseq.getFeatures();
3490 for (int f = 0; f < features.size(); f++)
3492 Feature feat = features.get(f);
3493 SequenceFeature sf = new SequenceFeature(feat.getType(),
3494 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3495 safeFloat(feat.getScore()), feat.getFeatureGroup());
3496 sf.setStatus(feat.getStatus());
3499 * load any feature attributes - include map-valued attributes
3501 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3502 for (int od = 0; od < feat.getOtherData().size(); od++)
3504 OtherData keyValue = feat.getOtherData().get(od);
3505 String attributeName = keyValue.getKey();
3506 String attributeValue = keyValue.getValue();
3507 if (attributeName.startsWith("LINK"))
3509 sf.addLink(attributeValue);
3513 String subAttribute = keyValue.getKey2();
3514 if (subAttribute == null)
3516 // simple string-valued attribute
3517 sf.setValue(attributeName, attributeValue);
3521 // attribute 'key' has sub-attribute 'key2'
3522 if (!mapAttributes.containsKey(attributeName))
3524 mapAttributes.put(attributeName, new HashMap<>());
3526 mapAttributes.get(attributeName).put(subAttribute,
3531 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3534 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3537 // adds feature to datasequence's feature set (since Jalview 2.10)
3538 al.getSequenceAt(i).addSequenceFeature(sf);
3541 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3543 // adds dbrefs to datasequence's set (since Jalview 2.10)
3545 al.getSequenceAt(i).getDatasetSequence() == null
3546 ? al.getSequenceAt(i)
3547 : al.getSequenceAt(i).getDatasetSequence(),
3550 if (jseq.getPdbids().size() > 0)
3552 List<Pdbids> ids = jseq.getPdbids();
3553 for (int p = 0; p < ids.size(); p++)
3555 Pdbids pdbid = ids.get(p);
3556 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3557 entry.setId(pdbid.getId());
3558 if (pdbid.getType() != null)
3560 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3562 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3566 entry.setType(PDBEntry.Type.FILE);
3569 // jprovider is null when executing 'New View'
3570 if (pdbid.getFile() != null && jprovider != null)
3572 if (!pdbloaded.containsKey(pdbid.getFile()))
3574 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3579 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3583 if (pdbid.getPdbentryItem() != null)
3585 for (PdbentryItem item : pdbid.getPdbentryItem())
3587 for (Property pr : item.getProperty())
3589 entry.setProperty(pr.getName(), pr.getValue());
3594 for (Property prop : pdbid.getProperty())
3596 entry.setProperty(prop.getName(), prop.getValue());
3598 StructureSelectionManager
3599 .getStructureSelectionManager(Desktop.instance)
3600 .registerPDBEntry(entry);
3601 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3602 if (al.getSequenceAt(i).getDatasetSequence() != null)
3604 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3608 al.getSequenceAt(i).addPDBId(entry);
3613 } // end !multipleview
3615 // ///////////////////////////////
3616 // LOAD SEQUENCE MAPPINGS
3618 if (vamsasSet.getAlcodonFrame().size() > 0)
3620 // TODO Potentially this should only be done once for all views of an
3622 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3623 for (int i = 0; i < alc.size(); i++)
3625 AlignedCodonFrame cf = new AlignedCodonFrame();
3626 if (alc.get(i).getAlcodMap().size() > 0)
3628 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3629 for (int m = 0; m < maps.size(); m++)
3631 AlcodMap map = maps.get(m);
3632 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3634 jalview.datamodel.Mapping mapping = null;
3635 // attach to dna sequence reference.
3636 if (map.getMapping() != null)
3638 mapping = addMapping(map.getMapping());
3639 if (dnaseq != null && mapping.getTo() != null)
3641 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3647 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3651 al.addCodonFrame(cf);
3656 // ////////////////////////////////
3658 List<JvAnnotRow> autoAlan = new ArrayList<>();
3661 * store any annotations which forward reference a group's ID
3663 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3665 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3667 List<Annotation> an = vamsasSet.getAnnotation();
3669 for (int i = 0; i < an.size(); i++)
3671 Annotation annotation = an.get(i);
3674 * test if annotation is automatically calculated for this view only
3676 boolean autoForView = false;
3677 if (annotation.getLabel().equals("Quality")
3678 || annotation.getLabel().equals("Conservation")
3679 || annotation.getLabel().equals("Consensus"))
3681 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3683 // JAXB has no has() test; schema defaults value to false
3684 // if (!annotation.hasAutoCalculated())
3686 // annotation.setAutoCalculated(true);
3689 if (autoForView || annotation.isAutoCalculated())
3691 // remove ID - we don't recover annotation from other views for
3692 // view-specific annotation
3693 annotation.setId(null);
3696 // set visibility for other annotation in this view
3697 String annotationId = annotation.getId();
3698 if (annotationId != null && annotationIds.containsKey(annotationId))
3700 AlignmentAnnotation jda = annotationIds.get(annotationId);
3701 // in principle Visible should always be true for annotation displayed
3702 // in multiple views
3703 if (annotation.isVisible() != null)
3705 jda.visible = annotation.isVisible();
3708 al.addAnnotation(jda);
3712 // Construct new annotation from model.
3713 List<AnnotationElement> ae = annotation.getAnnotationElement();
3714 jalview.datamodel.Annotation[] anot = null;
3715 java.awt.Color firstColour = null;
3717 if (!annotation.isScoreOnly())
3719 anot = new jalview.datamodel.Annotation[al.getWidth()];
3720 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3722 AnnotationElement annElement = ae.get(aa);
3723 anpos = annElement.getPosition();
3725 if (anpos >= anot.length)
3730 float value = safeFloat(annElement.getValue());
3731 anot[anpos] = new jalview.datamodel.Annotation(
3732 annElement.getDisplayCharacter(),
3733 annElement.getDescription(),
3734 (annElement.getSecondaryStructure() == null
3735 || annElement.getSecondaryStructure()
3739 .getSecondaryStructure()
3742 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3743 if (firstColour == null)
3745 firstColour = anot[anpos].colour;
3749 jalview.datamodel.AlignmentAnnotation jaa = null;
3751 if (annotation.isGraph())
3753 float llim = 0, hlim = 0;
3754 // if (autoForView || an[i].isAutoCalculated()) {
3757 jaa = new jalview.datamodel.AlignmentAnnotation(
3758 annotation.getLabel(), annotation.getDescription(), anot,
3759 llim, hlim, safeInt(annotation.getGraphType()));
3761 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3762 jaa._linecolour = firstColour;
3763 if (annotation.getThresholdLine() != null)
3765 jaa.setThreshold(new jalview.datamodel.GraphLine(
3766 safeFloat(annotation.getThresholdLine().getValue()),
3767 annotation.getThresholdLine().getLabel(),
3768 new java.awt.Color(safeInt(
3769 annotation.getThresholdLine().getColour()))));
3771 if (autoForView || annotation.isAutoCalculated())
3773 // Hardwire the symbol display line to ensure that labels for
3774 // histograms are displayed
3780 jaa = new jalview.datamodel.AlignmentAnnotation(
3781 annotation.getLabel(), annotation.getDescription(), anot);
3782 jaa._linecolour = firstColour;
3784 // register new annotation
3785 if (annotation.getId() != null)
3787 annotationIds.put(annotation.getId(), jaa);
3788 jaa.annotationId = annotation.getId();
3790 // recover sequence association
3791 String sequenceRef = annotation.getSequenceRef();
3792 if (sequenceRef != null)
3794 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3795 SequenceI sequence = seqRefIds.get(sequenceRef);
3796 if (sequence == null)
3798 // in pre-2.9 projects sequence ref is to sequence name
3799 sequence = al.findName(sequenceRef);
3801 if (sequence != null)
3803 jaa.createSequenceMapping(sequence, 1, true);
3804 sequence.addAlignmentAnnotation(jaa);
3807 // and make a note of any group association
3808 if (annotation.getGroupRef() != null
3809 && annotation.getGroupRef().length() > 0)
3811 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3812 .get(annotation.getGroupRef());
3815 aal = new ArrayList<>();
3816 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3821 if (annotation.getScore() != null)
3823 jaa.setScore(annotation.getScore().doubleValue());
3825 if (annotation.isVisible() != null)
3827 jaa.visible = annotation.isVisible().booleanValue();
3830 if (annotation.isCentreColLabels() != null)
3832 jaa.centreColLabels = annotation.isCentreColLabels()
3836 if (annotation.isScaleColLabels() != null)
3838 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3840 if (annotation.isAutoCalculated())
3842 // newer files have an 'autoCalculated' flag and store calculation
3843 // state in viewport properties
3844 jaa.autoCalculated = true; // means annotation will be marked for
3845 // update at end of load.
3847 if (annotation.getGraphHeight() != null)
3849 jaa.graphHeight = annotation.getGraphHeight().intValue();
3851 jaa.belowAlignment = annotation.isBelowAlignment();
3852 jaa.setCalcId(annotation.getCalcId());
3853 if (annotation.getProperty().size() > 0)
3855 for (Annotation.Property prop : annotation.getProperty())
3857 jaa.setProperty(prop.getName(), prop.getValue());
3860 if (jaa.autoCalculated)
3862 autoAlan.add(new JvAnnotRow(i, jaa));
3865 // if (!autoForView)
3867 // add autocalculated group annotation and any user created annotation
3869 al.addAnnotation(jaa);
3873 // ///////////////////////
3875 // Create alignment markup and styles for this view
3876 if (jalviewModel.getJGroup().size() > 0)
3878 List<JGroup> groups = jalviewModel.getJGroup();
3879 boolean addAnnotSchemeGroup = false;
3880 for (int i = 0; i < groups.size(); i++)
3882 JGroup jGroup = groups.get(i);
3883 ColourSchemeI cs = null;
3884 if (jGroup.getColour() != null)
3886 if (jGroup.getColour().startsWith("ucs"))
3888 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3890 else if (jGroup.getColour().equals("AnnotationColourGradient")
3891 && jGroup.getAnnotationColours() != null)
3893 addAnnotSchemeGroup = true;
3897 cs = ColourSchemeProperty.getColourScheme(null, al,
3898 jGroup.getColour());
3901 int pidThreshold = safeInt(jGroup.getPidThreshold());
3903 Vector<SequenceI> seqs = new Vector<>();
3905 for (int s = 0; s < jGroup.getSeq().size(); s++)
3907 String seqId = jGroup.getSeq().get(s);
3908 SequenceI ts = seqRefIds.get(seqId);
3912 seqs.addElement(ts);
3916 if (seqs.size() < 1)
3921 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3922 safeBoolean(jGroup.isDisplayBoxes()),
3923 safeBoolean(jGroup.isDisplayText()),
3924 safeBoolean(jGroup.isColourText()),
3925 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3926 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3927 sg.getGroupColourScheme()
3928 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3929 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3931 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3932 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3933 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3934 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3935 // attributes with a default in the schema are never null
3936 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3937 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3938 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3939 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3940 if (jGroup.getConsThreshold() != null
3941 && jGroup.getConsThreshold().intValue() != 0)
3943 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3946 c.verdict(false, 25);
3947 sg.cs.setConservation(c);
3950 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3952 // re-instate unique group/annotation row reference
3953 List<AlignmentAnnotation> jaal = groupAnnotRefs
3954 .get(jGroup.getId());
3957 for (AlignmentAnnotation jaa : jaal)
3960 if (jaa.autoCalculated)
3962 // match up and try to set group autocalc alignment row for this
3964 if (jaa.label.startsWith("Consensus for "))
3966 sg.setConsensus(jaa);
3968 // match up and try to set group autocalc alignment row for this
3970 if (jaa.label.startsWith("Conservation for "))
3972 sg.setConservationRow(jaa);
3979 if (addAnnotSchemeGroup)
3981 // reconstruct the annotation colourscheme
3983 constructAnnotationColour(jGroup.getAnnotationColours(),
3984 null, al, jalviewModel, false));
3990 // only dataset in this model, so just return.
3993 // ///////////////////////////////
3996 AlignFrame af = null;
3997 AlignViewport av = null;
3998 // now check to see if we really need to create a new viewport.
3999 if (multipleView && viewportsAdded.size() == 0)
4001 // We recovered an alignment for which a viewport already exists.
4002 // TODO: fix up any settings necessary for overlaying stored state onto
4003 // state recovered from another document. (may not be necessary).
4004 // we may need a binding from a viewport in memory to one recovered from
4006 // and then recover its containing af to allow the settings to be applied.
4007 // TODO: fix for vamsas demo
4009 "About to recover a viewport for existing alignment: Sequence set ID is "
4011 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4012 if (seqsetobj != null)
4014 if (seqsetobj instanceof String)
4016 uniqueSeqSetId = (String) seqsetobj;
4018 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4024 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4030 * indicate that annotation colours are applied across all groups (pre
4031 * Jalview 2.8.1 behaviour)
4033 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4034 jalviewModel.getVersion());
4036 AlignmentPanel ap = null;
4037 boolean isnewview = true;
4040 // Check to see if this alignment already has a view id == viewId
4041 jalview.gui.AlignmentPanel views[] = Desktop
4042 .getAlignmentPanels(uniqueSeqSetId);
4043 if (views != null && views.length > 0)
4045 for (int v = 0; v < views.length; v++)
4047 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4049 // recover the existing alignpanel, alignframe, viewport
4050 af = views[v].alignFrame;
4053 // TODO: could even skip resetting view settings if we don't want to
4054 // change the local settings from other jalview processes
4063 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4064 uniqueSeqSetId, viewId, autoAlan);
4065 av = af.getViewport();
4070 * Load any trees, PDB structures and viewers
4072 * Not done if flag is false (when this method is used for New View)
4074 if (loadTreesAndStructures)
4076 loadTrees(jalviewModel, view, af, av, ap);
4077 loadPCAViewers(jalviewModel, ap);
4078 loadPDBStructures(jprovider, jseqs, af, ap);
4079 loadRnaViewers(jprovider, jseqs, ap);
4081 // and finally return.
4086 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4087 * panel is restored from separate jar entries, two (gapped and trimmed) per
4088 * sequence and secondary structure.
4090 * Currently each viewer shows just one sequence and structure (gapped and
4091 * trimmed), however this method is designed to support multiple sequences or
4092 * structures in viewers if wanted in future.
4098 private void loadRnaViewers(jarInputStreamProvider jprovider,
4099 List<JSeq> jseqs, AlignmentPanel ap)
4102 * scan the sequences for references to viewers; create each one the first
4103 * time it is referenced, add Rna models to existing viewers
4105 for (JSeq jseq : jseqs)
4107 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4109 RnaViewer viewer = jseq.getRnaViewer().get(i);
4110 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4113 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4115 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4116 SequenceI seq = seqRefIds.get(jseq.getId());
4117 AlignmentAnnotation ann = this.annotationIds
4118 .get(ss.getAnnotationId());
4121 * add the structure to the Varna display (with session state copied
4122 * from the jar to a temporary file)
4124 boolean gapped = safeBoolean(ss.isGapped());
4125 String rnaTitle = ss.getTitle();
4126 String sessionState = ss.getViewerState();
4127 String tempStateFile = copyJarEntry(jprovider, sessionState,
4129 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4130 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4132 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4138 * Locate and return an already instantiated matching AppVarna, or create one
4142 * @param viewIdSuffix
4146 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4147 String viewIdSuffix, AlignmentPanel ap)
4150 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4151 * if load is repeated
4153 String postLoadId = viewer.getViewId() + viewIdSuffix;
4154 for (JInternalFrame frame : getAllFrames())
4156 if (frame instanceof AppVarna)
4158 AppVarna varna = (AppVarna) frame;
4159 if (postLoadId.equals(varna.getViewId()))
4161 // this viewer is already instantiated
4162 // could in future here add ap as another 'parent' of the
4163 // AppVarna window; currently just 1-to-many
4170 * viewer not found - make it
4172 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4173 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4174 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4175 safeInt(viewer.getDividerLocation()));
4176 AppVarna varna = new AppVarna(model, ap);
4182 * Load any saved trees
4190 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4191 AlignViewport av, AlignmentPanel ap)
4193 // TODO result of automated refactoring - are all these parameters needed?
4196 for (int t = 0; t < jm.getTree().size(); t++)
4199 Tree tree = jm.getTree().get(t);
4201 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4204 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4205 tree.getTitle(), safeInt(tree.getWidth()),
4206 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4207 safeInt(tree.getYpos()));
4208 if (tree.getId() != null)
4210 // perhaps bind the tree id to something ?
4215 // update local tree attributes ?
4216 // TODO: should check if tp has been manipulated by user - if so its
4217 // settings shouldn't be modified
4218 tp.setTitle(tree.getTitle());
4219 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4220 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4221 safeInt(tree.getHeight())));
4222 tp.setViewport(av); // af.viewport;
4223 // TODO: verify 'associate with all views' works still
4224 tp.getTreeCanvas().setViewport(av); // af.viewport;
4225 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4227 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4231 "There was a problem recovering stored Newick tree: \n"
4232 + tree.getNewick());
4236 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4237 tp.fitToWindow_actionPerformed(null);
4239 if (tree.getFontName() != null)
4242 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4243 safeInt(tree.getFontSize())));
4248 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4249 safeInt(view.getFontSize())));
4252 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4253 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4254 tp.showDistances(safeBoolean(tree.isShowDistances()));
4256 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4258 if (safeBoolean(tree.isCurrentTree()))
4260 af.getViewport().setCurrentTree(tp.getTree());
4264 } catch (Exception ex)
4266 ex.printStackTrace();
4271 * Load and link any saved structure viewers.
4278 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4279 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4282 * Run through all PDB ids on the alignment, and collect mappings between
4283 * distinct view ids and all sequences referring to that view.
4285 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4287 for (int i = 0; i < jseqs.size(); i++)
4289 JSeq jseq = jseqs.get(i);
4290 if (jseq.getPdbids().size() > 0)
4292 List<Pdbids> ids = jseq.getPdbids();
4293 for (int p = 0; p < ids.size(); p++)
4295 Pdbids pdbid = ids.get(p);
4296 final int structureStateCount = pdbid.getStructureState().size();
4297 for (int s = 0; s < structureStateCount; s++)
4299 // check to see if we haven't already created this structure view
4300 final StructureState structureState = pdbid.getStructureState()
4302 String sviewid = (structureState.getViewId() == null) ? null
4303 : structureState.getViewId() + uniqueSetSuffix;
4304 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4305 // Originally : pdbid.getFile()
4306 // : TODO: verify external PDB file recovery still works in normal
4307 // jalview project load
4309 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4310 jpdb.setId(pdbid.getId());
4312 int x = safeInt(structureState.getXpos());
4313 int y = safeInt(structureState.getYpos());
4314 int width = safeInt(structureState.getWidth());
4315 int height = safeInt(structureState.getHeight());
4317 // Probably don't need to do this anymore...
4318 // Desktop.desktop.getComponentAt(x, y);
4319 // TODO: NOW: check that this recovers the PDB file correctly.
4320 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4322 jalview.datamodel.SequenceI seq = seqRefIds
4323 .get(jseq.getId() + "");
4324 if (sviewid == null)
4326 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4329 if (!structureViewers.containsKey(sviewid))
4331 String viewerType = structureState.getType();
4332 if (viewerType == null) // pre Jalview 2.9
4334 viewerType = ViewerType.JMOL.toString();
4336 structureViewers.put(sviewid,
4337 new StructureViewerModel(x, y, width, height, false,
4338 false, true, structureState.getViewId(),
4340 // Legacy pre-2.7 conversion JAL-823 :
4341 // do not assume any view has to be linked for colour by
4345 // assemble String[] { pdb files }, String[] { id for each
4346 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4347 // seqs_file 2}, boolean[] {
4348 // linkAlignPanel,superposeWithAlignpanel}} from hash
4349 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4350 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4351 || structureState.isAlignwithAlignPanel());
4354 * Default colour by linked panel to false if not specified (e.g.
4355 * for pre-2.7 projects)
4357 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4358 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4359 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4362 * Default colour by viewer to true if not specified (e.g. for
4365 boolean colourByViewer = jmoldat.isColourByViewer();
4366 colourByViewer &= structureState.isColourByJmol();
4367 jmoldat.setColourByViewer(colourByViewer);
4369 if (jmoldat.getStateData().length() < structureState.getValue()
4370 /*Content()*/.length())
4372 jmoldat.setStateData(structureState.getValue());// Content());
4374 if (pdbid.getFile() != null)
4376 File mapkey = new File(pdbid.getFile());
4377 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4378 if (seqstrmaps == null)
4380 jmoldat.getFileData().put(mapkey,
4381 seqstrmaps = jmoldat.new StructureData(pdbFile,
4384 if (!seqstrmaps.getSeqList().contains(seq))
4386 seqstrmaps.getSeqList().add(seq);
4392 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");
4393 Console.warn(errorMessage);
4399 // Instantiate the associated structure views
4400 for (Entry<String, StructureViewerModel> entry : structureViewers
4405 createOrLinkStructureViewer(entry, af, ap, jprovider);
4406 } catch (Exception e)
4409 "Error loading structure viewer: " + e.getMessage());
4410 // failed - try the next one
4422 protected void createOrLinkStructureViewer(
4423 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4424 AlignmentPanel ap, jarInputStreamProvider jprovider)
4426 final StructureViewerModel stateData = viewerData.getValue();
4429 * Search for any viewer windows already open from other alignment views
4430 * that exactly match the stored structure state
4432 StructureViewerBase comp = findMatchingViewer(viewerData);
4436 linkStructureViewer(ap, comp, stateData);
4440 String type = stateData.getType();
4443 ViewerType viewerType = ViewerType.valueOf(type);
4444 createStructureViewer(viewerType, viewerData, af, jprovider);
4445 } catch (IllegalArgumentException | NullPointerException e)
4447 // TODO JAL-3619 show error dialog / offer an alternative viewer
4448 Console.error("Invalid structure viewer type: " + type);
4453 * Generates a name for the entry in the project jar file to hold state
4454 * information for a structure viewer
4459 protected String getViewerJarEntryName(String viewId)
4461 return VIEWER_PREFIX + viewId;
4465 * Returns any open frame that matches given structure viewer data. The match
4466 * is based on the unique viewId, or (for older project versions) the frame's
4472 protected StructureViewerBase findMatchingViewer(
4473 Entry<String, StructureViewerModel> viewerData)
4475 final String sviewid = viewerData.getKey();
4476 final StructureViewerModel svattrib = viewerData.getValue();
4477 StructureViewerBase comp = null;
4478 JInternalFrame[] frames = getAllFrames();
4479 for (JInternalFrame frame : frames)
4481 if (frame instanceof StructureViewerBase)
4484 * Post jalview 2.4 schema includes structure view id
4486 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4489 comp = (StructureViewerBase) frame;
4490 break; // break added in 2.9
4493 * Otherwise test for matching position and size of viewer frame
4495 else if (frame.getX() == svattrib.getX()
4496 && frame.getY() == svattrib.getY()
4497 && frame.getHeight() == svattrib.getHeight()
4498 && frame.getWidth() == svattrib.getWidth())
4500 comp = (StructureViewerBase) frame;
4501 // no break in faint hope of an exact match on viewId
4509 * Link an AlignmentPanel to an existing structure viewer.
4514 * @param useinViewerSuperpos
4515 * @param usetoColourbyseq
4516 * @param viewerColouring
4518 protected void linkStructureViewer(AlignmentPanel ap,
4519 StructureViewerBase viewer, StructureViewerModel stateData)
4521 // NOTE: if the jalview project is part of a shared session then
4522 // view synchronization should/could be done here.
4524 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4525 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4526 final boolean viewerColouring = stateData.isColourByViewer();
4527 Map<File, StructureData> oldFiles = stateData.getFileData();
4530 * Add mapping for sequences in this view to an already open viewer
4532 final AAStructureBindingModel binding = viewer.getBinding();
4533 for (File id : oldFiles.keySet())
4535 // add this and any other pdb files that should be present in the
4537 StructureData filedat = oldFiles.get(id);
4538 String pdbFile = filedat.getFilePath();
4539 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4540 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4542 binding.addSequenceForStructFile(pdbFile, seq);
4544 // and add the AlignmentPanel's reference to the view panel
4545 viewer.addAlignmentPanel(ap);
4546 if (useinViewerSuperpos)
4548 viewer.useAlignmentPanelForSuperposition(ap);
4552 viewer.excludeAlignmentPanelForSuperposition(ap);
4554 if (usetoColourbyseq)
4556 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4560 viewer.excludeAlignmentPanelForColourbyseq(ap);
4565 * Get all frames within the Desktop.
4569 protected JInternalFrame[] getAllFrames()
4571 JInternalFrame[] frames = null;
4572 // TODO is this necessary - is it safe - risk of hanging?
4577 frames = Desktop.desktop.getAllFrames();
4578 } catch (ArrayIndexOutOfBoundsException e)
4580 // occasional No such child exceptions are thrown here...
4584 } catch (InterruptedException f)
4588 } while (frames == null);
4593 * Answers true if 'version' is equal to or later than 'supported', where each
4594 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4595 * changes. Development and test values for 'version' are leniently treated
4599 * - minimum version we are comparing against
4601 * - version of data being processsed
4604 public static boolean isVersionStringLaterThan(String supported,
4607 if (supported == null || version == null
4608 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4609 || version.equalsIgnoreCase("Test")
4610 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4612 System.err.println("Assuming project file with "
4613 + (version == null ? "null" : version)
4614 + " is compatible with Jalview version " + supported);
4619 return StringUtils.compareVersions(version, supported, "b") >= 0;
4623 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4625 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4627 if (newStructureViewers != null)
4629 sview.getBinding().setFinishedLoadingFromArchive(false);
4630 newStructureViewers.add(sview);
4634 protected void setLoadingFinishedForNewStructureViewers()
4636 if (newStructureViewers != null)
4638 for (JalviewStructureDisplayI sview : newStructureViewers)
4640 sview.getBinding().setFinishedLoadingFromArchive(true);
4642 newStructureViewers.clear();
4643 newStructureViewers = null;
4647 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4648 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4649 Viewport view, String uniqueSeqSetId, String viewId,
4650 List<JvAnnotRow> autoAlan)
4652 AlignFrame af = null;
4653 af = new AlignFrame(al, safeInt(view.getWidth()),
4654 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4658 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4659 // System.out.println("Jalview2XML AF " + e);
4660 // super.processKeyEvent(e);
4667 af.setFileName(file, FileFormat.Jalview);
4669 final AlignViewport viewport = af.getViewport();
4670 for (int i = 0; i < JSEQ.size(); i++)
4672 int colour = safeInt(JSEQ.get(i).getColour());
4673 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4679 viewport.setColourByReferenceSeq(true);
4680 viewport.setDisplayReferenceSeq(true);
4683 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4685 if (view.getSequenceSetId() != null)
4687 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4689 viewport.setSequenceSetId(uniqueSeqSetId);
4692 // propagate shared settings to this new view
4693 viewport.setHistoryList(av.getHistoryList());
4694 viewport.setRedoList(av.getRedoList());
4698 viewportsAdded.put(uniqueSeqSetId, viewport);
4700 // TODO: check if this method can be called repeatedly without
4701 // side-effects if alignpanel already registered.
4702 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4704 // apply Hidden regions to view.
4705 if (hiddenSeqs != null)
4707 for (int s = 0; s < JSEQ.size(); s++)
4709 SequenceGroup hidden = new SequenceGroup();
4710 boolean isRepresentative = false;
4711 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4713 isRepresentative = true;
4714 SequenceI sequenceToHide = al
4715 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4716 hidden.addSequence(sequenceToHide, false);
4717 // remove from hiddenSeqs list so we don't try to hide it twice
4718 hiddenSeqs.remove(sequenceToHide);
4720 if (isRepresentative)
4722 SequenceI representativeSequence = al.getSequenceAt(s);
4723 hidden.addSequence(representativeSequence, false);
4724 viewport.hideRepSequences(representativeSequence, hidden);
4728 SequenceI[] hseqs = hiddenSeqs
4729 .toArray(new SequenceI[hiddenSeqs.size()]);
4730 viewport.hideSequence(hseqs);
4733 // recover view properties and display parameters
4735 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4736 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4737 final int pidThreshold = safeInt(view.getPidThreshold());
4738 viewport.setThreshold(pidThreshold);
4740 viewport.setColourText(safeBoolean(view.isShowColourText()));
4742 viewport.setConservationSelected(
4743 safeBoolean(view.isConservationSelected()));
4744 viewport.setIncrement(safeInt(view.getConsThreshold()));
4745 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4746 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4747 viewport.setFont(new Font(view.getFontName(),
4748 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4750 ViewStyleI vs = viewport.getViewStyle();
4751 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4752 viewport.setViewStyle(vs);
4753 // TODO: allow custom charWidth/Heights to be restored by updating them
4754 // after setting font - which means set above to false
4755 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4756 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4757 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4759 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4761 viewport.setShowText(safeBoolean(view.isShowText()));
4763 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4764 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4765 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4766 viewport.setShowUnconserved(view.isShowUnconserved());
4767 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4769 if (view.getViewName() != null)
4771 viewport.setViewName(view.getViewName());
4772 af.setInitialTabVisible();
4774 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4775 safeInt(view.getWidth()), safeInt(view.getHeight()));
4776 // startSeq set in af.alignPanel.updateLayout below
4777 af.alignPanel.updateLayout();
4778 ColourSchemeI cs = null;
4779 // apply colourschemes
4780 if (view.getBgColour() != null)
4782 if (view.getBgColour().startsWith("ucs"))
4784 cs = getUserColourScheme(jm, view.getBgColour());
4786 else if (view.getBgColour().startsWith("Annotation"))
4788 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4789 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4796 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4797 view.getBgColour());
4802 * turn off 'alignment colour applies to all groups'
4803 * while restoring global colour scheme
4805 viewport.setColourAppliesToAllGroups(false);
4806 viewport.setGlobalColourScheme(cs);
4807 viewport.getResidueShading().setThreshold(pidThreshold,
4808 view.isIgnoreGapsinConsensus());
4809 viewport.getResidueShading()
4810 .setConsensus(viewport.getSequenceConsensusHash());
4811 if (safeBoolean(view.isConservationSelected()) && cs != null)
4813 viewport.getResidueShading()
4814 .setConservationInc(safeInt(view.getConsThreshold()));
4816 af.changeColour(cs);
4817 viewport.setColourAppliesToAllGroups(true);
4819 viewport.setShowSequenceFeatures(
4820 safeBoolean(view.isShowSequenceFeatures()));
4822 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4823 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4824 viewport.setFollowHighlight(view.isFollowHighlight());
4825 viewport.followSelection = view.isFollowSelection();
4826 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4827 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4828 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4829 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4830 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4831 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4832 viewport.setShowGroupConservation(view.isShowGroupConservation());
4833 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4834 viewport.setShowComplementFeaturesOnTop(
4835 view.isShowComplementFeaturesOnTop());
4837 // recover feature settings
4838 if (jm.getFeatureSettings() != null)
4840 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4841 .getFeatureRenderer();
4842 FeaturesDisplayed fdi;
4843 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4844 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
4846 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4847 Map<String, Float> featureOrder = new Hashtable<>();
4849 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
4852 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4853 String featureType = setting.getType();
4856 * restore feature filters (if any)
4858 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4860 if (filters != null)
4862 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
4864 if (!filter.isEmpty())
4866 fr.setFeatureFilter(featureType, filter);
4871 * restore feature colour scheme
4873 Color maxColour = new Color(setting.getColour());
4874 if (setting.getMincolour() != null)
4877 * minColour is always set unless a simple colour
4878 * (including for colour by label though it doesn't use it)
4880 Color minColour = new Color(setting.getMincolour().intValue());
4881 Color noValueColour = minColour;
4882 NoValueColour noColour = setting.getNoValueColour();
4883 if (noColour == NoValueColour.NONE)
4885 noValueColour = null;
4887 else if (noColour == NoValueColour.MAX)
4889 noValueColour = maxColour;
4891 float min = safeFloat(safeFloat(setting.getMin()));
4892 float max = setting.getMax() == null ? 1f
4893 : setting.getMax().floatValue();
4894 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4895 maxColour, noValueColour, min, max);
4896 if (setting.getAttributeName().size() > 0)
4898 gc.setAttributeName(setting.getAttributeName().toArray(
4899 new String[setting.getAttributeName().size()]));
4901 if (setting.getThreshold() != null)
4903 gc.setThreshold(setting.getThreshold().floatValue());
4904 int threshstate = safeInt(setting.getThreshstate());
4905 // -1 = None, 0 = Below, 1 = Above threshold
4906 if (threshstate == 0)
4908 gc.setBelowThreshold(true);
4910 else if (threshstate == 1)
4912 gc.setAboveThreshold(true);
4915 gc.setAutoScaled(true); // default
4916 if (setting.isAutoScale() != null)
4918 gc.setAutoScaled(setting.isAutoScale());
4920 if (setting.isColourByLabel() != null)
4922 gc.setColourByLabel(setting.isColourByLabel());
4924 // and put in the feature colour table.
4925 featureColours.put(featureType, gc);
4929 featureColours.put(featureType, new FeatureColour(maxColour));
4931 renderOrder[fs] = featureType;
4932 if (setting.getOrder() != null)
4934 featureOrder.put(featureType, setting.getOrder().floatValue());
4938 featureOrder.put(featureType, Float.valueOf(
4939 fs / jm.getFeatureSettings().getSetting().size()));
4941 if (safeBoolean(setting.isDisplay()))
4943 fdi.setVisible(featureType);
4946 Map<String, Boolean> fgtable = new Hashtable<>();
4947 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4949 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4950 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4952 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4953 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4954 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4955 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4956 fgtable, featureColours, 1.0f, featureOrder);
4957 fr.transferSettings(frs);
4960 if (view.getHiddenColumns().size() > 0)
4962 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4964 final HiddenColumns hc = view.getHiddenColumns().get(c);
4965 viewport.hideColumns(safeInt(hc.getStart()),
4966 safeInt(hc.getEnd()) /* +1 */);
4969 if (view.getCalcIdParam() != null)
4971 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4973 if (calcIdParam != null)
4975 if (recoverCalcIdParam(calcIdParam, viewport))
4980 Console.warn("Couldn't recover parameters for "
4981 + calcIdParam.getCalcId());
4986 af.setMenusFromViewport(viewport);
4987 af.setTitle(view.getTitle());
4988 // TODO: we don't need to do this if the viewport is aready visible.
4990 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4991 * has a 'cdna/protein complement' view, in which case save it in order to
4992 * populate a SplitFrame once all views have been read in.
4994 String complementaryViewId = view.getComplementId();
4995 if (complementaryViewId == null)
4997 Desktop.addInternalFrame(af, view.getTitle(),
4998 safeInt(view.getWidth()), safeInt(view.getHeight()));
4999 // recompute any autoannotation
5000 af.alignPanel.updateAnnotation(false, true);
5001 reorderAutoannotation(af, al, autoAlan);
5002 af.alignPanel.alignmentChanged();
5006 splitFrameCandidates.put(view, af);
5012 * Reads saved data to restore Colour by Annotation settings
5014 * @param viewAnnColour
5018 * @param checkGroupAnnColour
5021 private ColourSchemeI constructAnnotationColour(
5022 AnnotationColourScheme viewAnnColour, AlignFrame af,
5023 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5025 boolean propagateAnnColour = false;
5026 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5028 if (checkGroupAnnColour && al.getGroups() != null
5029 && al.getGroups().size() > 0)
5031 // pre 2.8.1 behaviour
5032 // check to see if we should transfer annotation colours
5033 propagateAnnColour = true;
5034 for (SequenceGroup sg : al.getGroups())
5036 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5038 propagateAnnColour = false;
5044 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5046 String annotationId = viewAnnColour.getAnnotation();
5047 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5050 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5052 if (matchedAnnotation == null
5053 && annAlignment.getAlignmentAnnotation() != null)
5055 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5058 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5060 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5065 if (matchedAnnotation == null)
5067 System.err.println("Failed to match annotation colour scheme for "
5071 if (matchedAnnotation.getThreshold() == null)
5073 matchedAnnotation.setThreshold(
5074 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5075 "Threshold", Color.black));
5078 AnnotationColourGradient cs = null;
5079 if (viewAnnColour.getColourScheme().equals("None"))
5081 cs = new AnnotationColourGradient(matchedAnnotation,
5082 new Color(safeInt(viewAnnColour.getMinColour())),
5083 new Color(safeInt(viewAnnColour.getMaxColour())),
5084 safeInt(viewAnnColour.getAboveThreshold()));
5086 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5088 cs = new AnnotationColourGradient(matchedAnnotation,
5089 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5090 safeInt(viewAnnColour.getAboveThreshold()));
5094 cs = new AnnotationColourGradient(matchedAnnotation,
5095 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5096 viewAnnColour.getColourScheme()),
5097 safeInt(viewAnnColour.getAboveThreshold()));
5100 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5101 boolean useOriginalColours = safeBoolean(
5102 viewAnnColour.isPredefinedColours());
5103 cs.setSeqAssociated(perSequenceOnly);
5104 cs.setPredefinedColours(useOriginalColours);
5106 if (propagateAnnColour && al.getGroups() != null)
5108 // Also use these settings for all the groups
5109 for (int g = 0; g < al.getGroups().size(); g++)
5111 SequenceGroup sg = al.getGroups().get(g);
5112 if (sg.getGroupColourScheme() == null)
5117 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5118 matchedAnnotation, sg.getColourScheme(),
5119 safeInt(viewAnnColour.getAboveThreshold()));
5120 sg.setColourScheme(groupScheme);
5121 groupScheme.setSeqAssociated(perSequenceOnly);
5122 groupScheme.setPredefinedColours(useOriginalColours);
5128 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5129 List<JvAnnotRow> autoAlan)
5131 // copy over visualization settings for autocalculated annotation in the
5133 if (al.getAlignmentAnnotation() != null)
5136 * Kludge for magic autoannotation names (see JAL-811)
5138 String[] magicNames = new String[] { "Consensus", "Quality",
5140 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5141 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5142 for (String nm : magicNames)
5144 visan.put(nm, nullAnnot);
5146 for (JvAnnotRow auan : autoAlan)
5148 visan.put(auan.template.label
5149 + (auan.template.getCalcId() == null ? ""
5150 : "\t" + auan.template.getCalcId()),
5153 int hSize = al.getAlignmentAnnotation().length;
5154 List<JvAnnotRow> reorder = new ArrayList<>();
5155 // work through any autoCalculated annotation already on the view
5156 // removing it if it should be placed in a different location on the
5157 // annotation panel.
5158 List<String> remains = new ArrayList<>(visan.keySet());
5159 for (int h = 0; h < hSize; h++)
5161 jalview.datamodel.AlignmentAnnotation jalan = al
5162 .getAlignmentAnnotation()[h];
5163 if (jalan.autoCalculated)
5166 JvAnnotRow valan = visan.get(k = jalan.label);
5167 if (jalan.getCalcId() != null)
5169 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5174 // delete the auto calculated row from the alignment
5175 al.deleteAnnotation(jalan, false);
5179 if (valan != nullAnnot)
5181 if (jalan != valan.template)
5183 // newly created autoannotation row instance
5184 // so keep a reference to the visible annotation row
5185 // and copy over all relevant attributes
5186 if (valan.template.graphHeight >= 0)
5189 jalan.graphHeight = valan.template.graphHeight;
5191 jalan.visible = valan.template.visible;
5193 reorder.add(new JvAnnotRow(valan.order, jalan));
5198 // Add any (possibly stale) autocalculated rows that were not appended to
5199 // the view during construction
5200 for (String other : remains)
5202 JvAnnotRow othera = visan.get(other);
5203 if (othera != nullAnnot && othera.template.getCalcId() != null
5204 && othera.template.getCalcId().length() > 0)
5206 reorder.add(othera);
5209 // now put the automatic annotation in its correct place
5210 int s = 0, srt[] = new int[reorder.size()];
5211 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5212 for (JvAnnotRow jvar : reorder)
5215 srt[s++] = jvar.order;
5218 jalview.util.QuickSort.sort(srt, rws);
5219 // and re-insert the annotation at its correct position
5220 for (JvAnnotRow jvar : rws)
5222 al.addAnnotation(jvar.template, jvar.order);
5224 af.alignPanel.adjustAnnotationHeight();
5228 Hashtable skipList = null;
5231 * TODO remove this method
5234 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5235 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5236 * throw new Error("Implementation Error. No skipList defined for this
5237 * Jalview2XML instance."); } return (AlignFrame)
5238 * skipList.get(view.getSequenceSetId()); }
5242 * Check if the Jalview view contained in object should be skipped or not.
5245 * @return true if view's sequenceSetId is a key in skipList
5247 private boolean skipViewport(JalviewModel object)
5249 if (skipList == null)
5253 String id = object.getViewport().get(0).getSequenceSetId();
5254 if (skipList.containsKey(id))
5256 Console.debug("Skipping seuqence set id " + id);
5262 public void addToSkipList(AlignFrame af)
5264 if (skipList == null)
5266 skipList = new Hashtable();
5268 skipList.put(af.getViewport().getSequenceSetId(), af);
5271 public void clearSkipList()
5273 if (skipList != null)
5280 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5281 boolean ignoreUnrefed, String uniqueSeqSetId)
5283 jalview.datamodel.AlignmentI ds = getDatasetFor(
5284 vamsasSet.getDatasetId());
5285 AlignmentI xtant_ds = ds;
5286 if (xtant_ds == null)
5288 // good chance we are about to create a new dataset, but check if we've
5289 // seen some of the dataset sequence IDs before.
5290 // TODO: skip this check if we are working with project generated by
5291 // version 2.11 or later
5292 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5293 if (xtant_ds != null)
5296 addDatasetRef(vamsasSet.getDatasetId(), ds);
5299 Vector<SequenceI> dseqs = null;
5302 // recovering an alignment View
5303 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5304 if (seqSetDS != null)
5306 if (ds != null && ds != seqSetDS)
5309 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5310 + " - CDS/Protein crossreference data may be lost");
5311 if (xtant_ds != null)
5313 // This can only happen if the unique sequence set ID was bound to a
5314 // dataset that did not contain any of the sequences in the view
5315 // currently being restored.
5317 "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.");
5321 addDatasetRef(vamsasSet.getDatasetId(), ds);
5326 // try even harder to restore dataset
5327 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5328 // create a list of new dataset sequences
5329 dseqs = new Vector<>();
5331 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5333 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5334 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5336 // create a new dataset
5339 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5340 dseqs.copyInto(dsseqs);
5341 ds = new jalview.datamodel.Alignment(dsseqs);
5342 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5343 + " for alignment " + System.identityHashCode(al));
5344 addDatasetRef(vamsasSet.getDatasetId(), ds);
5346 // set the dataset for the newly imported alignment.
5347 if (al.getDataset() == null && !ignoreUnrefed)
5350 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5351 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5353 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5357 * XML dataset sequence ID to materialised dataset reference
5359 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5362 * @return the first materialised dataset reference containing a dataset
5363 * sequence referenced in the given view
5365 * - sequences from the view
5367 AlignmentI checkIfHasDataset(List<Sequence> list)
5369 for (Sequence restoredSeq : list)
5371 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5372 if (datasetFor != null)
5381 * Register ds as the containing dataset for the dataset sequences referenced
5382 * by sequences in list
5385 * - sequences in a view
5388 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5390 for (Sequence restoredSeq : list)
5392 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5393 if (prevDS != null && prevDS != ds)
5395 Console.warn("Dataset sequence appears in many datasets: "
5396 + restoredSeq.getDsseqid());
5397 // TODO: try to merge!
5405 * sequence definition to create/merge dataset sequence for
5409 * vector to add new dataset sequence to
5410 * @param ignoreUnrefed
5411 * - when true, don't create new sequences from vamsasSeq if it's id
5412 * doesn't already have an asssociated Jalview sequence.
5414 * - used to reorder the sequence in the alignment according to the
5415 * vamsasSeq array ordering, to preserve ordering of dataset
5417 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5418 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5421 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5423 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5424 boolean reorder = false;
5425 SequenceI dsq = null;
5426 if (sq != null && sq.getDatasetSequence() != null)
5428 dsq = sq.getDatasetSequence();
5434 if (sq == null && ignoreUnrefed)
5438 String sqid = vamsasSeq.getDsseqid();
5441 // need to create or add a new dataset sequence reference to this sequence
5444 dsq = seqRefIds.get(sqid);
5449 // make a new dataset sequence
5450 dsq = sq.createDatasetSequence();
5453 // make up a new dataset reference for this sequence
5454 sqid = seqHash(dsq);
5456 dsq.setVamsasId(uniqueSetSuffix + sqid);
5457 seqRefIds.put(sqid, dsq);
5462 dseqs.addElement(dsq);
5467 ds.addSequence(dsq);
5473 { // make this dataset sequence sq's dataset sequence
5474 sq.setDatasetSequence(dsq);
5475 // and update the current dataset alignment
5480 if (!dseqs.contains(dsq))
5487 if (ds.findIndex(dsq) < 0)
5489 ds.addSequence(dsq);
5496 // TODO: refactor this as a merge dataset sequence function
5497 // now check that sq (the dataset sequence) sequence really is the union of
5498 // all references to it
5499 // boolean pre = sq.getStart() < dsq.getStart();
5500 // boolean post = sq.getEnd() > dsq.getEnd();
5504 // StringBuffer sb = new StringBuffer();
5505 String newres = jalview.analysis.AlignSeq.extractGaps(
5506 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5507 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5508 && newres.length() > dsq.getLength())
5510 // Update with the longer sequence.
5514 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5515 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5516 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5517 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5519 dsq.setSequence(newres);
5521 // TODO: merges will never happen if we 'know' we have the real dataset
5522 // sequence - this should be detected when id==dssid
5524 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5525 // + (pre ? "prepended" : "") + " "
5526 // + (post ? "appended" : ""));
5531 // sequence refs are identical. We may need to update the existing dataset
5532 // alignment with this one, though.
5533 if (ds != null && dseqs == null)
5535 int opos = ds.findIndex(dsq);
5536 SequenceI tseq = null;
5537 if (opos != -1 && vseqpos != opos)
5539 // remove from old position
5540 ds.deleteSequence(dsq);
5542 if (vseqpos < ds.getHeight())
5544 if (vseqpos != opos)
5546 // save sequence at destination position
5547 tseq = ds.getSequenceAt(vseqpos);
5548 ds.replaceSequenceAt(vseqpos, dsq);
5549 ds.addSequence(tseq);
5554 ds.addSequence(dsq);
5561 * TODO use AlignmentI here and in related methods - needs
5562 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5564 Hashtable<String, AlignmentI> datasetIds = null;
5566 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5568 private AlignmentI getDatasetFor(String datasetId)
5570 if (datasetIds == null)
5572 datasetIds = new Hashtable<>();
5575 if (datasetIds.containsKey(datasetId))
5577 return datasetIds.get(datasetId);
5582 private void addDatasetRef(String datasetId, AlignmentI dataset)
5584 if (datasetIds == null)
5586 datasetIds = new Hashtable<>();
5588 datasetIds.put(datasetId, dataset);
5592 * make a new dataset ID for this jalview dataset alignment
5597 private String getDatasetIdRef(AlignmentI dataset)
5599 if (dataset.getDataset() != null)
5602 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5604 String datasetId = makeHashCode(dataset, null);
5605 if (datasetId == null)
5607 // make a new datasetId and record it
5608 if (dataset2Ids == null)
5610 dataset2Ids = new IdentityHashMap<>();
5614 datasetId = dataset2Ids.get(dataset);
5616 if (datasetId == null)
5618 datasetId = "ds" + dataset2Ids.size() + 1;
5619 dataset2Ids.put(dataset, datasetId);
5626 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5627 * constructed as a special subclass GeneLocus.
5629 * @param datasetSequence
5632 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5634 for (int d = 0; d < sequence.getDBRef().size(); d++)
5636 DBRef dr = sequence.getDBRef().get(d);
5640 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5641 dr.getAccessionId());
5645 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5646 dr.getAccessionId());
5648 if (dr.getMapping() != null)
5650 entry.setMap(addMapping(dr.getMapping()));
5652 entry.setCanonical(dr.isCanonical());
5653 datasetSequence.addDBRef(entry);
5657 private jalview.datamodel.Mapping addMapping(Mapping m)
5659 SequenceI dsto = null;
5660 // Mapping m = dr.getMapping();
5661 int fr[] = new int[m.getMapListFrom().size() * 2];
5662 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5663 for (int _i = 0; from.hasNext(); _i += 2)
5665 MapListFrom mf = from.next();
5666 fr[_i] = mf.getStart();
5667 fr[_i + 1] = mf.getEnd();
5669 int fto[] = new int[m.getMapListTo().size() * 2];
5670 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5671 for (int _i = 0; to.hasNext(); _i += 2)
5673 MapListTo mf = to.next();
5674 fto[_i] = mf.getStart();
5675 fto[_i + 1] = mf.getEnd();
5677 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5678 fto, m.getMapFromUnit().intValue(),
5679 m.getMapToUnit().intValue());
5682 * (optional) choice of dseqFor or Sequence
5684 if (m.getDseqFor() != null)
5686 String dsfor = m.getDseqFor();
5687 if (seqRefIds.containsKey(dsfor))
5692 jmap.setTo(seqRefIds.get(dsfor));
5696 frefedSequence.add(newMappingRef(dsfor, jmap));
5699 else if (m.getSequence() != null)
5702 * local sequence definition
5704 Sequence ms = m.getSequence();
5705 SequenceI djs = null;
5706 String sqid = ms.getDsseqid();
5707 if (sqid != null && sqid.length() > 0)
5710 * recover dataset sequence
5712 djs = seqRefIds.get(sqid);
5717 "Warning - making up dataset sequence id for DbRef sequence map reference");
5718 sqid = ((Object) ms).toString(); // make up a new hascode for
5719 // undefined dataset sequence hash
5720 // (unlikely to happen)
5726 * make a new dataset sequence and add it to refIds hash
5728 djs = new jalview.datamodel.Sequence(ms.getName(),
5730 djs.setStart(jmap.getMap().getToLowest());
5731 djs.setEnd(jmap.getMap().getToHighest());
5732 djs.setVamsasId(uniqueSetSuffix + sqid);
5734 incompleteSeqs.put(sqid, djs);
5735 seqRefIds.put(sqid, djs);
5738 Console.debug("about to recurse on addDBRefs.");
5747 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5748 * view as XML (but not to file), and then reloading it
5753 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5756 JalviewModel jm = saveState(ap, null, null, null);
5759 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5760 ap.getAlignment().getDataset());
5762 uniqueSetSuffix = "";
5763 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5764 jm.getViewport().get(0).setId(null);
5765 // we don't overwrite the view we just copied
5767 if (this.frefedSequence == null)
5769 frefedSequence = new Vector<>();
5772 viewportsAdded.clear();
5774 AlignFrame af = loadFromObject(jm, null, false, null);
5775 af.getAlignPanels().clear();
5776 af.closeMenuItem_actionPerformed(true);
5779 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5780 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5781 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5782 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5783 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5786 return af.alignPanel;
5789 private Hashtable jvids2vobj;
5792 * set the object to ID mapping tables used to write/recover objects and XML
5793 * ID strings for the jalview project. If external tables are provided then
5794 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5795 * object goes out of scope. - also populates the datasetIds hashtable with
5796 * alignment objects containing dataset sequences
5799 * Map from ID strings to jalview datamodel
5801 * Map from jalview datamodel to ID strings
5805 public void setObjectMappingTables(Hashtable vobj2jv,
5806 IdentityHashMap jv2vobj)
5808 this.jv2vobj = jv2vobj;
5809 this.vobj2jv = vobj2jv;
5810 Iterator ds = jv2vobj.keySet().iterator();
5812 while (ds.hasNext())
5814 Object jvobj = ds.next();
5815 id = jv2vobj.get(jvobj).toString();
5816 if (jvobj instanceof jalview.datamodel.Alignment)
5818 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5820 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5823 else if (jvobj instanceof jalview.datamodel.Sequence)
5825 // register sequence object so the XML parser can recover it.
5826 if (seqRefIds == null)
5828 seqRefIds = new HashMap<>();
5830 if (seqsToIds == null)
5832 seqsToIds = new IdentityHashMap<>();
5834 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5835 seqsToIds.put((SequenceI) jvobj, id);
5837 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5840 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5841 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5842 if (jvann.annotationId == null)
5844 jvann.annotationId = anid;
5846 if (!jvann.annotationId.equals(anid))
5848 // TODO verify that this is the correct behaviour
5849 Console.warn("Overriding Annotation ID for " + anid
5850 + " from different id : " + jvann.annotationId);
5851 jvann.annotationId = anid;
5854 else if (jvobj instanceof String)
5856 if (jvids2vobj == null)
5858 jvids2vobj = new Hashtable();
5859 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5864 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5870 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5871 * objects created from the project archive. If string is null (default for
5872 * construction) then suffix will be set automatically.
5876 public void setUniqueSetSuffix(String string)
5878 uniqueSetSuffix = string;
5883 * uses skipList2 as the skipList for skipping views on sequence sets
5884 * associated with keys in the skipList
5888 public void setSkipList(Hashtable skipList2)
5890 skipList = skipList2;
5894 * Reads the jar entry of given name and returns its contents, or null if the
5895 * entry is not found.
5898 * @param jarEntryName
5901 protected String readJarEntry(jarInputStreamProvider jprovider,
5902 String jarEntryName)
5904 String result = null;
5905 BufferedReader in = null;
5910 * Reopen the jar input stream and traverse its entries to find a matching
5913 JarInputStream jin = jprovider.getJarInputStream();
5914 JarEntry entry = null;
5917 entry = jin.getNextJarEntry();
5918 } while (entry != null && !entry.getName().equals(jarEntryName));
5922 StringBuilder out = new StringBuilder(256);
5923 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5926 while ((data = in.readLine()) != null)
5930 result = out.toString();
5935 "Couldn't find entry in Jalview Jar for " + jarEntryName);
5937 } catch (Exception ex)
5939 ex.printStackTrace();
5947 } catch (IOException e)
5958 * Returns an incrementing counter (0, 1, 2...)
5962 private synchronized int nextCounter()
5968 * Loads any saved PCA viewers
5973 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
5977 List<PcaViewer> pcaviewers = model.getPcaViewer();
5978 for (PcaViewer viewer : pcaviewers)
5980 String modelName = viewer.getScoreModelName();
5981 SimilarityParamsI params = new SimilarityParams(
5982 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
5983 viewer.isIncludeGaps(),
5984 viewer.isDenominateByShortestLength());
5987 * create the panel (without computing the PCA)
5989 PCAPanel panel = new PCAPanel(ap, modelName, params);
5991 panel.setTitle(viewer.getTitle());
5992 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
5993 viewer.getWidth(), viewer.getHeight()));
5995 boolean showLabels = viewer.isShowLabels();
5996 panel.setShowLabels(showLabels);
5997 panel.getRotatableCanvas().setShowLabels(showLabels);
5998 panel.getRotatableCanvas()
5999 .setBgColour(new Color(viewer.getBgColour()));
6000 panel.getRotatableCanvas()
6001 .setApplyToAllViews(viewer.isLinkToAllViews());
6004 * load PCA output data
6006 ScoreModelI scoreModel = ScoreModels.getInstance()
6007 .getScoreModel(modelName, ap);
6008 PCA pca = new PCA(null, scoreModel, params);
6009 PcaDataType pcaData = viewer.getPcaData();
6011 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6012 pca.setPairwiseScores(pairwise);
6014 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6015 pca.setTridiagonal(triDiag);
6017 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6018 pca.setEigenmatrix(result);
6020 panel.getPcaModel().setPCA(pca);
6023 * we haven't saved the input data! (JAL-2647 to do)
6025 panel.setInputData(null);
6028 * add the sequence points for the PCA display
6030 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6031 for (SequencePoint sp : viewer.getSequencePoint())
6033 String seqId = sp.getSequenceRef();
6034 SequenceI seq = seqRefIds.get(seqId);
6037 throw new IllegalStateException(
6038 "Unmatched seqref for PCA: " + seqId);
6040 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6041 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6043 seqPoints.add(seqPoint);
6045 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6048 * set min-max ranges and scale after setPoints (which recomputes them)
6050 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6051 SeqPointMin spMin = viewer.getSeqPointMin();
6052 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6054 SeqPointMax spMax = viewer.getSeqPointMax();
6055 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6057 panel.getRotatableCanvas().setSeqMinMax(min, max);
6059 // todo: hold points list in PCAModel only
6060 panel.getPcaModel().setSequencePoints(seqPoints);
6062 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6063 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6064 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6066 // is this duplication needed?
6067 panel.setTop(seqPoints.size() - 1);
6068 panel.getPcaModel().setTop(seqPoints.size() - 1);
6071 * add the axes' end points for the display
6073 for (int i = 0; i < 3; i++)
6075 Axis axis = viewer.getAxis().get(i);
6076 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6077 axis.getXPos(), axis.getYPos(), axis.getZPos());
6080 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6081 "label.calc_title", "PCA", modelName), 475, 450);
6083 } catch (Exception ex)
6085 Console.error("Error loading PCA: " + ex.toString());
6090 * Creates a new structure viewer window
6097 protected void createStructureViewer(ViewerType viewerType,
6098 final Entry<String, StructureViewerModel> viewerData,
6099 AlignFrame af, jarInputStreamProvider jprovider)
6101 final StructureViewerModel viewerModel = viewerData.getValue();
6102 String sessionFilePath = null;
6104 if (viewerType == ViewerType.JMOL)
6106 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6110 String viewerJarEntryName = getViewerJarEntryName(
6111 viewerModel.getViewId());
6112 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6113 "viewerSession", ".tmp");
6115 final String sessionPath = sessionFilePath;
6116 final String sviewid = viewerData.getKey();
6119 SwingUtilities.invokeAndWait(new Runnable()
6124 JalviewStructureDisplayI sview = null;
6127 sview = StructureViewer.createView(viewerType, af.alignPanel,
6128 viewerModel, sessionPath, sviewid);
6129 addNewStructureViewer(sview);
6130 } catch (OutOfMemoryError ex)
6132 new OOMWarning("Restoring structure view for " + viewerType,
6133 (OutOfMemoryError) ex.getCause());
6134 if (sview != null && sview.isVisible())
6136 sview.closeViewer(false);
6137 sview.setVisible(false);
6143 } catch (InvocationTargetException | InterruptedException ex)
6145 Console.warn("Unexpected error when opening " + viewerType
6146 + " structure viewer", ex);
6151 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6152 * the path of the file. "load file" commands are rewritten to change the
6153 * original PDB file names to those created as the Jalview project is loaded.
6159 private String rewriteJmolSession(StructureViewerModel svattrib,
6160 jarInputStreamProvider jprovider)
6162 String state = svattrib.getStateData(); // Jalview < 2.9
6163 if (state == null || state.isEmpty()) // Jalview >= 2.9
6165 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6166 state = readJarEntry(jprovider, jarEntryName);
6168 // TODO or simpler? for each key in oldFiles,
6169 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6170 // (allowing for different path escapings)
6171 StringBuilder rewritten = new StringBuilder(state.length());
6172 int cp = 0, ncp, ecp;
6173 Map<File, StructureData> oldFiles = svattrib.getFileData();
6174 while ((ncp = state.indexOf("load ", cp)) > -1)
6178 // look for next filename in load statement
6179 rewritten.append(state.substring(cp,
6180 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6181 String oldfilenam = state.substring(ncp,
6182 ecp = state.indexOf("\"", ncp));
6183 // recover the new mapping data for this old filename
6184 // have to normalize filename - since Jmol and jalview do
6185 // filename translation differently.
6186 StructureData filedat = oldFiles.get(new File(oldfilenam));
6187 if (filedat == null)
6189 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6190 filedat = oldFiles.get(new File(reformatedOldFilename));
6192 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6193 rewritten.append("\"");
6194 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6195 // look for next file statement.
6196 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6200 // just append rest of state
6201 rewritten.append(state.substring(cp));
6205 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6206 rewritten = new StringBuilder(state);
6207 rewritten.append("; load append ");
6208 for (File id : oldFiles.keySet())
6210 // add pdb files that should be present in the viewer
6211 StructureData filedat = oldFiles.get(id);
6212 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6214 rewritten.append(";");
6217 if (rewritten.length() == 0)
6221 final String history = "history = ";
6222 int historyIndex = rewritten.indexOf(history);
6223 if (historyIndex > -1)
6226 * change "history = [true|false];" to "history = [1|0];"
6228 historyIndex += history.length();
6229 String val = rewritten.substring(historyIndex, historyIndex + 5);
6230 if (val.startsWith("true"))
6232 rewritten.replace(historyIndex, historyIndex + 4, "1");
6234 else if (val.startsWith("false"))
6236 rewritten.replace(historyIndex, historyIndex + 5, "0");
6242 File tmp = File.createTempFile("viewerSession", ".tmp");
6243 try (OutputStream os = new FileOutputStream(tmp))
6245 InputStream is = new ByteArrayInputStream(
6246 rewritten.toString().getBytes());
6248 return tmp.getAbsolutePath();
6250 } catch (IOException e)
6252 Console.error("Error restoring Jmol session: " + e.toString());
6258 * Populates an XML model of the feature colour scheme for one feature type
6260 * @param featureType
6264 public static Colour marshalColour(String featureType,
6265 FeatureColourI fcol)
6267 Colour col = new Colour();
6268 if (fcol.isSimpleColour())
6270 col.setRGB(Format.getHexString(fcol.getColour()));
6274 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6275 col.setMin(fcol.getMin());
6276 col.setMax(fcol.getMax());
6277 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6278 col.setAutoScale(fcol.isAutoScaled());
6279 col.setThreshold(fcol.getThreshold());
6280 col.setColourByLabel(fcol.isColourByLabel());
6281 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6282 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6283 : ThresholdType.NONE));
6284 if (fcol.isColourByAttribute())
6286 final String[] attName = fcol.getAttributeName();
6287 col.getAttributeName().add(attName[0]);
6288 if (attName.length > 1)
6290 col.getAttributeName().add(attName[1]);
6293 Color noColour = fcol.getNoColour();
6294 if (noColour == null)
6296 col.setNoValueColour(NoValueColour.NONE);
6298 else if (noColour == fcol.getMaxColour())
6300 col.setNoValueColour(NoValueColour.MAX);
6304 col.setNoValueColour(NoValueColour.MIN);
6307 col.setName(featureType);
6312 * Populates an XML model of the feature filter(s) for one feature type
6314 * @param firstMatcher
6315 * the first (or only) match condition)
6317 * remaining match conditions (if any)
6319 * if true, conditions are and-ed, else or-ed
6321 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6322 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6325 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6327 if (filters.hasNext())
6332 CompoundMatcher compound = new CompoundMatcher();
6333 compound.setAnd(and);
6334 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6335 firstMatcher, Collections.emptyIterator(), and);
6336 // compound.addMatcherSet(matcher1);
6337 compound.getMatcherSet().add(matcher1);
6338 FeatureMatcherI nextMatcher = filters.next();
6339 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6340 nextMatcher, filters, and);
6341 // compound.addMatcherSet(matcher2);
6342 compound.getMatcherSet().add(matcher2);
6343 result.setCompoundMatcher(compound);
6348 * single condition matcher
6350 // MatchCondition matcherModel = new MatchCondition();
6351 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6352 matcherModel.setCondition(
6353 firstMatcher.getMatcher().getCondition().getStableName());
6354 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6355 if (firstMatcher.isByAttribute())
6357 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6358 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6359 String[] attName = firstMatcher.getAttribute();
6360 matcherModel.getAttributeName().add(attName[0]); // attribute
6361 if (attName.length > 1)
6363 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6366 else if (firstMatcher.isByLabel())
6368 matcherModel.setBy(FilterBy.BY_LABEL);
6370 else if (firstMatcher.isByScore())
6372 matcherModel.setBy(FilterBy.BY_SCORE);
6374 result.setMatchCondition(matcherModel);
6381 * Loads one XML model of a feature filter to a Jalview object
6383 * @param featureType
6384 * @param matcherSetModel
6387 public static FeatureMatcherSetI parseFilter(String featureType,
6388 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6390 FeatureMatcherSetI result = new FeatureMatcherSet();
6393 parseFilterConditions(result, matcherSetModel, true);
6394 } catch (IllegalStateException e)
6396 // mixing AND and OR conditions perhaps
6398 String.format("Error reading filter conditions for '%s': %s",
6399 featureType, e.getMessage()));
6400 // return as much as was parsed up to the error
6407 * Adds feature match conditions to matcherSet as unmarshalled from XML
6408 * (possibly recursively for compound conditions)
6411 * @param matcherSetModel
6413 * if true, multiple conditions are AND-ed, else they are OR-ed
6414 * @throws IllegalStateException
6415 * if AND and OR conditions are mixed
6417 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6418 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6421 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6422 .getMatchCondition();
6428 FilterBy filterBy = mc.getBy();
6429 Condition cond = Condition.fromString(mc.getCondition());
6430 String pattern = mc.getValue();
6431 FeatureMatcherI matchCondition = null;
6432 if (filterBy == FilterBy.BY_LABEL)
6434 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6436 else if (filterBy == FilterBy.BY_SCORE)
6438 matchCondition = FeatureMatcher.byScore(cond, pattern);
6441 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6443 final List<String> attributeName = mc.getAttributeName();
6444 String[] attNames = attributeName
6445 .toArray(new String[attributeName.size()]);
6446 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6451 * note this throws IllegalStateException if AND-ing to a
6452 * previously OR-ed compound condition, or vice versa
6456 matcherSet.and(matchCondition);
6460 matcherSet.or(matchCondition);
6466 * compound condition
6468 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6469 .getCompoundMatcher().getMatcherSet();
6470 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6471 if (matchers.size() == 2)
6473 parseFilterConditions(matcherSet, matchers.get(0), anded);
6474 parseFilterConditions(matcherSet, matchers.get(1), anded);
6478 System.err.println("Malformed compound filter condition");
6484 * Loads one XML model of a feature colour to a Jalview object
6486 * @param colourModel
6489 public static FeatureColourI parseColour(Colour colourModel)
6491 FeatureColourI colour = null;
6493 if (colourModel.getMax() != null)
6495 Color mincol = null;
6496 Color maxcol = null;
6497 Color noValueColour = null;
6501 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6502 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6503 } catch (Exception e)
6505 Console.warn("Couldn't parse out graduated feature color.", e);
6508 NoValueColour noCol = colourModel.getNoValueColour();
6509 if (noCol == NoValueColour.MIN)
6511 noValueColour = mincol;
6513 else if (noCol == NoValueColour.MAX)
6515 noValueColour = maxcol;
6518 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6519 safeFloat(colourModel.getMin()),
6520 safeFloat(colourModel.getMax()));
6521 final List<String> attributeName = colourModel.getAttributeName();
6522 String[] attributes = attributeName
6523 .toArray(new String[attributeName.size()]);
6524 if (attributes != null && attributes.length > 0)
6526 colour.setAttributeName(attributes);
6528 if (colourModel.isAutoScale() != null)
6530 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6532 if (colourModel.isColourByLabel() != null)
6534 colour.setColourByLabel(
6535 colourModel.isColourByLabel().booleanValue());
6537 if (colourModel.getThreshold() != null)
6539 colour.setThreshold(colourModel.getThreshold().floatValue());
6541 ThresholdType ttyp = colourModel.getThreshType();
6542 if (ttyp == ThresholdType.ABOVE)
6544 colour.setAboveThreshold(true);
6546 else if (ttyp == ThresholdType.BELOW)
6548 colour.setBelowThreshold(true);
6553 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6554 colour = new FeatureColour(color);