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 jalview.analysis.Conservation;
28 import jalview.analysis.PCA;
29 import jalview.analysis.scoremodels.ScoreModels;
30 import jalview.analysis.scoremodels.SimilarityParams;
31 import jalview.api.FeatureColourI;
32 import jalview.api.ViewStyleI;
33 import jalview.api.analysis.ScoreModelI;
34 import jalview.api.analysis.SimilarityParamsI;
35 import jalview.api.structures.JalviewStructureDisplayI;
36 import jalview.bin.Cache;
37 import jalview.datamodel.AlignedCodonFrame;
38 import jalview.datamodel.Alignment;
39 import jalview.datamodel.AlignmentAnnotation;
40 import jalview.datamodel.AlignmentI;
41 import jalview.datamodel.DBRefEntry;
42 import jalview.datamodel.GraphLine;
43 import jalview.datamodel.PDBEntry;
44 import jalview.datamodel.Point;
45 import jalview.datamodel.RnaViewerModel;
46 import jalview.datamodel.SequenceFeature;
47 import jalview.datamodel.SequenceGroup;
48 import jalview.datamodel.SequenceI;
49 import jalview.datamodel.StructureViewerModel;
50 import jalview.datamodel.StructureViewerModel.StructureData;
51 import jalview.datamodel.features.FeatureMatcher;
52 import jalview.datamodel.features.FeatureMatcherI;
53 import jalview.datamodel.features.FeatureMatcherSet;
54 import jalview.datamodel.features.FeatureMatcherSetI;
55 import jalview.ext.varna.RnaModel;
56 import jalview.gui.AlignFrame;
57 import jalview.gui.AlignViewport;
58 import jalview.gui.AlignmentPanel;
59 import jalview.gui.AppVarna;
60 import jalview.gui.ChimeraViewFrame;
61 import jalview.gui.Desktop;
62 import jalview.gui.FeatureRenderer;
63 import jalview.gui.JvOptionPane;
64 import jalview.gui.OOMWarning;
65 import jalview.gui.PCAPanel;
66 import jalview.gui.PaintRefresher;
67 import jalview.gui.SplitFrame;
68 import jalview.gui.StructureViewer;
69 import jalview.gui.StructureViewer.ViewerType;
70 import jalview.gui.StructureViewerBase;
71 import jalview.gui.TreePanel;
72 import jalview.io.BackupFiles;
73 import jalview.io.DataSourceType;
74 import jalview.io.FileFormat;
75 import jalview.io.NewickFile;
76 import jalview.math.Matrix;
77 import jalview.math.MatrixI;
78 import jalview.renderer.ResidueShaderI;
79 import jalview.schemes.AnnotationColourGradient;
80 import jalview.schemes.ColourSchemeI;
81 import jalview.schemes.ColourSchemeProperty;
82 import jalview.schemes.FeatureColour;
83 import jalview.schemes.ResidueProperties;
84 import jalview.schemes.UserColourScheme;
85 import jalview.structures.models.AAStructureBindingModel;
86 import jalview.util.Format;
87 import jalview.util.MessageManager;
88 import jalview.util.Platform;
89 import jalview.util.StringUtils;
90 import jalview.util.jarInputStreamProvider;
91 import jalview.util.matcher.Condition;
92 import jalview.viewmodel.AlignmentViewport;
93 import jalview.viewmodel.PCAModel;
94 import jalview.viewmodel.ViewportRanges;
95 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
96 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
97 import jalview.ws.jws2.Jws2Discoverer;
98 import jalview.ws.jws2.dm.AAConSettings;
99 import jalview.ws.jws2.jabaws2.Jws2Instance;
100 import jalview.ws.params.ArgumentI;
101 import jalview.ws.params.AutoCalcSetting;
102 import jalview.ws.params.WsParamSetI;
103 import jalview.xml.binding.jalview.AlcodonFrame;
104 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
105 import jalview.xml.binding.jalview.Annotation;
106 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
107 import jalview.xml.binding.jalview.AnnotationColourScheme;
108 import jalview.xml.binding.jalview.AnnotationElement;
109 import jalview.xml.binding.jalview.DoubleMatrix;
110 import jalview.xml.binding.jalview.DoubleVector;
111 import jalview.xml.binding.jalview.Feature;
112 import jalview.xml.binding.jalview.Feature.OtherData;
113 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
114 import jalview.xml.binding.jalview.FilterBy;
115 import jalview.xml.binding.jalview.JalviewModel;
116 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
117 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
118 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
119 import jalview.xml.binding.jalview.JalviewModel.JGroup;
120 import jalview.xml.binding.jalview.JalviewModel.JSeq;
121 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
122 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
123 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
124 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
125 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
126 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
127 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
128 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
129 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
130 import jalview.xml.binding.jalview.JalviewModel.Tree;
131 import jalview.xml.binding.jalview.JalviewModel.UserColours;
132 import jalview.xml.binding.jalview.JalviewModel.Viewport;
133 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
134 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
135 import jalview.xml.binding.jalview.JalviewUserColours;
136 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
137 import jalview.xml.binding.jalview.MapListType.MapListFrom;
138 import jalview.xml.binding.jalview.MapListType.MapListTo;
139 import jalview.xml.binding.jalview.Mapping;
140 import jalview.xml.binding.jalview.NoValueColour;
141 import jalview.xml.binding.jalview.ObjectFactory;
142 import jalview.xml.binding.jalview.PcaDataType;
143 import jalview.xml.binding.jalview.Pdbentry.Property;
144 import jalview.xml.binding.jalview.Sequence;
145 import jalview.xml.binding.jalview.Sequence.DBRef;
146 import jalview.xml.binding.jalview.SequenceSet;
147 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
148 import jalview.xml.binding.jalview.ThresholdType;
149 import jalview.xml.binding.jalview.VAMSAS;
151 import java.awt.Color;
152 import java.awt.Font;
153 import java.awt.Rectangle;
154 import java.io.BufferedReader;
155 import java.io.ByteArrayInputStream;
156 import java.io.DataInputStream;
157 import java.io.DataOutputStream;
159 import java.io.FileInputStream;
160 import java.io.FileOutputStream;
161 import java.io.IOException;
162 import java.io.InputStreamReader;
163 import java.io.OutputStreamWriter;
164 import java.io.PrintWriter;
165 import java.lang.reflect.InvocationTargetException;
166 import java.math.BigInteger;
167 import java.net.MalformedURLException;
169 import java.util.ArrayList;
170 import java.util.Arrays;
171 import java.util.Collections;
172 import java.util.Enumeration;
173 import java.util.GregorianCalendar;
174 import java.util.HashMap;
175 import java.util.HashSet;
176 import java.util.Hashtable;
177 import java.util.IdentityHashMap;
178 import java.util.Iterator;
179 import java.util.LinkedHashMap;
180 import java.util.List;
181 import java.util.Map;
182 import java.util.Map.Entry;
183 import java.util.Set;
184 import java.util.Vector;
185 import java.util.jar.JarEntry;
186 import java.util.jar.JarInputStream;
187 import java.util.jar.JarOutputStream;
189 import javax.swing.JInternalFrame;
190 import javax.swing.SwingUtilities;
191 import javax.xml.bind.JAXBContext;
192 import javax.xml.bind.JAXBElement;
193 import javax.xml.bind.Marshaller;
194 import javax.xml.datatype.DatatypeConfigurationException;
195 import javax.xml.datatype.DatatypeFactory;
196 import javax.xml.datatype.XMLGregorianCalendar;
197 import javax.xml.stream.XMLInputFactory;
198 import javax.xml.stream.XMLStreamReader;
201 * Write out the current jalview desktop state as a Jalview XML stream.
203 * Note: the vamsas objects referred to here are primitive versions of the
204 * VAMSAS project schema elements - they are not the same and most likely never
208 * @version $Revision: 1.134 $
210 public class Jalview2XML
213 // BH 2018 we add the .jvp binary extension to J2S so that
214 // it will declare that binary when we do the file save from the browser
218 Platform.addJ2SBinaryType(".jvp?");
221 private static final String VIEWER_PREFIX = "viewer_";
223 private static final String RNA_PREFIX = "rna_";
225 private static final String UTF_8 = "UTF-8";
228 * prefix for recovering datasets for alignments with multiple views where
229 * non-existent dataset IDs were written for some views
231 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
233 // use this with nextCounter() to make unique names for entities
234 private int counter = 0;
237 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
238 * of sequence objects are created.
240 IdentityHashMap<SequenceI, String> seqsToIds = null;
243 * jalview XML Sequence ID to jalview sequence object reference (both dataset
244 * and alignment sequences. Populated as XML reps of sequence objects are
247 Map<String, SequenceI> seqRefIds = null;
249 Map<String, SequenceI> incompleteSeqs = null;
251 List<SeqFref> frefedSequence = null;
253 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
256 * Map of reconstructed AlignFrame objects that appear to have come from
257 * SplitFrame objects (have a dna/protein complement view).
259 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
262 * Map from displayed rna structure models to their saved session state jar
265 private Map<RnaModel, String> rnaSessions = new HashMap<>();
268 * A helper method for safely using the value of an optional attribute that
269 * may be null if not present in the XML. Answers the boolean value, or false
275 public static boolean safeBoolean(Boolean b)
277 return b == null ? false : b.booleanValue();
281 * A helper method for safely using the value of an optional attribute that
282 * may be null if not present in the XML. Answers the integer value, or zero
288 public static int safeInt(Integer i)
290 return i == null ? 0 : i.intValue();
294 * A helper method for safely using the value of an optional attribute that
295 * may be null if not present in the XML. Answers the float value, or zero if
301 public static float safeFloat(Float f)
303 return f == null ? 0f : f.floatValue();
307 * create/return unique hash string for sq
310 * @return new or existing unique string for sq
312 String seqHash(SequenceI sq)
314 if (seqsToIds == null)
318 if (seqsToIds.containsKey(sq))
320 return seqsToIds.get(sq);
324 // create sequential key
325 String key = "sq" + (seqsToIds.size() + 1);
326 key = makeHashCode(sq, key); // check we don't have an external reference
328 seqsToIds.put(sq, key);
335 if (seqsToIds == null)
337 seqsToIds = new IdentityHashMap<>();
339 if (seqRefIds == null)
341 seqRefIds = new HashMap<>();
343 if (incompleteSeqs == null)
345 incompleteSeqs = new HashMap<>();
347 if (frefedSequence == null)
349 frefedSequence = new ArrayList<>();
357 public Jalview2XML(boolean raiseGUI)
359 this.raiseGUI = raiseGUI;
363 * base class for resolving forward references to sequences by their ID
368 abstract class SeqFref
374 public SeqFref(String _sref, String type)
380 public String getSref()
385 public SequenceI getSrefSeq()
387 return seqRefIds.get(sref);
390 public boolean isResolvable()
392 return seqRefIds.get(sref) != null;
395 public SequenceI getSrefDatasetSeq()
397 SequenceI sq = seqRefIds.get(sref);
400 while (sq.getDatasetSequence() != null)
402 sq = sq.getDatasetSequence();
409 * @return true if the forward reference was fully resolved
411 abstract boolean resolve();
414 public String toString()
416 return type + " reference to " + sref;
421 * create forward reference for a mapping
427 public SeqFref newMappingRef(final String sref,
428 final jalview.datamodel.Mapping _jmap)
430 SeqFref fref = new SeqFref(sref, "Mapping")
432 public jalview.datamodel.Mapping jmap = _jmap;
437 SequenceI seq = getSrefDatasetSeq();
449 public SeqFref newAlcodMapRef(final String sref,
450 final AlignedCodonFrame _cf,
451 final jalview.datamodel.Mapping _jmap)
454 SeqFref fref = new SeqFref(sref, "Codon Frame")
456 AlignedCodonFrame cf = _cf;
458 public jalview.datamodel.Mapping mp = _jmap;
461 public boolean isResolvable()
463 return super.isResolvable() && mp.getTo() != null;
469 SequenceI seq = getSrefDatasetSeq();
474 cf.addMap(seq, mp.getTo(), mp.getMap());
481 public void resolveFrefedSequences()
483 Iterator<SeqFref> nextFref = frefedSequence.iterator();
484 int toresolve = frefedSequence.size();
485 int unresolved = 0, failedtoresolve = 0;
486 while (nextFref.hasNext())
488 SeqFref ref = nextFref.next();
489 if (ref.isResolvable())
501 } catch (Exception x)
504 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
517 System.err.println("Jalview Project Import: There were " + unresolved
518 + " forward references left unresolved on the stack.");
520 if (failedtoresolve > 0)
522 System.err.println("SERIOUS! " + failedtoresolve
523 + " resolvable forward references failed to resolve.");
525 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
528 "Jalview Project Import: There are " + incompleteSeqs.size()
529 + " sequences which may have incomplete metadata.");
530 if (incompleteSeqs.size() < 10)
532 for (SequenceI s : incompleteSeqs.values())
534 System.err.println(s.toString());
540 "Too many to report. Skipping output of incomplete sequences.");
546 * This maintains a map of viewports, the key being the seqSetId. Important to
547 * set historyItem and redoList for multiple views
549 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
551 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
553 String uniqueSetSuffix = "";
556 * List of pdbfiles added to Jar
558 List<String> pdbfiles = null;
560 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
561 public void saveState(File statefile)
563 FileOutputStream fos = null;
568 fos = new FileOutputStream(statefile);
570 JarOutputStream jout = new JarOutputStream(fos);
574 } catch (Exception e)
576 Cache.log.error("Couln't write Jalview state to " + statefile, e);
577 // TODO: inform user of the problem - they need to know if their data was
579 if (errorMessage == null)
581 errorMessage = "Did't write Jalview Archive to output file '"
582 + statefile + "' - See console error log for details";
586 errorMessage += "(Didn't write Jalview Archive to output file '"
597 } catch (IOException e)
607 * Writes a jalview project archive to the given Jar output stream.
611 public void saveState(JarOutputStream jout)
613 AlignFrame[] frames = Desktop.getAlignFrames();
619 saveAllFrames(Arrays.asList(frames), jout);
623 * core method for storing state for a set of AlignFrames.
626 * - frames involving all data to be exported (including containing
629 * - project output stream
631 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
633 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
636 * ensure cached data is clear before starting
638 // todo tidy up seqRefIds, seqsToIds initialisation / reset
640 splitFrameCandidates.clear();
645 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
646 // //////////////////////////////////////////////////
648 List<String> shortNames = new ArrayList<>();
649 List<String> viewIds = new ArrayList<>();
652 for (int i = frames.size() - 1; i > -1; i--)
654 AlignFrame af = frames.get(i);
656 if (skipList != null && skipList
657 .containsKey(af.getViewport().getSequenceSetId()))
662 String shortName = makeFilename(af, shortNames);
664 int apSize = af.getAlignPanels().size();
666 for (int ap = 0; ap < apSize; ap++)
668 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
670 String fileName = apSize == 1 ? shortName : ap + shortName;
671 if (!fileName.endsWith(".xml"))
673 fileName = fileName + ".xml";
676 saveState(apanel, fileName, jout, viewIds);
678 String dssid = getDatasetIdRef(
679 af.getViewport().getAlignment().getDataset());
680 if (!dsses.containsKey(dssid))
682 dsses.put(dssid, af);
687 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
693 } catch (Exception foo)
697 } catch (Exception ex)
699 // TODO: inform user of the problem - they need to know if their data was
701 if (errorMessage == null)
703 errorMessage = "Couldn't write Jalview Archive - see error output for details";
705 ex.printStackTrace();
710 * Generates a distinct file name, based on the title of the AlignFrame, by
711 * appending _n for increasing n until an unused name is generated. The new
712 * name (without its extension) is added to the list.
716 * @return the generated name, with .xml extension
718 protected String makeFilename(AlignFrame af, List<String> namesUsed)
720 String shortName = af.getTitle();
722 if (shortName.indexOf(File.separatorChar) > -1)
724 shortName = shortName
725 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
730 while (namesUsed.contains(shortName))
732 if (shortName.endsWith("_" + (count - 1)))
734 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
737 shortName = shortName.concat("_" + count);
741 namesUsed.add(shortName);
743 if (!shortName.endsWith(".xml"))
745 shortName = shortName + ".xml";
750 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
751 public boolean saveAlignment(AlignFrame af, String jarFile,
756 // create backupfiles object and get new temp filename destination
757 boolean doBackup = BackupFiles.getEnabled();
758 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
759 FileOutputStream fos = new FileOutputStream(doBackup ?
760 backupfiles.getTempFilePath() : jarFile);
762 JarOutputStream jout = new JarOutputStream(fos);
763 List<AlignFrame> frames = new ArrayList<>();
765 // resolve splitframes
766 if (af.getViewport().getCodingComplement() != null)
768 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
774 saveAllFrames(frames, jout);
778 } catch (Exception foo)
782 boolean success = true;
786 backupfiles.setWriteSuccess(success);
787 success = backupfiles.rollBackupsAndRenameTempFile();
791 } catch (Exception ex)
793 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
794 ex.printStackTrace();
799 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
800 String fileName, JarOutputStream jout)
803 for (String dssids : dsses.keySet())
805 AlignFrame _af = dsses.get(dssids);
806 String jfileName = fileName + " Dataset for " + _af.getTitle();
807 if (!jfileName.endsWith(".xml"))
809 jfileName = jfileName + ".xml";
811 saveState(_af.alignPanel, jfileName, true, jout, null);
816 * create a JalviewModel from an alignment view and marshall it to a
820 * panel to create jalview model for
822 * name of alignment panel written to output stream
829 public JalviewModel saveState(AlignmentPanel ap, String fileName,
830 JarOutputStream jout, List<String> viewIds)
832 return saveState(ap, fileName, false, jout, viewIds);
836 * create a JalviewModel from an alignment view and marshall it to a
840 * panel to create jalview model for
842 * name of alignment panel written to output stream
844 * when true, only write the dataset for the alignment, not the data
845 * associated with the view.
851 public JalviewModel saveState(AlignmentPanel ap, String fileName,
852 boolean storeDS, JarOutputStream jout, List<String> viewIds)
856 viewIds = new ArrayList<>();
861 List<UserColourScheme> userColours = new ArrayList<>();
863 AlignViewport av = ap.av;
864 ViewportRanges vpRanges = av.getRanges();
866 final ObjectFactory objectFactory = new ObjectFactory();
867 JalviewModel object = objectFactory.createJalviewModel();
868 object.setVamsasModel(new VAMSAS());
870 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
873 GregorianCalendar c = new GregorianCalendar();
874 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
875 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
876 object.setCreationDate(now);
877 } catch (DatatypeConfigurationException e)
879 System.err.println("error writing date: " + e.toString());
882 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
885 * rjal is full height alignment, jal is actual alignment with full metadata
886 * but excludes hidden sequences.
888 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
890 if (av.hasHiddenRows())
892 rjal = jal.getHiddenSequences().getFullAlignment();
895 SequenceSet vamsasSet = new SequenceSet();
897 // JalviewModelSequence jms = new JalviewModelSequence();
899 vamsasSet.setGapChar(jal.getGapCharacter() + "");
901 if (jal.getDataset() != null)
903 // dataset id is the dataset's hashcode
904 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
907 // switch jal and the dataset
908 jal = jal.getDataset();
912 if (jal.getProperties() != null)
914 Enumeration en = jal.getProperties().keys();
915 while (en.hasMoreElements())
917 String key = en.nextElement().toString();
918 SequenceSetProperties ssp = new SequenceSetProperties();
920 ssp.setValue(jal.getProperties().get(key).toString());
921 // vamsasSet.addSequenceSetProperties(ssp);
922 vamsasSet.getSequenceSetProperties().add(ssp);
927 Set<String> calcIdSet = new HashSet<>();
928 // record the set of vamsas sequence XML POJO we create.
929 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
931 for (final SequenceI jds : rjal.getSequences())
933 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
934 : jds.getDatasetSequence();
935 String id = seqHash(jds);
936 if (vamsasSetIds.get(id) == null)
938 if (seqRefIds.get(id) != null && !storeDS)
940 // This happens for two reasons: 1. multiple views are being
942 // 2. the hashCode has collided with another sequence's code. This
944 // HAPPEN! (PF00072.15.stk does this)
945 // JBPNote: Uncomment to debug writing out of files that do not read
946 // back in due to ArrayOutOfBoundExceptions.
947 // System.err.println("vamsasSeq backref: "+id+"");
948 // System.err.println(jds.getName()+"
949 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
950 // System.err.println("Hashcode: "+seqHash(jds));
951 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
952 // System.err.println(rsq.getName()+"
953 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
954 // System.err.println("Hashcode: "+seqHash(rsq));
958 vamsasSeq = createVamsasSequence(id, jds);
959 // vamsasSet.addSequence(vamsasSeq);
960 vamsasSet.getSequence().add(vamsasSeq);
961 vamsasSetIds.put(id, vamsasSeq);
962 seqRefIds.put(id, jds);
966 jseq.setStart(jds.getStart());
967 jseq.setEnd(jds.getEnd());
968 jseq.setColour(av.getSequenceColour(jds).getRGB());
970 jseq.setId(id); // jseq id should be a string not a number
973 // Store any sequences this sequence represents
974 if (av.hasHiddenRows())
976 // use rjal, contains the full height alignment
978 av.getAlignment().getHiddenSequences().isHidden(jds));
980 if (av.isHiddenRepSequence(jds))
982 jalview.datamodel.SequenceI[] reps = av
983 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
985 for (int h = 0; h < reps.length; h++)
989 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
990 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
995 // mark sequence as reference - if it is the reference for this view
998 jseq.setViewreference(jds == jal.getSeqrep());
1002 // TODO: omit sequence features from each alignment view's XML dump if we
1003 // are storing dataset
1004 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1005 for (SequenceFeature sf : sfs)
1007 // Features features = new Features();
1008 Feature features = new Feature();
1010 features.setBegin(sf.getBegin());
1011 features.setEnd(sf.getEnd());
1012 features.setDescription(sf.getDescription());
1013 features.setType(sf.getType());
1014 features.setFeatureGroup(sf.getFeatureGroup());
1015 features.setScore(sf.getScore());
1016 if (sf.links != null)
1018 for (int l = 0; l < sf.links.size(); l++)
1020 OtherData keyValue = new OtherData();
1021 keyValue.setKey("LINK_" + l);
1022 keyValue.setValue(sf.links.elementAt(l).toString());
1023 // features.addOtherData(keyValue);
1024 features.getOtherData().add(keyValue);
1027 if (sf.otherDetails != null)
1030 * save feature attributes, which may be simple strings or
1031 * map valued (have sub-attributes)
1033 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1035 String key = entry.getKey();
1036 Object value = entry.getValue();
1037 if (value instanceof Map<?, ?>)
1039 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1042 OtherData otherData = new OtherData();
1043 otherData.setKey(key);
1044 otherData.setKey2(subAttribute.getKey());
1045 otherData.setValue(subAttribute.getValue().toString());
1046 // features.addOtherData(otherData);
1047 features.getOtherData().add(otherData);
1052 OtherData otherData = new OtherData();
1053 otherData.setKey(key);
1054 otherData.setValue(value.toString());
1055 // features.addOtherData(otherData);
1056 features.getOtherData().add(otherData);
1061 // jseq.addFeatures(features);
1062 jseq.getFeatures().add(features);
1065 if (jdatasq.getAllPDBEntries() != null)
1067 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1068 while (en.hasMoreElements())
1070 Pdbids pdb = new Pdbids();
1071 jalview.datamodel.PDBEntry entry = en.nextElement();
1073 String pdbId = entry.getId();
1075 pdb.setType(entry.getType());
1078 * Store any structure views associated with this sequence. This
1079 * section copes with duplicate entries in the project, so a dataset
1080 * only view *should* be coped with sensibly.
1082 // This must have been loaded, is it still visible?
1083 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1084 String matchedFile = null;
1085 for (int f = frames.length - 1; f > -1; f--)
1087 if (frames[f] instanceof StructureViewerBase)
1089 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1090 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1091 matchedFile, viewFrame);
1093 * Only store each structure viewer's state once in the project
1094 * jar. First time through only (storeDS==false)
1096 String viewId = viewFrame.getViewId();
1097 if (!storeDS && !viewIds.contains(viewId))
1099 viewIds.add(viewId);
1102 String viewerState = viewFrame.getStateInfo();
1103 writeJarEntry(jout, getViewerJarEntryName(viewId),
1104 viewerState.getBytes());
1105 } catch (IOException e)
1108 "Error saving viewer state: " + e.getMessage());
1114 if (matchedFile != null || entry.getFile() != null)
1116 if (entry.getFile() != null)
1119 matchedFile = entry.getFile();
1121 pdb.setFile(matchedFile); // entry.getFile());
1122 if (pdbfiles == null)
1124 pdbfiles = new ArrayList<>();
1127 if (!pdbfiles.contains(pdbId))
1129 pdbfiles.add(pdbId);
1130 copyFileToJar(jout, matchedFile, pdbId);
1134 Enumeration<String> props = entry.getProperties();
1135 if (props.hasMoreElements())
1137 // PdbentryItem item = new PdbentryItem();
1138 while (props.hasMoreElements())
1140 Property prop = new Property();
1141 String key = props.nextElement();
1143 prop.setValue(entry.getProperty(key).toString());
1144 // item.addProperty(prop);
1145 pdb.getProperty().add(prop);
1147 // pdb.addPdbentryItem(item);
1150 // jseq.addPdbids(pdb);
1151 jseq.getPdbids().add(pdb);
1155 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1157 // jms.addJSeq(jseq);
1158 object.getJSeq().add(jseq);
1161 if (!storeDS && av.hasHiddenRows())
1163 jal = av.getAlignment();
1167 if (storeDS && jal.getCodonFrames() != null)
1169 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1170 for (AlignedCodonFrame acf : jac)
1172 AlcodonFrame alc = new AlcodonFrame();
1173 if (acf.getProtMappings() != null
1174 && acf.getProtMappings().length > 0)
1176 boolean hasMap = false;
1177 SequenceI[] dnas = acf.getdnaSeqs();
1178 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1179 for (int m = 0; m < pmaps.length; m++)
1181 AlcodMap alcmap = new AlcodMap();
1182 alcmap.setDnasq(seqHash(dnas[m]));
1184 createVamsasMapping(pmaps[m], dnas[m], null, false));
1185 // alc.addAlcodMap(alcmap);
1186 alc.getAlcodMap().add(alcmap);
1191 // vamsasSet.addAlcodonFrame(alc);
1192 vamsasSet.getAlcodonFrame().add(alc);
1195 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1197 // AlcodonFrame alc = new AlcodonFrame();
1198 // vamsasSet.addAlcodonFrame(alc);
1199 // for (int p = 0; p < acf.aaWidth; p++)
1201 // Alcodon cmap = new Alcodon();
1202 // if (acf.codons[p] != null)
1204 // // Null codons indicate a gapped column in the translated peptide
1206 // cmap.setPos1(acf.codons[p][0]);
1207 // cmap.setPos2(acf.codons[p][1]);
1208 // cmap.setPos3(acf.codons[p][2]);
1210 // alc.addAlcodon(cmap);
1212 // if (acf.getProtMappings() != null
1213 // && acf.getProtMappings().length > 0)
1215 // SequenceI[] dnas = acf.getdnaSeqs();
1216 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1217 // for (int m = 0; m < pmaps.length; m++)
1219 // AlcodMap alcmap = new AlcodMap();
1220 // alcmap.setDnasq(seqHash(dnas[m]));
1221 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1223 // alc.addAlcodMap(alcmap);
1230 // /////////////////////////////////
1231 if (!storeDS && av.getCurrentTree() != null)
1233 // FIND ANY ASSOCIATED TREES
1234 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1235 if (Desktop.getDesktopPane() != null)
1237 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1239 for (int t = 0; t < frames.length; t++)
1241 if (frames[t] instanceof TreePanel)
1243 TreePanel tp = (TreePanel) frames[t];
1245 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1247 JalviewModel.Tree tree = new JalviewModel.Tree();
1248 tree.setTitle(tp.getTitle());
1249 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1250 tree.setNewick(tp.getTree().print());
1251 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1253 tree.setFitToWindow(tp.fitToWindow.getState());
1254 tree.setFontName(tp.getTreeFont().getName());
1255 tree.setFontSize(tp.getTreeFont().getSize());
1256 tree.setFontStyle(tp.getTreeFont().getStyle());
1257 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1259 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1260 tree.setShowDistances(tp.distanceMenu.getState());
1262 tree.setHeight(tp.getHeight());
1263 tree.setWidth(tp.getWidth());
1264 tree.setXpos(tp.getX());
1265 tree.setYpos(tp.getY());
1266 tree.setId(makeHashCode(tp, null));
1267 tree.setLinkToAllViews(
1268 tp.getTreeCanvas().isApplyToAllViews());
1270 // jms.addTree(tree);
1271 object.getTree().add(tree);
1281 if (!storeDS && Desktop.getDesktopPane() != null)
1283 for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames())
1285 if (frame instanceof PCAPanel)
1287 PCAPanel panel = (PCAPanel) frame;
1288 if (panel.getAlignViewport().getAlignment() == jal)
1290 savePCA(panel, object);
1298 * store forward refs from an annotationRow to any groups
1300 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1303 for (SequenceI sq : jal.getSequences())
1305 // Store annotation on dataset sequences only
1306 AlignmentAnnotation[] aa = sq.getAnnotation();
1307 if (aa != null && aa.length > 0)
1309 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1316 if (jal.getAlignmentAnnotation() != null)
1318 // Store the annotation shown on the alignment.
1319 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1320 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1325 if (jal.getGroups() != null)
1327 JGroup[] groups = new JGroup[jal.getGroups().size()];
1329 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1331 JGroup jGroup = new JGroup();
1332 groups[++i] = jGroup;
1334 jGroup.setStart(sg.getStartRes());
1335 jGroup.setEnd(sg.getEndRes());
1336 jGroup.setName(sg.getName());
1337 if (groupRefs.containsKey(sg))
1339 // group has references so set its ID field
1340 jGroup.setId(groupRefs.get(sg));
1342 ColourSchemeI colourScheme = sg.getColourScheme();
1343 if (colourScheme != null)
1345 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1346 if (groupColourScheme.conservationApplied())
1348 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1350 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1353 setUserColourScheme(colourScheme, userColours,
1358 jGroup.setColour(colourScheme.getSchemeName());
1361 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1363 jGroup.setColour("AnnotationColourGradient");
1364 jGroup.setAnnotationColours(constructAnnotationColours(
1365 (jalview.schemes.AnnotationColourGradient) colourScheme,
1366 userColours, object));
1368 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1371 setUserColourScheme(colourScheme, userColours, object));
1375 jGroup.setColour(colourScheme.getSchemeName());
1378 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1381 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1382 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1383 jGroup.setDisplayText(sg.getDisplayText());
1384 jGroup.setColourText(sg.getColourText());
1385 jGroup.setTextCol1(sg.textColour.getRGB());
1386 jGroup.setTextCol2(sg.textColour2.getRGB());
1387 jGroup.setTextColThreshold(sg.thresholdTextColour);
1388 jGroup.setShowUnconserved(sg.getShowNonconserved());
1389 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1390 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1391 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1392 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1393 for (SequenceI seq : sg.getSequences())
1395 // jGroup.addSeq(seqHash(seq));
1396 jGroup.getSeq().add(seqHash(seq));
1400 //jms.setJGroup(groups);
1402 for (JGroup grp : groups)
1404 object.getJGroup().add(grp);
1409 // /////////SAVE VIEWPORT
1410 Viewport view = new Viewport();
1411 view.setTitle(ap.alignFrame.getTitle());
1412 view.setSequenceSetId(
1413 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1414 view.setId(av.getViewId());
1415 if (av.getCodingComplement() != null)
1417 view.setComplementId(av.getCodingComplement().getViewId());
1419 view.setViewName(av.getViewName());
1420 view.setGatheredViews(av.isGatherViewsHere());
1422 Rectangle size = ap.av.getExplodedGeometry();
1423 Rectangle position = size;
1426 size = ap.alignFrame.getBounds();
1427 if (av.getCodingComplement() != null)
1429 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1437 view.setXpos(position.x);
1438 view.setYpos(position.y);
1440 view.setWidth(size.width);
1441 view.setHeight(size.height);
1443 view.setStartRes(vpRanges.getStartRes());
1444 view.setStartSeq(vpRanges.getStartSeq());
1446 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1448 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1449 userColours, object));
1452 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1454 AnnotationColourScheme ac = constructAnnotationColours(
1455 (jalview.schemes.AnnotationColourGradient) av
1456 .getGlobalColourScheme(),
1457 userColours, object);
1459 view.setAnnotationColours(ac);
1460 view.setBgColour("AnnotationColourGradient");
1464 view.setBgColour(ColourSchemeProperty
1465 .getColourName(av.getGlobalColourScheme()));
1468 ResidueShaderI vcs = av.getResidueShading();
1469 ColourSchemeI cs = av.getGlobalColourScheme();
1473 if (vcs.conservationApplied())
1475 view.setConsThreshold(vcs.getConservationInc());
1476 if (cs instanceof jalview.schemes.UserColourScheme)
1478 view.setBgColour(setUserColourScheme(cs, userColours, object));
1481 view.setPidThreshold(vcs.getThreshold());
1484 view.setConservationSelected(av.getConservationSelected());
1485 view.setPidSelected(av.getAbovePIDThreshold());
1486 final Font font = av.getFont();
1487 view.setFontName(font.getName());
1488 view.setFontSize(font.getSize());
1489 view.setFontStyle(font.getStyle());
1490 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1491 view.setRenderGaps(av.isRenderGaps());
1492 view.setShowAnnotation(av.isShowAnnotation());
1493 view.setShowBoxes(av.getShowBoxes());
1494 view.setShowColourText(av.getColourText());
1495 view.setShowFullId(av.getShowJVSuffix());
1496 view.setRightAlignIds(av.isRightAlignIds());
1497 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1498 view.setShowText(av.getShowText());
1499 view.setShowUnconserved(av.getShowUnconserved());
1500 view.setWrapAlignment(av.getWrapAlignment());
1501 view.setTextCol1(av.getTextColour().getRGB());
1502 view.setTextCol2(av.getTextColour2().getRGB());
1503 view.setTextColThreshold(av.getThresholdTextColour());
1504 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1505 view.setShowSequenceLogo(av.isShowSequenceLogo());
1506 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1507 view.setShowGroupConsensus(av.isShowGroupConsensus());
1508 view.setShowGroupConservation(av.isShowGroupConservation());
1509 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1510 view.setShowDbRefTooltip(av.isShowDBRefs());
1511 view.setFollowHighlight(av.isFollowHighlight());
1512 view.setFollowSelection(av.followSelection);
1513 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1514 if (av.getFeaturesDisplayed() != null)
1516 FeatureSettings fs = new FeatureSettings();
1518 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1519 .getFeatureRenderer();
1520 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1522 Vector<String> settingsAdded = new Vector<>();
1523 if (renderOrder != null)
1525 for (String featureType : renderOrder)
1527 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1528 setting.setType(featureType);
1531 * save any filter for the feature type
1533 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1534 if (filter != null) {
1535 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1536 FeatureMatcherI firstFilter = filters.next();
1537 setting.setMatcherSet(Jalview2XML.marshalFilter(
1538 firstFilter, filters, filter.isAnded()));
1542 * save colour scheme for the feature type
1544 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1545 if (!fcol.isSimpleColour())
1547 setting.setColour(fcol.getMaxColour().getRGB());
1548 setting.setMincolour(fcol.getMinColour().getRGB());
1549 setting.setMin(fcol.getMin());
1550 setting.setMax(fcol.getMax());
1551 setting.setColourByLabel(fcol.isColourByLabel());
1552 if (fcol.isColourByAttribute())
1554 String[] attName = fcol.getAttributeName();
1555 setting.getAttributeName().add(attName[0]);
1556 if (attName.length > 1)
1558 setting.getAttributeName().add(attName[1]);
1561 setting.setAutoScale(fcol.isAutoScaled());
1562 setting.setThreshold(fcol.getThreshold());
1563 Color noColour = fcol.getNoColour();
1564 if (noColour == null)
1566 setting.setNoValueColour(NoValueColour.NONE);
1568 else if (noColour.equals(fcol.getMaxColour()))
1570 setting.setNoValueColour(NoValueColour.MAX);
1574 setting.setNoValueColour(NoValueColour.MIN);
1576 // -1 = No threshold, 0 = Below, 1 = Above
1577 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1578 : (fcol.isBelowThreshold() ? 0 : -1));
1582 setting.setColour(fcol.getColour().getRGB());
1586 av.getFeaturesDisplayed().isVisible(featureType));
1588 .getOrder(featureType);
1591 setting.setOrder(rorder);
1593 /// fs.addSetting(setting);
1594 fs.getSetting().add(setting);
1595 settingsAdded.addElement(featureType);
1599 // is groups actually supposed to be a map here ?
1600 Iterator<String> en = fr.getFeatureGroups().iterator();
1601 Vector<String> groupsAdded = new Vector<>();
1602 while (en.hasNext())
1604 String grp = en.next();
1605 if (groupsAdded.contains(grp))
1609 Group g = new Group();
1611 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1614 fs.getGroup().add(g);
1615 groupsAdded.addElement(grp);
1617 // jms.setFeatureSettings(fs);
1618 object.setFeatureSettings(fs);
1621 if (av.hasHiddenColumns())
1623 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1624 .getHiddenColumns();
1627 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1631 Iterator<int[]> hiddenRegions = hidden.iterator();
1632 while (hiddenRegions.hasNext())
1634 int[] region = hiddenRegions.next();
1635 HiddenColumns hc = new HiddenColumns();
1636 hc.setStart(region[0]);
1637 hc.setEnd(region[1]);
1638 // view.addHiddenColumns(hc);
1639 view.getHiddenColumns().add(hc);
1643 if (calcIdSet.size() > 0)
1645 for (String calcId : calcIdSet)
1647 if (calcId.trim().length() > 0)
1649 CalcIdParam cidp = createCalcIdParam(calcId, av);
1650 // Some calcIds have no parameters.
1653 // view.addCalcIdParam(cidp);
1654 view.getCalcIdParam().add(cidp);
1660 // jms.addViewport(view);
1661 object.getViewport().add(view);
1663 // object.setJalviewModelSequence(jms);
1664 // object.getVamsasModel().addSequenceSet(vamsasSet);
1665 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1667 if (jout != null && fileName != null)
1669 // We may not want to write the object to disk,
1670 // eg we can copy the alignViewport to a new view object
1671 // using save and then load
1674 fileName = fileName.replace('\\', '/');
1675 System.out.println("Writing jar entry " + fileName);
1676 JarEntry entry = new JarEntry(fileName);
1677 jout.putNextEntry(entry);
1678 PrintWriter pout = new PrintWriter(
1679 new OutputStreamWriter(jout, UTF_8));
1680 JAXBContext jaxbContext = JAXBContext
1681 .newInstance(JalviewModel.class);
1682 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1684 // output pretty printed
1685 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1686 jaxbMarshaller.marshal(
1687 new ObjectFactory().createJalviewModel(object), pout);
1689 // jaxbMarshaller.marshal(object, pout);
1690 // marshaller.marshal(object);
1693 } catch (Exception ex)
1695 // TODO: raise error in GUI if marshalling failed.
1696 System.err.println("Error writing Jalview project");
1697 ex.printStackTrace();
1704 * Writes PCA viewer attributes and computed values to an XML model object and
1705 * adds it to the JalviewModel. Any exceptions are reported by logging.
1707 protected void savePCA(PCAPanel panel, JalviewModel object)
1711 PcaViewer viewer = new PcaViewer();
1712 viewer.setHeight(panel.getHeight());
1713 viewer.setWidth(panel.getWidth());
1714 viewer.setXpos(panel.getX());
1715 viewer.setYpos(panel.getY());
1716 viewer.setTitle(panel.getTitle());
1717 PCAModel pcaModel = panel.getPcaModel();
1718 viewer.setScoreModelName(pcaModel.getScoreModelName());
1719 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1720 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1721 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1723 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1724 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1725 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1726 SeqPointMin spmin = new SeqPointMin();
1727 spmin.setXPos(spMin[0]);
1728 spmin.setYPos(spMin[1]);
1729 spmin.setZPos(spMin[2]);
1730 viewer.setSeqPointMin(spmin);
1731 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1732 SeqPointMax spmax = new SeqPointMax();
1733 spmax.setXPos(spMax[0]);
1734 spmax.setYPos(spMax[1]);
1735 spmax.setZPos(spMax[2]);
1736 viewer.setSeqPointMax(spmax);
1737 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1738 viewer.setLinkToAllViews(
1739 panel.getRotatableCanvas().isApplyToAllViews());
1740 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1741 viewer.setIncludeGaps(sp.includeGaps());
1742 viewer.setMatchGaps(sp.matchGaps());
1743 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1744 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1747 * sequence points on display
1749 for (jalview.datamodel.SequencePoint spt : pcaModel
1750 .getSequencePoints())
1752 SequencePoint point = new SequencePoint();
1753 point.setSequenceRef(seqHash(spt.getSequence()));
1754 point.setXPos(spt.coord.x);
1755 point.setYPos(spt.coord.y);
1756 point.setZPos(spt.coord.z);
1757 viewer.getSequencePoint().add(point);
1761 * (end points of) axes on display
1763 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1766 Axis axis = new Axis();
1770 viewer.getAxis().add(axis);
1774 * raw PCA data (note we are not restoring PCA inputs here -
1775 * alignment view, score model, similarity parameters)
1777 PcaDataType data = new PcaDataType();
1778 viewer.setPcaData(data);
1779 PCA pca = pcaModel.getPcaData();
1781 DoubleMatrix pm = new DoubleMatrix();
1782 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1783 data.setPairwiseMatrix(pm);
1785 DoubleMatrix tm = new DoubleMatrix();
1786 saveDoubleMatrix(pca.getTridiagonal(), tm);
1787 data.setTridiagonalMatrix(tm);
1789 DoubleMatrix eigenMatrix = new DoubleMatrix();
1790 data.setEigenMatrix(eigenMatrix);
1791 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1793 object.getPcaViewer().add(viewer);
1794 } catch (Throwable t)
1796 Cache.log.error("Error saving PCA: " + t.getMessage());
1801 * Stores values from a matrix into an XML element, including (if present) the
1806 * @see #loadDoubleMatrix(DoubleMatrix)
1808 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1810 xmlMatrix.setRows(m.height());
1811 xmlMatrix.setColumns(m.width());
1812 for (int i = 0; i < m.height(); i++)
1814 DoubleVector row = new DoubleVector();
1815 for (int j = 0; j < m.width(); j++)
1817 row.getV().add(m.getValue(i, j));
1819 xmlMatrix.getRow().add(row);
1821 if (m.getD() != null)
1823 DoubleVector dVector = new DoubleVector();
1824 for (double d : m.getD())
1826 dVector.getV().add(d);
1828 xmlMatrix.setD(dVector);
1830 if (m.getE() != null)
1832 DoubleVector eVector = new DoubleVector();
1833 for (double e : m.getE())
1835 eVector.getV().add(e);
1837 xmlMatrix.setE(eVector);
1842 * Loads XML matrix data into a new Matrix object, including the D and/or E
1843 * vectors (if present)
1847 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1849 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1851 int rows = mData.getRows();
1852 double[][] vals = new double[rows][];
1854 for (int i = 0; i < rows; i++)
1856 List<Double> dVector = mData.getRow().get(i).getV();
1857 vals[i] = new double[dVector.size()];
1859 for (Double d : dVector)
1865 MatrixI m = new Matrix(vals);
1867 if (mData.getD() != null)
1869 List<Double> dVector = mData.getD().getV();
1870 double[] vec = new double[dVector.size()];
1872 for (Double d : dVector)
1878 if (mData.getE() != null)
1880 List<Double> dVector = mData.getE().getV();
1881 double[] vec = new double[dVector.size()];
1883 for (Double d : dVector)
1894 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1895 * for each viewer, with
1897 * <li>viewer geometry (position, size, split pane divider location)</li>
1898 * <li>index of the selected structure in the viewer (currently shows gapped
1900 * <li>the id of the annotation holding RNA secondary structure</li>
1901 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1903 * Varna viewer state is also written out (in native Varna XML) to separate
1904 * project jar entries. A separate entry is written for each RNA structure
1905 * displayed, with the naming convention
1907 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1915 * @param storeDataset
1917 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1918 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1919 boolean storeDataset)
1921 if (Desktop.getDesktopPane() == null)
1925 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
1926 for (int f = frames.length - 1; f > -1; f--)
1928 if (frames[f] instanceof AppVarna)
1930 AppVarna varna = (AppVarna) frames[f];
1932 * link the sequence to every viewer that is showing it and is linked to
1933 * its alignment panel
1935 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1937 String viewId = varna.getViewId();
1938 RnaViewer rna = new RnaViewer();
1939 rna.setViewId(viewId);
1940 rna.setTitle(varna.getTitle());
1941 rna.setXpos(varna.getX());
1942 rna.setYpos(varna.getY());
1943 rna.setWidth(varna.getWidth());
1944 rna.setHeight(varna.getHeight());
1945 rna.setDividerLocation(varna.getDividerLocation());
1946 rna.setSelectedRna(varna.getSelectedIndex());
1947 // jseq.addRnaViewer(rna);
1948 jseq.getRnaViewer().add(rna);
1951 * Store each Varna panel's state once in the project per sequence.
1952 * First time through only (storeDataset==false)
1954 // boolean storeSessions = false;
1955 // String sequenceViewId = viewId + seqsToIds.get(jds);
1956 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1958 // viewIds.add(sequenceViewId);
1959 // storeSessions = true;
1961 for (RnaModel model : varna.getModels())
1963 if (model.seq == jds)
1966 * VARNA saves each view (sequence or alignment secondary
1967 * structure, gapped or trimmed) as a separate XML file
1969 String jarEntryName = rnaSessions.get(model);
1970 if (jarEntryName == null)
1973 String varnaStateFile = varna.getStateInfo(model.rna);
1974 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1975 copyFileToJar(jout, varnaStateFile, jarEntryName);
1976 rnaSessions.put(model, jarEntryName);
1978 SecondaryStructure ss = new SecondaryStructure();
1979 String annotationId = varna.getAnnotation(jds).annotationId;
1980 ss.setAnnotationId(annotationId);
1981 ss.setViewerState(jarEntryName);
1982 ss.setGapped(model.gapped);
1983 ss.setTitle(model.title);
1984 // rna.addSecondaryStructure(ss);
1985 rna.getSecondaryStructure().add(ss);
1994 * Copy the contents of a file to a new entry added to the output jar
1998 * @param jarEntryName
2000 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2001 String jarEntryName)
2003 DataInputStream dis = null;
2006 File file = new File(infilePath);
2007 if (file.exists() && jout != null)
2009 dis = new DataInputStream(new FileInputStream(file));
2010 byte[] data = new byte[(int) file.length()];
2011 dis.readFully(data);
2012 writeJarEntry(jout, jarEntryName, data);
2014 } catch (Exception ex)
2016 ex.printStackTrace();
2024 } catch (IOException e)
2033 * Write the data to a new entry of given name in the output jar file
2036 * @param jarEntryName
2038 * @throws IOException
2040 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2041 byte[] data) throws IOException
2045 jarEntryName = jarEntryName.replace('\\','/');
2046 System.out.println("Writing jar entry " + jarEntryName);
2047 jout.putNextEntry(new JarEntry(jarEntryName));
2048 DataOutputStream dout = new DataOutputStream(jout);
2049 dout.write(data, 0, data.length);
2056 * Save the state of a structure viewer
2061 * the archive XML element under which to save the state
2064 * @param matchedFile
2068 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2069 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2070 String matchedFile, StructureViewerBase viewFrame)
2072 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2075 * Look for any bindings for this viewer to the PDB file of interest
2076 * (including part matches excluding chain id)
2078 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2080 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2081 final String pdbId = pdbentry.getId();
2082 if (!pdbId.equals(entry.getId())
2083 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2084 .startsWith(pdbId.toLowerCase())))
2087 * not interested in a binding to a different PDB entry here
2091 if (matchedFile == null)
2093 matchedFile = pdbentry.getFile();
2095 else if (!matchedFile.equals(pdbentry.getFile()))
2098 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2099 + pdbentry.getFile());
2103 // can get at it if the ID
2104 // match is ambiguous (e.g.
2107 for (int smap = 0; smap < viewFrame.getBinding()
2108 .getSequence()[peid].length; smap++)
2110 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2111 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2113 StructureState state = new StructureState();
2114 state.setVisible(true);
2115 state.setXpos(viewFrame.getX());
2116 state.setYpos(viewFrame.getY());
2117 state.setWidth(viewFrame.getWidth());
2118 state.setHeight(viewFrame.getHeight());
2119 final String viewId = viewFrame.getViewId();
2120 state.setViewId(viewId);
2121 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2122 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2123 state.setColourByJmol(viewFrame.isColouredByViewer());
2124 state.setType(viewFrame.getViewerType().toString());
2125 // pdb.addStructureState(state);
2126 pdb.getStructureState().add(state);
2134 * Populates the AnnotationColourScheme xml for save. This captures the
2135 * settings of the options in the 'Colour by Annotation' dialog.
2138 * @param userColours
2142 private AnnotationColourScheme constructAnnotationColours(
2143 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2146 AnnotationColourScheme ac = new AnnotationColourScheme();
2147 ac.setAboveThreshold(acg.getAboveThreshold());
2148 ac.setThreshold(acg.getAnnotationThreshold());
2149 // 2.10.2 save annotationId (unique) not annotation label
2150 ac.setAnnotation(acg.getAnnotation().annotationId);
2151 if (acg.getBaseColour() instanceof UserColourScheme)
2154 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2159 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2162 ac.setMaxColour(acg.getMaxColour().getRGB());
2163 ac.setMinColour(acg.getMinColour().getRGB());
2164 ac.setPerSequence(acg.isSeqAssociated());
2165 ac.setPredefinedColours(acg.isPredefinedColours());
2169 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2170 IdentityHashMap<SequenceGroup, String> groupRefs,
2171 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2172 SequenceSet vamsasSet)
2175 for (int i = 0; i < aa.length; i++)
2177 Annotation an = new Annotation();
2179 AlignmentAnnotation annotation = aa[i];
2180 if (annotation.annotationId != null)
2182 annotationIds.put(annotation.annotationId, annotation);
2185 an.setId(annotation.annotationId);
2187 an.setVisible(annotation.visible);
2189 an.setDescription(annotation.description);
2191 if (annotation.sequenceRef != null)
2193 // 2.9 JAL-1781 xref on sequence id rather than name
2194 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2196 if (annotation.groupRef != null)
2198 String groupIdr = groupRefs.get(annotation.groupRef);
2199 if (groupIdr == null)
2201 // make a locally unique String
2202 groupRefs.put(annotation.groupRef,
2203 groupIdr = ("" + System.currentTimeMillis()
2204 + annotation.groupRef.getName()
2205 + groupRefs.size()));
2207 an.setGroupRef(groupIdr.toString());
2210 // store all visualization attributes for annotation
2211 an.setGraphHeight(annotation.graphHeight);
2212 an.setCentreColLabels(annotation.centreColLabels);
2213 an.setScaleColLabels(annotation.scaleColLabel);
2214 an.setShowAllColLabels(annotation.showAllColLabels);
2215 an.setBelowAlignment(annotation.belowAlignment);
2217 if (annotation.graph > 0)
2220 an.setGraphType(annotation.graph);
2221 an.setGraphGroup(annotation.graphGroup);
2222 if (annotation.getThreshold() != null)
2224 ThresholdLine line = new ThresholdLine();
2225 line.setLabel(annotation.getThreshold().label);
2226 line.setValue(annotation.getThreshold().value);
2227 line.setColour(annotation.getThreshold().colour.getRGB());
2228 an.setThresholdLine(line);
2236 an.setLabel(annotation.label);
2238 if (annotation == av.getAlignmentQualityAnnot()
2239 || annotation == av.getAlignmentConservationAnnotation()
2240 || annotation == av.getAlignmentConsensusAnnotation()
2241 || annotation.autoCalculated)
2243 // new way of indicating autocalculated annotation -
2244 an.setAutoCalculated(annotation.autoCalculated);
2246 if (annotation.hasScore())
2248 an.setScore(annotation.getScore());
2251 if (annotation.getCalcId() != null)
2253 calcIdSet.add(annotation.getCalcId());
2254 an.setCalcId(annotation.getCalcId());
2256 if (annotation.hasProperties())
2258 for (String pr : annotation.getProperties())
2260 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2262 prop.setValue(annotation.getProperty(pr));
2263 // an.addProperty(prop);
2264 an.getProperty().add(prop);
2268 AnnotationElement ae;
2269 if (annotation.annotations != null)
2271 an.setScoreOnly(false);
2272 for (int a = 0; a < annotation.annotations.length; a++)
2274 if ((annotation == null) || (annotation.annotations[a] == null))
2279 ae = new AnnotationElement();
2280 if (annotation.annotations[a].description != null)
2282 ae.setDescription(annotation.annotations[a].description);
2284 if (annotation.annotations[a].displayCharacter != null)
2286 ae.setDisplayCharacter(
2287 annotation.annotations[a].displayCharacter);
2290 if (!Float.isNaN(annotation.annotations[a].value))
2292 ae.setValue(annotation.annotations[a].value);
2296 if (annotation.annotations[a].secondaryStructure > ' ')
2298 ae.setSecondaryStructure(
2299 annotation.annotations[a].secondaryStructure + "");
2302 if (annotation.annotations[a].colour != null
2303 && annotation.annotations[a].colour != java.awt.Color.black)
2305 ae.setColour(annotation.annotations[a].colour.getRGB());
2308 // an.addAnnotationElement(ae);
2309 an.getAnnotationElement().add(ae);
2310 if (annotation.autoCalculated)
2312 // only write one non-null entry into the annotation row -
2313 // sufficient to get the visualization attributes necessary to
2321 an.setScoreOnly(true);
2323 if (!storeDS || (storeDS && !annotation.autoCalculated))
2325 // skip autocalculated annotation - these are only provided for
2327 // vamsasSet.addAnnotation(an);
2328 vamsasSet.getAnnotation().add(an);
2334 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2336 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2337 if (settings != null)
2339 CalcIdParam vCalcIdParam = new CalcIdParam();
2340 vCalcIdParam.setCalcId(calcId);
2341 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2342 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2343 // generic URI allowing a third party to resolve another instance of the
2344 // service used for this calculation
2345 for (String url : settings.getServiceURLs())
2347 // vCalcIdParam.addServiceURL(urls);
2348 vCalcIdParam.getServiceURL().add(url);
2350 vCalcIdParam.setVersion("1.0");
2351 if (settings.getPreset() != null)
2353 WsParamSetI setting = settings.getPreset();
2354 vCalcIdParam.setName(setting.getName());
2355 vCalcIdParam.setDescription(setting.getDescription());
2359 vCalcIdParam.setName("");
2360 vCalcIdParam.setDescription("Last used parameters");
2362 // need to be able to recover 1) settings 2) user-defined presets or
2363 // recreate settings from preset 3) predefined settings provided by
2364 // service - or settings that can be transferred (or discarded)
2365 vCalcIdParam.setParameters(
2366 settings.getWsParamFile().replace("\n", "|\\n|"));
2367 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2368 // todo - decide if updateImmediately is needed for any projects.
2370 return vCalcIdParam;
2375 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2378 if (calcIdParam.getVersion().equals("1.0"))
2380 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2381 Jws2Instance service = Jws2Discoverer.getInstance()
2382 .getPreferredServiceFor(calcIds);
2383 if (service != null)
2385 WsParamSetI parmSet = null;
2388 parmSet = service.getParamStore().parseServiceParameterFile(
2389 calcIdParam.getName(), calcIdParam.getDescription(),
2391 calcIdParam.getParameters().replace("|\\n|", "\n"));
2392 } catch (IOException x)
2394 warn("Couldn't parse parameter data for "
2395 + calcIdParam.getCalcId(), x);
2398 List<ArgumentI> argList = null;
2399 if (calcIdParam.getName().length() > 0)
2401 parmSet = service.getParamStore()
2402 .getPreset(calcIdParam.getName());
2403 if (parmSet != null)
2405 // TODO : check we have a good match with settings in AACon -
2406 // otherwise we'll need to create a new preset
2411 argList = parmSet.getArguments();
2414 AAConSettings settings = new AAConSettings(
2415 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2416 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2417 calcIdParam.isNeedsUpdate());
2422 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2426 throw new Error(MessageManager.formatMessage(
2427 "error.unsupported_version_calcIdparam", new Object[]
2428 { calcIdParam.toString() }));
2432 * External mapping between jalview objects and objects yielding a valid and
2433 * unique object ID string. This is null for normal Jalview project IO, but
2434 * non-null when a jalview project is being read or written as part of a
2437 IdentityHashMap jv2vobj = null;
2440 * Construct a unique ID for jvobj using either existing bindings or if none
2441 * exist, the result of the hashcode call for the object.
2444 * jalview data object
2445 * @return unique ID for referring to jvobj
2447 private String makeHashCode(Object jvobj, String altCode)
2449 if (jv2vobj != null)
2451 Object id = jv2vobj.get(jvobj);
2454 return id.toString();
2456 // check string ID mappings
2457 if (jvids2vobj != null && jvobj instanceof String)
2459 id = jvids2vobj.get(jvobj);
2463 return id.toString();
2465 // give up and warn that something has gone wrong
2466 warn("Cannot find ID for object in external mapping : " + jvobj);
2472 * return local jalview object mapped to ID, if it exists
2476 * @return null or object bound to idcode
2478 private Object retrieveExistingObj(String idcode)
2480 if (idcode != null && vobj2jv != null)
2482 return vobj2jv.get(idcode);
2488 * binding from ID strings from external mapping table to jalview data model
2491 private Hashtable vobj2jv;
2493 private Sequence createVamsasSequence(String id, SequenceI jds)
2495 return createVamsasSequence(true, id, jds, null);
2498 private Sequence createVamsasSequence(boolean recurse, String id,
2499 SequenceI jds, SequenceI parentseq)
2501 Sequence vamsasSeq = new Sequence();
2502 vamsasSeq.setId(id);
2503 vamsasSeq.setName(jds.getName());
2504 vamsasSeq.setSequence(jds.getSequenceAsString());
2505 vamsasSeq.setDescription(jds.getDescription());
2506 List<DBRefEntry> dbrefs = null;
2507 if (jds.getDatasetSequence() != null)
2509 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2513 // seqId==dsseqid so we can tell which sequences really are
2514 // dataset sequences only
2515 vamsasSeq.setDsseqid(id);
2516 dbrefs = jds.getDBRefs();
2517 if (parentseq == null)
2524 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2526 DBRef dbref = new DBRef();
2527 DBRefEntry ref = dbrefs.get(d);
2528 dbref.setSource(ref.getSource());
2529 dbref.setVersion(ref.getVersion());
2530 dbref.setAccessionId(ref.getAccessionId());
2533 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2535 dbref.setMapping(mp);
2537 // vamsasSeq.addDBRef(dbref);
2538 vamsasSeq.getDBRef().add(dbref);
2544 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2545 SequenceI parentseq, SequenceI jds, boolean recurse)
2548 if (jmp.getMap() != null)
2552 jalview.util.MapList mlst = jmp.getMap();
2553 List<int[]> r = mlst.getFromRanges();
2554 for (int[] range : r)
2556 MapListFrom mfrom = new MapListFrom();
2557 mfrom.setStart(range[0]);
2558 mfrom.setEnd(range[1]);
2559 // mp.addMapListFrom(mfrom);
2560 mp.getMapListFrom().add(mfrom);
2562 r = mlst.getToRanges();
2563 for (int[] range : r)
2565 MapListTo mto = new MapListTo();
2566 mto.setStart(range[0]);
2567 mto.setEnd(range[1]);
2568 // mp.addMapListTo(mto);
2569 mp.getMapListTo().add(mto);
2571 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2572 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2573 if (jmp.getTo() != null)
2575 // MappingChoice mpc = new MappingChoice();
2577 // check/create ID for the sequence referenced by getTo()
2580 SequenceI ps = null;
2581 if (parentseq != jmp.getTo()
2582 && parentseq.getDatasetSequence() != jmp.getTo())
2584 // chaining dbref rather than a handshaking one
2585 jmpid = seqHash(ps = jmp.getTo());
2589 jmpid = seqHash(ps = parentseq);
2591 // mpc.setDseqFor(jmpid);
2592 mp.setDseqFor(jmpid);
2593 if (!seqRefIds.containsKey(jmpid))
2595 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2596 seqRefIds.put(jmpid, ps);
2600 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2603 // mp.setMappingChoice(mpc);
2609 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2610 List<UserColourScheme> userColours, JalviewModel jm)
2613 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2614 boolean newucs = false;
2615 if (!userColours.contains(ucs))
2617 userColours.add(ucs);
2620 id = "ucs" + userColours.indexOf(ucs);
2623 // actually create the scheme's entry in the XML model
2624 java.awt.Color[] colours = ucs.getColours();
2625 UserColours uc = new UserColours();
2626 // UserColourScheme jbucs = new UserColourScheme();
2627 JalviewUserColours jbucs = new JalviewUserColours();
2629 for (int i = 0; i < colours.length; i++)
2631 Colour col = new Colour();
2632 col.setName(ResidueProperties.aa[i]);
2633 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2634 // jbucs.addColour(col);
2635 jbucs.getColour().add(col);
2637 if (ucs.getLowerCaseColours() != null)
2639 colours = ucs.getLowerCaseColours();
2640 for (int i = 0; i < colours.length; i++)
2642 Colour col = new Colour();
2643 col.setName(ResidueProperties.aa[i].toLowerCase());
2644 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2645 // jbucs.addColour(col);
2646 jbucs.getColour().add(col);
2651 uc.setUserColourScheme(jbucs);
2652 // jm.addUserColours(uc);
2653 jm.getUserColours().add(uc);
2659 jalview.schemes.UserColourScheme getUserColourScheme(
2660 JalviewModel jm, String id)
2662 List<UserColours> uc = jm.getUserColours();
2663 UserColours colours = null;
2665 for (int i = 0; i < uc.length; i++)
2667 if (uc[i].getId().equals(id))
2674 for (UserColours c : uc)
2676 if (c.getId().equals(id))
2683 java.awt.Color[] newColours = new java.awt.Color[24];
2685 for (int i = 0; i < 24; i++)
2687 newColours[i] = new java.awt.Color(Integer.parseInt(
2688 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2689 colours.getUserColourScheme().getColour().get(i).getRGB(),
2693 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2696 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2698 newColours = new java.awt.Color[23];
2699 for (int i = 0; i < 23; i++)
2701 newColours[i] = new java.awt.Color(Integer.parseInt(
2702 colours.getUserColourScheme().getColour().get(i + 24)
2706 ucs.setLowerCaseColours(newColours);
2713 * contains last error message (if any) encountered by XML loader.
2715 String errorMessage = null;
2718 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2719 * exceptions are raised during project XML parsing
2721 public boolean attemptversion1parse = false;
2724 * Load a jalview project archive from a jar file
2727 * - HTTP URL or filename
2729 public AlignFrame loadJalviewAlign(final Object file)
2732 jalview.gui.AlignFrame af = null;
2736 // create list to store references for any new Jmol viewers created
2737 newStructureViewers = new Vector<>();
2738 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2739 // Workaround is to make sure caller implements the JarInputStreamProvider
2741 // so we can re-open the jar input stream for each entry.
2743 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2744 af = loadJalviewAlign(jprovider);
2747 af.setMenusForViewport();
2749 } catch (MalformedURLException e)
2751 errorMessage = "Invalid URL format for '" + file + "'";
2757 SwingUtilities.invokeAndWait(new Runnable()
2762 setLoadingFinishedForNewStructureViewers();
2765 } catch (Exception x)
2767 System.err.println("Error loading alignment: " + x.getMessage());
2773 @SuppressWarnings("unused")
2774 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2776 // BH 2018 allow for bytes already attached to File object
2778 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2779 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2782 errorMessage = null;
2783 uniqueSetSuffix = null;
2785 viewportsAdded.clear();
2786 frefedSequence = null;
2788 if (file.startsWith("http://")) {
2789 url = new URL(file);
2791 final URL _url = url;
2792 return new jarInputStreamProvider() {
2795 public JarInputStream getJarInputStream() throws IOException {
2796 if (bytes != null) {
2797 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2798 return new JarInputStream(new ByteArrayInputStream(bytes));
2801 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2802 return new JarInputStream(_url.openStream());
2804 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2805 return new JarInputStream(new FileInputStream(file));
2810 public String getFilename() {
2814 } catch (IOException e) {
2815 e.printStackTrace();
2821 * Recover jalview session from a jalview project archive. Caller may
2822 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2823 * themselves. Any null fields will be initialised with default values,
2824 * non-null fields are left alone.
2829 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2831 errorMessage = null;
2832 if (uniqueSetSuffix == null)
2834 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2836 if (seqRefIds == null)
2840 AlignFrame af = null, _af = null;
2841 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2842 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2843 final String file = jprovider.getFilename();
2846 JarInputStream jin = null;
2847 JarEntry jarentry = null;
2852 jin = jprovider.getJarInputStream();
2853 for (int i = 0; i < entryCount; i++)
2855 jarentry = jin.getNextJarEntry();
2857 String name = (jarentry == null ? null : jarentry.getName());
2858 if (name != null && name.endsWith(".xml")
2859 && name.indexOf(" Dataset for ") < 0 // BH 2019.05.21
2862 JAXBContext jc = JAXBContext
2863 .newInstance("jalview.xml.binding.jalview");
2864 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2865 .createXMLStreamReader(jin);
2866 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2867 JAXBElement<JalviewModel> jbe = um
2868 .unmarshal(streamReader, JalviewModel.class);
2869 JalviewModel object = jbe.getValue();
2871 if (true) // !skipViewport(object))
2873 _af = loadFromObject(object, file, true, jprovider);
2874 if (_af != null && object.getViewport().size() > 0)
2875 // getJalviewModelSequence().getViewportCount() > 0)
2879 // store a reference to the first view
2882 if (_af.getViewport().isGatherViewsHere())
2884 // if this is a gathered view, keep its reference since
2885 // after gathering views, only this frame will remain
2887 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2890 // Save dataset to register mappings once all resolved
2891 importedDatasets.put(
2892 af.getViewport().getAlignment().getDataset(),
2893 af.getViewport().getAlignment().getDataset());
2898 else if (jarentry != null)
2900 // Some other file here.
2903 } while (jarentry != null);
2904 resolveFrefedSequences();
2905 } catch (IOException ex)
2907 ex.printStackTrace();
2908 errorMessage = "Couldn't locate Jalview XML file : " + file;
2910 "Exception whilst loading jalview XML file : " + ex + "\n");
2911 } catch (Exception ex)
2913 System.err.println("Parsing as Jalview Version 2 file failed.");
2914 ex.printStackTrace(System.err);
2915 if (attemptversion1parse)
2917 // used to attempt to parse as V1 castor-generated xml
2919 if (Desktop.getInstance() != null)
2921 Desktop.getInstance().stopLoading();
2925 System.out.println("Successfully loaded archive file");
2928 ex.printStackTrace();
2931 "Exception whilst loading jalview XML file : " + ex + "\n");
2932 } catch (OutOfMemoryError e)
2934 // Don't use the OOM Window here
2935 errorMessage = "Out of memory loading jalview XML file";
2936 System.err.println("Out of memory whilst loading jalview XML file");
2937 e.printStackTrace();
2941 * Regather multiple views (with the same sequence set id) to the frame (if
2942 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2943 * views instead of separate frames. Note this doesn't restore a state where
2944 * some expanded views in turn have tabbed views - the last "first tab" read
2945 * in will play the role of gatherer for all.
2947 for (AlignFrame fr : gatherToThisFrame.values())
2949 Desktop.getInstance().gatherViews(fr);
2952 restoreSplitFrames();
2953 for (AlignmentI ds : importedDatasets.keySet())
2955 if (ds.getCodonFrames() != null)
2957 Desktop.getInstance().getStructureSelectionManager()
2958 .registerMappings(ds.getCodonFrames());
2961 if (errorMessage != null)
2966 if (Desktop.getInstance() != null)
2968 Desktop.getInstance().stopLoading();
2975 * Try to reconstruct and display SplitFrame windows, where each contains
2976 * complementary dna and protein alignments. Done by pairing up AlignFrame
2977 * objects (created earlier) which have complementary viewport ids associated.
2979 protected void restoreSplitFrames()
2981 List<SplitFrame> gatherTo = new ArrayList<>();
2982 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2983 Map<String, AlignFrame> dna = new HashMap<>();
2986 * Identify the DNA alignments
2988 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2991 AlignFrame af = candidate.getValue();
2992 if (af.getViewport().getAlignment().isNucleotide())
2994 dna.put(candidate.getKey().getId(), af);
2999 * Try to match up the protein complements
3001 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3004 AlignFrame af = candidate.getValue();
3005 if (!af.getViewport().getAlignment().isNucleotide())
3007 String complementId = candidate.getKey().getComplementId();
3008 // only non-null complements should be in the Map
3009 if (complementId != null && dna.containsKey(complementId))
3011 final AlignFrame dnaFrame = dna.get(complementId);
3012 SplitFrame sf = createSplitFrame(dnaFrame, af);
3013 addedToSplitFrames.add(dnaFrame);
3014 addedToSplitFrames.add(af);
3015 dnaFrame.setMenusForViewport();
3016 af.setMenusForViewport();
3017 if (af.getViewport().isGatherViewsHere())
3026 * Open any that we failed to pair up (which shouldn't happen!) as
3027 * standalone AlignFrame's.
3029 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3032 AlignFrame af = candidate.getValue();
3033 if (!addedToSplitFrames.contains(af))
3035 Viewport view = candidate.getKey();
3036 Desktop.addInternalFrame(af, view.getTitle(),
3037 safeInt(view.getWidth()), safeInt(view.getHeight()));
3038 af.setMenusForViewport();
3039 System.err.println("Failed to restore view " + view.getTitle()
3040 + " to split frame");
3045 * Gather back into tabbed views as flagged.
3047 for (SplitFrame sf : gatherTo)
3049 Desktop.getInstance().gatherViews(sf);
3052 splitFrameCandidates.clear();
3056 * Construct and display one SplitFrame holding DNA and protein alignments.
3059 * @param proteinFrame
3062 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3063 AlignFrame proteinFrame)
3065 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3066 String title = MessageManager.getString("label.linked_view_title");
3067 int width = (int) dnaFrame.getBounds().getWidth();
3068 int height = (int) (dnaFrame.getBounds().getHeight()
3069 + proteinFrame.getBounds().getHeight() + 50);
3072 * SplitFrame location is saved to both enclosed frames
3074 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3075 Desktop.addInternalFrame(splitFrame, title, width, height);
3078 * And compute cDNA consensus (couldn't do earlier with consensus as
3079 * mappings were not yet present)
3081 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3087 * check errorMessage for a valid error message and raise an error box in the
3088 * GUI or write the current errorMessage to stderr and then clear the error
3091 protected void reportErrors()
3093 reportErrors(false);
3096 protected void reportErrors(final boolean saving)
3098 if (errorMessage != null)
3100 final String finalErrorMessage = errorMessage;
3103 javax.swing.SwingUtilities.invokeLater(new Runnable()
3108 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3110 "Error " + (saving ? "saving" : "loading")
3112 JvOptionPane.WARNING_MESSAGE);
3118 System.err.println("Problem loading Jalview file: " + errorMessage);
3121 errorMessage = null;
3124 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3127 * when set, local views will be updated from view stored in JalviewXML
3128 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3129 * sync if this is set to true.
3131 private final boolean updateLocalViews = false;
3134 * Returns the path to a temporary file holding the PDB file for the given PDB
3135 * id. The first time of asking, searches for a file of that name in the
3136 * Jalview project jar, and copies it to a new temporary file. Any repeat
3137 * requests just return the path to the file previously created.
3143 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3146 if (alreadyLoadedPDB.containsKey(pdbId))
3148 return alreadyLoadedPDB.get(pdbId).toString();
3151 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3153 if (tempFile != null)
3155 alreadyLoadedPDB.put(pdbId, tempFile);
3161 * Copies the jar entry of given name to a new temporary file and returns the
3162 * path to the file, or null if the entry is not found.
3165 * @param jarEntryName
3167 * a prefix for the temporary file name, must be at least three
3170 * null or original file - so new file can be given the same suffix
3174 protected String copyJarEntry(jarInputStreamProvider jprovider,
3175 String jarEntryName, String prefix, String origFile)
3177 BufferedReader in = null;
3178 PrintWriter out = null;
3179 String suffix = ".tmp";
3180 if (origFile == null)
3182 origFile = jarEntryName;
3184 int sfpos = origFile.lastIndexOf(".");
3185 if (sfpos > -1 && sfpos < (origFile.length() - 3))
3187 suffix = "." + origFile.substring(sfpos + 1);
3191 JarInputStream jin = jprovider.getJarInputStream();
3193 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3194 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3195 * FileInputStream(jprovider)); }
3198 JarEntry entry = null;
3201 entry = jin.getNextJarEntry();
3202 } while (entry != null && !entry.getName().equals(jarEntryName));
3205 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3206 File outFile = File.createTempFile(prefix, suffix);
3207 outFile.deleteOnExit();
3208 out = new PrintWriter(new FileOutputStream(outFile));
3211 while ((data = in.readLine()) != null)
3216 String t = outFile.getAbsolutePath();
3221 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3223 } catch (Exception ex)
3225 ex.printStackTrace();
3233 } catch (IOException e)
3247 private class JvAnnotRow
3249 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3256 * persisted version of annotation row from which to take vis properties
3258 public jalview.datamodel.AlignmentAnnotation template;
3261 * original position of the annotation row in the alignment
3267 * Load alignment frame from jalview XML DOM object
3269 * @param jalviewModel
3272 * filename source string
3273 * @param loadTreesAndStructures
3274 * when false only create Viewport
3276 * data source provider
3277 * @return alignment frame created from view stored in DOM
3279 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3280 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3282 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3283 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3285 // JalviewModelSequence jms = object.getJalviewModelSequence();
3287 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3289 Viewport view = (jalviewModel.getViewport().size() > 0)
3290 ? jalviewModel.getViewport().get(0)
3293 // ////////////////////////////////
3294 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3297 // If we just load in the same jar file again, the sequenceSetId
3298 // will be the same, and we end up with multiple references
3299 // to the same sequenceSet. We must modify this id on load
3300 // so that each load of the file gives a unique id
3303 * used to resolve correct alignment dataset for alignments with multiple
3306 String uniqueSeqSetId = null;
3307 String viewId = null;
3310 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3311 viewId = (view.getId() == null ? null
3312 : view.getId() + uniqueSetSuffix);
3315 // ////////////////////////////////
3318 List<SequenceI> hiddenSeqs = null;
3320 List<SequenceI> tmpseqs = new ArrayList<>();
3322 boolean multipleView = false;
3323 SequenceI referenceseqForView = null;
3324 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3325 List<JSeq> jseqs = jalviewModel.getJSeq();
3326 int vi = 0; // counter in vamsasSeq array
3327 for (int i = 0; i < jseqs.size(); i++)
3329 JSeq jseq = jseqs.get(i);
3330 String seqId = jseq.getId();
3332 SequenceI tmpSeq = seqRefIds.get(seqId);
3335 if (!incompleteSeqs.containsKey(seqId))
3337 // may not need this check, but keep it for at least 2.9,1 release
3338 if (tmpSeq.getStart() != jseq.getStart()
3339 || tmpSeq.getEnd() != jseq.getEnd())
3342 "Warning JAL-2154 regression: updating start/end for sequence "
3343 + tmpSeq.toString() + " to " + jseq);
3348 incompleteSeqs.remove(seqId);
3350 if (vamsasSeqs.size() > vi
3351 && vamsasSeqs.get(vi).getId().equals(seqId))
3353 // most likely we are reading a dataset XML document so
3354 // update from vamsasSeq section of XML for this sequence
3355 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3356 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3357 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3362 // reading multiple views, so vamsasSeq set is a subset of JSeq
3363 multipleView = true;
3365 tmpSeq.setStart(jseq.getStart());
3366 tmpSeq.setEnd(jseq.getEnd());
3367 tmpseqs.add(tmpSeq);
3371 Sequence vamsasSeq = vamsasSeqs.get(vi);
3372 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3373 vamsasSeq.getSequence());
3374 tmpSeq.setDescription(vamsasSeq.getDescription());
3375 tmpSeq.setStart(jseq.getStart());
3376 tmpSeq.setEnd(jseq.getEnd());
3377 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3378 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3379 tmpseqs.add(tmpSeq);
3383 if (safeBoolean(jseq.isViewreference()))
3385 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3388 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3390 if (hiddenSeqs == null)
3392 hiddenSeqs = new ArrayList<>();
3395 hiddenSeqs.add(tmpSeq);
3400 // Create the alignment object from the sequence set
3401 // ///////////////////////////////
3402 SequenceI[] orderedSeqs = tmpseqs
3403 .toArray(new SequenceI[tmpseqs.size()]);
3405 AlignmentI al = null;
3406 // so we must create or recover the dataset alignment before going further
3407 // ///////////////////////////////
3408 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3410 // older jalview projects do not have a dataset - so creat alignment and
3412 al = new Alignment(orderedSeqs);
3413 al.setDataset(null);
3417 boolean isdsal = jalviewModel.getViewport().isEmpty();
3420 // we are importing a dataset record, so
3421 // recover reference to an alignment already materialsed as dataset
3422 al = getDatasetFor(vamsasSet.getDatasetId());
3426 // materialse the alignment
3427 al = new Alignment(orderedSeqs);
3431 addDatasetRef(vamsasSet.getDatasetId(), al);
3434 // finally, verify all data in vamsasSet is actually present in al
3435 // passing on flag indicating if it is actually a stored dataset
3436 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3439 if (referenceseqForView != null)
3441 al.setSeqrep(referenceseqForView);
3443 // / Add the alignment properties
3444 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3446 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3448 al.setProperty(ssp.getKey(), ssp.getValue());
3451 // ///////////////////////////////
3453 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3456 // load sequence features, database references and any associated PDB
3457 // structures for the alignment
3459 // prior to 2.10, this part would only be executed the first time a
3460 // sequence was encountered, but not afterwards.
3461 // now, for 2.10 projects, this is also done if the xml doc includes
3462 // dataset sequences not actually present in any particular view.
3464 for (int i = 0; i < vamsasSeqs.size(); i++)
3466 JSeq jseq = jseqs.get(i);
3467 if (jseq.getFeatures().size() > 0)
3469 List<Feature> features = jseq.getFeatures();
3470 for (int f = 0; f < features.size(); f++)
3472 Feature feat = features.get(f);
3473 SequenceFeature sf = new SequenceFeature(feat.getType(),
3474 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3475 safeFloat(feat.getScore()), feat.getFeatureGroup());
3476 sf.setStatus(feat.getStatus());
3479 * load any feature attributes - include map-valued attributes
3481 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3482 for (int od = 0; od < feat.getOtherData().size(); od++)
3484 OtherData keyValue = feat.getOtherData().get(od);
3485 String attributeName = keyValue.getKey();
3486 String attributeValue = keyValue.getValue();
3487 if (attributeName.startsWith("LINK"))
3489 sf.addLink(attributeValue);
3493 String subAttribute = keyValue.getKey2();
3494 if (subAttribute == null)
3496 // simple string-valued attribute
3497 sf.setValue(attributeName, attributeValue);
3501 // attribute 'key' has sub-attribute 'key2'
3502 if (!mapAttributes.containsKey(attributeName))
3504 mapAttributes.put(attributeName, new HashMap<>());
3506 mapAttributes.get(attributeName).put(subAttribute,
3511 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3514 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3517 // adds feature to datasequence's feature set (since Jalview 2.10)
3518 al.getSequenceAt(i).addSequenceFeature(sf);
3521 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3523 // adds dbrefs to datasequence's set (since Jalview 2.10)
3525 al.getSequenceAt(i).getDatasetSequence() == null
3526 ? al.getSequenceAt(i)
3527 : al.getSequenceAt(i).getDatasetSequence(),
3530 if (jseq.getPdbids().size() > 0)
3532 List<Pdbids> ids = jseq.getPdbids();
3533 for (int p = 0; p < ids.size(); p++)
3535 Pdbids pdbid = ids.get(p);
3536 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3537 entry.setId(pdbid.getId());
3538 if (pdbid.getType() != null)
3540 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3542 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3546 entry.setType(PDBEntry.Type.FILE);
3549 // jprovider is null when executing 'New View'
3550 if (pdbid.getFile() != null && jprovider != null)
3552 if (!pdbloaded.containsKey(pdbid.getFile()))
3554 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3559 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3563 if (pdbid.getPdbentryItem() != null)
3565 for (PdbentryItem item : pdbid.getPdbentryItem())
3567 for (Property pr : item.getProperty())
3569 entry.setProperty(pr.getName(), pr.getValue());
3574 for (Property prop : pdbid.getProperty())
3576 entry.setProperty(prop.getName(), prop.getValue());
3578 Desktop.getInstance().getStructureSelectionManager()
3579 .registerPDBEntry(entry);
3580 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3581 if (al.getSequenceAt(i).getDatasetSequence() != null)
3583 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3587 al.getSequenceAt(i).addPDBId(entry);
3592 } // end !multipleview
3594 // ///////////////////////////////
3595 // LOAD SEQUENCE MAPPINGS
3597 if (vamsasSet.getAlcodonFrame().size() > 0)
3599 // TODO Potentially this should only be done once for all views of an
3601 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3602 for (int i = 0; i < alc.size(); i++)
3604 AlignedCodonFrame cf = new AlignedCodonFrame();
3605 if (alc.get(i).getAlcodMap().size() > 0)
3607 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3608 for (int m = 0; m < maps.size(); m++)
3610 AlcodMap map = maps.get(m);
3611 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3613 jalview.datamodel.Mapping mapping = null;
3614 // attach to dna sequence reference.
3615 if (map.getMapping() != null)
3617 mapping = addMapping(map.getMapping());
3618 if (dnaseq != null && mapping.getTo() != null)
3620 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3626 newAlcodMapRef(map.getDnasq(), cf, mapping));
3630 al.addCodonFrame(cf);
3635 // ////////////////////////////////
3637 List<JvAnnotRow> autoAlan = new ArrayList<>();
3640 * store any annotations which forward reference a group's ID
3642 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3644 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3646 List<Annotation> an = vamsasSet.getAnnotation();
3648 for (int i = 0; i < an.size(); i++)
3650 Annotation annotation = an.get(i);
3653 * test if annotation is automatically calculated for this view only
3655 boolean autoForView = false;
3656 if (annotation.getLabel().equals("Quality")
3657 || annotation.getLabel().equals("Conservation")
3658 || annotation.getLabel().equals("Consensus"))
3660 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3662 // JAXB has no has() test; schema defaults value to false
3663 // if (!annotation.hasAutoCalculated())
3665 // annotation.setAutoCalculated(true);
3668 if (autoForView || annotation.isAutoCalculated())
3670 // remove ID - we don't recover annotation from other views for
3671 // view-specific annotation
3672 annotation.setId(null);
3675 // set visibility for other annotation in this view
3676 String annotationId = annotation.getId();
3677 if (annotationId != null && annotationIds.containsKey(annotationId))
3679 AlignmentAnnotation jda = annotationIds.get(annotationId);
3680 // in principle Visible should always be true for annotation displayed
3681 // in multiple views
3682 if (annotation.isVisible() != null)
3684 jda.visible = annotation.isVisible();
3687 al.addAnnotation(jda);
3691 // Construct new annotation from model.
3692 List<AnnotationElement> ae = annotation.getAnnotationElement();
3693 jalview.datamodel.Annotation[] anot = null;
3694 java.awt.Color firstColour = null;
3696 if (!annotation.isScoreOnly())
3698 anot = new jalview.datamodel.Annotation[al.getWidth()];
3699 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3701 AnnotationElement annElement = ae.get(aa);
3702 anpos = annElement.getPosition();
3704 if (anpos >= anot.length)
3709 float value = safeFloat(annElement.getValue());
3710 anot[anpos] = new jalview.datamodel.Annotation(
3711 annElement.getDisplayCharacter(),
3712 annElement.getDescription(),
3713 (annElement.getSecondaryStructure() == null
3714 || annElement.getSecondaryStructure()
3718 .getSecondaryStructure()
3721 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3722 if (firstColour == null)
3724 firstColour = anot[anpos].colour;
3728 jalview.datamodel.AlignmentAnnotation jaa = null;
3730 if (annotation.isGraph())
3732 float llim = 0, hlim = 0;
3733 // if (autoForView || an[i].isAutoCalculated()) {
3736 jaa = new jalview.datamodel.AlignmentAnnotation(
3737 annotation.getLabel(), annotation.getDescription(), anot,
3738 llim, hlim, safeInt(annotation.getGraphType()));
3740 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3741 jaa._linecolour = firstColour;
3742 if (annotation.getThresholdLine() != null)
3744 jaa.setThreshold(new jalview.datamodel.GraphLine(
3745 safeFloat(annotation.getThresholdLine().getValue()),
3746 annotation.getThresholdLine().getLabel(),
3747 new java.awt.Color(safeInt(
3748 annotation.getThresholdLine().getColour()))));
3750 if (autoForView || annotation.isAutoCalculated())
3752 // Hardwire the symbol display line to ensure that labels for
3753 // histograms are displayed
3759 jaa = new jalview.datamodel.AlignmentAnnotation(
3760 annotation.getLabel(), annotation.getDescription(), anot);
3761 jaa._linecolour = firstColour;
3763 // register new annotation
3764 if (annotation.getId() != null)
3766 annotationIds.put(annotation.getId(), jaa);
3767 jaa.annotationId = annotation.getId();
3769 // recover sequence association
3770 String sequenceRef = annotation.getSequenceRef();
3771 if (sequenceRef != null)
3773 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3774 SequenceI sequence = seqRefIds.get(sequenceRef);
3775 if (sequence == null)
3777 // in pre-2.9 projects sequence ref is to sequence name
3778 sequence = al.findName(sequenceRef);
3780 if (sequence != null)
3782 jaa.createSequenceMapping(sequence, 1, true);
3783 sequence.addAlignmentAnnotation(jaa);
3786 // and make a note of any group association
3787 if (annotation.getGroupRef() != null
3788 && annotation.getGroupRef().length() > 0)
3790 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3791 .get(annotation.getGroupRef());
3794 aal = new ArrayList<>();
3795 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3800 if (annotation.getScore() != null)
3802 jaa.setScore(annotation.getScore().doubleValue());
3804 if (annotation.isVisible() != null)
3806 jaa.visible = annotation.isVisible().booleanValue();
3809 if (annotation.isCentreColLabels() != null)
3811 jaa.centreColLabels = annotation.isCentreColLabels()
3815 if (annotation.isScaleColLabels() != null)
3817 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3819 if (annotation.isAutoCalculated())
3821 // newer files have an 'autoCalculated' flag and store calculation
3822 // state in viewport properties
3823 jaa.autoCalculated = true; // means annotation will be marked for
3824 // update at end of load.
3826 if (annotation.getGraphHeight() != null)
3828 jaa.graphHeight = annotation.getGraphHeight().intValue();
3830 jaa.belowAlignment = annotation.isBelowAlignment();
3831 jaa.setCalcId(annotation.getCalcId());
3832 if (annotation.getProperty().size() > 0)
3834 for (Annotation.Property prop : annotation
3837 jaa.setProperty(prop.getName(), prop.getValue());
3840 if (jaa.autoCalculated)
3842 autoAlan.add(new JvAnnotRow(i, jaa));
3845 // if (!autoForView)
3847 // add autocalculated group annotation and any user created annotation
3849 al.addAnnotation(jaa);
3853 // ///////////////////////
3855 // Create alignment markup and styles for this view
3856 if (jalviewModel.getJGroup().size() > 0)
3858 List<JGroup> groups = jalviewModel.getJGroup();
3859 boolean addAnnotSchemeGroup = false;
3860 for (int i = 0; i < groups.size(); i++)
3862 JGroup jGroup = groups.get(i);
3863 ColourSchemeI cs = null;
3864 if (jGroup.getColour() != null)
3866 if (jGroup.getColour().startsWith("ucs"))
3868 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3870 else if (jGroup.getColour().equals("AnnotationColourGradient")
3871 && jGroup.getAnnotationColours() != null)
3873 addAnnotSchemeGroup = true;
3877 cs = ColourSchemeProperty.getColourScheme(null, al,
3878 jGroup.getColour());
3881 int pidThreshold = safeInt(jGroup.getPidThreshold());
3883 Vector<SequenceI> seqs = new Vector<>();
3885 for (int s = 0; s < jGroup.getSeq().size(); s++)
3887 String seqId = jGroup.getSeq().get(s);
3888 SequenceI ts = seqRefIds.get(seqId);
3892 seqs.addElement(ts);
3896 if (seqs.size() < 1)
3901 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3902 safeBoolean(jGroup.isDisplayBoxes()),
3903 safeBoolean(jGroup.isDisplayText()),
3904 safeBoolean(jGroup.isColourText()),
3905 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3906 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3907 sg.getGroupColourScheme()
3908 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3909 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3911 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3912 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3913 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3914 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3915 // attributes with a default in the schema are never null
3916 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3917 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3918 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3919 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3920 if (jGroup.getConsThreshold() != null
3921 && jGroup.getConsThreshold().intValue() != 0)
3923 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3926 c.verdict(false, 25);
3927 sg.cs.setConservation(c);
3930 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3932 // re-instate unique group/annotation row reference
3933 List<AlignmentAnnotation> jaal = groupAnnotRefs
3934 .get(jGroup.getId());
3937 for (AlignmentAnnotation jaa : jaal)
3940 if (jaa.autoCalculated)
3942 // match up and try to set group autocalc alignment row for this
3944 if (jaa.label.startsWith("Consensus for "))
3946 sg.setConsensus(jaa);
3948 // match up and try to set group autocalc alignment row for this
3950 if (jaa.label.startsWith("Conservation for "))
3952 sg.setConservationRow(jaa);
3959 if (addAnnotSchemeGroup)
3961 // reconstruct the annotation colourscheme
3962 sg.setColourScheme(constructAnnotationColour(
3963 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3969 // only dataset in this model, so just return.
3972 // ///////////////////////////////
3975 AlignFrame af = null;
3976 AlignViewport av = null;
3977 // now check to see if we really need to create a new viewport.
3978 if (multipleView && viewportsAdded.size() == 0)
3980 // We recovered an alignment for which a viewport already exists.
3981 // TODO: fix up any settings necessary for overlaying stored state onto
3982 // state recovered from another document. (may not be necessary).
3983 // we may need a binding from a viewport in memory to one recovered from
3985 // and then recover its containing af to allow the settings to be applied.
3986 // TODO: fix for vamsas demo
3988 "About to recover a viewport for existing alignment: Sequence set ID is "
3990 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3991 if (seqsetobj != null)
3993 if (seqsetobj instanceof String)
3995 uniqueSeqSetId = (String) seqsetobj;
3997 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4003 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4009 * indicate that annotation colours are applied across all groups (pre
4010 * Jalview 2.8.1 behaviour)
4012 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4013 jalviewModel.getVersion());
4015 AlignmentPanel ap = null;
4016 boolean isnewview = true;
4019 // Check to see if this alignment already has a view id == viewId
4020 jalview.gui.AlignmentPanel views[] = Desktop
4021 .getAlignmentPanels(uniqueSeqSetId);
4022 if (views != null && views.length > 0)
4024 for (int v = 0; v < views.length; v++)
4026 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4028 // recover the existing alignpanel, alignframe, viewport
4029 af = views[v].alignFrame;
4032 // TODO: could even skip resetting view settings if we don't want to
4033 // change the local settings from other jalview processes
4042 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4043 uniqueSeqSetId, viewId, autoAlan);
4044 av = af.getViewport();
4049 * Load any trees, PDB structures and viewers
4051 * Not done if flag is false (when this method is used for New View)
4053 if (loadTreesAndStructures)
4055 loadTrees(jalviewModel, view, af, av, ap);
4056 loadPCAViewers(jalviewModel, ap);
4057 loadPDBStructures(jprovider, jseqs, af, ap);
4058 loadRnaViewers(jprovider, jseqs, ap);
4060 // and finally return.
4065 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4066 * panel is restored from separate jar entries, two (gapped and trimmed) per
4067 * sequence and secondary structure.
4069 * Currently each viewer shows just one sequence and structure (gapped and
4070 * trimmed), however this method is designed to support multiple sequences or
4071 * structures in viewers if wanted in future.
4077 private void loadRnaViewers(jarInputStreamProvider jprovider,
4078 List<JSeq> jseqs, AlignmentPanel ap)
4081 * scan the sequences for references to viewers; create each one the first
4082 * time it is referenced, add Rna models to existing viewers
4084 for (JSeq jseq : jseqs)
4086 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4088 RnaViewer viewer = jseq.getRnaViewer().get(i);
4089 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4092 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4094 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4095 SequenceI seq = seqRefIds.get(jseq.getId());
4096 AlignmentAnnotation ann = this.annotationIds
4097 .get(ss.getAnnotationId());
4100 * add the structure to the Varna display (with session state copied
4101 * from the jar to a temporary file)
4103 boolean gapped = safeBoolean(ss.isGapped());
4104 String rnaTitle = ss.getTitle();
4105 String sessionState = ss.getViewerState();
4106 String tempStateFile = copyJarEntry(jprovider, sessionState,
4108 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4109 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4111 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4117 * Locate and return an already instantiated matching AppVarna, or create one
4121 * @param viewIdSuffix
4125 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4126 String viewIdSuffix, AlignmentPanel ap)
4129 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4130 * if load is repeated
4132 String postLoadId = viewer.getViewId() + viewIdSuffix;
4133 for (JInternalFrame frame : getAllFrames())
4135 if (frame instanceof AppVarna)
4137 AppVarna varna = (AppVarna) frame;
4138 if (postLoadId.equals(varna.getViewId()))
4140 // this viewer is already instantiated
4141 // could in future here add ap as another 'parent' of the
4142 // AppVarna window; currently just 1-to-many
4149 * viewer not found - make it
4151 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4152 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4153 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4154 safeInt(viewer.getDividerLocation()));
4155 AppVarna varna = new AppVarna(model, ap);
4161 * Load any saved trees
4169 protected void loadTrees(JalviewModel jm, Viewport view,
4170 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4172 // TODO result of automated refactoring - are all these parameters needed?
4175 for (int t = 0; t < jm.getTree().size(); t++)
4178 Tree tree = jm.getTree().get(t);
4180 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4183 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4184 tree.getTitle(), safeInt(tree.getWidth()),
4185 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4186 safeInt(tree.getYpos()));
4187 if (tree.getId() != null)
4189 // perhaps bind the tree id to something ?
4194 // update local tree attributes ?
4195 // TODO: should check if tp has been manipulated by user - if so its
4196 // settings shouldn't be modified
4197 tp.setTitle(tree.getTitle());
4198 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4199 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4200 safeInt(tree.getHeight())));
4201 tp.setViewport(av); // af.viewport;
4202 // TODO: verify 'associate with all views' works still
4203 tp.getTreeCanvas().setViewport(av); // af.viewport;
4204 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4206 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4209 warn("There was a problem recovering stored Newick tree: \n"
4210 + tree.getNewick());
4214 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4215 tp.fitToWindow_actionPerformed(null);
4217 if (tree.getFontName() != null)
4220 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4221 safeInt(tree.getFontSize())));
4226 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4227 safeInt(view.getFontSize())));
4230 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4231 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4232 tp.showDistances(safeBoolean(tree.isShowDistances()));
4234 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4236 if (safeBoolean(tree.isCurrentTree()))
4238 af.getViewport().setCurrentTree(tp.getTree());
4242 } catch (Exception ex)
4244 ex.printStackTrace();
4249 * Load and link any saved structure viewers.
4256 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4257 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4260 * Run through all PDB ids on the alignment, and collect mappings between
4261 * distinct view ids and all sequences referring to that view.
4263 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4265 for (int i = 0; i < jseqs.size(); i++)
4267 JSeq jseq = jseqs.get(i);
4268 if (jseq.getPdbids().size() > 0)
4270 List<Pdbids> ids = jseq.getPdbids();
4271 for (int p = 0; p < ids.size(); p++)
4273 Pdbids pdbid = ids.get(p);
4274 final int structureStateCount = pdbid.getStructureState().size();
4275 for (int s = 0; s < structureStateCount; s++)
4277 // check to see if we haven't already created this structure view
4278 final StructureState structureState = pdbid
4279 .getStructureState().get(s);
4280 String sviewid = (structureState.getViewId() == null) ? null
4281 : structureState.getViewId() + uniqueSetSuffix;
4282 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4283 // Originally : pdbid.getFile()
4284 // : TODO: verify external PDB file recovery still works in normal
4285 // jalview project load
4287 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4288 jpdb.setId(pdbid.getId());
4290 int x = safeInt(structureState.getXpos());
4291 int y = safeInt(structureState.getYpos());
4292 int width = safeInt(structureState.getWidth());
4293 int height = safeInt(structureState.getHeight());
4295 // Probably don't need to do this anymore...
4296 // Desktop.getDesktop().getComponentAt(x, y);
4297 // TODO: NOW: check that this recovers the PDB file correctly.
4298 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4300 jalview.datamodel.SequenceI seq = seqRefIds
4301 .get(jseq.getId() + "");
4302 if (sviewid == null)
4304 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4307 if (!structureViewers.containsKey(sviewid))
4309 structureViewers.put(sviewid,
4310 new StructureViewerModel(x, y, width, height, false,
4311 false, true, structureState.getViewId(),
4312 structureState.getType()));
4313 // Legacy pre-2.7 conversion JAL-823 :
4314 // do not assume any view has to be linked for colour by
4318 // assemble String[] { pdb files }, String[] { id for each
4319 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4320 // seqs_file 2}, boolean[] {
4321 // linkAlignPanel,superposeWithAlignpanel}} from hash
4322 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4323 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4324 || structureState.isAlignwithAlignPanel());
4327 * Default colour by linked panel to false if not specified (e.g.
4328 * for pre-2.7 projects)
4330 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4331 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4332 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4335 * Default colour by viewer to true if not specified (e.g. for
4338 boolean colourByViewer = jmoldat.isColourByViewer();
4339 colourByViewer &= structureState.isColourByJmol();
4340 jmoldat.setColourByViewer(colourByViewer);
4342 if (jmoldat.getStateData().length() < structureState
4343 .getValue()/*Content()*/.length())
4345 jmoldat.setStateData(structureState.getValue());// Content());
4347 if (pdbid.getFile() != null)
4349 File mapkey = new File(pdbid.getFile());
4350 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4351 if (seqstrmaps == null)
4353 jmoldat.getFileData().put(mapkey,
4354 seqstrmaps = jmoldat.new StructureData(pdbFile,
4357 if (!seqstrmaps.getSeqList().contains(seq))
4359 seqstrmaps.getSeqList().add(seq);
4365 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");
4372 // Instantiate the associated structure views
4373 for (Entry<String, StructureViewerModel> entry : structureViewers
4378 createOrLinkStructureViewer(entry, af, ap, jprovider);
4379 } catch (Exception e)
4382 "Error loading structure viewer: " + e.getMessage());
4383 // failed - try the next one
4395 protected void createOrLinkStructureViewer(
4396 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4397 AlignmentPanel ap, jarInputStreamProvider jprovider)
4399 final StructureViewerModel stateData = viewerData.getValue();
4402 * Search for any viewer windows already open from other alignment views
4403 * that exactly match the stored structure state
4405 StructureViewerBase comp = findMatchingViewer(viewerData);
4409 linkStructureViewer(ap, comp, stateData);
4414 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4415 * "viewer_"+stateData.viewId
4417 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4419 createChimeraViewer(viewerData, af, jprovider);
4424 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4426 createJmolViewer(viewerData, af, jprovider);
4431 * Create a new Chimera viewer.
4437 protected void createChimeraViewer(
4438 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4439 jarInputStreamProvider jprovider)
4441 StructureViewerModel data = viewerData.getValue();
4442 String chimeraSessionFile = data.getStateData();
4445 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4447 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4448 * 'uniquified' sviewid used to reconstruct the viewer here
4450 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4451 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4454 Set<Entry<File, StructureData>> fileData = data.getFileData()
4456 List<PDBEntry> pdbs = new ArrayList<>();
4457 List<SequenceI[]> allseqs = new ArrayList<>();
4458 for (Entry<File, StructureData> pdb : fileData)
4460 String filePath = pdb.getValue().getFilePath();
4461 String pdbId = pdb.getValue().getPdbId();
4462 // pdbs.add(new PDBEntry(filePath, pdbId));
4463 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4464 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4465 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4469 boolean colourByChimera = data.isColourByViewer();
4470 boolean colourBySequence = data.isColourWithAlignPanel();
4472 // TODO use StructureViewer as a factory here, see JAL-1761
4473 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4474 final SequenceI[][] seqsArray = allseqs
4475 .toArray(new SequenceI[allseqs.size()][]);
4476 String newViewId = viewerData.getKey();
4478 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4479 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4480 colourBySequence, newViewId);
4481 cvf.setSize(data.getWidth(), data.getHeight());
4482 cvf.setLocation(data.getX(), data.getY());
4486 * Create a new Jmol window. First parse the Jmol state to translate filenames
4487 * loaded into the view, and record the order in which files are shown in the
4488 * Jmol view, so we can add the sequence mappings in same order.
4494 protected void createJmolViewer(
4495 final Entry<String, StructureViewerModel> viewerData,
4496 AlignFrame af, jarInputStreamProvider jprovider)
4498 final StructureViewerModel svattrib = viewerData.getValue();
4499 String state = svattrib.getStateData();
4502 * Pre-2.9: state element value is the Jmol state string
4504 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4507 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4509 state = readJarEntry(jprovider,
4510 getViewerJarEntryName(svattrib.getViewId()));
4513 List<String> pdbfilenames = new ArrayList<>();
4514 List<SequenceI[]> seqmaps = new ArrayList<>();
4515 List<String> pdbids = new ArrayList<>();
4516 StringBuilder newFileLoc = new StringBuilder(64);
4517 int cp = 0, ncp, ecp;
4518 Map<File, StructureData> oldFiles = svattrib.getFileData();
4519 while ((ncp = state.indexOf("load ", cp)) > -1)
4523 // look for next filename in load statement
4524 newFileLoc.append(state.substring(cp,
4525 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4526 String oldfilenam = state.substring(ncp,
4527 ecp = state.indexOf("\"", ncp));
4528 // recover the new mapping data for this old filename
4529 // have to normalize filename - since Jmol and jalview do
4531 // translation differently.
4532 StructureData filedat = oldFiles.get(new File(oldfilenam));
4533 if (filedat == null)
4535 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4536 filedat = oldFiles.get(new File(reformatedOldFilename));
4538 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4539 pdbfilenames.add(filedat.getFilePath());
4540 pdbids.add(filedat.getPdbId());
4541 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4542 newFileLoc.append("\"");
4543 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4544 // look for next file statement.
4545 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4549 // just append rest of state
4550 newFileLoc.append(state.substring(cp));
4554 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4555 newFileLoc = new StringBuilder(state);
4556 newFileLoc.append("; load append ");
4557 for (File id : oldFiles.keySet())
4559 // add this and any other pdb files that should be present in
4561 StructureData filedat = oldFiles.get(id);
4562 newFileLoc.append(filedat.getFilePath());
4563 pdbfilenames.add(filedat.getFilePath());
4564 pdbids.add(filedat.getPdbId());
4565 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4566 newFileLoc.append(" \"");
4567 newFileLoc.append(filedat.getFilePath());
4568 newFileLoc.append("\"");
4571 newFileLoc.append(";");
4574 if (newFileLoc.length() == 0)
4578 int histbug = newFileLoc.indexOf("history = ");
4582 * change "history = [true|false];" to "history = [1|0];"
4585 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4586 String val = (diff == -1) ? null
4587 : newFileLoc.substring(histbug, diff);
4588 if (val != null && val.length() >= 4)
4590 if (val.contains("e")) // eh? what can it be?
4592 if (val.trim().equals("true"))
4600 newFileLoc.replace(histbug, diff, val);
4605 final String[] pdbf = pdbfilenames
4606 .toArray(new String[pdbfilenames.size()]);
4607 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4608 final SequenceI[][] sq = seqmaps
4609 .toArray(new SequenceI[seqmaps.size()][]);
4610 final String fileloc = newFileLoc.toString();
4611 final String sviewid = viewerData.getKey();
4612 final AlignFrame alf = af;
4613 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4614 svattrib.getWidth(), svattrib.getHeight());
4617 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4622 JalviewStructureDisplayI sview = null;
4625 sview = new StructureViewer(
4626 alf.alignPanel.getStructureSelectionManager())
4627 .createView(StructureViewer.ViewerType.JMOL,
4628 pdbf, id, sq, alf.alignPanel, svattrib,
4629 fileloc, rect, sviewid);
4630 addNewStructureViewer(sview);
4631 } catch (OutOfMemoryError ex)
4633 new OOMWarning("restoring structure view for PDB id " + id,
4634 (OutOfMemoryError) ex.getCause());
4635 if (sview != null && sview.isVisible())
4637 sview.closeViewer(false);
4638 sview.setVisible(false);
4644 } catch (InvocationTargetException ex)
4646 warn("Unexpected error when opening Jmol view.", ex);
4648 } catch (InterruptedException e)
4650 // e.printStackTrace();
4656 * Generates a name for the entry in the project jar file to hold state
4657 * information for a structure viewer
4662 protected String getViewerJarEntryName(String viewId)
4664 return VIEWER_PREFIX + viewId;
4668 * Returns any open frame that matches given structure viewer data. The match
4669 * is based on the unique viewId, or (for older project versions) the frame's
4675 protected StructureViewerBase findMatchingViewer(
4676 Entry<String, StructureViewerModel> viewerData)
4678 final String sviewid = viewerData.getKey();
4679 final StructureViewerModel svattrib = viewerData.getValue();
4680 StructureViewerBase comp = null;
4681 JInternalFrame[] frames = getAllFrames();
4682 for (JInternalFrame frame : frames)
4684 if (frame instanceof StructureViewerBase)
4687 * Post jalview 2.4 schema includes structure view id
4689 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4692 comp = (StructureViewerBase) frame;
4693 break; // break added in 2.9
4696 * Otherwise test for matching position and size of viewer frame
4698 else if (frame.getX() == svattrib.getX()
4699 && frame.getY() == svattrib.getY()
4700 && frame.getHeight() == svattrib.getHeight()
4701 && frame.getWidth() == svattrib.getWidth())
4703 comp = (StructureViewerBase) frame;
4704 // no break in faint hope of an exact match on viewId
4712 * Link an AlignmentPanel to an existing structure viewer.
4717 * @param useinViewerSuperpos
4718 * @param usetoColourbyseq
4719 * @param viewerColouring
4721 protected void linkStructureViewer(AlignmentPanel ap,
4722 StructureViewerBase viewer, StructureViewerModel stateData)
4724 // NOTE: if the jalview project is part of a shared session then
4725 // view synchronization should/could be done here.
4727 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4728 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4729 final boolean viewerColouring = stateData.isColourByViewer();
4730 Map<File, StructureData> oldFiles = stateData.getFileData();
4733 * Add mapping for sequences in this view to an already open viewer
4735 final AAStructureBindingModel binding = viewer.getBinding();
4736 for (File id : oldFiles.keySet())
4738 // add this and any other pdb files that should be present in the
4740 StructureData filedat = oldFiles.get(id);
4741 String pdbFile = filedat.getFilePath();
4742 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4743 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4745 binding.addSequenceForStructFile(pdbFile, seq);
4747 // and add the AlignmentPanel's reference to the view panel
4748 viewer.addAlignmentPanel(ap);
4749 if (useinViewerSuperpos)
4751 viewer.useAlignmentPanelForSuperposition(ap);
4755 viewer.excludeAlignmentPanelForSuperposition(ap);
4757 if (usetoColourbyseq)
4759 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4763 viewer.excludeAlignmentPanelForColourbyseq(ap);
4768 * Get all frames within the Desktop.
4772 protected JInternalFrame[] getAllFrames()
4774 JInternalFrame[] frames = null;
4775 // TODO is this necessary - is it safe - risk of hanging?
4780 frames = Desktop.getDesktopPane().getAllFrames();
4781 } catch (ArrayIndexOutOfBoundsException e)
4783 // occasional No such child exceptions are thrown here...
4787 } catch (InterruptedException f)
4791 } while (frames == null);
4796 * Answers true if 'version' is equal to or later than 'supported', where each
4797 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4798 * changes. Development and test values for 'version' are leniently treated
4802 * - minimum version we are comparing against
4804 * - version of data being processsed
4807 public static boolean isVersionStringLaterThan(String supported,
4810 if (supported == null || version == null
4811 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4812 || version.equalsIgnoreCase("Test")
4813 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4815 System.err.println("Assuming project file with "
4816 + (version == null ? "null" : version)
4817 + " is compatible with Jalview version " + supported);
4822 return StringUtils.compareVersions(version, supported, "b") >= 0;
4826 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4828 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4830 if (newStructureViewers != null)
4832 sview.getBinding().setFinishedLoadingFromArchive(false);
4833 newStructureViewers.add(sview);
4837 protected void setLoadingFinishedForNewStructureViewers()
4839 if (newStructureViewers != null)
4841 for (JalviewStructureDisplayI sview : newStructureViewers)
4843 sview.getBinding().setFinishedLoadingFromArchive(true);
4845 newStructureViewers.clear();
4846 newStructureViewers = null;
4850 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4851 List<SequenceI> hiddenSeqs, AlignmentI al,
4852 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4853 String viewId, List<JvAnnotRow> autoAlan)
4855 AlignFrame af = null;
4856 af = new AlignFrame(al, safeInt(view.getWidth()),
4857 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4861 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4862 // System.out.println("Jalview2XML AF " + e);
4863 // super.processKeyEvent(e);
4870 af.setFileName(file, FileFormat.Jalview);
4872 final AlignViewport viewport = af.getViewport();
4873 for (int i = 0; i < JSEQ.size(); i++)
4875 int colour = safeInt(JSEQ.get(i).getColour());
4876 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4882 viewport.setColourByReferenceSeq(true);
4883 viewport.setDisplayReferenceSeq(true);
4886 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4888 if (view.getSequenceSetId() != null)
4890 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4892 viewport.setSequenceSetId(uniqueSeqSetId);
4895 // propagate shared settings to this new view
4896 viewport.setHistoryList(av.getHistoryList());
4897 viewport.setRedoList(av.getRedoList());
4901 viewportsAdded.put(uniqueSeqSetId, viewport);
4903 // TODO: check if this method can be called repeatedly without
4904 // side-effects if alignpanel already registered.
4905 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4907 // apply Hidden regions to view.
4908 if (hiddenSeqs != null)
4910 for (int s = 0; s < JSEQ.size(); s++)
4912 SequenceGroup hidden = new SequenceGroup();
4913 boolean isRepresentative = false;
4914 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4916 isRepresentative = true;
4917 SequenceI sequenceToHide = al
4918 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4919 hidden.addSequence(sequenceToHide, false);
4920 // remove from hiddenSeqs list so we don't try to hide it twice
4921 hiddenSeqs.remove(sequenceToHide);
4923 if (isRepresentative)
4925 SequenceI representativeSequence = al.getSequenceAt(s);
4926 hidden.addSequence(representativeSequence, false);
4927 viewport.hideRepSequences(representativeSequence, hidden);
4931 SequenceI[] hseqs = hiddenSeqs
4932 .toArray(new SequenceI[hiddenSeqs.size()]);
4933 viewport.hideSequence(hseqs);
4936 // recover view properties and display parameters
4938 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4939 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4940 final int pidThreshold = safeInt(view.getPidThreshold());
4941 viewport.setThreshold(pidThreshold);
4943 viewport.setColourText(safeBoolean(view.isShowColourText()));
4946 .setConservationSelected(
4947 safeBoolean(view.isConservationSelected()));
4948 viewport.setIncrement(safeInt(view.getConsThreshold()));
4949 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4950 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4951 viewport.setFont(new Font(view.getFontName(),
4952 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4954 ViewStyleI vs = viewport.getViewStyle();
4955 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4956 viewport.setViewStyle(vs);
4957 // TODO: allow custom charWidth/Heights to be restored by updating them
4958 // after setting font - which means set above to false
4959 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4960 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4961 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4963 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4965 viewport.setShowText(safeBoolean(view.isShowText()));
4967 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4968 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4969 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4970 viewport.setShowUnconserved(view.isShowUnconserved());
4971 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4973 if (view.getViewName() != null)
4975 viewport.setViewName(view.getViewName());
4976 af.setInitialTabVisible();
4978 int x = safeInt(view.getXpos());
4979 int y = safeInt(view.getYpos());
4980 int w = safeInt(view.getWidth());
4981 int h = safeInt(view.getHeight());
4982 // // BH we cannot let the title bar go off the top
4983 // if (Platform.isJS())
4985 // x = Math.max(50 - w, x);
4986 // y = Math.max(0, y);
4989 af.setBounds(x, y, w, h);
4990 // startSeq set in af.alignPanel.updateLayout below
4991 af.alignPanel.updateLayout();
4992 ColourSchemeI cs = null;
4993 // apply colourschemes
4994 if (view.getBgColour() != null)
4996 if (view.getBgColour().startsWith("ucs"))
4998 cs = getUserColourScheme(jm, view.getBgColour());
5000 else if (view.getBgColour().startsWith("Annotation"))
5002 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5003 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5010 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5011 view.getBgColour());
5016 * turn off 'alignment colour applies to all groups'
5017 * while restoring global colour scheme
5019 viewport.setColourAppliesToAllGroups(false);
5020 viewport.setGlobalColourScheme(cs);
5021 viewport.getResidueShading().setThreshold(pidThreshold,
5022 view.isIgnoreGapsinConsensus());
5023 viewport.getResidueShading()
5024 .setConsensus(viewport.getSequenceConsensusHash());
5025 if (safeBoolean(view.isConservationSelected()) && cs != null)
5027 viewport.getResidueShading()
5028 .setConservationInc(safeInt(view.getConsThreshold()));
5030 af.changeColour(cs);
5031 viewport.setColourAppliesToAllGroups(true);
5034 .setShowSequenceFeatures(
5035 safeBoolean(view.isShowSequenceFeatures()));
5037 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5038 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5039 viewport.setFollowHighlight(view.isFollowHighlight());
5040 viewport.followSelection = view.isFollowSelection();
5041 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5042 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5043 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5044 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5045 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5046 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5047 viewport.setShowGroupConservation(view.isShowGroupConservation());
5049 // recover feature settings
5050 if (jm.getFeatureSettings() != null)
5052 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
5053 .getFeatureRenderer();
5054 FeaturesDisplayed fdi;
5055 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5056 String[] renderOrder = new String[jm.getFeatureSettings()
5057 .getSetting().size()];
5058 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5059 Map<String, Float> featureOrder = new Hashtable<>();
5061 for (int fs = 0; fs < jm.getFeatureSettings()
5062 .getSetting().size(); fs++)
5064 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5065 String featureType = setting.getType();
5068 * restore feature filters (if any)
5070 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5072 if (filters != null)
5074 FeatureMatcherSetI filter = Jalview2XML
5075 .parseFilter(featureType, filters);
5076 if (!filter.isEmpty())
5078 fr.setFeatureFilter(featureType, filter);
5083 * restore feature colour scheme
5085 Color maxColour = new Color(setting.getColour());
5086 if (setting.getMincolour() != null)
5089 * minColour is always set unless a simple colour
5090 * (including for colour by label though it doesn't use it)
5092 Color minColour = new Color(setting.getMincolour().intValue());
5093 Color noValueColour = minColour;
5094 NoValueColour noColour = setting.getNoValueColour();
5095 if (noColour == NoValueColour.NONE)
5097 noValueColour = null;
5099 else if (noColour == NoValueColour.MAX)
5101 noValueColour = maxColour;
5103 float min = safeFloat(safeFloat(setting.getMin()));
5104 float max = setting.getMax() == null ? 1f
5105 : setting.getMax().floatValue();
5106 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5108 noValueColour, min, max);
5109 if (setting.getAttributeName().size() > 0)
5111 gc.setAttributeName(setting.getAttributeName().toArray(
5112 new String[setting.getAttributeName().size()]));
5114 if (setting.getThreshold() != null)
5116 gc.setThreshold(setting.getThreshold().floatValue());
5117 int threshstate = safeInt(setting.getThreshstate());
5118 // -1 = None, 0 = Below, 1 = Above threshold
5119 if (threshstate == 0)
5121 gc.setBelowThreshold(true);
5123 else if (threshstate == 1)
5125 gc.setAboveThreshold(true);
5128 gc.setAutoScaled(true); // default
5129 if (setting.isAutoScale() != null)
5131 gc.setAutoScaled(setting.isAutoScale());
5133 if (setting.isColourByLabel() != null)
5135 gc.setColourByLabel(setting.isColourByLabel());
5137 // and put in the feature colour table.
5138 featureColours.put(featureType, gc);
5142 featureColours.put(featureType,
5143 new FeatureColour(maxColour));
5145 renderOrder[fs] = featureType;
5146 if (setting.getOrder() != null)
5148 featureOrder.put(featureType, setting.getOrder().floatValue());
5152 featureOrder.put(featureType, new Float(
5153 fs / jm.getFeatureSettings().getSetting().size()));
5155 if (safeBoolean(setting.isDisplay()))
5157 fdi.setVisible(featureType);
5160 Map<String, Boolean> fgtable = new Hashtable<>();
5161 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5163 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5164 fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
5166 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5167 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5168 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5169 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5170 fgtable, featureColours, 1.0f, featureOrder);
5171 fr.transferSettings(frs);
5174 if (view.getHiddenColumns().size() > 0)
5176 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5178 final HiddenColumns hc = view.getHiddenColumns().get(c);
5179 viewport.hideColumns(safeInt(hc.getStart()),
5180 safeInt(hc.getEnd()) /* +1 */);
5183 if (view.getCalcIdParam() != null)
5185 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5187 if (calcIdParam != null)
5189 if (recoverCalcIdParam(calcIdParam, viewport))
5194 warn("Couldn't recover parameters for "
5195 + calcIdParam.getCalcId());
5200 af.setMenusFromViewport(viewport);
5201 af.setTitle(view.getTitle());
5202 // TODO: we don't need to do this if the viewport is aready visible.
5204 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5205 * has a 'cdna/protein complement' view, in which case save it in order to
5206 * populate a SplitFrame once all views have been read in.
5208 String complementaryViewId = view.getComplementId();
5209 if (complementaryViewId == null)
5211 Desktop.addInternalFrame(af, view.getTitle(),
5212 safeInt(view.getWidth()), safeInt(view.getHeight()));
5213 // recompute any autoannotation
5214 af.alignPanel.updateAnnotation(false, true);
5215 reorderAutoannotation(af, al, autoAlan);
5216 af.alignPanel.alignmentChanged();
5220 splitFrameCandidates.put(view, af);
5226 * Reads saved data to restore Colour by Annotation settings
5228 * @param viewAnnColour
5232 * @param checkGroupAnnColour
5235 private ColourSchemeI constructAnnotationColour(
5236 AnnotationColourScheme viewAnnColour, AlignFrame af,
5237 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5239 boolean propagateAnnColour = false;
5240 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5242 if (checkGroupAnnColour && al.getGroups() != null
5243 && al.getGroups().size() > 0)
5245 // pre 2.8.1 behaviour
5246 // check to see if we should transfer annotation colours
5247 propagateAnnColour = true;
5248 for (SequenceGroup sg : al.getGroups())
5250 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5252 propagateAnnColour = false;
5258 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5260 String annotationId = viewAnnColour.getAnnotation();
5261 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5264 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5266 if (matchedAnnotation == null
5267 && annAlignment.getAlignmentAnnotation() != null)
5269 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5272 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5274 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5279 if (matchedAnnotation == null)
5281 System.err.println("Failed to match annotation colour scheme for "
5285 if (matchedAnnotation.getThreshold() == null)
5287 matchedAnnotation.setThreshold(
5288 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5289 "Threshold", Color.black));
5292 AnnotationColourGradient cs = null;
5293 if (viewAnnColour.getColourScheme().equals("None"))
5295 cs = new AnnotationColourGradient(matchedAnnotation,
5296 new Color(safeInt(viewAnnColour.getMinColour())),
5297 new Color(safeInt(viewAnnColour.getMaxColour())),
5298 safeInt(viewAnnColour.getAboveThreshold()));
5300 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5302 cs = new AnnotationColourGradient(matchedAnnotation,
5303 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5304 safeInt(viewAnnColour.getAboveThreshold()));
5308 cs = new AnnotationColourGradient(matchedAnnotation,
5309 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5310 viewAnnColour.getColourScheme()),
5311 safeInt(viewAnnColour.getAboveThreshold()));
5314 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5315 boolean useOriginalColours = safeBoolean(
5316 viewAnnColour.isPredefinedColours());
5317 cs.setSeqAssociated(perSequenceOnly);
5318 cs.setPredefinedColours(useOriginalColours);
5320 if (propagateAnnColour && al.getGroups() != null)
5322 // Also use these settings for all the groups
5323 for (int g = 0; g < al.getGroups().size(); g++)
5325 SequenceGroup sg = al.getGroups().get(g);
5326 if (sg.getGroupColourScheme() == null)
5331 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5332 matchedAnnotation, sg.getColourScheme(),
5333 safeInt(viewAnnColour.getAboveThreshold()));
5334 sg.setColourScheme(groupScheme);
5335 groupScheme.setSeqAssociated(perSequenceOnly);
5336 groupScheme.setPredefinedColours(useOriginalColours);
5342 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5343 List<JvAnnotRow> autoAlan)
5345 // copy over visualization settings for autocalculated annotation in the
5347 if (al.getAlignmentAnnotation() != null)
5350 * Kludge for magic autoannotation names (see JAL-811)
5352 String[] magicNames = new String[] { "Consensus", "Quality",
5354 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5355 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5356 for (String nm : magicNames)
5358 visan.put(nm, nullAnnot);
5360 for (JvAnnotRow auan : autoAlan)
5362 visan.put(auan.template.label
5363 + (auan.template.getCalcId() == null ? ""
5364 : "\t" + auan.template.getCalcId()),
5367 int hSize = al.getAlignmentAnnotation().length;
5368 List<JvAnnotRow> reorder = new ArrayList<>();
5369 // work through any autoCalculated annotation already on the view
5370 // removing it if it should be placed in a different location on the
5371 // annotation panel.
5372 List<String> remains = new ArrayList<>(visan.keySet());
5373 for (int h = 0; h < hSize; h++)
5375 jalview.datamodel.AlignmentAnnotation jalan = al
5376 .getAlignmentAnnotation()[h];
5377 if (jalan.autoCalculated)
5380 JvAnnotRow valan = visan.get(k = jalan.label);
5381 if (jalan.getCalcId() != null)
5383 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5388 // delete the auto calculated row from the alignment
5389 al.deleteAnnotation(jalan, false);
5393 if (valan != nullAnnot)
5395 if (jalan != valan.template)
5397 // newly created autoannotation row instance
5398 // so keep a reference to the visible annotation row
5399 // and copy over all relevant attributes
5400 if (valan.template.graphHeight >= 0)
5403 jalan.graphHeight = valan.template.graphHeight;
5405 jalan.visible = valan.template.visible;
5407 reorder.add(new JvAnnotRow(valan.order, jalan));
5412 // Add any (possibly stale) autocalculated rows that were not appended to
5413 // the view during construction
5414 for (String other : remains)
5416 JvAnnotRow othera = visan.get(other);
5417 if (othera != nullAnnot && othera.template.getCalcId() != null
5418 && othera.template.getCalcId().length() > 0)
5420 reorder.add(othera);
5423 // now put the automatic annotation in its correct place
5424 int s = 0, srt[] = new int[reorder.size()];
5425 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5426 for (JvAnnotRow jvar : reorder)
5429 srt[s++] = jvar.order;
5432 jalview.util.QuickSort.sort(srt, rws);
5433 // and re-insert the annotation at its correct position
5434 for (JvAnnotRow jvar : rws)
5436 al.addAnnotation(jvar.template, jvar.order);
5438 af.alignPanel.adjustAnnotationHeight();
5442 Hashtable skipList = null;
5445 * TODO remove this method
5448 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5449 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5450 * throw new Error("Implementation Error. No skipList defined for this
5451 * Jalview2XML instance."); } return (AlignFrame)
5452 * skipList.get(view.getSequenceSetId()); }
5456 * Check if the Jalview view contained in object should be skipped or not.
5459 * @return true if view's sequenceSetId is a key in skipList
5461 private boolean skipViewport(JalviewModel object)
5463 if (skipList == null)
5467 String id = object.getViewport().get(0).getSequenceSetId();
5468 if (skipList.containsKey(id))
5470 if (Cache.log != null && Cache.log.isDebugEnabled())
5472 Cache.log.debug("Skipping seuqence set id " + id);
5479 public void addToSkipList(AlignFrame af)
5481 if (skipList == null)
5483 skipList = new Hashtable();
5485 skipList.put(af.getViewport().getSequenceSetId(), af);
5488 public void clearSkipList()
5490 if (skipList != null)
5497 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5498 boolean ignoreUnrefed, String uniqueSeqSetId)
5500 jalview.datamodel.AlignmentI ds = getDatasetFor(
5501 vamsasSet.getDatasetId());
5502 AlignmentI xtant_ds = ds;
5503 if (xtant_ds == null)
5505 // good chance we are about to create a new dataset, but check if we've
5506 // seen some of the dataset sequence IDs before.
5507 // TODO: skip this check if we are working with project generated by
5508 // version 2.11 or later
5509 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5510 if (xtant_ds != null)
5513 addDatasetRef(vamsasSet.getDatasetId(), ds);
5516 Vector dseqs = null;
5519 // recovering an alignment View
5520 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5521 if (seqSetDS != null)
5523 if (ds != null && ds != seqSetDS)
5525 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5526 + " - CDS/Protein crossreference data may be lost");
5527 if (xtant_ds != null)
5529 // This can only happen if the unique sequence set ID was bound to a
5530 // dataset that did not contain any of the sequences in the view
5531 // currently being restored.
5532 warn("JAL-3171 SERIOUS! TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed.");
5536 addDatasetRef(vamsasSet.getDatasetId(), ds);
5541 // try even harder to restore dataset
5542 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5543 // create a list of new dataset sequences
5544 dseqs = new Vector();
5546 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5548 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5549 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5551 // create a new dataset
5554 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5555 dseqs.copyInto(dsseqs);
5556 ds = new jalview.datamodel.Alignment(dsseqs);
5557 debug("Created new dataset " + vamsasSet.getDatasetId()
5558 + " for alignment " + System.identityHashCode(al));
5559 addDatasetRef(vamsasSet.getDatasetId(), ds);
5561 // set the dataset for the newly imported alignment.
5562 if (al.getDataset() == null && !ignoreUnrefed)
5565 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5566 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5568 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5572 * XML dataset sequence ID to materialised dataset reference
5574 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5577 * @return the first materialised dataset reference containing a dataset
5578 * sequence referenced in the given view
5580 * - sequences from the view
5582 AlignmentI checkIfHasDataset(List<Sequence> list)
5584 for (Sequence restoredSeq : list)
5586 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5587 if (datasetFor != null)
5596 * Register ds as the containing dataset for the dataset sequences referenced
5597 * by sequences in list
5600 * - sequences in a view
5603 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5605 for (Sequence restoredSeq : list)
5607 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5608 if (prevDS != null && prevDS != ds)
5610 warn("Dataset sequence appears in many datasets: "
5611 + restoredSeq.getDsseqid());
5612 // TODO: try to merge!
5619 * sequence definition to create/merge dataset sequence for
5623 * vector to add new dataset sequence to
5624 * @param ignoreUnrefed
5625 * - when true, don't create new sequences from vamsasSeq if it's id
5626 * doesn't already have an asssociated Jalview sequence.
5628 * - used to reorder the sequence in the alignment according to the
5629 * vamsasSeq array ordering, to preserve ordering of dataset
5631 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5632 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5634 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5636 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5637 boolean reorder = false;
5638 SequenceI dsq = null;
5639 if (sq != null && sq.getDatasetSequence() != null)
5641 dsq = sq.getDatasetSequence();
5647 if (sq == null && ignoreUnrefed)
5651 String sqid = vamsasSeq.getDsseqid();
5654 // need to create or add a new dataset sequence reference to this sequence
5657 dsq = seqRefIds.get(sqid);
5662 // make a new dataset sequence
5663 dsq = sq.createDatasetSequence();
5666 // make up a new dataset reference for this sequence
5667 sqid = seqHash(dsq);
5669 dsq.setVamsasId(uniqueSetSuffix + sqid);
5670 seqRefIds.put(sqid, dsq);
5675 dseqs.addElement(dsq);
5680 ds.addSequence(dsq);
5686 { // make this dataset sequence sq's dataset sequence
5687 sq.setDatasetSequence(dsq);
5688 // and update the current dataset alignment
5693 if (!dseqs.contains(dsq))
5700 if (ds.findIndex(dsq) < 0)
5702 ds.addSequence(dsq);
5709 // TODO: refactor this as a merge dataset sequence function
5710 // now check that sq (the dataset sequence) sequence really is the union of
5711 // all references to it
5712 // boolean pre = sq.getStart() < dsq.getStart();
5713 // boolean post = sq.getEnd() > dsq.getEnd();
5717 // StringBuffer sb = new StringBuffer();
5718 String newres = jalview.analysis.AlignSeq.extractGaps(
5719 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5720 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5721 && newres.length() > dsq.getLength())
5723 // Update with the longer sequence.
5727 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5728 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5729 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5730 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5732 dsq.setSequence(newres);
5734 // TODO: merges will never happen if we 'know' we have the real dataset
5735 // sequence - this should be detected when id==dssid
5737 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5738 // + (pre ? "prepended" : "") + " "
5739 // + (post ? "appended" : ""));
5744 // sequence refs are identical. We may need to update the existing dataset
5745 // alignment with this one, though.
5746 if (ds != null && dseqs == null)
5748 int opos = ds.findIndex(dsq);
5749 SequenceI tseq = null;
5750 if (opos != -1 && vseqpos != opos)
5752 // remove from old position
5753 ds.deleteSequence(dsq);
5755 if (vseqpos < ds.getHeight())
5757 if (vseqpos != opos)
5759 // save sequence at destination position
5760 tseq = ds.getSequenceAt(vseqpos);
5761 ds.replaceSequenceAt(vseqpos, dsq);
5762 ds.addSequence(tseq);
5767 ds.addSequence(dsq);
5774 * TODO use AlignmentI here and in related methods - needs
5775 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5777 Hashtable<String, AlignmentI> datasetIds = null;
5779 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5781 private AlignmentI getDatasetFor(String datasetId)
5783 if (datasetIds == null)
5785 datasetIds = new Hashtable<>();
5788 if (datasetIds.containsKey(datasetId))
5790 return datasetIds.get(datasetId);
5795 private void addDatasetRef(String datasetId, AlignmentI dataset)
5797 if (datasetIds == null)
5799 datasetIds = new Hashtable<>();
5801 datasetIds.put(datasetId, dataset);
5805 * make a new dataset ID for this jalview dataset alignment
5810 private String getDatasetIdRef(AlignmentI dataset)
5812 if (dataset.getDataset() != null)
5814 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5816 String datasetId = makeHashCode(dataset, null);
5817 if (datasetId == null)
5819 // make a new datasetId and record it
5820 if (dataset2Ids == null)
5822 dataset2Ids = new IdentityHashMap<>();
5826 datasetId = dataset2Ids.get(dataset);
5828 if (datasetId == null)
5830 datasetId = "ds" + dataset2Ids.size() + 1;
5831 dataset2Ids.put(dataset, datasetId);
5837 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5839 for (int d = 0; d < sequence.getDBRef().size(); d++)
5841 DBRef dr = sequence.getDBRef().get(d);
5842 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5843 dr.getSource(), dr.getVersion(), dr.getAccessionId());
5844 if (dr.getMapping() != null)
5846 entry.setMap(addMapping(dr.getMapping()));
5848 datasetSequence.addDBRef(entry);
5852 private jalview.datamodel.Mapping addMapping(Mapping m)
5854 SequenceI dsto = null;
5855 // Mapping m = dr.getMapping();
5856 int fr[] = new int[m.getMapListFrom().size() * 2];
5857 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5858 for (int _i = 0; from.hasNext(); _i += 2)
5860 MapListFrom mf = from.next();
5861 fr[_i] = mf.getStart();
5862 fr[_i + 1] = mf.getEnd();
5864 int fto[] = new int[m.getMapListTo().size() * 2];
5865 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5866 for (int _i = 0; to.hasNext(); _i += 2)
5868 MapListTo mf = to.next();
5869 fto[_i] = mf.getStart();
5870 fto[_i + 1] = mf.getEnd();
5872 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5873 fto, m.getMapFromUnit().intValue(),
5874 m.getMapToUnit().intValue());
5877 * (optional) choice of dseqFor or Sequence
5879 if (m.getDseqFor() != null)
5881 String dsfor = m.getDseqFor();
5882 if (seqRefIds.containsKey(dsfor))
5887 jmap.setTo(seqRefIds.get(dsfor));
5891 frefedSequence.add(newMappingRef(dsfor, jmap));
5894 else if (m.getSequence() != null)
5897 * local sequence definition
5899 Sequence ms = m.getSequence();
5900 SequenceI djs = null;
5901 String sqid = ms.getDsseqid();
5902 if (sqid != null && sqid.length() > 0)
5905 * recover dataset sequence
5907 djs = seqRefIds.get(sqid);
5912 "Warning - making up dataset sequence id for DbRef sequence map reference");
5913 sqid = ((Object) ms).toString(); // make up a new hascode for
5914 // undefined dataset sequence hash
5915 // (unlikely to happen)
5921 * make a new dataset sequence and add it to refIds hash
5923 djs = new jalview.datamodel.Sequence(ms.getName(),
5925 djs.setStart(jmap.getMap().getToLowest());
5926 djs.setEnd(jmap.getMap().getToHighest());
5927 djs.setVamsasId(uniqueSetSuffix + sqid);
5929 incompleteSeqs.put(sqid, djs);
5930 seqRefIds.put(sqid, djs);
5933 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5942 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5943 * view as XML (but not to file), and then reloading it
5948 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5951 JalviewModel jm = saveState(ap, null, null, null);
5954 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5955 ap.getAlignment().getDataset());
5957 uniqueSetSuffix = "";
5958 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5959 jm.getViewport().get(0).setId(null);
5960 // we don't overwrite the view we just copied
5962 if (this.frefedSequence == null)
5964 frefedSequence = new Vector<>();
5967 viewportsAdded.clear();
5969 AlignFrame af = loadFromObject(jm, null, false, null);
5970 af.getAlignPanels().clear();
5971 af.closeMenuItem_actionPerformed(true);
5974 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5975 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5976 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5977 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5978 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5981 return af.alignPanel;
5984 private Hashtable jvids2vobj;
5986 private void warn(String msg)
5991 private void warn(String msg, Exception e)
5993 if (Cache.log != null)
5997 Cache.log.warn(msg, e);
6001 Cache.log.warn(msg);
6006 System.err.println("Warning: " + msg);
6009 e.printStackTrace();
6014 private void debug(String string)
6016 debug(string, null);
6019 private void debug(String msg, Exception e)
6021 if (Cache.log != null)
6025 Cache.log.debug(msg, e);
6029 Cache.log.debug(msg);
6034 System.err.println("Warning: " + msg);
6037 e.printStackTrace();
6043 * set the object to ID mapping tables used to write/recover objects and XML
6044 * ID strings for the jalview project. If external tables are provided then
6045 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6046 * object goes out of scope. - also populates the datasetIds hashtable with
6047 * alignment objects containing dataset sequences
6050 * Map from ID strings to jalview datamodel
6052 * Map from jalview datamodel to ID strings
6056 public void setObjectMappingTables(Hashtable vobj2jv,
6057 IdentityHashMap jv2vobj)
6059 this.jv2vobj = jv2vobj;
6060 this.vobj2jv = vobj2jv;
6061 Iterator ds = jv2vobj.keySet().iterator();
6063 while (ds.hasNext())
6065 Object jvobj = ds.next();
6066 id = jv2vobj.get(jvobj).toString();
6067 if (jvobj instanceof jalview.datamodel.Alignment)
6069 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6071 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6074 else if (jvobj instanceof jalview.datamodel.Sequence)
6076 // register sequence object so the XML parser can recover it.
6077 if (seqRefIds == null)
6079 seqRefIds = new HashMap<>();
6081 if (seqsToIds == null)
6083 seqsToIds = new IdentityHashMap<>();
6085 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6086 seqsToIds.put((SequenceI) jvobj, id);
6088 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6091 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6092 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6093 if (jvann.annotationId == null)
6095 jvann.annotationId = anid;
6097 if (!jvann.annotationId.equals(anid))
6099 // TODO verify that this is the correct behaviour
6100 this.warn("Overriding Annotation ID for " + anid
6101 + " from different id : " + jvann.annotationId);
6102 jvann.annotationId = anid;
6105 else if (jvobj instanceof String)
6107 if (jvids2vobj == null)
6109 jvids2vobj = new Hashtable();
6110 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6115 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6121 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6122 * objects created from the project archive. If string is null (default for
6123 * construction) then suffix will be set automatically.
6127 public void setUniqueSetSuffix(String string)
6129 uniqueSetSuffix = string;
6134 * uses skipList2 as the skipList for skipping views on sequence sets
6135 * associated with keys in the skipList
6139 public void setSkipList(Hashtable skipList2)
6141 skipList = skipList2;
6145 * Reads the jar entry of given name and returns its contents, or null if the
6146 * entry is not found.
6149 * @param jarEntryName
6152 protected String readJarEntry(jarInputStreamProvider jprovider,
6153 String jarEntryName)
6155 String result = null;
6156 BufferedReader in = null;
6161 * Reopen the jar input stream and traverse its entries to find a matching
6164 JarInputStream jin = jprovider.getJarInputStream();
6165 JarEntry entry = null;
6168 entry = jin.getNextJarEntry();
6169 } while (entry != null && !entry.getName().equals(jarEntryName));
6173 StringBuilder out = new StringBuilder(256);
6174 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6177 while ((data = in.readLine()) != null)
6181 result = out.toString();
6185 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6187 } catch (Exception ex)
6189 ex.printStackTrace();
6197 } catch (IOException e)
6208 * Returns an incrementing counter (0, 1, 2...)
6212 private synchronized int nextCounter()
6218 * Loads any saved PCA viewers
6223 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6227 List<PcaViewer> pcaviewers = model.getPcaViewer();
6228 for (PcaViewer viewer : pcaviewers)
6230 String modelName = viewer.getScoreModelName();
6231 SimilarityParamsI params = new SimilarityParams(
6232 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6233 viewer.isIncludeGaps(),
6234 viewer.isDenominateByShortestLength());
6237 * create the panel (without computing the PCA)
6239 PCAPanel panel = new PCAPanel(ap, modelName, params);
6241 panel.setTitle(viewer.getTitle());
6242 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6243 viewer.getWidth(), viewer.getHeight()));
6245 boolean showLabels = viewer.isShowLabels();
6246 panel.setShowLabels(showLabels);
6247 panel.getRotatableCanvas().setShowLabels(showLabels);
6248 panel.getRotatableCanvas()
6249 .setBgColour(new Color(viewer.getBgColour()));
6250 panel.getRotatableCanvas()
6251 .setApplyToAllViews(viewer.isLinkToAllViews());
6254 * load PCA output data
6256 ScoreModelI scoreModel = ScoreModels.getInstance()
6257 .getScoreModel(modelName, ap);
6258 PCA pca = new PCA(null, scoreModel, params);
6259 PcaDataType pcaData = viewer.getPcaData();
6261 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6262 pca.setPairwiseScores(pairwise);
6264 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6265 pca.setTridiagonal(triDiag);
6267 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6268 pca.setEigenmatrix(result);
6270 panel.getPcaModel().setPCA(pca);
6273 * we haven't saved the input data! (JAL-2647 to do)
6275 panel.setInputData(null);
6278 * add the sequence points for the PCA display
6280 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6281 for (SequencePoint sp : viewer.getSequencePoint())
6283 String seqId = sp.getSequenceRef();
6284 SequenceI seq = seqRefIds.get(seqId);
6287 throw new IllegalStateException(
6288 "Unmatched seqref for PCA: " + seqId);
6290 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6291 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6293 seqPoints.add(seqPoint);
6295 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6298 * set min-max ranges and scale after setPoints (which recomputes them)
6300 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6301 SeqPointMin spMin = viewer.getSeqPointMin();
6302 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6304 SeqPointMax spMax = viewer.getSeqPointMax();
6305 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6307 panel.getRotatableCanvas().setSeqMinMax(min, max);
6309 // todo: hold points list in PCAModel only
6310 panel.getPcaModel().setSequencePoints(seqPoints);
6312 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6313 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6314 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6316 // is this duplication needed?
6317 panel.setTop(seqPoints.size() - 1);
6318 panel.getPcaModel().setTop(seqPoints.size() - 1);
6321 * add the axes' end points for the display
6323 for (int i = 0; i < 3; i++)
6325 Axis axis = viewer.getAxis().get(i);
6326 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6327 axis.getXPos(), axis.getYPos(), axis.getZPos());
6330 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6331 "label.calc_title", "PCA", modelName), 475, 450);
6333 } catch (Exception ex)
6335 Cache.log.error("Error loading PCA: " + ex.toString());
6340 * Populates an XML model of the feature colour scheme for one feature type
6342 * @param featureType
6346 public static Colour marshalColour(
6347 String featureType, FeatureColourI fcol)
6349 Colour col = new Colour();
6350 if (fcol.isSimpleColour())
6352 col.setRGB(Format.getHexString(fcol.getColour()));
6356 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6357 col.setMin(fcol.getMin());
6358 col.setMax(fcol.getMax());
6359 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6360 col.setAutoScale(fcol.isAutoScaled());
6361 col.setThreshold(fcol.getThreshold());
6362 col.setColourByLabel(fcol.isColourByLabel());
6363 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6364 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6365 : ThresholdType.NONE));
6366 if (fcol.isColourByAttribute())
6368 final String[] attName = fcol.getAttributeName();
6369 col.getAttributeName().add(attName[0]);
6370 if (attName.length > 1)
6372 col.getAttributeName().add(attName[1]);
6375 Color noColour = fcol.getNoColour();
6376 if (noColour == null)
6378 col.setNoValueColour(NoValueColour.NONE);
6380 else if (noColour == fcol.getMaxColour())
6382 col.setNoValueColour(NoValueColour.MAX);
6386 col.setNoValueColour(NoValueColour.MIN);
6389 col.setName(featureType);
6394 * Populates an XML model of the feature filter(s) for one feature type
6396 * @param firstMatcher
6397 * the first (or only) match condition)
6399 * remaining match conditions (if any)
6401 * if true, conditions are and-ed, else or-ed
6403 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6404 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6407 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6409 if (filters.hasNext())
6414 CompoundMatcher compound = new CompoundMatcher();
6415 compound.setAnd(and);
6416 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6417 firstMatcher, Collections.emptyIterator(), and);
6418 // compound.addMatcherSet(matcher1);
6419 compound.getMatcherSet().add(matcher1);
6420 FeatureMatcherI nextMatcher = filters.next();
6421 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6422 nextMatcher, filters, and);
6423 // compound.addMatcherSet(matcher2);
6424 compound.getMatcherSet().add(matcher2);
6425 result.setCompoundMatcher(compound);
6430 * single condition matcher
6432 // MatchCondition matcherModel = new MatchCondition();
6433 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6434 matcherModel.setCondition(
6435 firstMatcher.getMatcher().getCondition().getStableName());
6436 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6437 if (firstMatcher.isByAttribute())
6439 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6440 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6441 String[] attName = firstMatcher.getAttribute();
6442 matcherModel.getAttributeName().add(attName[0]); // attribute
6443 if (attName.length > 1)
6445 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6448 else if (firstMatcher.isByLabel())
6450 matcherModel.setBy(FilterBy.BY_LABEL);
6452 else if (firstMatcher.isByScore())
6454 matcherModel.setBy(FilterBy.BY_SCORE);
6456 result.setMatchCondition(matcherModel);
6463 * Loads one XML model of a feature filter to a Jalview object
6465 * @param featureType
6466 * @param matcherSetModel
6469 public static FeatureMatcherSetI parseFilter(
6471 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6473 FeatureMatcherSetI result = new FeatureMatcherSet();
6476 parseFilterConditions(result, matcherSetModel, true);
6477 } catch (IllegalStateException e)
6479 // mixing AND and OR conditions perhaps
6481 String.format("Error reading filter conditions for '%s': %s",
6482 featureType, e.getMessage()));
6483 // return as much as was parsed up to the error
6490 * Adds feature match conditions to matcherSet as unmarshalled from XML
6491 * (possibly recursively for compound conditions)
6494 * @param matcherSetModel
6496 * if true, multiple conditions are AND-ed, else they are OR-ed
6497 * @throws IllegalStateException
6498 * if AND and OR conditions are mixed
6500 protected static void parseFilterConditions(
6501 FeatureMatcherSetI matcherSet,
6502 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6505 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6506 .getMatchCondition();
6512 FilterBy filterBy = mc.getBy();
6513 Condition cond = Condition.fromString(mc.getCondition());
6514 String pattern = mc.getValue();
6515 FeatureMatcherI matchCondition = null;
6516 if (filterBy == FilterBy.BY_LABEL)
6518 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6520 else if (filterBy == FilterBy.BY_SCORE)
6522 matchCondition = FeatureMatcher.byScore(cond, pattern);
6525 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6527 final List<String> attributeName = mc.getAttributeName();
6528 String[] attNames = attributeName
6529 .toArray(new String[attributeName.size()]);
6530 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6535 * note this throws IllegalStateException if AND-ing to a
6536 * previously OR-ed compound condition, or vice versa
6540 matcherSet.and(matchCondition);
6544 matcherSet.or(matchCondition);
6550 * compound condition
6552 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6553 .getCompoundMatcher().getMatcherSet();
6554 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6555 if (matchers.size() == 2)
6557 parseFilterConditions(matcherSet, matchers.get(0), anded);
6558 parseFilterConditions(matcherSet, matchers.get(1), anded);
6562 System.err.println("Malformed compound filter condition");
6568 * Loads one XML model of a feature colour to a Jalview object
6570 * @param colourModel
6573 public static FeatureColourI parseColour(Colour colourModel)
6575 FeatureColourI colour = null;
6577 if (colourModel.getMax() != null)
6579 Color mincol = null;
6580 Color maxcol = null;
6581 Color noValueColour = null;
6585 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6586 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6587 } catch (Exception e)
6589 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6592 NoValueColour noCol = colourModel.getNoValueColour();
6593 if (noCol == NoValueColour.MIN)
6595 noValueColour = mincol;
6597 else if (noCol == NoValueColour.MAX)
6599 noValueColour = maxcol;
6602 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6603 safeFloat(colourModel.getMin()),
6604 safeFloat(colourModel.getMax()));
6605 final List<String> attributeName = colourModel.getAttributeName();
6606 String[] attributes = attributeName
6607 .toArray(new String[attributeName.size()]);
6608 if (attributes != null && attributes.length > 0)
6610 colour.setAttributeName(attributes);
6612 if (colourModel.isAutoScale() != null)
6614 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6616 if (colourModel.isColourByLabel() != null)
6618 colour.setColourByLabel(
6619 colourModel.isColourByLabel().booleanValue());
6621 if (colourModel.getThreshold() != null)
6623 colour.setThreshold(colourModel.getThreshold().floatValue());
6625 ThresholdType ttyp = colourModel.getThreshType();
6626 if (ttyp == ThresholdType.ABOVE)
6628 colour.setAboveThreshold(true);
6630 else if (ttyp == ThresholdType.BELOW)
6632 colour.setBelowThreshold(true);
6637 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6638 colour = new FeatureColour(color);