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.GraphLine;
42 import jalview.datamodel.PDBEntry;
43 import jalview.datamodel.Point;
44 import jalview.datamodel.RnaViewerModel;
45 import jalview.datamodel.SequenceFeature;
46 import jalview.datamodel.SequenceGroup;
47 import jalview.datamodel.SequenceI;
48 import jalview.datamodel.StructureViewerModel;
49 import jalview.datamodel.StructureViewerModel.StructureData;
50 import jalview.datamodel.features.FeatureMatcher;
51 import jalview.datamodel.features.FeatureMatcherI;
52 import jalview.datamodel.features.FeatureMatcherSet;
53 import jalview.datamodel.features.FeatureMatcherSetI;
54 import jalview.ext.varna.RnaModel;
55 import jalview.gui.AlignFrame;
56 import jalview.gui.AlignViewport;
57 import jalview.gui.AlignmentPanel;
58 import jalview.gui.AppVarna;
59 import jalview.gui.ChimeraViewFrame;
60 import jalview.gui.Desktop;
61 import jalview.gui.FeatureRenderer;
62 import jalview.gui.JvOptionPane;
63 import jalview.gui.OOMWarning;
64 import jalview.gui.PCAPanel;
65 import jalview.gui.PaintRefresher;
66 import jalview.gui.SplitFrame;
67 import jalview.gui.StructureViewer;
68 import jalview.gui.StructureViewer.ViewerType;
69 import jalview.gui.StructureViewerBase;
70 import jalview.gui.TreePanel;
71 import jalview.io.BackupFiles;
72 import jalview.io.DataSourceType;
73 import jalview.io.FileFormat;
74 import jalview.io.NewickFile;
75 import jalview.math.Matrix;
76 import jalview.math.MatrixI;
77 import jalview.renderer.ResidueShaderI;
78 import jalview.schemes.AnnotationColourGradient;
79 import jalview.schemes.ColourSchemeI;
80 import jalview.schemes.ColourSchemeProperty;
81 import jalview.schemes.FeatureColour;
82 import jalview.schemes.ResidueProperties;
83 import jalview.schemes.UserColourScheme;
84 import jalview.structure.StructureSelectionManager;
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.DataInputStream;
156 import java.io.DataOutputStream;
158 import java.io.FileInputStream;
159 import java.io.FileOutputStream;
160 import java.io.IOException;
161 import java.io.InputStreamReader;
162 import java.io.OutputStreamWriter;
163 import java.io.PrintWriter;
164 import java.lang.reflect.InvocationTargetException;
165 import java.math.BigInteger;
166 import java.net.MalformedURLException;
168 import java.util.ArrayList;
169 import java.util.Arrays;
170 import java.util.Collections;
171 import java.util.Enumeration;
172 import java.util.GregorianCalendar;
173 import java.util.HashMap;
174 import java.util.HashSet;
175 import java.util.Hashtable;
176 import java.util.IdentityHashMap;
177 import java.util.Iterator;
178 import java.util.LinkedHashMap;
179 import java.util.List;
180 import java.util.Map;
181 import java.util.Map.Entry;
182 import java.util.Set;
183 import java.util.Vector;
184 import java.util.jar.JarEntry;
185 import java.util.jar.JarInputStream;
186 import java.util.jar.JarOutputStream;
188 import javax.swing.JInternalFrame;
189 import javax.swing.SwingUtilities;
190 import javax.xml.bind.JAXBContext;
191 import javax.xml.bind.JAXBElement;
192 import javax.xml.bind.Marshaller;
193 import javax.xml.datatype.DatatypeConfigurationException;
194 import javax.xml.datatype.DatatypeFactory;
195 import javax.xml.datatype.XMLGregorianCalendar;
196 import javax.xml.stream.XMLInputFactory;
197 import javax.xml.stream.XMLStreamReader;
200 * Write out the current jalview desktop state as a Jalview XML stream.
202 * Note: the vamsas objects referred to here are primitive versions of the
203 * VAMSAS project schema elements - they are not the same and most likely never
207 * @version $Revision: 1.134 $
209 public class Jalview2XML
211 private static final String VIEWER_PREFIX = "viewer_";
213 private static final String RNA_PREFIX = "rna_";
215 private static final String UTF_8 = "UTF-8";
218 * prefix for recovering datasets for alignments with multiple views where
219 * non-existent dataset IDs were written for some views
221 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
223 // use this with nextCounter() to make unique names for entities
224 private int counter = 0;
227 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
228 * of sequence objects are created.
230 IdentityHashMap<SequenceI, String> seqsToIds = null;
233 * jalview XML Sequence ID to jalview sequence object reference (both dataset
234 * and alignment sequences. Populated as XML reps of sequence objects are
237 Map<String, SequenceI> seqRefIds = null;
239 Map<String, SequenceI> incompleteSeqs = null;
241 List<SeqFref> frefedSequence = null;
243 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
246 * Map of reconstructed AlignFrame objects that appear to have come from
247 * SplitFrame objects (have a dna/protein complement view).
249 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
252 * Map from displayed rna structure models to their saved session state jar
255 private Map<RnaModel, String> rnaSessions = new HashMap<>();
258 * A helper method for safely using the value of an optional attribute that
259 * may be null if not present in the XML. Answers the boolean value, or false
265 public static boolean safeBoolean(Boolean b)
267 return b == null ? false : b.booleanValue();
271 * A helper method for safely using the value of an optional attribute that
272 * may be null if not present in the XML. Answers the integer value, or zero
278 public static int safeInt(Integer i)
280 return i == null ? 0 : i.intValue();
284 * A helper method for safely using the value of an optional attribute that
285 * may be null if not present in the XML. Answers the float value, or zero if
291 public static float safeFloat(Float f)
293 return f == null ? 0f : f.floatValue();
297 * create/return unique hash string for sq
300 * @return new or existing unique string for sq
302 String seqHash(SequenceI sq)
304 if (seqsToIds == null)
308 if (seqsToIds.containsKey(sq))
310 return seqsToIds.get(sq);
314 // create sequential key
315 String key = "sq" + (seqsToIds.size() + 1);
316 key = makeHashCode(sq, key); // check we don't have an external reference
318 seqsToIds.put(sq, key);
325 if (seqsToIds == null)
327 seqsToIds = new IdentityHashMap<>();
329 if (seqRefIds == null)
331 seqRefIds = new HashMap<>();
333 if (incompleteSeqs == null)
335 incompleteSeqs = new HashMap<>();
337 if (frefedSequence == null)
339 frefedSequence = new ArrayList<>();
347 public Jalview2XML(boolean raiseGUI)
349 this.raiseGUI = raiseGUI;
353 * base class for resolving forward references to sequences by their ID
358 abstract class SeqFref
364 public SeqFref(String _sref, String type)
370 public String getSref()
375 public SequenceI getSrefSeq()
377 return seqRefIds.get(sref);
380 public boolean isResolvable()
382 return seqRefIds.get(sref) != null;
385 public SequenceI getSrefDatasetSeq()
387 SequenceI sq = seqRefIds.get(sref);
390 while (sq.getDatasetSequence() != null)
392 sq = sq.getDatasetSequence();
399 * @return true if the forward reference was fully resolved
401 abstract boolean resolve();
404 public String toString()
406 return type + " reference to " + sref;
411 * create forward reference for a mapping
417 public SeqFref newMappingRef(final String sref,
418 final jalview.datamodel.Mapping _jmap)
420 SeqFref fref = new SeqFref(sref, "Mapping")
422 public jalview.datamodel.Mapping jmap = _jmap;
427 SequenceI seq = getSrefDatasetSeq();
439 public SeqFref newAlcodMapRef(final String sref,
440 final AlignedCodonFrame _cf,
441 final jalview.datamodel.Mapping _jmap)
444 SeqFref fref = new SeqFref(sref, "Codon Frame")
446 AlignedCodonFrame cf = _cf;
448 public jalview.datamodel.Mapping mp = _jmap;
451 public boolean isResolvable()
453 return super.isResolvable() && mp.getTo() != null;
459 SequenceI seq = getSrefDatasetSeq();
464 cf.addMap(seq, mp.getTo(), mp.getMap());
471 public void resolveFrefedSequences()
473 Iterator<SeqFref> nextFref = frefedSequence.iterator();
474 int toresolve = frefedSequence.size();
475 int unresolved = 0, failedtoresolve = 0;
476 while (nextFref.hasNext())
478 SeqFref ref = nextFref.next();
479 if (ref.isResolvable())
491 } catch (Exception x)
494 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
507 System.err.println("Jalview Project Import: There were " + unresolved
508 + " forward references left unresolved on the stack.");
510 if (failedtoresolve > 0)
512 System.err.println("SERIOUS! " + failedtoresolve
513 + " resolvable forward references failed to resolve.");
515 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
518 "Jalview Project Import: There are " + incompleteSeqs.size()
519 + " sequences which may have incomplete metadata.");
520 if (incompleteSeqs.size() < 10)
522 for (SequenceI s : incompleteSeqs.values())
524 System.err.println(s.toString());
530 "Too many to report. Skipping output of incomplete sequences.");
536 * This maintains a map of viewports, the key being the seqSetId. Important to
537 * set historyItem and redoList for multiple views
539 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
541 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
543 String uniqueSetSuffix = "";
546 * List of pdbfiles added to Jar
548 List<String> pdbfiles = null;
550 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
551 public void saveState(File statefile)
553 FileOutputStream fos = null;
554 // create backupfiles object and get new temp filename destination
555 BackupFiles backupfiles = new BackupFiles(statefile);
560 fos = new FileOutputStream(backupfiles.getTempFilePath());
562 JarOutputStream jout = new JarOutputStream(fos);
565 backupfiles.setWriteSuccess(true);
566 backupfiles.rollBackupsAndRenameTempFile();
568 } catch (Exception e)
570 Cache.log.error("Couln't write Jalview state to " + statefile
571 + ". Temporary file is at: " + backupfiles.getTempFile(), e);
572 // TODO: inform user of the problem - they need to know if their data was
574 if (errorMessage == null)
576 errorMessage = "Did't write Jalview Archive to output file '"
577 + statefile + "' - See console error log for details";
581 errorMessage += "(Didn't write Jalview Archive to output file '"
582 + statefile + "\nTemporary file is at: "
583 + backupfiles.getTempFile() + ")";
593 } catch (IOException e)
603 * Writes a jalview project archive to the given Jar output stream.
607 public void saveState(JarOutputStream jout)
609 AlignFrame[] frames = Desktop.getAlignFrames();
615 saveAllFrames(Arrays.asList(frames), jout);
619 * core method for storing state for a set of AlignFrames.
622 * - frames involving all data to be exported (including containing
625 * - project output stream
627 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
629 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
632 * ensure cached data is clear before starting
634 // todo tidy up seqRefIds, seqsToIds initialisation / reset
636 splitFrameCandidates.clear();
641 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
642 // //////////////////////////////////////////////////
644 List<String> shortNames = new ArrayList<>();
645 List<String> viewIds = new ArrayList<>();
648 for (int i = frames.size() - 1; i > -1; i--)
650 AlignFrame af = frames.get(i);
652 if (skipList != null && skipList
653 .containsKey(af.getViewport().getSequenceSetId()))
658 String shortName = makeFilename(af, shortNames);
660 int apSize = af.getAlignPanels().size();
662 for (int ap = 0; ap < apSize; ap++)
664 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
666 String fileName = apSize == 1 ? shortName : ap + shortName;
667 if (!fileName.endsWith(".xml"))
669 fileName = fileName + ".xml";
672 saveState(apanel, fileName, jout, viewIds);
674 String dssid = getDatasetIdRef(
675 af.getViewport().getAlignment().getDataset());
676 if (!dsses.containsKey(dssid))
678 dsses.put(dssid, af);
683 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
689 } catch (Exception foo)
694 } catch (Exception ex)
696 // TODO: inform user of the problem - they need to know if their data was
698 if (errorMessage == null)
700 errorMessage = "Couldn't write Jalview Archive - see error output for details";
702 ex.printStackTrace();
707 * Generates a distinct file name, based on the title of the AlignFrame, by
708 * appending _n for increasing n until an unused name is generated. The new
709 * name (without its extension) is added to the list.
713 * @return the generated name, with .xml extension
715 protected String makeFilename(AlignFrame af, List<String> namesUsed)
717 String shortName = af.getTitle();
719 if (shortName.indexOf(File.separatorChar) > -1)
721 shortName = shortName
722 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
727 while (namesUsed.contains(shortName))
729 if (shortName.endsWith("_" + (count - 1)))
731 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
734 shortName = shortName.concat("_" + count);
738 namesUsed.add(shortName);
740 if (!shortName.endsWith(".xml"))
742 shortName = shortName + ".xml";
747 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
748 public boolean saveAlignment(AlignFrame af, String jarFile,
753 // create backupfiles object and get new temp filename destination
754 BackupFiles backupfiles = new BackupFiles(jarFile);
755 FileOutputStream fos = new FileOutputStream(
756 backupfiles.getTempFilePath());
758 JarOutputStream jout = new JarOutputStream(fos);
759 List<AlignFrame> frames = new ArrayList<>();
761 // resolve splitframes
762 if (af.getViewport().getCodingComplement() != null)
764 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
770 saveAllFrames(frames, jout);
774 } catch (Exception foo)
779 boolean success = true;
781 backupfiles.setWriteSuccess(success);
782 success = backupfiles.rollBackupsAndRenameTempFile();
785 } catch (Exception ex)
787 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
788 ex.printStackTrace();
793 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
794 String fileName, JarOutputStream jout)
797 for (String dssids : dsses.keySet())
799 AlignFrame _af = dsses.get(dssids);
800 String jfileName = fileName + " Dataset for " + _af.getTitle();
801 if (!jfileName.endsWith(".xml"))
803 jfileName = jfileName + ".xml";
805 saveState(_af.alignPanel, jfileName, true, jout, null);
810 * create a JalviewModel from an alignment view and marshall it to a
814 * panel to create jalview model for
816 * name of alignment panel written to output stream
823 public JalviewModel saveState(AlignmentPanel ap, String fileName,
824 JarOutputStream jout, List<String> viewIds)
826 return saveState(ap, fileName, false, jout, viewIds);
830 * create a JalviewModel from an alignment view and marshall it to a
834 * panel to create jalview model for
836 * name of alignment panel written to output stream
838 * when true, only write the dataset for the alignment, not the data
839 * associated with the view.
845 public JalviewModel saveState(AlignmentPanel ap, String fileName,
846 boolean storeDS, JarOutputStream jout, List<String> viewIds)
850 viewIds = new ArrayList<>();
855 List<UserColourScheme> userColours = new ArrayList<>();
857 AlignViewport av = ap.av;
858 ViewportRanges vpRanges = av.getRanges();
860 final ObjectFactory objectFactory = new ObjectFactory();
861 JalviewModel object = objectFactory.createJalviewModel();
862 object.setVamsasModel(new VAMSAS());
864 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
867 GregorianCalendar c = new GregorianCalendar();
868 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
869 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
870 object.setCreationDate(now);
871 } catch (DatatypeConfigurationException e)
873 System.err.println("error writing date: " + e.toString());
876 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
879 * rjal is full height alignment, jal is actual alignment with full metadata
880 * but excludes hidden sequences.
882 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
884 if (av.hasHiddenRows())
886 rjal = jal.getHiddenSequences().getFullAlignment();
889 SequenceSet vamsasSet = new SequenceSet();
891 // JalviewModelSequence jms = new JalviewModelSequence();
893 vamsasSet.setGapChar(jal.getGapCharacter() + "");
895 if (jal.getDataset() != null)
897 // dataset id is the dataset's hashcode
898 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
901 // switch jal and the dataset
902 jal = jal.getDataset();
906 if (jal.getProperties() != null)
908 Enumeration en = jal.getProperties().keys();
909 while (en.hasMoreElements())
911 String key = en.nextElement().toString();
912 SequenceSetProperties ssp = new SequenceSetProperties();
914 ssp.setValue(jal.getProperties().get(key).toString());
915 // vamsasSet.addSequenceSetProperties(ssp);
916 vamsasSet.getSequenceSetProperties().add(ssp);
921 Set<String> calcIdSet = new HashSet<>();
922 // record the set of vamsas sequence XML POJO we create.
923 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
925 for (final SequenceI jds : rjal.getSequences())
927 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
928 : jds.getDatasetSequence();
929 String id = seqHash(jds);
930 if (vamsasSetIds.get(id) == null)
932 if (seqRefIds.get(id) != null && !storeDS)
934 // This happens for two reasons: 1. multiple views are being
936 // 2. the hashCode has collided with another sequence's code. This
938 // HAPPEN! (PF00072.15.stk does this)
939 // JBPNote: Uncomment to debug writing out of files that do not read
940 // back in due to ArrayOutOfBoundExceptions.
941 // System.err.println("vamsasSeq backref: "+id+"");
942 // System.err.println(jds.getName()+"
943 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
944 // System.err.println("Hashcode: "+seqHash(jds));
945 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
946 // System.err.println(rsq.getName()+"
947 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
948 // System.err.println("Hashcode: "+seqHash(rsq));
952 vamsasSeq = createVamsasSequence(id, jds);
953 // vamsasSet.addSequence(vamsasSeq);
954 vamsasSet.getSequence().add(vamsasSeq);
955 vamsasSetIds.put(id, vamsasSeq);
956 seqRefIds.put(id, jds);
960 jseq.setStart(jds.getStart());
961 jseq.setEnd(jds.getEnd());
962 jseq.setColour(av.getSequenceColour(jds).getRGB());
964 jseq.setId(id); // jseq id should be a string not a number
967 // Store any sequences this sequence represents
968 if (av.hasHiddenRows())
970 // use rjal, contains the full height alignment
972 av.getAlignment().getHiddenSequences().isHidden(jds));
974 if (av.isHiddenRepSequence(jds))
976 jalview.datamodel.SequenceI[] reps = av
977 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
979 for (int h = 0; h < reps.length; h++)
983 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
984 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
989 // mark sequence as reference - if it is the reference for this view
992 jseq.setViewreference(jds == jal.getSeqrep());
996 // TODO: omit sequence features from each alignment view's XML dump if we
997 // are storing dataset
998 List<SequenceFeature> sfs = jds.getSequenceFeatures();
999 for (SequenceFeature sf : sfs)
1001 // Features features = new Features();
1002 Feature features = new Feature();
1004 features.setBegin(sf.getBegin());
1005 features.setEnd(sf.getEnd());
1006 features.setDescription(sf.getDescription());
1007 features.setType(sf.getType());
1008 features.setFeatureGroup(sf.getFeatureGroup());
1009 features.setScore(sf.getScore());
1010 if (sf.links != null)
1012 for (int l = 0; l < sf.links.size(); l++)
1014 OtherData keyValue = new OtherData();
1015 keyValue.setKey("LINK_" + l);
1016 keyValue.setValue(sf.links.elementAt(l).toString());
1017 // features.addOtherData(keyValue);
1018 features.getOtherData().add(keyValue);
1021 if (sf.otherDetails != null)
1024 * save feature attributes, which may be simple strings or
1025 * map valued (have sub-attributes)
1027 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1029 String key = entry.getKey();
1030 Object value = entry.getValue();
1031 if (value instanceof Map<?, ?>)
1033 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1036 OtherData otherData = new OtherData();
1037 otherData.setKey(key);
1038 otherData.setKey2(subAttribute.getKey());
1039 otherData.setValue(subAttribute.getValue().toString());
1040 // features.addOtherData(otherData);
1041 features.getOtherData().add(otherData);
1046 OtherData otherData = new OtherData();
1047 otherData.setKey(key);
1048 otherData.setValue(value.toString());
1049 // features.addOtherData(otherData);
1050 features.getOtherData().add(otherData);
1055 // jseq.addFeatures(features);
1056 jseq.getFeatures().add(features);
1059 if (jdatasq.getAllPDBEntries() != null)
1061 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1062 while (en.hasMoreElements())
1064 Pdbids pdb = new Pdbids();
1065 jalview.datamodel.PDBEntry entry = en.nextElement();
1067 String pdbId = entry.getId();
1069 pdb.setType(entry.getType());
1072 * Store any structure views associated with this sequence. This
1073 * section copes with duplicate entries in the project, so a dataset
1074 * only view *should* be coped with sensibly.
1076 // This must have been loaded, is it still visible?
1077 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1078 String matchedFile = null;
1079 for (int f = frames.length - 1; f > -1; f--)
1081 if (frames[f] instanceof StructureViewerBase)
1083 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1084 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1085 matchedFile, viewFrame);
1087 * Only store each structure viewer's state once in the project
1088 * jar. First time through only (storeDS==false)
1090 String viewId = viewFrame.getViewId();
1091 if (!storeDS && !viewIds.contains(viewId))
1093 viewIds.add(viewId);
1096 String viewerState = viewFrame.getStateInfo();
1097 writeJarEntry(jout, getViewerJarEntryName(viewId),
1098 viewerState.getBytes());
1099 } catch (IOException e)
1102 "Error saving viewer state: " + e.getMessage());
1108 if (matchedFile != null || entry.getFile() != null)
1110 if (entry.getFile() != null)
1113 matchedFile = entry.getFile();
1115 pdb.setFile(matchedFile); // entry.getFile());
1116 if (pdbfiles == null)
1118 pdbfiles = new ArrayList<>();
1121 if (!pdbfiles.contains(pdbId))
1123 pdbfiles.add(pdbId);
1124 copyFileToJar(jout, matchedFile, pdbId);
1128 Enumeration<String> props = entry.getProperties();
1129 if (props.hasMoreElements())
1131 // PdbentryItem item = new PdbentryItem();
1132 while (props.hasMoreElements())
1134 Property prop = new Property();
1135 String key = props.nextElement();
1137 prop.setValue(entry.getProperty(key).toString());
1138 // item.addProperty(prop);
1139 pdb.getProperty().add(prop);
1141 // pdb.addPdbentryItem(item);
1144 // jseq.addPdbids(pdb);
1145 jseq.getPdbids().add(pdb);
1149 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1151 // jms.addJSeq(jseq);
1152 object.getJSeq().add(jseq);
1155 if (!storeDS && av.hasHiddenRows())
1157 jal = av.getAlignment();
1161 if (storeDS && jal.getCodonFrames() != null)
1163 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1164 for (AlignedCodonFrame acf : jac)
1166 AlcodonFrame alc = new AlcodonFrame();
1167 if (acf.getProtMappings() != null
1168 && acf.getProtMappings().length > 0)
1170 boolean hasMap = false;
1171 SequenceI[] dnas = acf.getdnaSeqs();
1172 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1173 for (int m = 0; m < pmaps.length; m++)
1175 AlcodMap alcmap = new AlcodMap();
1176 alcmap.setDnasq(seqHash(dnas[m]));
1178 createVamsasMapping(pmaps[m], dnas[m], null, false));
1179 // alc.addAlcodMap(alcmap);
1180 alc.getAlcodMap().add(alcmap);
1185 // vamsasSet.addAlcodonFrame(alc);
1186 vamsasSet.getAlcodonFrame().add(alc);
1189 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1191 // AlcodonFrame alc = new AlcodonFrame();
1192 // vamsasSet.addAlcodonFrame(alc);
1193 // for (int p = 0; p < acf.aaWidth; p++)
1195 // Alcodon cmap = new Alcodon();
1196 // if (acf.codons[p] != null)
1198 // // Null codons indicate a gapped column in the translated peptide
1200 // cmap.setPos1(acf.codons[p][0]);
1201 // cmap.setPos2(acf.codons[p][1]);
1202 // cmap.setPos3(acf.codons[p][2]);
1204 // alc.addAlcodon(cmap);
1206 // if (acf.getProtMappings() != null
1207 // && acf.getProtMappings().length > 0)
1209 // SequenceI[] dnas = acf.getdnaSeqs();
1210 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1211 // for (int m = 0; m < pmaps.length; m++)
1213 // AlcodMap alcmap = new AlcodMap();
1214 // alcmap.setDnasq(seqHash(dnas[m]));
1215 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1217 // alc.addAlcodMap(alcmap);
1224 // /////////////////////////////////
1225 if (!storeDS && av.getCurrentTree() != null)
1227 // FIND ANY ASSOCIATED TREES
1228 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1229 if (Desktop.desktop != null)
1231 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1233 for (int t = 0; t < frames.length; t++)
1235 if (frames[t] instanceof TreePanel)
1237 TreePanel tp = (TreePanel) frames[t];
1239 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1241 JalviewModel.Tree tree = new JalviewModel.Tree();
1242 tree.setTitle(tp.getTitle());
1243 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1244 tree.setNewick(tp.getTree().print());
1245 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1247 tree.setFitToWindow(tp.fitToWindow.getState());
1248 tree.setFontName(tp.getTreeFont().getName());
1249 tree.setFontSize(tp.getTreeFont().getSize());
1250 tree.setFontStyle(tp.getTreeFont().getStyle());
1251 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1253 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1254 tree.setShowDistances(tp.distanceMenu.getState());
1256 tree.setHeight(tp.getHeight());
1257 tree.setWidth(tp.getWidth());
1258 tree.setXpos(tp.getX());
1259 tree.setYpos(tp.getY());
1260 tree.setId(makeHashCode(tp, null));
1261 tree.setLinkToAllViews(
1262 tp.getTreeCanvas().isApplyToAllViews());
1264 // jms.addTree(tree);
1265 object.getTree().add(tree);
1275 if (!storeDS && Desktop.desktop != null)
1277 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1279 if (frame instanceof PCAPanel)
1281 PCAPanel panel = (PCAPanel) frame;
1282 if (panel.getAlignViewport().getAlignment() == jal)
1284 savePCA(panel, object);
1292 * store forward refs from an annotationRow to any groups
1294 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1297 for (SequenceI sq : jal.getSequences())
1299 // Store annotation on dataset sequences only
1300 AlignmentAnnotation[] aa = sq.getAnnotation();
1301 if (aa != null && aa.length > 0)
1303 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1310 if (jal.getAlignmentAnnotation() != null)
1312 // Store the annotation shown on the alignment.
1313 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1314 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1319 if (jal.getGroups() != null)
1321 JGroup[] groups = new JGroup[jal.getGroups().size()];
1323 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1325 JGroup jGroup = new JGroup();
1326 groups[++i] = jGroup;
1328 jGroup.setStart(sg.getStartRes());
1329 jGroup.setEnd(sg.getEndRes());
1330 jGroup.setName(sg.getName());
1331 if (groupRefs.containsKey(sg))
1333 // group has references so set its ID field
1334 jGroup.setId(groupRefs.get(sg));
1336 ColourSchemeI colourScheme = sg.getColourScheme();
1337 if (colourScheme != null)
1339 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1340 if (groupColourScheme.conservationApplied())
1342 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1344 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1347 setUserColourScheme(colourScheme, userColours,
1352 jGroup.setColour(colourScheme.getSchemeName());
1355 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1357 jGroup.setColour("AnnotationColourGradient");
1358 jGroup.setAnnotationColours(constructAnnotationColours(
1359 (jalview.schemes.AnnotationColourGradient) colourScheme,
1360 userColours, object));
1362 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1365 setUserColourScheme(colourScheme, userColours, object));
1369 jGroup.setColour(colourScheme.getSchemeName());
1372 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1375 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1376 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1377 jGroup.setDisplayText(sg.getDisplayText());
1378 jGroup.setColourText(sg.getColourText());
1379 jGroup.setTextCol1(sg.textColour.getRGB());
1380 jGroup.setTextCol2(sg.textColour2.getRGB());
1381 jGroup.setTextColThreshold(sg.thresholdTextColour);
1382 jGroup.setShowUnconserved(sg.getShowNonconserved());
1383 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1384 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1385 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1386 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1387 for (SequenceI seq : sg.getSequences())
1389 // jGroup.addSeq(seqHash(seq));
1390 jGroup.getSeq().add(seqHash(seq));
1394 //jms.setJGroup(groups);
1396 for (JGroup grp : groups)
1398 object.getJGroup().add(grp);
1403 // /////////SAVE VIEWPORT
1404 Viewport view = new Viewport();
1405 view.setTitle(ap.alignFrame.getTitle());
1406 view.setSequenceSetId(
1407 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1408 view.setId(av.getViewId());
1409 if (av.getCodingComplement() != null)
1411 view.setComplementId(av.getCodingComplement().getViewId());
1413 view.setViewName(av.getViewName());
1414 view.setGatheredViews(av.isGatherViewsHere());
1416 Rectangle size = ap.av.getExplodedGeometry();
1417 Rectangle position = size;
1420 size = ap.alignFrame.getBounds();
1421 if (av.getCodingComplement() != null)
1423 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1431 view.setXpos(position.x);
1432 view.setYpos(position.y);
1434 view.setWidth(size.width);
1435 view.setHeight(size.height);
1437 view.setStartRes(vpRanges.getStartRes());
1438 view.setStartSeq(vpRanges.getStartSeq());
1440 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1442 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1443 userColours, object));
1446 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1448 AnnotationColourScheme ac = constructAnnotationColours(
1449 (jalview.schemes.AnnotationColourGradient) av
1450 .getGlobalColourScheme(),
1451 userColours, object);
1453 view.setAnnotationColours(ac);
1454 view.setBgColour("AnnotationColourGradient");
1458 view.setBgColour(ColourSchemeProperty
1459 .getColourName(av.getGlobalColourScheme()));
1462 ResidueShaderI vcs = av.getResidueShading();
1463 ColourSchemeI cs = av.getGlobalColourScheme();
1467 if (vcs.conservationApplied())
1469 view.setConsThreshold(vcs.getConservationInc());
1470 if (cs instanceof jalview.schemes.UserColourScheme)
1472 view.setBgColour(setUserColourScheme(cs, userColours, object));
1475 view.setPidThreshold(vcs.getThreshold());
1478 view.setConservationSelected(av.getConservationSelected());
1479 view.setPidSelected(av.getAbovePIDThreshold());
1480 final Font font = av.getFont();
1481 view.setFontName(font.getName());
1482 view.setFontSize(font.getSize());
1483 view.setFontStyle(font.getStyle());
1484 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1485 view.setRenderGaps(av.isRenderGaps());
1486 view.setShowAnnotation(av.isShowAnnotation());
1487 view.setShowBoxes(av.getShowBoxes());
1488 view.setShowColourText(av.getColourText());
1489 view.setShowFullId(av.getShowJVSuffix());
1490 view.setRightAlignIds(av.isRightAlignIds());
1491 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1492 view.setShowText(av.getShowText());
1493 view.setShowUnconserved(av.getShowUnconserved());
1494 view.setWrapAlignment(av.getWrapAlignment());
1495 view.setTextCol1(av.getTextColour().getRGB());
1496 view.setTextCol2(av.getTextColour2().getRGB());
1497 view.setTextColThreshold(av.getThresholdTextColour());
1498 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1499 view.setShowSequenceLogo(av.isShowSequenceLogo());
1500 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1501 view.setShowGroupConsensus(av.isShowGroupConsensus());
1502 view.setShowGroupConservation(av.isShowGroupConservation());
1503 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1504 view.setShowDbRefTooltip(av.isShowDBRefs());
1505 view.setFollowHighlight(av.isFollowHighlight());
1506 view.setFollowSelection(av.followSelection);
1507 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1508 if (av.getFeaturesDisplayed() != null)
1510 FeatureSettings fs = new FeatureSettings();
1512 FeatureRenderer fr = ap.getSeqPanel().seqCanvas
1513 .getFeatureRenderer();
1514 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1516 Vector<String> settingsAdded = new Vector<>();
1517 if (renderOrder != null)
1519 for (String featureType : renderOrder)
1521 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1522 setting.setType(featureType);
1525 * save any filter for the feature type
1527 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1528 if (filter != null) {
1529 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1530 FeatureMatcherI firstFilter = filters.next();
1531 setting.setMatcherSet(Jalview2XML.marshalFilter(
1532 firstFilter, filters, filter.isAnded()));
1536 * save colour scheme for the feature type
1538 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1539 if (!fcol.isSimpleColour())
1541 setting.setColour(fcol.getMaxColour().getRGB());
1542 setting.setMincolour(fcol.getMinColour().getRGB());
1543 setting.setMin(fcol.getMin());
1544 setting.setMax(fcol.getMax());
1545 setting.setColourByLabel(fcol.isColourByLabel());
1546 if (fcol.isColourByAttribute())
1548 String[] attName = fcol.getAttributeName();
1549 setting.getAttributeName().add(attName[0]);
1550 if (attName.length > 1)
1552 setting.getAttributeName().add(attName[1]);
1555 setting.setAutoScale(fcol.isAutoScaled());
1556 setting.setThreshold(fcol.getThreshold());
1557 Color noColour = fcol.getNoColour();
1558 if (noColour == null)
1560 setting.setNoValueColour(NoValueColour.NONE);
1562 else if (noColour.equals(fcol.getMaxColour()))
1564 setting.setNoValueColour(NoValueColour.MAX);
1568 setting.setNoValueColour(NoValueColour.MIN);
1570 // -1 = No threshold, 0 = Below, 1 = Above
1571 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1572 : (fcol.isBelowThreshold() ? 0 : -1));
1576 setting.setColour(fcol.getColour().getRGB());
1580 av.getFeaturesDisplayed().isVisible(featureType));
1582 .getOrder(featureType);
1585 setting.setOrder(rorder);
1587 /// fs.addSetting(setting);
1588 fs.getSetting().add(setting);
1589 settingsAdded.addElement(featureType);
1593 // is groups actually supposed to be a map here ?
1594 Iterator<String> en = fr.getFeatureGroups().iterator();
1595 Vector<String> groupsAdded = new Vector<>();
1596 while (en.hasNext())
1598 String grp = en.next();
1599 if (groupsAdded.contains(grp))
1603 Group g = new Group();
1605 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1608 fs.getGroup().add(g);
1609 groupsAdded.addElement(grp);
1611 // jms.setFeatureSettings(fs);
1612 object.setFeatureSettings(fs);
1615 if (av.hasHiddenColumns())
1617 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1618 .getHiddenColumns();
1621 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1625 Iterator<int[]> hiddenRegions = hidden.iterator();
1626 while (hiddenRegions.hasNext())
1628 int[] region = hiddenRegions.next();
1629 HiddenColumns hc = new HiddenColumns();
1630 hc.setStart(region[0]);
1631 hc.setEnd(region[1]);
1632 // view.addHiddenColumns(hc);
1633 view.getHiddenColumns().add(hc);
1637 if (calcIdSet.size() > 0)
1639 for (String calcId : calcIdSet)
1641 if (calcId.trim().length() > 0)
1643 CalcIdParam cidp = createCalcIdParam(calcId, av);
1644 // Some calcIds have no parameters.
1647 // view.addCalcIdParam(cidp);
1648 view.getCalcIdParam().add(cidp);
1654 // jms.addViewport(view);
1655 object.getViewport().add(view);
1657 // object.setJalviewModelSequence(jms);
1658 // object.getVamsasModel().addSequenceSet(vamsasSet);
1659 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1661 if (jout != null && fileName != null)
1663 // We may not want to write the object to disk,
1664 // eg we can copy the alignViewport to a new view object
1665 // using save and then load
1668 System.out.println("Writing jar entry " + fileName);
1669 JarEntry entry = new JarEntry(fileName);
1670 jout.putNextEntry(entry);
1671 PrintWriter pout = new PrintWriter(
1672 new OutputStreamWriter(jout, UTF_8));
1673 JAXBContext jaxbContext = JAXBContext
1674 .newInstance(JalviewModel.class);
1675 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1677 // output pretty printed
1678 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1679 jaxbMarshaller.marshal(
1680 new ObjectFactory().createJalviewModel(object), pout);
1682 // jaxbMarshaller.marshal(object, pout);
1683 // marshaller.marshal(object);
1686 } catch (Exception ex)
1688 // TODO: raise error in GUI if marshalling failed.
1689 System.err.println("Error writing Jalview project");
1690 ex.printStackTrace();
1697 * Writes PCA viewer attributes and computed values to an XML model object and
1698 * adds it to the JalviewModel. Any exceptions are reported by logging.
1700 protected void savePCA(PCAPanel panel, JalviewModel object)
1704 PcaViewer viewer = new PcaViewer();
1705 viewer.setHeight(panel.getHeight());
1706 viewer.setWidth(panel.getWidth());
1707 viewer.setXpos(panel.getX());
1708 viewer.setYpos(panel.getY());
1709 viewer.setTitle(panel.getTitle());
1710 PCAModel pcaModel = panel.getPcaModel();
1711 viewer.setScoreModelName(pcaModel.getScoreModelName());
1712 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1713 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1714 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1716 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1717 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1718 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1719 SeqPointMin spmin = new SeqPointMin();
1720 spmin.setXPos(spMin[0]);
1721 spmin.setYPos(spMin[1]);
1722 spmin.setZPos(spMin[2]);
1723 viewer.setSeqPointMin(spmin);
1724 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1725 SeqPointMax spmax = new SeqPointMax();
1726 spmax.setXPos(spMax[0]);
1727 spmax.setYPos(spMax[1]);
1728 spmax.setZPos(spMax[2]);
1729 viewer.setSeqPointMax(spmax);
1730 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1731 viewer.setLinkToAllViews(
1732 panel.getRotatableCanvas().isApplyToAllViews());
1733 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1734 viewer.setIncludeGaps(sp.includeGaps());
1735 viewer.setMatchGaps(sp.matchGaps());
1736 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1737 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1740 * sequence points on display
1742 for (jalview.datamodel.SequencePoint spt : pcaModel
1743 .getSequencePoints())
1745 SequencePoint point = new SequencePoint();
1746 point.setSequenceRef(seqHash(spt.getSequence()));
1747 point.setXPos(spt.coord.x);
1748 point.setYPos(spt.coord.y);
1749 point.setZPos(spt.coord.z);
1750 viewer.getSequencePoint().add(point);
1754 * (end points of) axes on display
1756 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1759 Axis axis = new Axis();
1763 viewer.getAxis().add(axis);
1767 * raw PCA data (note we are not restoring PCA inputs here -
1768 * alignment view, score model, similarity parameters)
1770 PcaDataType data = new PcaDataType();
1771 viewer.setPcaData(data);
1772 PCA pca = pcaModel.getPcaData();
1774 DoubleMatrix pm = new DoubleMatrix();
1775 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1776 data.setPairwiseMatrix(pm);
1778 DoubleMatrix tm = new DoubleMatrix();
1779 saveDoubleMatrix(pca.getTridiagonal(), tm);
1780 data.setTridiagonalMatrix(tm);
1782 DoubleMatrix eigenMatrix = new DoubleMatrix();
1783 data.setEigenMatrix(eigenMatrix);
1784 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1786 object.getPcaViewer().add(viewer);
1787 } catch (Throwable t)
1789 Cache.log.error("Error saving PCA: " + t.getMessage());
1794 * Stores values from a matrix into an XML element, including (if present) the
1799 * @see #loadDoubleMatrix(DoubleMatrix)
1801 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1803 xmlMatrix.setRows(m.height());
1804 xmlMatrix.setColumns(m.width());
1805 for (int i = 0; i < m.height(); i++)
1807 DoubleVector row = new DoubleVector();
1808 for (int j = 0; j < m.width(); j++)
1810 row.getV().add(m.getValue(i, j));
1812 xmlMatrix.getRow().add(row);
1814 if (m.getD() != null)
1816 DoubleVector dVector = new DoubleVector();
1817 for (double d : m.getD())
1819 dVector.getV().add(d);
1821 xmlMatrix.setD(dVector);
1823 if (m.getE() != null)
1825 DoubleVector eVector = new DoubleVector();
1826 for (double e : m.getE())
1828 eVector.getV().add(e);
1830 xmlMatrix.setE(eVector);
1835 * Loads XML matrix data into a new Matrix object, including the D and/or E
1836 * vectors (if present)
1840 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1842 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1844 int rows = mData.getRows();
1845 double[][] vals = new double[rows][];
1847 for (int i = 0; i < rows; i++)
1849 List<Double> dVector = mData.getRow().get(i).getV();
1850 vals[i] = new double[dVector.size()];
1852 for (Double d : dVector)
1858 MatrixI m = new Matrix(vals);
1860 if (mData.getD() != null)
1862 List<Double> dVector = mData.getD().getV();
1863 double[] vec = new double[dVector.size()];
1865 for (Double d : dVector)
1871 if (mData.getE() != null)
1873 List<Double> dVector = mData.getE().getV();
1874 double[] vec = new double[dVector.size()];
1876 for (Double d : dVector)
1887 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1888 * for each viewer, with
1890 * <li>viewer geometry (position, size, split pane divider location)</li>
1891 * <li>index of the selected structure in the viewer (currently shows gapped
1893 * <li>the id of the annotation holding RNA secondary structure</li>
1894 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1896 * Varna viewer state is also written out (in native Varna XML) to separate
1897 * project jar entries. A separate entry is written for each RNA structure
1898 * displayed, with the naming convention
1900 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1908 * @param storeDataset
1910 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1911 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1912 boolean storeDataset)
1914 if (Desktop.desktop == null)
1918 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1919 for (int f = frames.length - 1; f > -1; f--)
1921 if (frames[f] instanceof AppVarna)
1923 AppVarna varna = (AppVarna) frames[f];
1925 * link the sequence to every viewer that is showing it and is linked to
1926 * its alignment panel
1928 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1930 String viewId = varna.getViewId();
1931 RnaViewer rna = new RnaViewer();
1932 rna.setViewId(viewId);
1933 rna.setTitle(varna.getTitle());
1934 rna.setXpos(varna.getX());
1935 rna.setYpos(varna.getY());
1936 rna.setWidth(varna.getWidth());
1937 rna.setHeight(varna.getHeight());
1938 rna.setDividerLocation(varna.getDividerLocation());
1939 rna.setSelectedRna(varna.getSelectedIndex());
1940 // jseq.addRnaViewer(rna);
1941 jseq.getRnaViewer().add(rna);
1944 * Store each Varna panel's state once in the project per sequence.
1945 * First time through only (storeDataset==false)
1947 // boolean storeSessions = false;
1948 // String sequenceViewId = viewId + seqsToIds.get(jds);
1949 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1951 // viewIds.add(sequenceViewId);
1952 // storeSessions = true;
1954 for (RnaModel model : varna.getModels())
1956 if (model.seq == jds)
1959 * VARNA saves each view (sequence or alignment secondary
1960 * structure, gapped or trimmed) as a separate XML file
1962 String jarEntryName = rnaSessions.get(model);
1963 if (jarEntryName == null)
1966 String varnaStateFile = varna.getStateInfo(model.rna);
1967 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1968 copyFileToJar(jout, varnaStateFile, jarEntryName);
1969 rnaSessions.put(model, jarEntryName);
1971 SecondaryStructure ss = new SecondaryStructure();
1972 String annotationId = varna.getAnnotation(jds).annotationId;
1973 ss.setAnnotationId(annotationId);
1974 ss.setViewerState(jarEntryName);
1975 ss.setGapped(model.gapped);
1976 ss.setTitle(model.title);
1977 // rna.addSecondaryStructure(ss);
1978 rna.getSecondaryStructure().add(ss);
1987 * Copy the contents of a file to a new entry added to the output jar
1991 * @param jarEntryName
1993 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1994 String jarEntryName)
1996 DataInputStream dis = null;
1999 File file = new File(infilePath);
2000 if (file.exists() && jout != null)
2002 dis = new DataInputStream(new FileInputStream(file));
2003 byte[] data = new byte[(int) file.length()];
2004 dis.readFully(data);
2005 writeJarEntry(jout, jarEntryName, data);
2007 } catch (Exception ex)
2009 ex.printStackTrace();
2017 } catch (IOException e)
2026 * Write the data to a new entry of given name in the output jar file
2029 * @param jarEntryName
2031 * @throws IOException
2033 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2034 byte[] data) throws IOException
2038 System.out.println("Writing jar entry " + jarEntryName);
2039 jout.putNextEntry(new JarEntry(jarEntryName));
2040 DataOutputStream dout = new DataOutputStream(jout);
2041 dout.write(data, 0, data.length);
2048 * Save the state of a structure viewer
2053 * the archive XML element under which to save the state
2056 * @param matchedFile
2060 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2061 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2062 String matchedFile, StructureViewerBase viewFrame)
2064 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2067 * Look for any bindings for this viewer to the PDB file of interest
2068 * (including part matches excluding chain id)
2070 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2072 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2073 final String pdbId = pdbentry.getId();
2074 if (!pdbId.equals(entry.getId())
2075 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2076 .startsWith(pdbId.toLowerCase())))
2079 * not interested in a binding to a different PDB entry here
2083 if (matchedFile == null)
2085 matchedFile = pdbentry.getFile();
2087 else if (!matchedFile.equals(pdbentry.getFile()))
2090 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2091 + pdbentry.getFile());
2095 // can get at it if the ID
2096 // match is ambiguous (e.g.
2099 for (int smap = 0; smap < viewFrame.getBinding()
2100 .getSequence()[peid].length; smap++)
2102 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2103 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2105 StructureState state = new StructureState();
2106 state.setVisible(true);
2107 state.setXpos(viewFrame.getX());
2108 state.setYpos(viewFrame.getY());
2109 state.setWidth(viewFrame.getWidth());
2110 state.setHeight(viewFrame.getHeight());
2111 final String viewId = viewFrame.getViewId();
2112 state.setViewId(viewId);
2113 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2114 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2115 state.setColourByJmol(viewFrame.isColouredByViewer());
2116 state.setType(viewFrame.getViewerType().toString());
2117 // pdb.addStructureState(state);
2118 pdb.getStructureState().add(state);
2126 * Populates the AnnotationColourScheme xml for save. This captures the
2127 * settings of the options in the 'Colour by Annotation' dialog.
2130 * @param userColours
2134 private AnnotationColourScheme constructAnnotationColours(
2135 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2138 AnnotationColourScheme ac = new AnnotationColourScheme();
2139 ac.setAboveThreshold(acg.getAboveThreshold());
2140 ac.setThreshold(acg.getAnnotationThreshold());
2141 // 2.10.2 save annotationId (unique) not annotation label
2142 ac.setAnnotation(acg.getAnnotation().annotationId);
2143 if (acg.getBaseColour() instanceof UserColourScheme)
2146 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2151 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2154 ac.setMaxColour(acg.getMaxColour().getRGB());
2155 ac.setMinColour(acg.getMinColour().getRGB());
2156 ac.setPerSequence(acg.isSeqAssociated());
2157 ac.setPredefinedColours(acg.isPredefinedColours());
2161 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2162 IdentityHashMap<SequenceGroup, String> groupRefs,
2163 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2164 SequenceSet vamsasSet)
2167 for (int i = 0; i < aa.length; i++)
2169 Annotation an = new Annotation();
2171 AlignmentAnnotation annotation = aa[i];
2172 if (annotation.annotationId != null)
2174 annotationIds.put(annotation.annotationId, annotation);
2177 an.setId(annotation.annotationId);
2179 an.setVisible(annotation.visible);
2181 an.setDescription(annotation.description);
2183 if (annotation.sequenceRef != null)
2185 // 2.9 JAL-1781 xref on sequence id rather than name
2186 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2188 if (annotation.groupRef != null)
2190 String groupIdr = groupRefs.get(annotation.groupRef);
2191 if (groupIdr == null)
2193 // make a locally unique String
2194 groupRefs.put(annotation.groupRef,
2195 groupIdr = ("" + System.currentTimeMillis()
2196 + annotation.groupRef.getName()
2197 + groupRefs.size()));
2199 an.setGroupRef(groupIdr.toString());
2202 // store all visualization attributes for annotation
2203 an.setGraphHeight(annotation.graphHeight);
2204 an.setCentreColLabels(annotation.centreColLabels);
2205 an.setScaleColLabels(annotation.scaleColLabel);
2206 an.setShowAllColLabels(annotation.showAllColLabels);
2207 an.setBelowAlignment(annotation.belowAlignment);
2209 if (annotation.graph > 0)
2212 an.setGraphType(annotation.graph);
2213 an.setGraphGroup(annotation.graphGroup);
2214 if (annotation.getThreshold() != null)
2216 ThresholdLine line = new ThresholdLine();
2217 line.setLabel(annotation.getThreshold().label);
2218 line.setValue(annotation.getThreshold().value);
2219 line.setColour(annotation.getThreshold().colour.getRGB());
2220 an.setThresholdLine(line);
2228 an.setLabel(annotation.label);
2230 if (annotation == av.getAlignmentQualityAnnot()
2231 || annotation == av.getAlignmentConservationAnnotation()
2232 || annotation == av.getAlignmentConsensusAnnotation()
2233 || annotation.autoCalculated)
2235 // new way of indicating autocalculated annotation -
2236 an.setAutoCalculated(annotation.autoCalculated);
2238 if (annotation.hasScore())
2240 an.setScore(annotation.getScore());
2243 if (annotation.getCalcId() != null)
2245 calcIdSet.add(annotation.getCalcId());
2246 an.setCalcId(annotation.getCalcId());
2248 if (annotation.hasProperties())
2250 for (String pr : annotation.getProperties())
2252 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2254 prop.setValue(annotation.getProperty(pr));
2255 // an.addProperty(prop);
2256 an.getProperty().add(prop);
2260 AnnotationElement ae;
2261 if (annotation.annotations != null)
2263 an.setScoreOnly(false);
2264 for (int a = 0; a < annotation.annotations.length; a++)
2266 if ((annotation == null) || (annotation.annotations[a] == null))
2271 ae = new AnnotationElement();
2272 if (annotation.annotations[a].description != null)
2274 ae.setDescription(annotation.annotations[a].description);
2276 if (annotation.annotations[a].displayCharacter != null)
2278 ae.setDisplayCharacter(
2279 annotation.annotations[a].displayCharacter);
2282 if (!Float.isNaN(annotation.annotations[a].value))
2284 ae.setValue(annotation.annotations[a].value);
2288 if (annotation.annotations[a].secondaryStructure > ' ')
2290 ae.setSecondaryStructure(
2291 annotation.annotations[a].secondaryStructure + "");
2294 if (annotation.annotations[a].colour != null
2295 && annotation.annotations[a].colour != java.awt.Color.black)
2297 ae.setColour(annotation.annotations[a].colour.getRGB());
2300 // an.addAnnotationElement(ae);
2301 an.getAnnotationElement().add(ae);
2302 if (annotation.autoCalculated)
2304 // only write one non-null entry into the annotation row -
2305 // sufficient to get the visualization attributes necessary to
2313 an.setScoreOnly(true);
2315 if (!storeDS || (storeDS && !annotation.autoCalculated))
2317 // skip autocalculated annotation - these are only provided for
2319 // vamsasSet.addAnnotation(an);
2320 vamsasSet.getAnnotation().add(an);
2326 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2328 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2329 if (settings != null)
2331 CalcIdParam vCalcIdParam = new CalcIdParam();
2332 vCalcIdParam.setCalcId(calcId);
2333 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2334 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2335 // generic URI allowing a third party to resolve another instance of the
2336 // service used for this calculation
2337 for (String url : settings.getServiceURLs())
2339 // vCalcIdParam.addServiceURL(urls);
2340 vCalcIdParam.getServiceURL().add(url);
2342 vCalcIdParam.setVersion("1.0");
2343 if (settings.getPreset() != null)
2345 WsParamSetI setting = settings.getPreset();
2346 vCalcIdParam.setName(setting.getName());
2347 vCalcIdParam.setDescription(setting.getDescription());
2351 vCalcIdParam.setName("");
2352 vCalcIdParam.setDescription("Last used parameters");
2354 // need to be able to recover 1) settings 2) user-defined presets or
2355 // recreate settings from preset 3) predefined settings provided by
2356 // service - or settings that can be transferred (or discarded)
2357 vCalcIdParam.setParameters(
2358 settings.getWsParamFile().replace("\n", "|\\n|"));
2359 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2360 // todo - decide if updateImmediately is needed for any projects.
2362 return vCalcIdParam;
2367 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2370 if (calcIdParam.getVersion().equals("1.0"))
2372 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2373 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2374 .getPreferredServiceFor(calcIds);
2375 if (service != null)
2377 WsParamSetI parmSet = null;
2380 parmSet = service.getParamStore().parseServiceParameterFile(
2381 calcIdParam.getName(), calcIdParam.getDescription(),
2383 calcIdParam.getParameters().replace("|\\n|", "\n"));
2384 } catch (IOException x)
2386 warn("Couldn't parse parameter data for "
2387 + calcIdParam.getCalcId(), x);
2390 List<ArgumentI> argList = null;
2391 if (calcIdParam.getName().length() > 0)
2393 parmSet = service.getParamStore()
2394 .getPreset(calcIdParam.getName());
2395 if (parmSet != null)
2397 // TODO : check we have a good match with settings in AACon -
2398 // otherwise we'll need to create a new preset
2403 argList = parmSet.getArguments();
2406 AAConSettings settings = new AAConSettings(
2407 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2408 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2409 calcIdParam.isNeedsUpdate());
2414 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2418 throw new Error(MessageManager.formatMessage(
2419 "error.unsupported_version_calcIdparam", new Object[]
2420 { calcIdParam.toString() }));
2424 * External mapping between jalview objects and objects yielding a valid and
2425 * unique object ID string. This is null for normal Jalview project IO, but
2426 * non-null when a jalview project is being read or written as part of a
2429 IdentityHashMap jv2vobj = null;
2432 * Construct a unique ID for jvobj using either existing bindings or if none
2433 * exist, the result of the hashcode call for the object.
2436 * jalview data object
2437 * @return unique ID for referring to jvobj
2439 private String makeHashCode(Object jvobj, String altCode)
2441 if (jv2vobj != null)
2443 Object id = jv2vobj.get(jvobj);
2446 return id.toString();
2448 // check string ID mappings
2449 if (jvids2vobj != null && jvobj instanceof String)
2451 id = jvids2vobj.get(jvobj);
2455 return id.toString();
2457 // give up and warn that something has gone wrong
2458 warn("Cannot find ID for object in external mapping : " + jvobj);
2464 * return local jalview object mapped to ID, if it exists
2468 * @return null or object bound to idcode
2470 private Object retrieveExistingObj(String idcode)
2472 if (idcode != null && vobj2jv != null)
2474 return vobj2jv.get(idcode);
2480 * binding from ID strings from external mapping table to jalview data model
2483 private Hashtable vobj2jv;
2485 private Sequence createVamsasSequence(String id, SequenceI jds)
2487 return createVamsasSequence(true, id, jds, null);
2490 private Sequence createVamsasSequence(boolean recurse, String id,
2491 SequenceI jds, SequenceI parentseq)
2493 Sequence vamsasSeq = new Sequence();
2494 vamsasSeq.setId(id);
2495 vamsasSeq.setName(jds.getName());
2496 vamsasSeq.setSequence(jds.getSequenceAsString());
2497 vamsasSeq.setDescription(jds.getDescription());
2498 jalview.datamodel.DBRefEntry[] dbrefs = null;
2499 if (jds.getDatasetSequence() != null)
2501 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2505 // seqId==dsseqid so we can tell which sequences really are
2506 // dataset sequences only
2507 vamsasSeq.setDsseqid(id);
2508 dbrefs = jds.getDBRefs();
2509 if (parentseq == null)
2516 for (int d = 0; d < dbrefs.length; d++)
2518 DBRef dbref = new DBRef();
2519 dbref.setSource(dbrefs[d].getSource());
2520 dbref.setVersion(dbrefs[d].getVersion());
2521 dbref.setAccessionId(dbrefs[d].getAccessionId());
2522 if (dbrefs[d].hasMap())
2524 Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
2526 dbref.setMapping(mp);
2528 // vamsasSeq.addDBRef(dbref);
2529 vamsasSeq.getDBRef().add(dbref);
2535 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2536 SequenceI parentseq, SequenceI jds, boolean recurse)
2539 if (jmp.getMap() != null)
2543 jalview.util.MapList mlst = jmp.getMap();
2544 List<int[]> r = mlst.getFromRanges();
2545 for (int[] range : r)
2547 MapListFrom mfrom = new MapListFrom();
2548 mfrom.setStart(range[0]);
2549 mfrom.setEnd(range[1]);
2550 // mp.addMapListFrom(mfrom);
2551 mp.getMapListFrom().add(mfrom);
2553 r = mlst.getToRanges();
2554 for (int[] range : r)
2556 MapListTo mto = new MapListTo();
2557 mto.setStart(range[0]);
2558 mto.setEnd(range[1]);
2559 // mp.addMapListTo(mto);
2560 mp.getMapListTo().add(mto);
2562 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2563 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2564 if (jmp.getTo() != null)
2566 // MappingChoice mpc = new MappingChoice();
2568 // check/create ID for the sequence referenced by getTo()
2571 SequenceI ps = null;
2572 if (parentseq != jmp.getTo()
2573 && parentseq.getDatasetSequence() != jmp.getTo())
2575 // chaining dbref rather than a handshaking one
2576 jmpid = seqHash(ps = jmp.getTo());
2580 jmpid = seqHash(ps = parentseq);
2582 // mpc.setDseqFor(jmpid);
2583 mp.setDseqFor(jmpid);
2584 if (!seqRefIds.containsKey(jmpid))
2586 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2587 seqRefIds.put(jmpid, ps);
2591 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2594 // mp.setMappingChoice(mpc);
2600 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2601 List<UserColourScheme> userColours, JalviewModel jm)
2604 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2605 boolean newucs = false;
2606 if (!userColours.contains(ucs))
2608 userColours.add(ucs);
2611 id = "ucs" + userColours.indexOf(ucs);
2614 // actually create the scheme's entry in the XML model
2615 java.awt.Color[] colours = ucs.getColours();
2616 UserColours uc = new UserColours();
2617 // UserColourScheme jbucs = new UserColourScheme();
2618 JalviewUserColours jbucs = new JalviewUserColours();
2620 for (int i = 0; i < colours.length; i++)
2622 Colour col = new Colour();
2623 col.setName(ResidueProperties.aa[i]);
2624 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2625 // jbucs.addColour(col);
2626 jbucs.getColour().add(col);
2628 if (ucs.getLowerCaseColours() != null)
2630 colours = ucs.getLowerCaseColours();
2631 for (int i = 0; i < colours.length; i++)
2633 Colour col = new Colour();
2634 col.setName(ResidueProperties.aa[i].toLowerCase());
2635 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2636 // jbucs.addColour(col);
2637 jbucs.getColour().add(col);
2642 uc.setUserColourScheme(jbucs);
2643 // jm.addUserColours(uc);
2644 jm.getUserColours().add(uc);
2650 jalview.schemes.UserColourScheme getUserColourScheme(
2651 JalviewModel jm, String id)
2653 List<UserColours> uc = jm.getUserColours();
2654 UserColours colours = null;
2656 for (int i = 0; i < uc.length; i++)
2658 if (uc[i].getId().equals(id))
2665 for (UserColours c : uc)
2667 if (c.getId().equals(id))
2674 java.awt.Color[] newColours = new java.awt.Color[24];
2676 for (int i = 0; i < 24; i++)
2678 newColours[i] = new java.awt.Color(Integer.parseInt(
2679 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2680 colours.getUserColourScheme().getColour().get(i).getRGB(),
2684 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2687 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2689 newColours = new java.awt.Color[23];
2690 for (int i = 0; i < 23; i++)
2692 newColours[i] = new java.awt.Color(Integer.parseInt(
2693 colours.getUserColourScheme().getColour().get(i + 24)
2697 ucs.setLowerCaseColours(newColours);
2704 * contains last error message (if any) encountered by XML loader.
2706 String errorMessage = null;
2709 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2710 * exceptions are raised during project XML parsing
2712 public boolean attemptversion1parse = false;
2715 * Load a jalview project archive from a jar file
2718 * - HTTP URL or filename
2720 public AlignFrame loadJalviewAlign(final String file)
2723 jalview.gui.AlignFrame af = null;
2727 // create list to store references for any new Jmol viewers created
2728 newStructureViewers = new Vector<>();
2729 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2730 // Workaround is to make sure caller implements the JarInputStreamProvider
2732 // so we can re-open the jar input stream for each entry.
2734 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2735 af = loadJalviewAlign(jprovider);
2738 af.setMenusForViewport();
2740 } catch (MalformedURLException e)
2742 errorMessage = "Invalid URL format for '" + file + "'";
2748 SwingUtilities.invokeAndWait(new Runnable()
2753 setLoadingFinishedForNewStructureViewers();
2756 } catch (Exception x)
2758 System.err.println("Error loading alignment: " + x.getMessage());
2764 private jarInputStreamProvider createjarInputStreamProvider(
2765 final String file) throws MalformedURLException
2768 errorMessage = null;
2769 uniqueSetSuffix = null;
2771 viewportsAdded.clear();
2772 frefedSequence = null;
2774 if (file.startsWith("http://"))
2776 url = new URL(file);
2778 final URL _url = url;
2779 return new jarInputStreamProvider()
2783 public JarInputStream getJarInputStream() throws IOException
2787 return new JarInputStream(_url.openStream());
2791 return new JarInputStream(new FileInputStream(file));
2796 public String getFilename()
2804 * Recover jalview session from a jalview project archive. Caller may
2805 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2806 * themselves. Any null fields will be initialised with default values,
2807 * non-null fields are left alone.
2812 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2814 errorMessage = null;
2815 if (uniqueSetSuffix == null)
2817 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2819 if (seqRefIds == null)
2823 AlignFrame af = null, _af = null;
2824 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2825 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2826 final String file = jprovider.getFilename();
2829 JarInputStream jin = null;
2830 JarEntry jarentry = null;
2835 jin = jprovider.getJarInputStream();
2836 for (int i = 0; i < entryCount; i++)
2838 jarentry = jin.getNextJarEntry();
2841 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2843 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2844 // JalviewModel object = new JalviewModel();
2846 JAXBContext jc = JAXBContext
2847 .newInstance("jalview.xml.binding.jalview");
2848 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2849 .createXMLStreamReader(jin);
2850 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2851 JAXBElement<JalviewModel> jbe = um
2852 .unmarshal(streamReader, JalviewModel.class);
2853 JalviewModel object = jbe.getValue();
2856 Unmarshaller unmar = new Unmarshaller(object);
2857 unmar.setValidation(false);
2858 object = (JalviewModel) unmar.unmarshal(in);
2860 if (true) // !skipViewport(object))
2862 _af = loadFromObject(object, file, true, jprovider);
2863 if (_af != null && object.getViewport().size() > 0)
2864 // getJalviewModelSequence().getViewportCount() > 0)
2868 // store a reference to the first view
2871 if (_af.getViewport().isGatherViewsHere())
2873 // if this is a gathered view, keep its reference since
2874 // after gathering views, only this frame will remain
2876 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2879 // Save dataset to register mappings once all resolved
2880 importedDatasets.put(
2881 af.getViewport().getAlignment().getDataset(),
2882 af.getViewport().getAlignment().getDataset());
2887 else if (jarentry != null)
2889 // Some other file here.
2892 } while (jarentry != null);
2893 resolveFrefedSequences();
2894 } catch (IOException ex)
2896 ex.printStackTrace();
2897 errorMessage = "Couldn't locate Jalview XML file : " + file;
2899 "Exception whilst loading jalview XML file : " + ex + "\n");
2900 } catch (Exception ex)
2902 System.err.println("Parsing as Jalview Version 2 file failed.");
2903 ex.printStackTrace(System.err);
2904 if (attemptversion1parse)
2906 // used to attempt to parse as V1 castor-generated xml
2908 if (Desktop.instance != null)
2910 Desktop.instance.stopLoading();
2914 System.out.println("Successfully loaded archive file");
2917 ex.printStackTrace();
2920 "Exception whilst loading jalview XML file : " + ex + "\n");
2921 } catch (OutOfMemoryError e)
2923 // Don't use the OOM Window here
2924 errorMessage = "Out of memory loading jalview XML file";
2925 System.err.println("Out of memory whilst loading jalview XML file");
2926 e.printStackTrace();
2930 * Regather multiple views (with the same sequence set id) to the frame (if
2931 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2932 * views instead of separate frames. Note this doesn't restore a state where
2933 * some expanded views in turn have tabbed views - the last "first tab" read
2934 * in will play the role of gatherer for all.
2936 for (AlignFrame fr : gatherToThisFrame.values())
2938 Desktop.instance.gatherViews(fr);
2941 restoreSplitFrames();
2942 for (AlignmentI ds : importedDatasets.keySet())
2944 if (ds.getCodonFrames() != null)
2946 StructureSelectionManager
2947 .getStructureSelectionManager(Desktop.instance)
2948 .registerMappings(ds.getCodonFrames());
2951 if (errorMessage != null)
2956 if (Desktop.instance != null)
2958 Desktop.instance.stopLoading();
2965 * Try to reconstruct and display SplitFrame windows, where each contains
2966 * complementary dna and protein alignments. Done by pairing up AlignFrame
2967 * objects (created earlier) which have complementary viewport ids associated.
2969 protected void restoreSplitFrames()
2971 List<SplitFrame> gatherTo = new ArrayList<>();
2972 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2973 Map<String, AlignFrame> dna = new HashMap<>();
2976 * Identify the DNA alignments
2978 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2981 AlignFrame af = candidate.getValue();
2982 if (af.getViewport().getAlignment().isNucleotide())
2984 dna.put(candidate.getKey().getId(), af);
2989 * Try to match up the protein complements
2991 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2994 AlignFrame af = candidate.getValue();
2995 if (!af.getViewport().getAlignment().isNucleotide())
2997 String complementId = candidate.getKey().getComplementId();
2998 // only non-null complements should be in the Map
2999 if (complementId != null && dna.containsKey(complementId))
3001 final AlignFrame dnaFrame = dna.get(complementId);
3002 SplitFrame sf = createSplitFrame(dnaFrame, af);
3003 addedToSplitFrames.add(dnaFrame);
3004 addedToSplitFrames.add(af);
3005 dnaFrame.setMenusForViewport();
3006 af.setMenusForViewport();
3007 if (af.getViewport().isGatherViewsHere())
3016 * Open any that we failed to pair up (which shouldn't happen!) as
3017 * standalone AlignFrame's.
3019 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3022 AlignFrame af = candidate.getValue();
3023 if (!addedToSplitFrames.contains(af))
3025 Viewport view = candidate.getKey();
3026 Desktop.addInternalFrame(af, view.getTitle(),
3027 safeInt(view.getWidth()), safeInt(view.getHeight()));
3028 af.setMenusForViewport();
3029 System.err.println("Failed to restore view " + view.getTitle()
3030 + " to split frame");
3035 * Gather back into tabbed views as flagged.
3037 for (SplitFrame sf : gatherTo)
3039 Desktop.instance.gatherViews(sf);
3042 splitFrameCandidates.clear();
3046 * Construct and display one SplitFrame holding DNA and protein alignments.
3049 * @param proteinFrame
3052 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3053 AlignFrame proteinFrame)
3055 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3056 String title = MessageManager.getString("label.linked_view_title");
3057 int width = (int) dnaFrame.getBounds().getWidth();
3058 int height = (int) (dnaFrame.getBounds().getHeight()
3059 + proteinFrame.getBounds().getHeight() + 50);
3062 * SplitFrame location is saved to both enclosed frames
3064 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3065 Desktop.addInternalFrame(splitFrame, title, width, height);
3068 * And compute cDNA consensus (couldn't do earlier with consensus as
3069 * mappings were not yet present)
3071 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3077 * check errorMessage for a valid error message and raise an error box in the
3078 * GUI or write the current errorMessage to stderr and then clear the error
3081 protected void reportErrors()
3083 reportErrors(false);
3086 protected void reportErrors(final boolean saving)
3088 if (errorMessage != null)
3090 final String finalErrorMessage = errorMessage;
3093 javax.swing.SwingUtilities.invokeLater(new Runnable()
3098 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3100 "Error " + (saving ? "saving" : "loading")
3102 JvOptionPane.WARNING_MESSAGE);
3108 System.err.println("Problem loading Jalview file: " + errorMessage);
3111 errorMessage = null;
3114 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3117 * when set, local views will be updated from view stored in JalviewXML
3118 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3119 * sync if this is set to true.
3121 private final boolean updateLocalViews = false;
3124 * Returns the path to a temporary file holding the PDB file for the given PDB
3125 * id. The first time of asking, searches for a file of that name in the
3126 * Jalview project jar, and copies it to a new temporary file. Any repeat
3127 * requests just return the path to the file previously created.
3133 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3136 if (alreadyLoadedPDB.containsKey(pdbId))
3138 return alreadyLoadedPDB.get(pdbId).toString();
3141 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3143 if (tempFile != null)
3145 alreadyLoadedPDB.put(pdbId, tempFile);
3151 * Copies the jar entry of given name to a new temporary file and returns the
3152 * path to the file, or null if the entry is not found.
3155 * @param jarEntryName
3157 * a prefix for the temporary file name, must be at least three
3160 * null or original file - so new file can be given the same suffix
3164 protected String copyJarEntry(jarInputStreamProvider jprovider,
3165 String jarEntryName, String prefix, String origFile)
3167 BufferedReader in = null;
3168 PrintWriter out = null;
3169 String suffix = ".tmp";
3170 if (origFile == null)
3172 origFile = jarEntryName;
3174 int sfpos = origFile.lastIndexOf(".");
3175 if (sfpos > -1 && sfpos < (origFile.length() - 3))
3177 suffix = "." + origFile.substring(sfpos + 1);
3181 JarInputStream jin = jprovider.getJarInputStream();
3183 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3184 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3185 * FileInputStream(jprovider)); }
3188 JarEntry entry = null;
3191 entry = jin.getNextJarEntry();
3192 } while (entry != null && !entry.getName().equals(jarEntryName));
3195 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3196 File outFile = File.createTempFile(prefix, suffix);
3197 outFile.deleteOnExit();
3198 out = new PrintWriter(new FileOutputStream(outFile));
3201 while ((data = in.readLine()) != null)
3206 String t = outFile.getAbsolutePath();
3211 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3213 } catch (Exception ex)
3215 ex.printStackTrace();
3223 } catch (IOException e)
3237 private class JvAnnotRow
3239 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3246 * persisted version of annotation row from which to take vis properties
3248 public jalview.datamodel.AlignmentAnnotation template;
3251 * original position of the annotation row in the alignment
3257 * Load alignment frame from jalview XML DOM object
3259 * @param jalviewModel
3262 * filename source string
3263 * @param loadTreesAndStructures
3264 * when false only create Viewport
3266 * data source provider
3267 * @return alignment frame created from view stored in DOM
3269 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3270 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3272 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3273 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3275 // JalviewModelSequence jms = object.getJalviewModelSequence();
3277 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3279 Viewport view = (jalviewModel.getViewport().size() > 0)
3280 ? jalviewModel.getViewport().get(0)
3283 // ////////////////////////////////
3284 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3287 // If we just load in the same jar file again, the sequenceSetId
3288 // will be the same, and we end up with multiple references
3289 // to the same sequenceSet. We must modify this id on load
3290 // so that each load of the file gives a unique id
3293 * used to resolve correct alignment dataset for alignments with multiple
3296 String uniqueSeqSetId = null;
3297 String viewId = null;
3300 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3301 viewId = (view.getId() == null ? null
3302 : view.getId() + uniqueSetSuffix);
3305 // ////////////////////////////////
3308 List<SequenceI> hiddenSeqs = null;
3310 List<SequenceI> tmpseqs = new ArrayList<>();
3312 boolean multipleView = false;
3313 SequenceI referenceseqForView = null;
3314 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3315 List<JSeq> jseqs = jalviewModel.getJSeq();
3316 int vi = 0; // counter in vamsasSeq array
3317 for (int i = 0; i < jseqs.size(); i++)
3319 JSeq jseq = jseqs.get(i);
3320 String seqId = jseq.getId();
3322 SequenceI tmpSeq = seqRefIds.get(seqId);
3325 if (!incompleteSeqs.containsKey(seqId))
3327 // may not need this check, but keep it for at least 2.9,1 release
3328 if (tmpSeq.getStart() != jseq.getStart()
3329 || tmpSeq.getEnd() != jseq.getEnd())
3332 "Warning JAL-2154 regression: updating start/end for sequence "
3333 + tmpSeq.toString() + " to " + jseq);
3338 incompleteSeqs.remove(seqId);
3340 if (vamsasSeqs.size() > vi
3341 && vamsasSeqs.get(vi).getId().equals(seqId))
3343 // most likely we are reading a dataset XML document so
3344 // update from vamsasSeq section of XML for this sequence
3345 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3346 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3347 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3352 // reading multiple views, so vamsasSeq set is a subset of JSeq
3353 multipleView = true;
3355 tmpSeq.setStart(jseq.getStart());
3356 tmpSeq.setEnd(jseq.getEnd());
3357 tmpseqs.add(tmpSeq);
3361 Sequence vamsasSeq = vamsasSeqs.get(vi);
3362 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3363 vamsasSeq.getSequence());
3364 tmpSeq.setDescription(vamsasSeq.getDescription());
3365 tmpSeq.setStart(jseq.getStart());
3366 tmpSeq.setEnd(jseq.getEnd());
3367 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3368 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3369 tmpseqs.add(tmpSeq);
3373 if (safeBoolean(jseq.isViewreference()))
3375 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3378 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3380 if (hiddenSeqs == null)
3382 hiddenSeqs = new ArrayList<>();
3385 hiddenSeqs.add(tmpSeq);
3390 // Create the alignment object from the sequence set
3391 // ///////////////////////////////
3392 SequenceI[] orderedSeqs = tmpseqs
3393 .toArray(new SequenceI[tmpseqs.size()]);
3395 AlignmentI al = null;
3396 // so we must create or recover the dataset alignment before going further
3397 // ///////////////////////////////
3398 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3400 // older jalview projects do not have a dataset - so creat alignment and
3402 al = new Alignment(orderedSeqs);
3403 al.setDataset(null);
3407 boolean isdsal = jalviewModel.getViewport().isEmpty();
3410 // we are importing a dataset record, so
3411 // recover reference to an alignment already materialsed as dataset
3412 al = getDatasetFor(vamsasSet.getDatasetId());
3416 // materialse the alignment
3417 al = new Alignment(orderedSeqs);
3421 addDatasetRef(vamsasSet.getDatasetId(), al);
3424 // finally, verify all data in vamsasSet is actually present in al
3425 // passing on flag indicating if it is actually a stored dataset
3426 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3429 if (referenceseqForView != null)
3431 al.setSeqrep(referenceseqForView);
3433 // / Add the alignment properties
3434 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3436 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3438 al.setProperty(ssp.getKey(), ssp.getValue());
3441 // ///////////////////////////////
3443 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3446 // load sequence features, database references and any associated PDB
3447 // structures for the alignment
3449 // prior to 2.10, this part would only be executed the first time a
3450 // sequence was encountered, but not afterwards.
3451 // now, for 2.10 projects, this is also done if the xml doc includes
3452 // dataset sequences not actually present in any particular view.
3454 for (int i = 0; i < vamsasSeqs.size(); i++)
3456 JSeq jseq = jseqs.get(i);
3457 if (jseq.getFeatures().size() > 0)
3459 List<Feature> features = jseq.getFeatures();
3460 for (int f = 0; f < features.size(); f++)
3462 Feature feat = features.get(f);
3463 SequenceFeature sf = new SequenceFeature(feat.getType(),
3464 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3465 safeFloat(feat.getScore()), feat.getFeatureGroup());
3466 sf.setStatus(feat.getStatus());
3469 * load any feature attributes - include map-valued attributes
3471 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3472 for (int od = 0; od < feat.getOtherData().size(); od++)
3474 OtherData keyValue = feat.getOtherData().get(od);
3475 String attributeName = keyValue.getKey();
3476 String attributeValue = keyValue.getValue();
3477 if (attributeName.startsWith("LINK"))
3479 sf.addLink(attributeValue);
3483 String subAttribute = keyValue.getKey2();
3484 if (subAttribute == null)
3486 // simple string-valued attribute
3487 sf.setValue(attributeName, attributeValue);
3491 // attribute 'key' has sub-attribute 'key2'
3492 if (!mapAttributes.containsKey(attributeName))
3494 mapAttributes.put(attributeName, new HashMap<>());
3496 mapAttributes.get(attributeName).put(subAttribute,
3501 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3504 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3507 // adds feature to datasequence's feature set (since Jalview 2.10)
3508 al.getSequenceAt(i).addSequenceFeature(sf);
3511 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3513 // adds dbrefs to datasequence's set (since Jalview 2.10)
3515 al.getSequenceAt(i).getDatasetSequence() == null
3516 ? al.getSequenceAt(i)
3517 : al.getSequenceAt(i).getDatasetSequence(),
3520 if (jseq.getPdbids().size() > 0)
3522 List<Pdbids> ids = jseq.getPdbids();
3523 for (int p = 0; p < ids.size(); p++)
3525 Pdbids pdbid = ids.get(p);
3526 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3527 entry.setId(pdbid.getId());
3528 if (pdbid.getType() != null)
3530 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3532 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3536 entry.setType(PDBEntry.Type.FILE);
3539 // jprovider is null when executing 'New View'
3540 if (pdbid.getFile() != null && jprovider != null)
3542 if (!pdbloaded.containsKey(pdbid.getFile()))
3544 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3549 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3553 if (pdbid.getPdbentryItem() != null)
3555 for (PdbentryItem item : pdbid.getPdbentryItem())
3557 for (Property pr : item.getProperty())
3559 entry.setProperty(pr.getName(), pr.getValue());
3564 for (Property prop : pdbid.getProperty())
3566 entry.setProperty(prop.getName(), prop.getValue());
3568 StructureSelectionManager
3569 .getStructureSelectionManager(Desktop.instance)
3570 .registerPDBEntry(entry);
3571 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3572 if (al.getSequenceAt(i).getDatasetSequence() != null)
3574 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3578 al.getSequenceAt(i).addPDBId(entry);
3583 } // end !multipleview
3585 // ///////////////////////////////
3586 // LOAD SEQUENCE MAPPINGS
3588 if (vamsasSet.getAlcodonFrame().size() > 0)
3590 // TODO Potentially this should only be done once for all views of an
3592 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3593 for (int i = 0; i < alc.size(); i++)
3595 AlignedCodonFrame cf = new AlignedCodonFrame();
3596 if (alc.get(i).getAlcodMap().size() > 0)
3598 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3599 for (int m = 0; m < maps.size(); m++)
3601 AlcodMap map = maps.get(m);
3602 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3604 jalview.datamodel.Mapping mapping = null;
3605 // attach to dna sequence reference.
3606 if (map.getMapping() != null)
3608 mapping = addMapping(map.getMapping());
3609 if (dnaseq != null && mapping.getTo() != null)
3611 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3617 newAlcodMapRef(map.getDnasq(), cf, mapping));
3621 al.addCodonFrame(cf);
3626 // ////////////////////////////////
3628 List<JvAnnotRow> autoAlan = new ArrayList<>();
3631 * store any annotations which forward reference a group's ID
3633 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3635 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3637 List<Annotation> an = vamsasSet.getAnnotation();
3639 for (int i = 0; i < an.size(); i++)
3641 Annotation annotation = an.get(i);
3644 * test if annotation is automatically calculated for this view only
3646 boolean autoForView = false;
3647 if (annotation.getLabel().equals("Quality")
3648 || annotation.getLabel().equals("Conservation")
3649 || annotation.getLabel().equals("Consensus"))
3651 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3653 // JAXB has no has() test; schema defaults value to false
3654 // if (!annotation.hasAutoCalculated())
3656 // annotation.setAutoCalculated(true);
3659 if (autoForView || annotation.isAutoCalculated())
3661 // remove ID - we don't recover annotation from other views for
3662 // view-specific annotation
3663 annotation.setId(null);
3666 // set visibility for other annotation in this view
3667 String annotationId = annotation.getId();
3668 if (annotationId != null && annotationIds.containsKey(annotationId))
3670 AlignmentAnnotation jda = annotationIds.get(annotationId);
3671 // in principle Visible should always be true for annotation displayed
3672 // in multiple views
3673 if (annotation.isVisible() != null)
3675 jda.visible = annotation.isVisible();
3678 al.addAnnotation(jda);
3682 // Construct new annotation from model.
3683 List<AnnotationElement> ae = annotation.getAnnotationElement();
3684 jalview.datamodel.Annotation[] anot = null;
3685 java.awt.Color firstColour = null;
3687 if (!annotation.isScoreOnly())
3689 anot = new jalview.datamodel.Annotation[al.getWidth()];
3690 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3692 AnnotationElement annElement = ae.get(aa);
3693 anpos = annElement.getPosition();
3695 if (anpos >= anot.length)
3700 float value = safeFloat(annElement.getValue());
3701 anot[anpos] = new jalview.datamodel.Annotation(
3702 annElement.getDisplayCharacter(),
3703 annElement.getDescription(),
3704 (annElement.getSecondaryStructure() == null
3705 || annElement.getSecondaryStructure()
3709 .getSecondaryStructure()
3712 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3713 if (firstColour == null)
3715 firstColour = anot[anpos].colour;
3719 jalview.datamodel.AlignmentAnnotation jaa = null;
3721 if (annotation.isGraph())
3723 float llim = 0, hlim = 0;
3724 // if (autoForView || an[i].isAutoCalculated()) {
3727 jaa = new jalview.datamodel.AlignmentAnnotation(
3728 annotation.getLabel(), annotation.getDescription(), anot,
3729 llim, hlim, safeInt(annotation.getGraphType()));
3731 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3732 jaa._linecolour = firstColour;
3733 if (annotation.getThresholdLine() != null)
3735 jaa.setThreshold(new jalview.datamodel.GraphLine(
3736 safeFloat(annotation.getThresholdLine().getValue()),
3737 annotation.getThresholdLine().getLabel(),
3738 new java.awt.Color(safeInt(
3739 annotation.getThresholdLine().getColour()))));
3741 if (autoForView || annotation.isAutoCalculated())
3743 // Hardwire the symbol display line to ensure that labels for
3744 // histograms are displayed
3750 jaa = new jalview.datamodel.AlignmentAnnotation(
3751 annotation.getLabel(), annotation.getDescription(), anot);
3752 jaa._linecolour = firstColour;
3754 // register new annotation
3755 if (annotation.getId() != null)
3757 annotationIds.put(annotation.getId(), jaa);
3758 jaa.annotationId = annotation.getId();
3760 // recover sequence association
3761 String sequenceRef = annotation.getSequenceRef();
3762 if (sequenceRef != null)
3764 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3765 SequenceI sequence = seqRefIds.get(sequenceRef);
3766 if (sequence == null)
3768 // in pre-2.9 projects sequence ref is to sequence name
3769 sequence = al.findName(sequenceRef);
3771 if (sequence != null)
3773 jaa.createSequenceMapping(sequence, 1, true);
3774 sequence.addAlignmentAnnotation(jaa);
3777 // and make a note of any group association
3778 if (annotation.getGroupRef() != null
3779 && annotation.getGroupRef().length() > 0)
3781 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3782 .get(annotation.getGroupRef());
3785 aal = new ArrayList<>();
3786 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3791 if (annotation.getScore() != null)
3793 jaa.setScore(annotation.getScore().doubleValue());
3795 if (annotation.isVisible() != null)
3797 jaa.visible = annotation.isVisible().booleanValue();
3800 if (annotation.isCentreColLabels() != null)
3802 jaa.centreColLabels = annotation.isCentreColLabels()
3806 if (annotation.isScaleColLabels() != null)
3808 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3810 if (annotation.isAutoCalculated())
3812 // newer files have an 'autoCalculated' flag and store calculation
3813 // state in viewport properties
3814 jaa.autoCalculated = true; // means annotation will be marked for
3815 // update at end of load.
3817 if (annotation.getGraphHeight() != null)
3819 jaa.graphHeight = annotation.getGraphHeight().intValue();
3821 jaa.belowAlignment = annotation.isBelowAlignment();
3822 jaa.setCalcId(annotation.getCalcId());
3823 if (annotation.getProperty().size() > 0)
3825 for (Annotation.Property prop : annotation
3828 jaa.setProperty(prop.getName(), prop.getValue());
3831 if (jaa.autoCalculated)
3833 autoAlan.add(new JvAnnotRow(i, jaa));
3836 // if (!autoForView)
3838 // add autocalculated group annotation and any user created annotation
3840 al.addAnnotation(jaa);
3844 // ///////////////////////
3846 // Create alignment markup and styles for this view
3847 if (jalviewModel.getJGroup().size() > 0)
3849 List<JGroup> groups = jalviewModel.getJGroup();
3850 boolean addAnnotSchemeGroup = false;
3851 for (int i = 0; i < groups.size(); i++)
3853 JGroup jGroup = groups.get(i);
3854 ColourSchemeI cs = null;
3855 if (jGroup.getColour() != null)
3857 if (jGroup.getColour().startsWith("ucs"))
3859 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3861 else if (jGroup.getColour().equals("AnnotationColourGradient")
3862 && jGroup.getAnnotationColours() != null)
3864 addAnnotSchemeGroup = true;
3868 cs = ColourSchemeProperty.getColourScheme(al,
3869 jGroup.getColour());
3872 int pidThreshold = safeInt(jGroup.getPidThreshold());
3874 Vector<SequenceI> seqs = new Vector<>();
3876 for (int s = 0; s < jGroup.getSeq().size(); s++)
3878 String seqId = jGroup.getSeq().get(s);
3879 SequenceI ts = seqRefIds.get(seqId);
3883 seqs.addElement(ts);
3887 if (seqs.size() < 1)
3892 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3893 safeBoolean(jGroup.isDisplayBoxes()),
3894 safeBoolean(jGroup.isDisplayText()),
3895 safeBoolean(jGroup.isColourText()),
3896 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3897 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3898 sg.getGroupColourScheme()
3899 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3900 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3902 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3903 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3904 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3905 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3906 // attributes with a default in the schema are never null
3907 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3908 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3909 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3910 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3911 if (jGroup.getConsThreshold() != null
3912 && jGroup.getConsThreshold().intValue() != 0)
3914 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3917 c.verdict(false, 25);
3918 sg.cs.setConservation(c);
3921 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3923 // re-instate unique group/annotation row reference
3924 List<AlignmentAnnotation> jaal = groupAnnotRefs
3925 .get(jGroup.getId());
3928 for (AlignmentAnnotation jaa : jaal)
3931 if (jaa.autoCalculated)
3933 // match up and try to set group autocalc alignment row for this
3935 if (jaa.label.startsWith("Consensus for "))
3937 sg.setConsensus(jaa);
3939 // match up and try to set group autocalc alignment row for this
3941 if (jaa.label.startsWith("Conservation for "))
3943 sg.setConservationRow(jaa);
3950 if (addAnnotSchemeGroup)
3952 // reconstruct the annotation colourscheme
3953 sg.setColourScheme(constructAnnotationColour(
3954 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3960 // only dataset in this model, so just return.
3963 // ///////////////////////////////
3966 AlignFrame af = null;
3967 AlignViewport av = null;
3968 // now check to see if we really need to create a new viewport.
3969 if (multipleView && viewportsAdded.size() == 0)
3971 // We recovered an alignment for which a viewport already exists.
3972 // TODO: fix up any settings necessary for overlaying stored state onto
3973 // state recovered from another document. (may not be necessary).
3974 // we may need a binding from a viewport in memory to one recovered from
3976 // and then recover its containing af to allow the settings to be applied.
3977 // TODO: fix for vamsas demo
3979 "About to recover a viewport for existing alignment: Sequence set ID is "
3981 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3982 if (seqsetobj != null)
3984 if (seqsetobj instanceof String)
3986 uniqueSeqSetId = (String) seqsetobj;
3988 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3994 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4000 * indicate that annotation colours are applied across all groups (pre
4001 * Jalview 2.8.1 behaviour)
4003 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4004 jalviewModel.getVersion());
4006 AlignmentPanel ap = null;
4007 boolean isnewview = true;
4010 // Check to see if this alignment already has a view id == viewId
4011 jalview.gui.AlignmentPanel views[] = Desktop
4012 .getAlignmentPanels(uniqueSeqSetId);
4013 if (views != null && views.length > 0)
4015 for (int v = 0; v < views.length; v++)
4017 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4019 // recover the existing alignpanel, alignframe, viewport
4020 af = views[v].alignFrame;
4023 // TODO: could even skip resetting view settings if we don't want to
4024 // change the local settings from other jalview processes
4033 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4034 uniqueSeqSetId, viewId, autoAlan);
4035 av = af.getViewport();
4040 * Load any trees, PDB structures and viewers
4042 * Not done if flag is false (when this method is used for New View)
4044 if (loadTreesAndStructures)
4046 loadTrees(jalviewModel, view, af, av, ap);
4047 loadPCAViewers(jalviewModel, ap);
4048 loadPDBStructures(jprovider, jseqs, af, ap);
4049 loadRnaViewers(jprovider, jseqs, ap);
4051 // and finally return.
4056 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4057 * panel is restored from separate jar entries, two (gapped and trimmed) per
4058 * sequence and secondary structure.
4060 * Currently each viewer shows just one sequence and structure (gapped and
4061 * trimmed), however this method is designed to support multiple sequences or
4062 * structures in viewers if wanted in future.
4068 private void loadRnaViewers(jarInputStreamProvider jprovider,
4069 List<JSeq> jseqs, AlignmentPanel ap)
4072 * scan the sequences for references to viewers; create each one the first
4073 * time it is referenced, add Rna models to existing viewers
4075 for (JSeq jseq : jseqs)
4077 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4079 RnaViewer viewer = jseq.getRnaViewer().get(i);
4080 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4083 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4085 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4086 SequenceI seq = seqRefIds.get(jseq.getId());
4087 AlignmentAnnotation ann = this.annotationIds
4088 .get(ss.getAnnotationId());
4091 * add the structure to the Varna display (with session state copied
4092 * from the jar to a temporary file)
4094 boolean gapped = safeBoolean(ss.isGapped());
4095 String rnaTitle = ss.getTitle();
4096 String sessionState = ss.getViewerState();
4097 String tempStateFile = copyJarEntry(jprovider, sessionState,
4099 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4100 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4102 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4108 * Locate and return an already instantiated matching AppVarna, or create one
4112 * @param viewIdSuffix
4116 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4117 String viewIdSuffix, AlignmentPanel ap)
4120 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4121 * if load is repeated
4123 String postLoadId = viewer.getViewId() + viewIdSuffix;
4124 for (JInternalFrame frame : getAllFrames())
4126 if (frame instanceof AppVarna)
4128 AppVarna varna = (AppVarna) frame;
4129 if (postLoadId.equals(varna.getViewId()))
4131 // this viewer is already instantiated
4132 // could in future here add ap as another 'parent' of the
4133 // AppVarna window; currently just 1-to-many
4140 * viewer not found - make it
4142 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4143 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4144 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4145 safeInt(viewer.getDividerLocation()));
4146 AppVarna varna = new AppVarna(model, ap);
4152 * Load any saved trees
4160 protected void loadTrees(JalviewModel jm, Viewport view,
4161 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4163 // TODO result of automated refactoring - are all these parameters needed?
4166 for (int t = 0; t < jm.getTree().size(); t++)
4169 Tree tree = jm.getTree().get(t);
4171 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4174 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4175 tree.getTitle(), safeInt(tree.getWidth()),
4176 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4177 safeInt(tree.getYpos()));
4178 if (tree.getId() != null)
4180 // perhaps bind the tree id to something ?
4185 // update local tree attributes ?
4186 // TODO: should check if tp has been manipulated by user - if so its
4187 // settings shouldn't be modified
4188 tp.setTitle(tree.getTitle());
4189 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4190 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4191 safeInt(tree.getHeight())));
4192 tp.setViewport(av); // af.viewport;
4193 // TODO: verify 'associate with all views' works still
4194 tp.getTreeCanvas().setViewport(av); // af.viewport;
4195 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4196 // FIXME: should we use safeBoolean here ?
4197 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4202 warn("There was a problem recovering stored Newick tree: \n"
4203 + tree.getNewick());
4207 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4208 tp.fitToWindow_actionPerformed(null);
4210 if (tree.getFontName() != null)
4213 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4214 safeInt(tree.getFontSize())));
4219 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4220 safeInt(view.getFontSize())));
4223 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4224 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4225 tp.showDistances(safeBoolean(tree.isShowDistances()));
4227 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4229 if (safeBoolean(tree.isCurrentTree()))
4231 af.getViewport().setCurrentTree(tp.getTree());
4235 } catch (Exception ex)
4237 ex.printStackTrace();
4242 * Load and link any saved structure viewers.
4249 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4250 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4253 * Run through all PDB ids on the alignment, and collect mappings between
4254 * distinct view ids and all sequences referring to that view.
4256 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4258 for (int i = 0; i < jseqs.size(); i++)
4260 JSeq jseq = jseqs.get(i);
4261 if (jseq.getPdbids().size() > 0)
4263 List<Pdbids> ids = jseq.getPdbids();
4264 for (int p = 0; p < ids.size(); p++)
4266 Pdbids pdbid = ids.get(p);
4267 final int structureStateCount = pdbid.getStructureState().size();
4268 for (int s = 0; s < structureStateCount; s++)
4270 // check to see if we haven't already created this structure view
4271 final StructureState structureState = pdbid
4272 .getStructureState().get(s);
4273 String sviewid = (structureState.getViewId() == null) ? null
4274 : structureState.getViewId() + uniqueSetSuffix;
4275 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4276 // Originally : pdbid.getFile()
4277 // : TODO: verify external PDB file recovery still works in normal
4278 // jalview project load
4280 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4281 jpdb.setId(pdbid.getId());
4283 int x = safeInt(structureState.getXpos());
4284 int y = safeInt(structureState.getYpos());
4285 int width = safeInt(structureState.getWidth());
4286 int height = safeInt(structureState.getHeight());
4288 // Probably don't need to do this anymore...
4289 // Desktop.desktop.getComponentAt(x, y);
4290 // TODO: NOW: check that this recovers the PDB file correctly.
4291 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4293 jalview.datamodel.SequenceI seq = seqRefIds
4294 .get(jseq.getId() + "");
4295 if (sviewid == null)
4297 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4300 if (!structureViewers.containsKey(sviewid))
4302 structureViewers.put(sviewid,
4303 new StructureViewerModel(x, y, width, height, false,
4304 false, true, structureState.getViewId(),
4305 structureState.getType()));
4306 // Legacy pre-2.7 conversion JAL-823 :
4307 // do not assume any view has to be linked for colour by
4311 // assemble String[] { pdb files }, String[] { id for each
4312 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4313 // seqs_file 2}, boolean[] {
4314 // linkAlignPanel,superposeWithAlignpanel}} from hash
4315 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4316 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4317 || structureState.isAlignwithAlignPanel());
4320 * Default colour by linked panel to false if not specified (e.g.
4321 * for pre-2.7 projects)
4323 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4324 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4325 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4328 * Default colour by viewer to true if not specified (e.g. for
4331 boolean colourByViewer = jmoldat.isColourByViewer();
4332 colourByViewer &= structureState.isColourByJmol();
4333 jmoldat.setColourByViewer(colourByViewer);
4335 if (jmoldat.getStateData().length() < structureState
4336 .getValue()/*Content()*/.length())
4338 jmoldat.setStateData(structureState.getValue());// Content());
4340 if (pdbid.getFile() != null)
4342 File mapkey = new File(pdbid.getFile());
4343 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4344 if (seqstrmaps == null)
4346 jmoldat.getFileData().put(mapkey,
4347 seqstrmaps = jmoldat.new StructureData(pdbFile,
4350 if (!seqstrmaps.getSeqList().contains(seq))
4352 seqstrmaps.getSeqList().add(seq);
4358 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");
4365 // Instantiate the associated structure views
4366 for (Entry<String, StructureViewerModel> entry : structureViewers
4371 createOrLinkStructureViewer(entry, af, ap, jprovider);
4372 } catch (Exception e)
4375 "Error loading structure viewer: " + e.getMessage());
4376 // failed - try the next one
4388 protected void createOrLinkStructureViewer(
4389 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4390 AlignmentPanel ap, jarInputStreamProvider jprovider)
4392 final StructureViewerModel stateData = viewerData.getValue();
4395 * Search for any viewer windows already open from other alignment views
4396 * that exactly match the stored structure state
4398 StructureViewerBase comp = findMatchingViewer(viewerData);
4402 linkStructureViewer(ap, comp, stateData);
4407 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4408 * "viewer_"+stateData.viewId
4410 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4412 createChimeraViewer(viewerData, af, jprovider);
4417 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4419 createJmolViewer(viewerData, af, jprovider);
4424 * Create a new Chimera viewer.
4430 protected void createChimeraViewer(
4431 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4432 jarInputStreamProvider jprovider)
4434 StructureViewerModel data = viewerData.getValue();
4435 String chimeraSessionFile = data.getStateData();
4438 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4440 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4441 * 'uniquified' sviewid used to reconstruct the viewer here
4443 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4444 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4447 Set<Entry<File, StructureData>> fileData = data.getFileData()
4449 List<PDBEntry> pdbs = new ArrayList<>();
4450 List<SequenceI[]> allseqs = new ArrayList<>();
4451 for (Entry<File, StructureData> pdb : fileData)
4453 String filePath = pdb.getValue().getFilePath();
4454 String pdbId = pdb.getValue().getPdbId();
4455 // pdbs.add(new PDBEntry(filePath, pdbId));
4456 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4457 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4458 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4462 boolean colourByChimera = data.isColourByViewer();
4463 boolean colourBySequence = data.isColourWithAlignPanel();
4465 // TODO use StructureViewer as a factory here, see JAL-1761
4466 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4467 final SequenceI[][] seqsArray = allseqs
4468 .toArray(new SequenceI[allseqs.size()][]);
4469 String newViewId = viewerData.getKey();
4471 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4472 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4473 colourBySequence, newViewId);
4474 cvf.setSize(data.getWidth(), data.getHeight());
4475 cvf.setLocation(data.getX(), data.getY());
4479 * Create a new Jmol window. First parse the Jmol state to translate filenames
4480 * loaded into the view, and record the order in which files are shown in the
4481 * Jmol view, so we can add the sequence mappings in same order.
4487 protected void createJmolViewer(
4488 final Entry<String, StructureViewerModel> viewerData,
4489 AlignFrame af, jarInputStreamProvider jprovider)
4491 final StructureViewerModel svattrib = viewerData.getValue();
4492 String state = svattrib.getStateData();
4495 * Pre-2.9: state element value is the Jmol state string
4497 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4500 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4502 state = readJarEntry(jprovider,
4503 getViewerJarEntryName(svattrib.getViewId()));
4506 List<String> pdbfilenames = new ArrayList<>();
4507 List<SequenceI[]> seqmaps = new ArrayList<>();
4508 List<String> pdbids = new ArrayList<>();
4509 StringBuilder newFileLoc = new StringBuilder(64);
4510 int cp = 0, ncp, ecp;
4511 Map<File, StructureData> oldFiles = svattrib.getFileData();
4512 while ((ncp = state.indexOf("load ", cp)) > -1)
4516 // look for next filename in load statement
4517 newFileLoc.append(state.substring(cp,
4518 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4519 String oldfilenam = state.substring(ncp,
4520 ecp = state.indexOf("\"", ncp));
4521 // recover the new mapping data for this old filename
4522 // have to normalize filename - since Jmol and jalview do
4524 // translation differently.
4525 StructureData filedat = oldFiles.get(new File(oldfilenam));
4526 if (filedat == null)
4528 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4529 filedat = oldFiles.get(new File(reformatedOldFilename));
4531 newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
4532 pdbfilenames.add(filedat.getFilePath());
4533 pdbids.add(filedat.getPdbId());
4534 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4535 newFileLoc.append("\"");
4536 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4537 // look for next file statement.
4538 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4542 // just append rest of state
4543 newFileLoc.append(state.substring(cp));
4547 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4548 newFileLoc = new StringBuilder(state);
4549 newFileLoc.append("; load append ");
4550 for (File id : oldFiles.keySet())
4552 // add this and any other pdb files that should be present in
4554 StructureData filedat = oldFiles.get(id);
4555 newFileLoc.append(filedat.getFilePath());
4556 pdbfilenames.add(filedat.getFilePath());
4557 pdbids.add(filedat.getPdbId());
4558 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4559 newFileLoc.append(" \"");
4560 newFileLoc.append(filedat.getFilePath());
4561 newFileLoc.append("\"");
4564 newFileLoc.append(";");
4567 if (newFileLoc.length() == 0)
4571 int histbug = newFileLoc.indexOf("history = ");
4575 * change "history = [true|false];" to "history = [1|0];"
4578 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4579 String val = (diff == -1) ? null
4580 : newFileLoc.substring(histbug, diff);
4581 if (val != null && val.length() >= 4)
4583 if (val.contains("e")) // eh? what can it be?
4585 if (val.trim().equals("true"))
4593 newFileLoc.replace(histbug, diff, val);
4598 final String[] pdbf = pdbfilenames
4599 .toArray(new String[pdbfilenames.size()]);
4600 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4601 final SequenceI[][] sq = seqmaps
4602 .toArray(new SequenceI[seqmaps.size()][]);
4603 final String fileloc = newFileLoc.toString();
4604 final String sviewid = viewerData.getKey();
4605 final AlignFrame alf = af;
4606 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4607 svattrib.getWidth(), svattrib.getHeight());
4610 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4615 JalviewStructureDisplayI sview = null;
4618 sview = new StructureViewer(
4619 alf.alignPanel.getStructureSelectionManager())
4620 .createView(StructureViewer.ViewerType.JMOL,
4621 pdbf, id, sq, alf.alignPanel, svattrib,
4622 fileloc, rect, sviewid);
4623 addNewStructureViewer(sview);
4624 } catch (OutOfMemoryError ex)
4626 new OOMWarning("restoring structure view for PDB id " + id,
4627 (OutOfMemoryError) ex.getCause());
4628 if (sview != null && sview.isVisible())
4630 sview.closeViewer(false);
4631 sview.setVisible(false);
4637 } catch (InvocationTargetException ex)
4639 warn("Unexpected error when opening Jmol view.", ex);
4641 } catch (InterruptedException e)
4643 // e.printStackTrace();
4649 * Generates a name for the entry in the project jar file to hold state
4650 * information for a structure viewer
4655 protected String getViewerJarEntryName(String viewId)
4657 return VIEWER_PREFIX + viewId;
4661 * Returns any open frame that matches given structure viewer data. The match
4662 * is based on the unique viewId, or (for older project versions) the frame's
4668 protected StructureViewerBase findMatchingViewer(
4669 Entry<String, StructureViewerModel> viewerData)
4671 final String sviewid = viewerData.getKey();
4672 final StructureViewerModel svattrib = viewerData.getValue();
4673 StructureViewerBase comp = null;
4674 JInternalFrame[] frames = getAllFrames();
4675 for (JInternalFrame frame : frames)
4677 if (frame instanceof StructureViewerBase)
4680 * Post jalview 2.4 schema includes structure view id
4682 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4685 comp = (StructureViewerBase) frame;
4686 break; // break added in 2.9
4689 * Otherwise test for matching position and size of viewer frame
4691 else if (frame.getX() == svattrib.getX()
4692 && frame.getY() == svattrib.getY()
4693 && frame.getHeight() == svattrib.getHeight()
4694 && frame.getWidth() == svattrib.getWidth())
4696 comp = (StructureViewerBase) frame;
4697 // no break in faint hope of an exact match on viewId
4705 * Link an AlignmentPanel to an existing structure viewer.
4710 * @param useinViewerSuperpos
4711 * @param usetoColourbyseq
4712 * @param viewerColouring
4714 protected void linkStructureViewer(AlignmentPanel ap,
4715 StructureViewerBase viewer, StructureViewerModel stateData)
4717 // NOTE: if the jalview project is part of a shared session then
4718 // view synchronization should/could be done here.
4720 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4721 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4722 final boolean viewerColouring = stateData.isColourByViewer();
4723 Map<File, StructureData> oldFiles = stateData.getFileData();
4726 * Add mapping for sequences in this view to an already open viewer
4728 final AAStructureBindingModel binding = viewer.getBinding();
4729 for (File id : oldFiles.keySet())
4731 // add this and any other pdb files that should be present in the
4733 StructureData filedat = oldFiles.get(id);
4734 String pdbFile = filedat.getFilePath();
4735 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4736 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4738 binding.addSequenceForStructFile(pdbFile, seq);
4740 // and add the AlignmentPanel's reference to the view panel
4741 viewer.addAlignmentPanel(ap);
4742 if (useinViewerSuperpos)
4744 viewer.useAlignmentPanelForSuperposition(ap);
4748 viewer.excludeAlignmentPanelForSuperposition(ap);
4750 if (usetoColourbyseq)
4752 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4756 viewer.excludeAlignmentPanelForColourbyseq(ap);
4761 * Get all frames within the Desktop.
4765 protected JInternalFrame[] getAllFrames()
4767 JInternalFrame[] frames = null;
4768 // TODO is this necessary - is it safe - risk of hanging?
4773 frames = Desktop.desktop.getAllFrames();
4774 } catch (ArrayIndexOutOfBoundsException e)
4776 // occasional No such child exceptions are thrown here...
4780 } catch (InterruptedException f)
4784 } while (frames == null);
4789 * Answers true if 'version' is equal to or later than 'supported', where each
4790 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4791 * changes. Development and test values for 'version' are leniently treated
4795 * - minimum version we are comparing against
4797 * - version of data being processsed
4800 public static boolean isVersionStringLaterThan(String supported,
4803 if (supported == null || version == null
4804 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4805 || version.equalsIgnoreCase("Test")
4806 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4808 System.err.println("Assuming project file with "
4809 + (version == null ? "null" : version)
4810 + " is compatible with Jalview version " + supported);
4815 return StringUtils.compareVersions(version, supported, "b") >= 0;
4819 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4821 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4823 if (newStructureViewers != null)
4825 sview.getBinding().setFinishedLoadingFromArchive(false);
4826 newStructureViewers.add(sview);
4830 protected void setLoadingFinishedForNewStructureViewers()
4832 if (newStructureViewers != null)
4834 for (JalviewStructureDisplayI sview : newStructureViewers)
4836 sview.getBinding().setFinishedLoadingFromArchive(true);
4838 newStructureViewers.clear();
4839 newStructureViewers = null;
4843 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4844 List<SequenceI> hiddenSeqs, AlignmentI al,
4845 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4846 String viewId, List<JvAnnotRow> autoAlan)
4848 AlignFrame af = null;
4849 af = new AlignFrame(al, safeInt(view.getWidth()),
4850 safeInt(view.getHeight()), uniqueSeqSetId, viewId);
4852 af.setFileName(file, FileFormat.Jalview);
4854 final AlignViewport viewport = af.getViewport();
4855 for (int i = 0; i < JSEQ.size(); i++)
4857 int colour = safeInt(JSEQ.get(i).getColour());
4858 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4864 viewport.setColourByReferenceSeq(true);
4865 viewport.setDisplayReferenceSeq(true);
4868 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4870 if (view.getSequenceSetId() != null)
4872 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4874 viewport.setSequenceSetId(uniqueSeqSetId);
4877 // propagate shared settings to this new view
4878 viewport.setHistoryList(av.getHistoryList());
4879 viewport.setRedoList(av.getRedoList());
4883 viewportsAdded.put(uniqueSeqSetId, viewport);
4885 // TODO: check if this method can be called repeatedly without
4886 // side-effects if alignpanel already registered.
4887 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4889 // apply Hidden regions to view.
4890 if (hiddenSeqs != null)
4892 for (int s = 0; s < JSEQ.size(); s++)
4894 SequenceGroup hidden = new SequenceGroup();
4895 boolean isRepresentative = false;
4896 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4898 isRepresentative = true;
4899 SequenceI sequenceToHide = al
4900 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4901 hidden.addSequence(sequenceToHide, false);
4902 // remove from hiddenSeqs list so we don't try to hide it twice
4903 hiddenSeqs.remove(sequenceToHide);
4905 if (isRepresentative)
4907 SequenceI representativeSequence = al.getSequenceAt(s);
4908 hidden.addSequence(representativeSequence, false);
4909 viewport.hideRepSequences(representativeSequence, hidden);
4913 SequenceI[] hseqs = hiddenSeqs
4914 .toArray(new SequenceI[hiddenSeqs.size()]);
4915 viewport.hideSequence(hseqs);
4918 // recover view properties and display parameters
4920 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4921 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4922 final int pidThreshold = safeInt(view.getPidThreshold());
4923 viewport.setThreshold(pidThreshold);
4925 viewport.setColourText(safeBoolean(view.isShowColourText()));
4928 .setConservationSelected(
4929 safeBoolean(view.isConservationSelected()));
4930 viewport.setIncrement(safeInt(view.getConsThreshold()));
4931 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4932 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4933 viewport.setFont(new Font(view.getFontName(),
4934 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4936 ViewStyleI vs = viewport.getViewStyle();
4937 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4938 viewport.setViewStyle(vs);
4939 // TODO: allow custom charWidth/Heights to be restored by updating them
4940 // after setting font - which means set above to false
4941 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4942 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4943 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4945 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4947 viewport.setShowText(safeBoolean(view.isShowText()));
4949 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4950 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4951 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4952 viewport.setShowUnconserved(view.isShowUnconserved());
4953 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4955 if (view.getViewName() != null)
4957 viewport.setViewName(view.getViewName());
4958 af.setInitialTabVisible();
4960 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4961 safeInt(view.getWidth()), safeInt(view.getHeight()));
4962 // startSeq set in af.alignPanel.updateLayout below
4963 af.alignPanel.updateLayout();
4964 ColourSchemeI cs = null;
4965 // apply colourschemes
4966 if (view.getBgColour() != null)
4968 if (view.getBgColour().startsWith("ucs"))
4970 cs = getUserColourScheme(jm, view.getBgColour());
4972 else if (view.getBgColour().startsWith("Annotation"))
4974 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4975 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4982 cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
4986 viewport.setGlobalColourScheme(cs);
4987 viewport.getResidueShading().setThreshold(pidThreshold,
4988 view.isIgnoreGapsinConsensus());
4989 viewport.getResidueShading()
4990 .setConsensus(viewport.getSequenceConsensusHash());
4991 viewport.setColourAppliesToAllGroups(false);
4993 if (safeBoolean(view.isConservationSelected()) && cs != null)
4995 viewport.getResidueShading()
4996 .setConservationInc(safeInt(view.getConsThreshold()));
4999 af.changeColour(cs);
5001 viewport.setColourAppliesToAllGroups(true);
5004 .setShowSequenceFeatures(
5005 safeBoolean(view.isShowSequenceFeatures()));
5007 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5008 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5009 viewport.setFollowHighlight(view.isFollowHighlight());
5010 viewport.followSelection = view.isFollowSelection();
5011 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5012 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5013 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5014 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5015 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5016 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5017 viewport.setShowGroupConservation(view.isShowGroupConservation());
5019 // recover feature settings
5020 if (jm.getFeatureSettings() != null)
5022 FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
5023 .getFeatureRenderer();
5024 FeaturesDisplayed fdi;
5025 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5026 String[] renderOrder = new String[jm.getFeatureSettings()
5027 .getSetting().size()];
5028 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5029 Map<String, Float> featureOrder = new Hashtable<>();
5031 for (int fs = 0; fs < jm.getFeatureSettings()
5032 .getSetting().size(); fs++)
5034 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5035 String featureType = setting.getType();
5038 * restore feature filters (if any)
5040 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5042 if (filters != null)
5044 FeatureMatcherSetI filter = Jalview2XML
5045 .parseFilter(featureType, filters);
5046 if (!filter.isEmpty())
5048 fr.setFeatureFilter(featureType, filter);
5053 * restore feature colour scheme
5055 Color maxColour = new Color(setting.getColour());
5056 if (setting.getMincolour() != null)
5059 * minColour is always set unless a simple colour
5060 * (including for colour by label though it doesn't use it)
5062 Color minColour = new Color(setting.getMincolour().intValue());
5063 Color noValueColour = minColour;
5064 NoValueColour noColour = setting.getNoValueColour();
5065 if (noColour == NoValueColour.NONE)
5067 noValueColour = null;
5069 else if (noColour == NoValueColour.MAX)
5071 noValueColour = maxColour;
5073 float min = safeFloat(safeFloat(setting.getMin()));
5074 float max = setting.getMax() == null ? 1f
5075 : setting.getMax().floatValue();
5076 FeatureColourI gc = new FeatureColour(minColour, maxColour,
5077 noValueColour, min, max);
5078 if (setting.getAttributeName().size() > 0)
5080 gc.setAttributeName(setting.getAttributeName().toArray(
5081 new String[setting.getAttributeName().size()]));
5083 if (setting.getThreshold() != null)
5085 gc.setThreshold(setting.getThreshold().floatValue());
5086 int threshstate = safeInt(setting.getThreshstate());
5087 // -1 = None, 0 = Below, 1 = Above threshold
5088 if (threshstate == 0)
5090 gc.setBelowThreshold(true);
5092 else if (threshstate == 1)
5094 gc.setAboveThreshold(true);
5097 gc.setAutoScaled(true); // default
5098 if (setting.isAutoScale() != null)
5100 gc.setAutoScaled(setting.isAutoScale());
5102 if (setting.isColourByLabel() != null)
5104 gc.setColourByLabel(setting.isColourByLabel());
5106 // and put in the feature colour table.
5107 featureColours.put(featureType, gc);
5111 featureColours.put(featureType,
5112 new FeatureColour(maxColour));
5114 renderOrder[fs] = featureType;
5115 if (setting.getOrder() != null)
5117 featureOrder.put(featureType, setting.getOrder().floatValue());
5121 featureOrder.put(featureType, new Float(
5122 fs / jm.getFeatureSettings().getSetting().size()));
5124 if (safeBoolean(setting.isDisplay()))
5126 fdi.setVisible(featureType);
5129 Map<String, Boolean> fgtable = new Hashtable<>();
5130 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5132 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5133 fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
5135 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5136 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5137 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5138 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5139 fgtable, featureColours, 1.0f, featureOrder);
5140 fr.transferSettings(frs);
5143 if (view.getHiddenColumns().size() > 0)
5145 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5147 final HiddenColumns hc = view.getHiddenColumns().get(c);
5148 viewport.hideColumns(safeInt(hc.getStart()),
5149 safeInt(hc.getEnd()) /* +1 */);
5152 if (view.getCalcIdParam() != null)
5154 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5156 if (calcIdParam != null)
5158 if (recoverCalcIdParam(calcIdParam, viewport))
5163 warn("Couldn't recover parameters for "
5164 + calcIdParam.getCalcId());
5169 af.setMenusFromViewport(viewport);
5170 af.setTitle(view.getTitle());
5171 // TODO: we don't need to do this if the viewport is aready visible.
5173 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5174 * has a 'cdna/protein complement' view, in which case save it in order to
5175 * populate a SplitFrame once all views have been read in.
5177 String complementaryViewId = view.getComplementId();
5178 if (complementaryViewId == null)
5180 Desktop.addInternalFrame(af, view.getTitle(),
5181 safeInt(view.getWidth()), safeInt(view.getHeight()));
5182 // recompute any autoannotation
5183 af.alignPanel.updateAnnotation(false, true);
5184 reorderAutoannotation(af, al, autoAlan);
5185 af.alignPanel.alignmentChanged();
5189 splitFrameCandidates.put(view, af);
5195 * Reads saved data to restore Colour by Annotation settings
5197 * @param viewAnnColour
5201 * @param checkGroupAnnColour
5204 private ColourSchemeI constructAnnotationColour(
5205 AnnotationColourScheme viewAnnColour, AlignFrame af,
5206 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5208 boolean propagateAnnColour = false;
5209 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5211 if (checkGroupAnnColour && al.getGroups() != null
5212 && al.getGroups().size() > 0)
5214 // pre 2.8.1 behaviour
5215 // check to see if we should transfer annotation colours
5216 propagateAnnColour = true;
5217 for (SequenceGroup sg : al.getGroups())
5219 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5221 propagateAnnColour = false;
5227 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5229 String annotationId = viewAnnColour.getAnnotation();
5230 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5233 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5235 if (matchedAnnotation == null
5236 && annAlignment.getAlignmentAnnotation() != null)
5238 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5241 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5243 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5248 if (matchedAnnotation == null)
5250 System.err.println("Failed to match annotation colour scheme for "
5254 if (matchedAnnotation.getThreshold() == null)
5256 matchedAnnotation.setThreshold(
5257 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5258 "Threshold", Color.black));
5261 AnnotationColourGradient cs = null;
5262 if (viewAnnColour.getColourScheme().equals("None"))
5264 cs = new AnnotationColourGradient(matchedAnnotation,
5265 new Color(safeInt(viewAnnColour.getMinColour())),
5266 new Color(safeInt(viewAnnColour.getMaxColour())),
5267 safeInt(viewAnnColour.getAboveThreshold()));
5269 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5271 cs = new AnnotationColourGradient(matchedAnnotation,
5272 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5273 safeInt(viewAnnColour.getAboveThreshold()));
5277 cs = new AnnotationColourGradient(matchedAnnotation,
5278 ColourSchemeProperty.getColourScheme(al,
5279 viewAnnColour.getColourScheme()),
5280 safeInt(viewAnnColour.getAboveThreshold()));
5283 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5284 boolean useOriginalColours = safeBoolean(
5285 viewAnnColour.isPredefinedColours());
5286 cs.setSeqAssociated(perSequenceOnly);
5287 cs.setPredefinedColours(useOriginalColours);
5289 if (propagateAnnColour && al.getGroups() != null)
5291 // Also use these settings for all the groups
5292 for (int g = 0; g < al.getGroups().size(); g++)
5294 SequenceGroup sg = al.getGroups().get(g);
5295 if (sg.getGroupColourScheme() == null)
5300 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5301 matchedAnnotation, sg.getColourScheme(),
5302 safeInt(viewAnnColour.getAboveThreshold()));
5303 sg.setColourScheme(groupScheme);
5304 groupScheme.setSeqAssociated(perSequenceOnly);
5305 groupScheme.setPredefinedColours(useOriginalColours);
5311 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5312 List<JvAnnotRow> autoAlan)
5314 // copy over visualization settings for autocalculated annotation in the
5316 if (al.getAlignmentAnnotation() != null)
5319 * Kludge for magic autoannotation names (see JAL-811)
5321 String[] magicNames = new String[] { "Consensus", "Quality",
5323 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5324 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5325 for (String nm : magicNames)
5327 visan.put(nm, nullAnnot);
5329 for (JvAnnotRow auan : autoAlan)
5331 visan.put(auan.template.label
5332 + (auan.template.getCalcId() == null ? ""
5333 : "\t" + auan.template.getCalcId()),
5336 int hSize = al.getAlignmentAnnotation().length;
5337 List<JvAnnotRow> reorder = new ArrayList<>();
5338 // work through any autoCalculated annotation already on the view
5339 // removing it if it should be placed in a different location on the
5340 // annotation panel.
5341 List<String> remains = new ArrayList<>(visan.keySet());
5342 for (int h = 0; h < hSize; h++)
5344 jalview.datamodel.AlignmentAnnotation jalan = al
5345 .getAlignmentAnnotation()[h];
5346 if (jalan.autoCalculated)
5349 JvAnnotRow valan = visan.get(k = jalan.label);
5350 if (jalan.getCalcId() != null)
5352 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5357 // delete the auto calculated row from the alignment
5358 al.deleteAnnotation(jalan, false);
5362 if (valan != nullAnnot)
5364 if (jalan != valan.template)
5366 // newly created autoannotation row instance
5367 // so keep a reference to the visible annotation row
5368 // and copy over all relevant attributes
5369 if (valan.template.graphHeight >= 0)
5372 jalan.graphHeight = valan.template.graphHeight;
5374 jalan.visible = valan.template.visible;
5376 reorder.add(new JvAnnotRow(valan.order, jalan));
5381 // Add any (possibly stale) autocalculated rows that were not appended to
5382 // the view during construction
5383 for (String other : remains)
5385 JvAnnotRow othera = visan.get(other);
5386 if (othera != nullAnnot && othera.template.getCalcId() != null
5387 && othera.template.getCalcId().length() > 0)
5389 reorder.add(othera);
5392 // now put the automatic annotation in its correct place
5393 int s = 0, srt[] = new int[reorder.size()];
5394 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5395 for (JvAnnotRow jvar : reorder)
5398 srt[s++] = jvar.order;
5401 jalview.util.QuickSort.sort(srt, rws);
5402 // and re-insert the annotation at its correct position
5403 for (JvAnnotRow jvar : rws)
5405 al.addAnnotation(jvar.template, jvar.order);
5407 af.alignPanel.adjustAnnotationHeight();
5411 Hashtable skipList = null;
5414 * TODO remove this method
5417 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5418 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5419 * throw new Error("Implementation Error. No skipList defined for this
5420 * Jalview2XML instance."); } return (AlignFrame)
5421 * skipList.get(view.getSequenceSetId()); }
5425 * Check if the Jalview view contained in object should be skipped or not.
5428 * @return true if view's sequenceSetId is a key in skipList
5430 private boolean skipViewport(JalviewModel object)
5432 if (skipList == null)
5436 String id = object.getViewport().get(0).getSequenceSetId();
5437 if (skipList.containsKey(id))
5439 if (Cache.log != null && Cache.log.isDebugEnabled())
5441 Cache.log.debug("Skipping seuqence set id " + id);
5448 public void addToSkipList(AlignFrame af)
5450 if (skipList == null)
5452 skipList = new Hashtable();
5454 skipList.put(af.getViewport().getSequenceSetId(), af);
5457 public void clearSkipList()
5459 if (skipList != null)
5466 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5467 boolean ignoreUnrefed, String uniqueSeqSetId)
5469 jalview.datamodel.AlignmentI ds = getDatasetFor(
5470 vamsasSet.getDatasetId());
5471 AlignmentI xtant_ds = ds;
5472 if (xtant_ds == null)
5474 // good chance we are about to create a new dataset, but check if we've
5475 // seen some of the dataset sequence IDs before.
5476 // TODO: skip this check if we are working with project generated by
5477 // version 2.11 or later
5478 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5479 if (xtant_ds != null)
5482 addDatasetRef(vamsasSet.getDatasetId(), ds);
5485 Vector dseqs = null;
5488 // recovering an alignment View
5489 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5490 if (seqSetDS != null)
5492 if (ds != null && ds != seqSetDS)
5494 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5495 + " - CDS/Protein crossreference data may be lost");
5496 if (xtant_ds != null)
5498 // This can only happen if the unique sequence set ID was bound to a
5499 // dataset that did not contain any of the sequences in the view
5500 // currently being restored.
5501 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.");
5505 addDatasetRef(vamsasSet.getDatasetId(), ds);
5510 // try even harder to restore dataset
5511 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5512 // create a list of new dataset sequences
5513 dseqs = new Vector();
5515 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5517 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5518 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5520 // create a new dataset
5523 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5524 dseqs.copyInto(dsseqs);
5525 ds = new jalview.datamodel.Alignment(dsseqs);
5526 debug("Created new dataset " + vamsasSet.getDatasetId()
5527 + " for alignment " + System.identityHashCode(al));
5528 addDatasetRef(vamsasSet.getDatasetId(), ds);
5530 // set the dataset for the newly imported alignment.
5531 if (al.getDataset() == null && !ignoreUnrefed)
5534 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5535 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5537 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5541 * XML dataset sequence ID to materialised dataset reference
5543 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5546 * @return the first materialised dataset reference containing a dataset
5547 * sequence referenced in the given view
5549 * - sequences from the view
5551 AlignmentI checkIfHasDataset(List<Sequence> list)
5553 for (Sequence restoredSeq : list)
5555 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5556 if (datasetFor != null)
5565 * Register ds as the containing dataset for the dataset sequences referenced
5566 * by sequences in list
5569 * - sequences in a view
5572 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5574 for (Sequence restoredSeq : list)
5576 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5577 if (prevDS != null && prevDS != ds)
5579 warn("Dataset sequence appears in many datasets: "
5580 + restoredSeq.getDsseqid());
5581 // TODO: try to merge!
5588 * sequence definition to create/merge dataset sequence for
5592 * vector to add new dataset sequence to
5593 * @param ignoreUnrefed
5594 * - when true, don't create new sequences from vamsasSeq if it's id
5595 * doesn't already have an asssociated Jalview sequence.
5597 * - used to reorder the sequence in the alignment according to the
5598 * vamsasSeq array ordering, to preserve ordering of dataset
5600 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5601 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5603 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5605 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5606 boolean reorder = false;
5607 SequenceI dsq = null;
5608 if (sq != null && sq.getDatasetSequence() != null)
5610 dsq = sq.getDatasetSequence();
5616 if (sq == null && ignoreUnrefed)
5620 String sqid = vamsasSeq.getDsseqid();
5623 // need to create or add a new dataset sequence reference to this sequence
5626 dsq = seqRefIds.get(sqid);
5631 // make a new dataset sequence
5632 dsq = sq.createDatasetSequence();
5635 // make up a new dataset reference for this sequence
5636 sqid = seqHash(dsq);
5638 dsq.setVamsasId(uniqueSetSuffix + sqid);
5639 seqRefIds.put(sqid, dsq);
5644 dseqs.addElement(dsq);
5649 ds.addSequence(dsq);
5655 { // make this dataset sequence sq's dataset sequence
5656 sq.setDatasetSequence(dsq);
5657 // and update the current dataset alignment
5662 if (!dseqs.contains(dsq))
5669 if (ds.findIndex(dsq) < 0)
5671 ds.addSequence(dsq);
5678 // TODO: refactor this as a merge dataset sequence function
5679 // now check that sq (the dataset sequence) sequence really is the union of
5680 // all references to it
5681 // boolean pre = sq.getStart() < dsq.getStart();
5682 // boolean post = sq.getEnd() > dsq.getEnd();
5686 // StringBuffer sb = new StringBuffer();
5687 String newres = jalview.analysis.AlignSeq.extractGaps(
5688 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5689 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5690 && newres.length() > dsq.getLength())
5692 // Update with the longer sequence.
5696 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5697 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5698 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5699 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5701 dsq.setSequence(newres);
5703 // TODO: merges will never happen if we 'know' we have the real dataset
5704 // sequence - this should be detected when id==dssid
5706 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5707 // + (pre ? "prepended" : "") + " "
5708 // + (post ? "appended" : ""));
5713 // sequence refs are identical. We may need to update the existing dataset
5714 // alignment with this one, though.
5715 if (ds != null && dseqs == null)
5717 int opos = ds.findIndex(dsq);
5718 SequenceI tseq = null;
5719 if (opos != -1 && vseqpos != opos)
5721 // remove from old position
5722 ds.deleteSequence(dsq);
5724 if (vseqpos < ds.getHeight())
5726 if (vseqpos != opos)
5728 // save sequence at destination position
5729 tseq = ds.getSequenceAt(vseqpos);
5730 ds.replaceSequenceAt(vseqpos, dsq);
5731 ds.addSequence(tseq);
5736 ds.addSequence(dsq);
5743 * TODO use AlignmentI here and in related methods - needs
5744 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5746 Hashtable<String, AlignmentI> datasetIds = null;
5748 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5750 private AlignmentI getDatasetFor(String datasetId)
5752 if (datasetIds == null)
5754 datasetIds = new Hashtable<>();
5757 if (datasetIds.containsKey(datasetId))
5759 return datasetIds.get(datasetId);
5764 private void addDatasetRef(String datasetId, AlignmentI dataset)
5766 if (datasetIds == null)
5768 datasetIds = new Hashtable<>();
5770 datasetIds.put(datasetId, dataset);
5774 * make a new dataset ID for this jalview dataset alignment
5779 private String getDatasetIdRef(AlignmentI dataset)
5781 if (dataset.getDataset() != null)
5783 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5785 String datasetId = makeHashCode(dataset, null);
5786 if (datasetId == null)
5788 // make a new datasetId and record it
5789 if (dataset2Ids == null)
5791 dataset2Ids = new IdentityHashMap<>();
5795 datasetId = dataset2Ids.get(dataset);
5797 if (datasetId == null)
5799 datasetId = "ds" + dataset2Ids.size() + 1;
5800 dataset2Ids.put(dataset, datasetId);
5806 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5808 for (int d = 0; d < sequence.getDBRef().size(); d++)
5810 DBRef dr = sequence.getDBRef().get(d);
5811 jalview.datamodel.DBRefEntry entry = new jalview.datamodel.DBRefEntry(
5812 dr.getSource(), dr.getVersion(), dr.getAccessionId());
5813 if (dr.getMapping() != null)
5815 entry.setMap(addMapping(dr.getMapping()));
5817 datasetSequence.addDBRef(entry);
5821 private jalview.datamodel.Mapping addMapping(Mapping m)
5823 SequenceI dsto = null;
5824 // Mapping m = dr.getMapping();
5825 int fr[] = new int[m.getMapListFrom().size() * 2];
5826 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5827 for (int _i = 0; from.hasNext(); _i += 2)
5829 MapListFrom mf = from.next();
5830 fr[_i] = mf.getStart();
5831 fr[_i + 1] = mf.getEnd();
5833 int fto[] = new int[m.getMapListTo().size() * 2];
5834 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5835 for (int _i = 0; to.hasNext(); _i += 2)
5837 MapListTo mf = to.next();
5838 fto[_i] = mf.getStart();
5839 fto[_i + 1] = mf.getEnd();
5841 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5842 fto, m.getMapFromUnit().intValue(),
5843 m.getMapToUnit().intValue());
5844 // if (m.getMappingChoice() != null)
5846 // MappingChoice mc = m.getMappingChoice();
5847 if (m.getDseqFor() != null)
5849 String dsfor = m.getDseqFor();
5850 if (seqRefIds.containsKey(dsfor))
5855 jmap.setTo(seqRefIds.get(dsfor));
5859 frefedSequence.add(newMappingRef(dsfor, jmap));
5865 * local sequence definition
5867 Sequence ms = m.getSequence();
5868 SequenceI djs = null;
5869 String sqid = ms.getDsseqid();
5870 if (sqid != null && sqid.length() > 0)
5873 * recover dataset sequence
5875 djs = seqRefIds.get(sqid);
5880 "Warning - making up dataset sequence id for DbRef sequence map reference");
5881 sqid = ((Object) ms).toString(); // make up a new hascode for
5882 // undefined dataset sequence hash
5883 // (unlikely to happen)
5889 * make a new dataset sequence and add it to refIds hash
5891 djs = new jalview.datamodel.Sequence(ms.getName(),
5893 djs.setStart(jmap.getMap().getToLowest());
5894 djs.setEnd(jmap.getMap().getToHighest());
5895 djs.setVamsasId(uniqueSetSuffix + sqid);
5897 incompleteSeqs.put(sqid, djs);
5898 seqRefIds.put(sqid, djs);
5901 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5910 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5911 * view as XML (but not to file), and then reloading it
5916 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5919 JalviewModel jm = saveState(ap, null, null, null);
5922 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5923 ap.getAlignment().getDataset());
5925 uniqueSetSuffix = "";
5926 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5927 jm.getViewport().get(0).setId(null);
5928 // we don't overwrite the view we just copied
5930 if (this.frefedSequence == null)
5932 frefedSequence = new Vector<>();
5935 viewportsAdded.clear();
5937 AlignFrame af = loadFromObject(jm, null, false, null);
5938 af.getAlignPanels().clear();
5939 af.closeMenuItem_actionPerformed(true);
5942 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5943 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5944 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5945 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5946 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5949 return af.alignPanel;
5952 private Hashtable jvids2vobj;
5954 private void warn(String msg)
5959 private void warn(String msg, Exception e)
5961 if (Cache.log != null)
5965 Cache.log.warn(msg, e);
5969 Cache.log.warn(msg);
5974 System.err.println("Warning: " + msg);
5977 e.printStackTrace();
5982 private void debug(String string)
5984 debug(string, null);
5987 private void debug(String msg, Exception e)
5989 if (Cache.log != null)
5993 Cache.log.debug(msg, e);
5997 Cache.log.debug(msg);
6002 System.err.println("Warning: " + msg);
6005 e.printStackTrace();
6011 * set the object to ID mapping tables used to write/recover objects and XML
6012 * ID strings for the jalview project. If external tables are provided then
6013 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6014 * object goes out of scope. - also populates the datasetIds hashtable with
6015 * alignment objects containing dataset sequences
6018 * Map from ID strings to jalview datamodel
6020 * Map from jalview datamodel to ID strings
6024 public void setObjectMappingTables(Hashtable vobj2jv,
6025 IdentityHashMap jv2vobj)
6027 this.jv2vobj = jv2vobj;
6028 this.vobj2jv = vobj2jv;
6029 Iterator ds = jv2vobj.keySet().iterator();
6031 while (ds.hasNext())
6033 Object jvobj = ds.next();
6034 id = jv2vobj.get(jvobj).toString();
6035 if (jvobj instanceof jalview.datamodel.Alignment)
6037 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6039 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6042 else if (jvobj instanceof jalview.datamodel.Sequence)
6044 // register sequence object so the XML parser can recover it.
6045 if (seqRefIds == null)
6047 seqRefIds = new HashMap<>();
6049 if (seqsToIds == null)
6051 seqsToIds = new IdentityHashMap<>();
6053 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6054 seqsToIds.put((SequenceI) jvobj, id);
6056 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6059 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6060 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6061 if (jvann.annotationId == null)
6063 jvann.annotationId = anid;
6065 if (!jvann.annotationId.equals(anid))
6067 // TODO verify that this is the correct behaviour
6068 this.warn("Overriding Annotation ID for " + anid
6069 + " from different id : " + jvann.annotationId);
6070 jvann.annotationId = anid;
6073 else if (jvobj instanceof String)
6075 if (jvids2vobj == null)
6077 jvids2vobj = new Hashtable();
6078 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6083 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6089 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6090 * objects created from the project archive. If string is null (default for
6091 * construction) then suffix will be set automatically.
6095 public void setUniqueSetSuffix(String string)
6097 uniqueSetSuffix = string;
6102 * uses skipList2 as the skipList for skipping views on sequence sets
6103 * associated with keys in the skipList
6107 public void setSkipList(Hashtable skipList2)
6109 skipList = skipList2;
6113 * Reads the jar entry of given name and returns its contents, or null if the
6114 * entry is not found.
6117 * @param jarEntryName
6120 protected String readJarEntry(jarInputStreamProvider jprovider,
6121 String jarEntryName)
6123 String result = null;
6124 BufferedReader in = null;
6129 * Reopen the jar input stream and traverse its entries to find a matching
6132 JarInputStream jin = jprovider.getJarInputStream();
6133 JarEntry entry = null;
6136 entry = jin.getNextJarEntry();
6137 } while (entry != null && !entry.getName().equals(jarEntryName));
6141 StringBuilder out = new StringBuilder(256);
6142 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6145 while ((data = in.readLine()) != null)
6149 result = out.toString();
6153 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6155 } catch (Exception ex)
6157 ex.printStackTrace();
6165 } catch (IOException e)
6176 * Returns an incrementing counter (0, 1, 2...)
6180 private synchronized int nextCounter()
6186 * Loads any saved PCA viewers
6191 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6195 List<PcaViewer> pcaviewers = model.getPcaViewer();
6196 for (PcaViewer viewer : pcaviewers)
6198 String modelName = viewer.getScoreModelName();
6199 SimilarityParamsI params = new SimilarityParams(
6200 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6201 viewer.isIncludeGaps(),
6202 viewer.isDenominateByShortestLength());
6205 * create the panel (without computing the PCA)
6207 PCAPanel panel = new PCAPanel(ap, modelName, params);
6209 panel.setTitle(viewer.getTitle());
6210 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6211 viewer.getWidth(), viewer.getHeight()));
6213 boolean showLabels = viewer.isShowLabels();
6214 panel.setShowLabels(showLabels);
6215 panel.getRotatableCanvas().setShowLabels(showLabels);
6216 panel.getRotatableCanvas()
6217 .setBgColour(new Color(viewer.getBgColour()));
6218 panel.getRotatableCanvas()
6219 .setApplyToAllViews(viewer.isLinkToAllViews());
6222 * load PCA output data
6224 ScoreModelI scoreModel = ScoreModels.getInstance()
6225 .getScoreModel(modelName, ap);
6226 PCA pca = new PCA(null, scoreModel, params);
6227 PcaDataType pcaData = viewer.getPcaData();
6229 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6230 pca.setPairwiseScores(pairwise);
6232 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6233 pca.setTridiagonal(triDiag);
6235 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6236 pca.setEigenmatrix(result);
6238 panel.getPcaModel().setPCA(pca);
6241 * we haven't saved the input data! (JAL-2647 to do)
6243 panel.setInputData(null);
6246 * add the sequence points for the PCA display
6248 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6249 for (SequencePoint sp : viewer.getSequencePoint())
6251 String seqId = sp.getSequenceRef();
6252 SequenceI seq = seqRefIds.get(seqId);
6255 throw new IllegalStateException(
6256 "Unmatched seqref for PCA: " + seqId);
6258 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6259 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6261 seqPoints.add(seqPoint);
6263 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6266 * set min-max ranges and scale after setPoints (which recomputes them)
6268 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6269 SeqPointMin spMin = viewer.getSeqPointMin();
6270 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6272 SeqPointMax spMax = viewer.getSeqPointMax();
6273 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6275 panel.getRotatableCanvas().setSeqMinMax(min, max);
6277 // todo: hold points list in PCAModel only
6278 panel.getPcaModel().setSequencePoints(seqPoints);
6280 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6281 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6282 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6284 // is this duplication needed?
6285 panel.setTop(seqPoints.size() - 1);
6286 panel.getPcaModel().setTop(seqPoints.size() - 1);
6289 * add the axes' end points for the display
6291 for (int i = 0; i < 3; i++)
6293 Axis axis = viewer.getAxis().get(i);
6294 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6295 axis.getXPos(), axis.getYPos(), axis.getZPos());
6298 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6299 "label.calc_title", "PCA", modelName), 475, 450);
6301 } catch (Exception ex)
6303 Cache.log.error("Error loading PCA: " + ex.toString());
6308 * Populates an XML model of the feature colour scheme for one feature type
6310 * @param featureType
6314 public static Colour marshalColour(
6315 String featureType, FeatureColourI fcol)
6317 Colour col = new Colour();
6318 if (fcol.isSimpleColour())
6320 col.setRGB(Format.getHexString(fcol.getColour()));
6324 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6325 col.setMin(fcol.getMin());
6326 col.setMax(fcol.getMax());
6327 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6328 col.setAutoScale(fcol.isAutoScaled());
6329 col.setThreshold(fcol.getThreshold());
6330 col.setColourByLabel(fcol.isColourByLabel());
6331 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6332 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6333 : ThresholdType.NONE));
6334 if (fcol.isColourByAttribute())
6336 final String[] attName = fcol.getAttributeName();
6337 col.getAttributeName().add(attName[0]);
6338 if (attName.length > 1)
6340 col.getAttributeName().add(attName[1]);
6343 Color noColour = fcol.getNoColour();
6344 if (noColour == null)
6346 col.setNoValueColour(NoValueColour.NONE);
6348 else if (noColour == fcol.getMaxColour())
6350 col.setNoValueColour(NoValueColour.MAX);
6354 col.setNoValueColour(NoValueColour.MIN);
6357 col.setName(featureType);
6362 * Populates an XML model of the feature filter(s) for one feature type
6364 * @param firstMatcher
6365 * the first (or only) match condition)
6367 * remaining match conditions (if any)
6369 * if true, conditions are and-ed, else or-ed
6371 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6372 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6375 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6377 if (filters.hasNext())
6382 CompoundMatcher compound = new CompoundMatcher();
6383 compound.setAnd(and);
6384 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6385 firstMatcher, Collections.emptyIterator(), and);
6386 // compound.addMatcherSet(matcher1);
6387 compound.getMatcherSet().add(matcher1);
6388 FeatureMatcherI nextMatcher = filters.next();
6389 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6390 nextMatcher, filters, and);
6391 // compound.addMatcherSet(matcher2);
6392 compound.getMatcherSet().add(matcher2);
6393 result.setCompoundMatcher(compound);
6398 * single condition matcher
6400 // MatchCondition matcherModel = new MatchCondition();
6401 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6402 matcherModel.setCondition(
6403 firstMatcher.getMatcher().getCondition().getStableName());
6404 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6405 if (firstMatcher.isByAttribute())
6407 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6408 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6409 String[] attName = firstMatcher.getAttribute();
6410 matcherModel.getAttributeName().add(attName[0]); // attribute
6411 if (attName.length > 1)
6413 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6416 else if (firstMatcher.isByLabel())
6418 matcherModel.setBy(FilterBy.BY_LABEL);
6420 else if (firstMatcher.isByScore())
6422 matcherModel.setBy(FilterBy.BY_SCORE);
6424 result.setMatchCondition(matcherModel);
6431 * Loads one XML model of a feature filter to a Jalview object
6433 * @param featureType
6434 * @param matcherSetModel
6437 public static FeatureMatcherSetI parseFilter(
6439 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6441 FeatureMatcherSetI result = new FeatureMatcherSet();
6444 parseFilterConditions(result, matcherSetModel, true);
6445 } catch (IllegalStateException e)
6447 // mixing AND and OR conditions perhaps
6449 String.format("Error reading filter conditions for '%s': %s",
6450 featureType, e.getMessage()));
6451 // return as much as was parsed up to the error
6458 * Adds feature match conditions to matcherSet as unmarshalled from XML
6459 * (possibly recursively for compound conditions)
6462 * @param matcherSetModel
6464 * if true, multiple conditions are AND-ed, else they are OR-ed
6465 * @throws IllegalStateException
6466 * if AND and OR conditions are mixed
6468 protected static void parseFilterConditions(
6469 FeatureMatcherSetI matcherSet,
6470 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6473 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6474 .getMatchCondition();
6480 FilterBy filterBy = mc.getBy();
6481 Condition cond = Condition.fromString(mc.getCondition());
6482 String pattern = mc.getValue();
6483 FeatureMatcherI matchCondition = null;
6484 if (filterBy == FilterBy.BY_LABEL)
6486 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6488 else if (filterBy == FilterBy.BY_SCORE)
6490 matchCondition = FeatureMatcher.byScore(cond, pattern);
6493 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6495 final List<String> attributeName = mc.getAttributeName();
6496 String[] attNames = attributeName
6497 .toArray(new String[attributeName.size()]);
6498 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6503 * note this throws IllegalStateException if AND-ing to a
6504 * previously OR-ed compound condition, or vice versa
6508 matcherSet.and(matchCondition);
6512 matcherSet.or(matchCondition);
6518 * compound condition
6520 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6521 .getCompoundMatcher().getMatcherSet();
6522 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6523 if (matchers.size() == 2)
6525 parseFilterConditions(matcherSet, matchers.get(0), anded);
6526 parseFilterConditions(matcherSet, matchers.get(1), anded);
6530 System.err.println("Malformed compound filter condition");
6536 * Loads one XML model of a feature colour to a Jalview object
6538 * @param colourModel
6541 public static FeatureColourI parseColour(Colour colourModel)
6543 FeatureColourI colour = null;
6545 if (colourModel.getMax() != null)
6547 Color mincol = null;
6548 Color maxcol = null;
6549 Color noValueColour = null;
6553 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6554 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6555 } catch (Exception e)
6557 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6560 NoValueColour noCol = colourModel.getNoValueColour();
6561 if (noCol == NoValueColour.MIN)
6563 noValueColour = mincol;
6565 else if (noCol == NoValueColour.MAX)
6567 noValueColour = maxcol;
6570 colour = new FeatureColour(mincol, maxcol, noValueColour,
6571 safeFloat(colourModel.getMin()),
6572 safeFloat(colourModel.getMax()));
6573 final List<String> attributeName = colourModel.getAttributeName();
6574 String[] attributes = attributeName
6575 .toArray(new String[attributeName.size()]);
6576 if (attributes != null && attributes.length > 0)
6578 colour.setAttributeName(attributes);
6580 if (colourModel.isAutoScale() != null)
6582 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6584 if (colourModel.isColourByLabel() != null)
6586 colour.setColourByLabel(
6587 colourModel.isColourByLabel().booleanValue());
6589 if (colourModel.getThreshold() != null)
6591 colour.setThreshold(colourModel.getThreshold().floatValue());
6593 ThresholdType ttyp = colourModel.getThreshType();
6594 if (ttyp == ThresholdType.ABOVE)
6596 colour.setAboveThreshold(true);
6598 else if (ttyp == ThresholdType.BELOW)
6600 colour.setBelowThreshold(true);
6605 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6606 colour = new FeatureColour(color);