2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import jalview.analysis.Conservation;
28 import jalview.analysis.PCA;
29 import jalview.analysis.scoremodels.ScoreModels;
30 import jalview.analysis.scoremodels.SimilarityParams;
31 import jalview.api.FeatureColourI;
32 import jalview.api.ViewStyleI;
33 import jalview.api.analysis.ScoreModelI;
34 import jalview.api.analysis.SimilarityParamsI;
35 import jalview.api.structures.JalviewStructureDisplayI;
36 import jalview.bin.Cache;
37 import jalview.datamodel.AlignedCodonFrame;
38 import jalview.datamodel.Alignment;
39 import jalview.datamodel.AlignmentAnnotation;
40 import jalview.datamodel.AlignmentI;
41 import jalview.datamodel.DBRefEntry;
42 import jalview.datamodel.GeneLocus;
43 import jalview.datamodel.GraphLine;
44 import jalview.datamodel.PDBEntry;
45 import jalview.datamodel.Point;
46 import jalview.datamodel.RnaViewerModel;
47 import jalview.datamodel.SequenceFeature;
48 import jalview.datamodel.SequenceGroup;
49 import jalview.datamodel.SequenceI;
50 import jalview.datamodel.StructureViewerModel;
51 import jalview.datamodel.StructureViewerModel.StructureData;
52 import jalview.datamodel.features.FeatureMatcher;
53 import jalview.datamodel.features.FeatureMatcherI;
54 import jalview.datamodel.features.FeatureMatcherSet;
55 import jalview.datamodel.features.FeatureMatcherSetI;
56 import jalview.ext.varna.RnaModel;
57 import jalview.gui.AlignFrame;
58 import jalview.gui.AlignViewport;
59 import jalview.gui.AlignmentPanel;
60 import jalview.gui.AppVarna;
61 import jalview.gui.ChimeraViewFrame;
62 import jalview.gui.Desktop;
63 import jalview.gui.JvOptionPane;
64 import jalview.gui.OOMWarning;
65 import jalview.gui.PCAPanel;
66 import jalview.gui.PaintRefresher;
67 import jalview.gui.SplitFrame;
68 import jalview.gui.StructureViewer;
69 import jalview.gui.StructureViewer.ViewerType;
70 import jalview.gui.StructureViewerBase;
71 import jalview.gui.TreePanel;
72 import jalview.io.BackupFiles;
73 import jalview.io.DataSourceType;
74 import jalview.io.FileFormat;
75 import jalview.io.NewickFile;
76 import jalview.math.Matrix;
77 import jalview.math.MatrixI;
78 import jalview.renderer.ResidueShaderI;
79 import jalview.schemes.AnnotationColourGradient;
80 import jalview.schemes.ColourSchemeI;
81 import jalview.schemes.ColourSchemeProperty;
82 import jalview.schemes.FeatureColour;
83 import jalview.schemes.ResidueProperties;
84 import jalview.schemes.UserColourScheme;
85 import jalview.structure.StructureSelectionManager;
86 import jalview.structures.models.AAStructureBindingModel;
87 import jalview.util.Format;
88 import jalview.util.MessageManager;
89 import jalview.util.Platform;
90 import jalview.util.StringUtils;
91 import jalview.util.jarInputStreamProvider;
92 import jalview.util.matcher.Condition;
93 import jalview.viewmodel.AlignmentViewport;
94 import jalview.viewmodel.PCAModel;
95 import jalview.viewmodel.ViewportRanges;
96 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
97 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
98 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
99 import jalview.ws.jws2.Jws2Discoverer;
100 import jalview.ws.jws2.dm.AAConSettings;
101 import jalview.ws.jws2.jabaws2.Jws2Instance;
102 import jalview.ws.params.ArgumentI;
103 import jalview.ws.params.AutoCalcSetting;
104 import jalview.ws.params.WsParamSetI;
105 import jalview.xml.binding.jalview.AlcodonFrame;
106 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
107 import jalview.xml.binding.jalview.Annotation;
108 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
109 import jalview.xml.binding.jalview.AnnotationColourScheme;
110 import jalview.xml.binding.jalview.AnnotationElement;
111 import jalview.xml.binding.jalview.DoubleMatrix;
112 import jalview.xml.binding.jalview.DoubleVector;
113 import jalview.xml.binding.jalview.Feature;
114 import jalview.xml.binding.jalview.Feature.OtherData;
115 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
116 import jalview.xml.binding.jalview.FilterBy;
117 import jalview.xml.binding.jalview.JalviewModel;
118 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
119 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
120 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
121 import jalview.xml.binding.jalview.JalviewModel.JGroup;
122 import jalview.xml.binding.jalview.JalviewModel.JSeq;
123 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
124 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
125 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
126 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
127 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
128 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
129 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
130 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
131 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
132 import jalview.xml.binding.jalview.JalviewModel.Tree;
133 import jalview.xml.binding.jalview.JalviewModel.UserColours;
134 import jalview.xml.binding.jalview.JalviewModel.Viewport;
135 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
136 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
137 import jalview.xml.binding.jalview.JalviewUserColours;
138 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
139 import jalview.xml.binding.jalview.MapListType.MapListFrom;
140 import jalview.xml.binding.jalview.MapListType.MapListTo;
141 import jalview.xml.binding.jalview.Mapping;
142 import jalview.xml.binding.jalview.NoValueColour;
143 import jalview.xml.binding.jalview.ObjectFactory;
144 import jalview.xml.binding.jalview.PcaDataType;
145 import jalview.xml.binding.jalview.Pdbentry.Property;
146 import jalview.xml.binding.jalview.Sequence;
147 import jalview.xml.binding.jalview.Sequence.DBRef;
148 import jalview.xml.binding.jalview.SequenceSet;
149 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
150 import jalview.xml.binding.jalview.ThresholdType;
151 import jalview.xml.binding.jalview.VAMSAS;
153 import java.awt.Color;
154 import java.awt.Dimension;
155 import java.awt.Font;
156 import java.awt.Rectangle;
157 import java.io.BufferedReader;
158 import java.io.ByteArrayInputStream;
159 import java.io.DataInputStream;
160 import java.io.DataOutputStream;
162 import java.io.FileInputStream;
163 import java.io.FileOutputStream;
164 import java.io.IOException;
165 import java.io.InputStreamReader;
166 import java.io.OutputStreamWriter;
167 import java.io.PrintWriter;
168 import java.lang.reflect.InvocationTargetException;
169 import java.math.BigInteger;
170 import java.net.MalformedURLException;
172 import java.util.ArrayList;
173 import java.util.Arrays;
174 import java.util.Collections;
175 import java.util.Enumeration;
176 import java.util.GregorianCalendar;
177 import java.util.HashMap;
178 import java.util.HashSet;
179 import java.util.Hashtable;
180 import java.util.IdentityHashMap;
181 import java.util.Iterator;
182 import java.util.LinkedHashMap;
183 import java.util.List;
184 import java.util.Map;
185 import java.util.Map.Entry;
186 import java.util.Set;
187 import java.util.Vector;
188 import java.util.jar.JarEntry;
189 import java.util.jar.JarInputStream;
190 import java.util.jar.JarOutputStream;
192 import javax.swing.JInternalFrame;
193 import javax.swing.SwingUtilities;
194 import javax.xml.bind.JAXBContext;
195 import javax.xml.bind.JAXBElement;
196 import javax.xml.bind.Marshaller;
197 import javax.xml.datatype.DatatypeConfigurationException;
198 import javax.xml.datatype.DatatypeFactory;
199 import javax.xml.datatype.XMLGregorianCalendar;
200 import javax.xml.stream.XMLInputFactory;
201 import javax.xml.stream.XMLStreamReader;
204 * Write out the current jalview desktop state as a Jalview XML stream.
206 * Note: the vamsas objects referred to here are primitive versions of the
207 * VAMSAS project schema elements - they are not the same and most likely never
211 * @version $Revision: 1.134 $
213 public class Jalview2XML
216 // BH 2018 we add the .jvp binary extension to J2S so that
217 // it will declare that binary when we do the file save from the browser
221 Platform.addJ2SBinaryType(".jvp?");
224 private static final String VIEWER_PREFIX = "viewer_";
226 private static final String RNA_PREFIX = "rna_";
228 private static final String UTF_8 = "UTF-8";
231 * prefix for recovering datasets for alignments with multiple views where
232 * non-existent dataset IDs were written for some views
234 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
236 // use this with nextCounter() to make unique names for entities
237 private int counter = 0;
240 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
241 * of sequence objects are created.
243 IdentityHashMap<SequenceI, String> seqsToIds = null;
246 * jalview XML Sequence ID to jalview sequence object reference (both dataset
247 * and alignment sequences. Populated as XML reps of sequence objects are
250 Map<String, SequenceI> seqRefIds = null;
252 Map<String, SequenceI> incompleteSeqs = null;
254 List<SeqFref> frefedSequence = null;
256 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
259 * Map of reconstructed AlignFrame objects that appear to have come from
260 * SplitFrame objects (have a dna/protein complement view).
262 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
265 * Map from displayed rna structure models to their saved session state jar
268 private Map<RnaModel, String> rnaSessions = new HashMap<>();
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 boolean value, or false
278 public static boolean safeBoolean(Boolean b)
280 return b == null ? false : b.booleanValue();
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 integer value, or zero
291 public static int safeInt(Integer i)
293 return i == null ? 0 : i.intValue();
297 * A helper method for safely using the value of an optional attribute that
298 * may be null if not present in the XML. Answers the float value, or zero if
304 public static float safeFloat(Float f)
306 return f == null ? 0f : f.floatValue();
310 * create/return unique hash string for sq
313 * @return new or existing unique string for sq
315 String seqHash(SequenceI sq)
317 if (seqsToIds == null)
321 if (seqsToIds.containsKey(sq))
323 return seqsToIds.get(sq);
327 // create sequential key
328 String key = "sq" + (seqsToIds.size() + 1);
329 key = makeHashCode(sq, key); // check we don't have an external reference
331 seqsToIds.put(sq, key);
338 if (seqsToIds == null)
340 seqsToIds = new IdentityHashMap<>();
342 if (seqRefIds == null)
344 seqRefIds = new HashMap<>();
346 if (incompleteSeqs == null)
348 incompleteSeqs = new HashMap<>();
350 if (frefedSequence == null)
352 frefedSequence = new ArrayList<>();
360 public Jalview2XML(boolean raiseGUI)
362 this.raiseGUI = raiseGUI;
366 * base class for resolving forward references to sequences by their ID
371 abstract class SeqFref
377 public SeqFref(String _sref, String type)
383 public String getSref()
388 public SequenceI getSrefSeq()
390 return seqRefIds.get(sref);
393 public boolean isResolvable()
395 return seqRefIds.get(sref) != null;
398 public SequenceI getSrefDatasetSeq()
400 SequenceI sq = seqRefIds.get(sref);
403 while (sq.getDatasetSequence() != null)
405 sq = sq.getDatasetSequence();
412 * @return true if the forward reference was fully resolved
414 abstract boolean resolve();
417 public String toString()
419 return type + " reference to " + sref;
424 * create forward reference for a mapping
430 public SeqFref newMappingRef(final String sref,
431 final jalview.datamodel.Mapping _jmap)
433 SeqFref fref = new SeqFref(sref, "Mapping")
435 public jalview.datamodel.Mapping jmap = _jmap;
440 SequenceI seq = getSrefDatasetSeq();
452 public SeqFref newAlcodMapRef(final String sref,
453 final AlignedCodonFrame _cf,
454 final jalview.datamodel.Mapping _jmap)
457 SeqFref fref = new SeqFref(sref, "Codon Frame")
459 AlignedCodonFrame cf = _cf;
461 public jalview.datamodel.Mapping mp = _jmap;
464 public boolean isResolvable()
466 return super.isResolvable() && mp.getTo() != null;
472 SequenceI seq = getSrefDatasetSeq();
477 cf.addMap(seq, mp.getTo(), mp.getMap());
484 public void resolveFrefedSequences()
486 Iterator<SeqFref> nextFref = frefedSequence.iterator();
487 int toresolve = frefedSequence.size();
488 int unresolved = 0, failedtoresolve = 0;
489 while (nextFref.hasNext())
491 SeqFref ref = nextFref.next();
492 if (ref.isResolvable())
504 } catch (Exception x)
507 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
520 System.err.println("Jalview Project Import: There were " + unresolved
521 + " forward references left unresolved on the stack.");
523 if (failedtoresolve > 0)
525 System.err.println("SERIOUS! " + failedtoresolve
526 + " resolvable forward references failed to resolve.");
528 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
531 "Jalview Project Import: There are " + incompleteSeqs.size()
532 + " sequences which may have incomplete metadata.");
533 if (incompleteSeqs.size() < 10)
535 for (SequenceI s : incompleteSeqs.values())
537 System.err.println(s.toString());
543 "Too many to report. Skipping output of incomplete sequences.");
549 * This maintains a map of viewports, the key being the seqSetId. Important to
550 * set historyItem and redoList for multiple views
552 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
554 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
556 String uniqueSetSuffix = "";
559 * List of pdbfiles added to Jar
561 List<String> pdbfiles = null;
563 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
564 public void saveState(File statefile)
566 FileOutputStream fos = null;
571 fos = new FileOutputStream(statefile);
573 JarOutputStream jout = new JarOutputStream(fos);
577 } catch (Exception e)
579 Cache.log.error("Couln't write Jalview state to " + statefile, e);
580 // TODO: inform user of the problem - they need to know if their data was
582 if (errorMessage == null)
584 errorMessage = "Did't write Jalview Archive to output file '"
585 + statefile + "' - See console error log for details";
589 errorMessage += "(Didn't write Jalview Archive to output file '"
600 } catch (IOException e)
610 * Writes a jalview project archive to the given Jar output stream.
614 public void saveState(JarOutputStream jout)
616 AlignFrame[] frames = Desktop.getAlignFrames();
622 saveAllFrames(Arrays.asList(frames), jout);
626 * core method for storing state for a set of AlignFrames.
629 * - frames involving all data to be exported (including containing
632 * - project output stream
634 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
636 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
639 * ensure cached data is clear before starting
641 // todo tidy up seqRefIds, seqsToIds initialisation / reset
643 splitFrameCandidates.clear();
648 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
649 // //////////////////////////////////////////////////
651 List<String> shortNames = new ArrayList<>();
652 List<String> viewIds = new ArrayList<>();
655 for (int i = frames.size() - 1; i > -1; i--)
657 AlignFrame af = frames.get(i);
659 if (skipList != null && skipList
660 .containsKey(af.getViewport().getSequenceSetId()))
665 String shortName = makeFilename(af, shortNames);
667 int apSize = af.getAlignPanels().size();
669 for (int ap = 0; ap < apSize; ap++)
671 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
673 String fileName = apSize == 1 ? shortName : ap + shortName;
674 if (!fileName.endsWith(".xml"))
676 fileName = fileName + ".xml";
679 saveState(apanel, fileName, jout, viewIds);
681 String dssid = getDatasetIdRef(
682 af.getViewport().getAlignment().getDataset());
683 if (!dsses.containsKey(dssid))
685 dsses.put(dssid, af);
690 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
696 } catch (Exception foo)
700 } catch (Exception ex)
702 // TODO: inform user of the problem - they need to know if their data was
704 if (errorMessage == null)
706 errorMessage = "Couldn't write Jalview Archive - see error output for details";
708 ex.printStackTrace();
713 * Generates a distinct file name, based on the title of the AlignFrame, by
714 * appending _n for increasing n until an unused name is generated. The new
715 * name (without its extension) is added to the list.
719 * @return the generated name, with .xml extension
721 protected String makeFilename(AlignFrame af, List<String> namesUsed)
723 String shortName = af.getTitle();
725 if (shortName.indexOf(File.separatorChar) > -1)
727 shortName = shortName
728 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
733 while (namesUsed.contains(shortName))
735 if (shortName.endsWith("_" + (count - 1)))
737 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
740 shortName = shortName.concat("_" + count);
744 namesUsed.add(shortName);
746 if (!shortName.endsWith(".xml"))
748 shortName = shortName + ".xml";
753 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
754 public boolean saveAlignment(AlignFrame af, String jarFile,
759 // create backupfiles object and get new temp filename destination
760 boolean doBackup = BackupFiles.getEnabled();
761 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
762 FileOutputStream fos = new FileOutputStream(doBackup ?
763 backupfiles.getTempFilePath() : jarFile);
765 JarOutputStream jout = new JarOutputStream(fos);
766 List<AlignFrame> frames = new ArrayList<>();
768 // resolve splitframes
769 if (af.getViewport().getCodingComplement() != null)
771 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
777 saveAllFrames(frames, jout);
781 } catch (Exception foo)
785 boolean success = true;
789 backupfiles.setWriteSuccess(success);
790 success = backupfiles.rollBackupsAndRenameTempFile();
794 } catch (Exception ex)
796 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
797 ex.printStackTrace();
802 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
803 String fileName, JarOutputStream jout)
806 for (String dssids : dsses.keySet())
808 AlignFrame _af = dsses.get(dssids);
809 String jfileName = fileName + " Dataset for " + _af.getTitle();
810 if (!jfileName.endsWith(".xml"))
812 jfileName = jfileName + ".xml";
814 saveState(_af.alignPanel, jfileName, true, jout, null);
819 * create a JalviewModel from an alignment view and marshall it to a
823 * panel to create jalview model for
825 * name of alignment panel written to output stream
832 public JalviewModel saveState(AlignmentPanel ap, String fileName,
833 JarOutputStream jout, List<String> viewIds)
835 return saveState(ap, fileName, false, jout, viewIds);
839 * create a JalviewModel from an alignment view and marshall it to a
843 * panel to create jalview model for
845 * name of alignment panel written to output stream
847 * when true, only write the dataset for the alignment, not the data
848 * associated with the view.
854 public JalviewModel saveState(AlignmentPanel ap, String fileName,
855 boolean storeDS, JarOutputStream jout, List<String> viewIds)
859 viewIds = new ArrayList<>();
864 List<UserColourScheme> userColours = new ArrayList<>();
866 AlignViewport av = ap.av;
867 ViewportRanges vpRanges = av.getRanges();
869 final ObjectFactory objectFactory = new ObjectFactory();
870 JalviewModel object = objectFactory.createJalviewModel();
871 object.setVamsasModel(new VAMSAS());
873 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
876 GregorianCalendar c = new GregorianCalendar();
877 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
878 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
879 object.setCreationDate(now);
880 } catch (DatatypeConfigurationException e)
882 System.err.println("error writing date: " + e.toString());
885 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
888 * rjal is full height alignment, jal is actual alignment with full metadata
889 * but excludes hidden sequences.
891 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
893 if (av.hasHiddenRows())
895 rjal = jal.getHiddenSequences().getFullAlignment();
898 SequenceSet vamsasSet = new SequenceSet();
900 // JalviewModelSequence jms = new JalviewModelSequence();
902 vamsasSet.setGapChar(jal.getGapCharacter() + "");
904 if (jal.getDataset() != null)
906 // dataset id is the dataset's hashcode
907 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
910 // switch jal and the dataset
911 jal = jal.getDataset();
915 if (jal.getProperties() != null)
917 Enumeration en = jal.getProperties().keys();
918 while (en.hasMoreElements())
920 String key = en.nextElement().toString();
921 SequenceSetProperties ssp = new SequenceSetProperties();
923 ssp.setValue(jal.getProperties().get(key).toString());
924 // vamsasSet.addSequenceSetProperties(ssp);
925 vamsasSet.getSequenceSetProperties().add(ssp);
930 Set<String> calcIdSet = new HashSet<>();
931 // record the set of vamsas sequence XML POJO we create.
932 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
934 for (final SequenceI jds : rjal.getSequences())
936 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
937 : jds.getDatasetSequence();
938 String id = seqHash(jds);
939 if (vamsasSetIds.get(id) == null)
941 if (seqRefIds.get(id) != null && !storeDS)
943 // This happens for two reasons: 1. multiple views are being
945 // 2. the hashCode has collided with another sequence's code. This
947 // HAPPEN! (PF00072.15.stk does this)
948 // JBPNote: Uncomment to debug writing out of files that do not read
949 // back in due to ArrayOutOfBoundExceptions.
950 // System.err.println("vamsasSeq backref: "+id+"");
951 // System.err.println(jds.getName()+"
952 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
953 // System.err.println("Hashcode: "+seqHash(jds));
954 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
955 // System.err.println(rsq.getName()+"
956 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
957 // System.err.println("Hashcode: "+seqHash(rsq));
961 vamsasSeq = createVamsasSequence(id, jds);
962 // vamsasSet.addSequence(vamsasSeq);
963 vamsasSet.getSequence().add(vamsasSeq);
964 vamsasSetIds.put(id, vamsasSeq);
965 seqRefIds.put(id, jds);
969 jseq.setStart(jds.getStart());
970 jseq.setEnd(jds.getEnd());
971 jseq.setColour(av.getSequenceColour(jds).getRGB());
973 jseq.setId(id); // jseq id should be a string not a number
976 // Store any sequences this sequence represents
977 if (av.hasHiddenRows())
979 // use rjal, contains the full height alignment
981 av.getAlignment().getHiddenSequences().isHidden(jds));
983 if (av.isHiddenRepSequence(jds))
985 jalview.datamodel.SequenceI[] reps = av
986 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
988 for (int h = 0; h < reps.length; h++)
992 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
993 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
998 // mark sequence as reference - if it is the reference for this view
1001 jseq.setViewreference(jds == jal.getSeqrep());
1005 // TODO: omit sequence features from each alignment view's XML dump if we
1006 // are storing dataset
1007 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1008 for (SequenceFeature sf : sfs)
1010 // Features features = new Features();
1011 Feature features = new Feature();
1013 features.setBegin(sf.getBegin());
1014 features.setEnd(sf.getEnd());
1015 features.setDescription(sf.getDescription());
1016 features.setType(sf.getType());
1017 features.setFeatureGroup(sf.getFeatureGroup());
1018 features.setScore(sf.getScore());
1019 if (sf.links != null)
1021 for (int l = 0; l < sf.links.size(); l++)
1023 OtherData keyValue = new OtherData();
1024 keyValue.setKey("LINK_" + l);
1025 keyValue.setValue(sf.links.elementAt(l).toString());
1026 // features.addOtherData(keyValue);
1027 features.getOtherData().add(keyValue);
1030 if (sf.otherDetails != null)
1033 * save feature attributes, which may be simple strings or
1034 * map valued (have sub-attributes)
1036 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1038 String key = entry.getKey();
1039 Object value = entry.getValue();
1040 if (value instanceof Map<?, ?>)
1042 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1045 OtherData otherData = new OtherData();
1046 otherData.setKey(key);
1047 otherData.setKey2(subAttribute.getKey());
1048 otherData.setValue(subAttribute.getValue().toString());
1049 // features.addOtherData(otherData);
1050 features.getOtherData().add(otherData);
1055 OtherData otherData = new OtherData();
1056 otherData.setKey(key);
1057 otherData.setValue(value.toString());
1058 // features.addOtherData(otherData);
1059 features.getOtherData().add(otherData);
1064 // jseq.addFeatures(features);
1065 jseq.getFeatures().add(features);
1068 if (jdatasq.getAllPDBEntries() != null)
1070 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1071 while (en.hasMoreElements())
1073 Pdbids pdb = new Pdbids();
1074 jalview.datamodel.PDBEntry entry = en.nextElement();
1076 String pdbId = entry.getId();
1078 pdb.setType(entry.getType());
1081 * Store any structure views associated with this sequence. This
1082 * section copes with duplicate entries in the project, so a dataset
1083 * only view *should* be coped with sensibly.
1085 // This must have been loaded, is it still visible?
1086 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1087 String matchedFile = null;
1088 for (int f = frames.length - 1; f > -1; f--)
1090 if (frames[f] instanceof StructureViewerBase)
1092 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1093 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1094 matchedFile, viewFrame);
1096 * Only store each structure viewer's state once in the project
1097 * jar. First time through only (storeDS==false)
1099 String viewId = viewFrame.getViewId();
1100 if (!storeDS && !viewIds.contains(viewId))
1102 viewIds.add(viewId);
1105 String viewerState = viewFrame.getStateInfo();
1106 writeJarEntry(jout, getViewerJarEntryName(viewId),
1107 viewerState.getBytes());
1108 } catch (IOException e)
1111 "Error saving viewer state: " + e.getMessage());
1117 if (matchedFile != null || entry.getFile() != null)
1119 if (entry.getFile() != null)
1122 matchedFile = entry.getFile();
1124 pdb.setFile(matchedFile); // entry.getFile());
1125 if (pdbfiles == null)
1127 pdbfiles = new ArrayList<>();
1130 if (!pdbfiles.contains(pdbId))
1132 pdbfiles.add(pdbId);
1133 copyFileToJar(jout, matchedFile, pdbId);
1137 Enumeration<String> props = entry.getProperties();
1138 if (props.hasMoreElements())
1140 // PdbentryItem item = new PdbentryItem();
1141 while (props.hasMoreElements())
1143 Property prop = new Property();
1144 String key = props.nextElement();
1146 prop.setValue(entry.getProperty(key).toString());
1147 // item.addProperty(prop);
1148 pdb.getProperty().add(prop);
1150 // pdb.addPdbentryItem(item);
1153 // jseq.addPdbids(pdb);
1154 jseq.getPdbids().add(pdb);
1158 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1160 // jms.addJSeq(jseq);
1161 object.getJSeq().add(jseq);
1164 if (!storeDS && av.hasHiddenRows())
1166 jal = av.getAlignment();
1170 if (storeDS && jal.getCodonFrames() != null)
1172 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1173 for (AlignedCodonFrame acf : jac)
1175 AlcodonFrame alc = new AlcodonFrame();
1176 if (acf.getProtMappings() != null
1177 && acf.getProtMappings().length > 0)
1179 boolean hasMap = false;
1180 SequenceI[] dnas = acf.getdnaSeqs();
1181 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1182 for (int m = 0; m < pmaps.length; m++)
1184 AlcodMap alcmap = new AlcodMap();
1185 alcmap.setDnasq(seqHash(dnas[m]));
1187 createVamsasMapping(pmaps[m], dnas[m], null, false));
1188 // alc.addAlcodMap(alcmap);
1189 alc.getAlcodMap().add(alcmap);
1194 // vamsasSet.addAlcodonFrame(alc);
1195 vamsasSet.getAlcodonFrame().add(alc);
1198 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1200 // AlcodonFrame alc = new AlcodonFrame();
1201 // vamsasSet.addAlcodonFrame(alc);
1202 // for (int p = 0; p < acf.aaWidth; p++)
1204 // Alcodon cmap = new Alcodon();
1205 // if (acf.codons[p] != null)
1207 // // Null codons indicate a gapped column in the translated peptide
1209 // cmap.setPos1(acf.codons[p][0]);
1210 // cmap.setPos2(acf.codons[p][1]);
1211 // cmap.setPos3(acf.codons[p][2]);
1213 // alc.addAlcodon(cmap);
1215 // if (acf.getProtMappings() != null
1216 // && acf.getProtMappings().length > 0)
1218 // SequenceI[] dnas = acf.getdnaSeqs();
1219 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1220 // for (int m = 0; m < pmaps.length; m++)
1222 // AlcodMap alcmap = new AlcodMap();
1223 // alcmap.setDnasq(seqHash(dnas[m]));
1224 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1226 // alc.addAlcodMap(alcmap);
1233 // /////////////////////////////////
1234 if (!storeDS && av.getCurrentTree() != null)
1236 // FIND ANY ASSOCIATED TREES
1237 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1238 if (Desktop.desktop != null)
1240 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1242 for (int t = 0; t < frames.length; t++)
1244 if (frames[t] instanceof TreePanel)
1246 TreePanel tp = (TreePanel) frames[t];
1248 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1250 JalviewModel.Tree tree = new JalviewModel.Tree();
1251 tree.setTitle(tp.getTitle());
1252 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1253 tree.setNewick(tp.getTree().print());
1254 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1256 tree.setFitToWindow(tp.fitToWindow.getState());
1257 tree.setFontName(tp.getTreeFont().getName());
1258 tree.setFontSize(tp.getTreeFont().getSize());
1259 tree.setFontStyle(tp.getTreeFont().getStyle());
1260 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1262 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1263 tree.setShowDistances(tp.distanceMenu.getState());
1265 tree.setHeight(tp.getHeight());
1266 tree.setWidth(tp.getWidth());
1267 tree.setXpos(tp.getX());
1268 tree.setYpos(tp.getY());
1269 tree.setId(makeHashCode(tp, null));
1270 tree.setLinkToAllViews(
1271 tp.getTreeCanvas().isApplyToAllViews());
1273 // jms.addTree(tree);
1274 object.getTree().add(tree);
1284 if (!storeDS && Desktop.desktop != null)
1286 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1288 if (frame instanceof PCAPanel)
1290 PCAPanel panel = (PCAPanel) frame;
1291 if (panel.getAlignViewport().getAlignment() == jal)
1293 savePCA(panel, object);
1301 * store forward refs from an annotationRow to any groups
1303 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1306 for (SequenceI sq : jal.getSequences())
1308 // Store annotation on dataset sequences only
1309 AlignmentAnnotation[] aa = sq.getAnnotation();
1310 if (aa != null && aa.length > 0)
1312 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1319 if (jal.getAlignmentAnnotation() != null)
1321 // Store the annotation shown on the alignment.
1322 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1323 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1328 if (jal.getGroups() != null)
1330 JGroup[] groups = new JGroup[jal.getGroups().size()];
1332 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1334 JGroup jGroup = new JGroup();
1335 groups[++i] = jGroup;
1337 jGroup.setStart(sg.getStartRes());
1338 jGroup.setEnd(sg.getEndRes());
1339 jGroup.setName(sg.getName());
1340 if (groupRefs.containsKey(sg))
1342 // group has references so set its ID field
1343 jGroup.setId(groupRefs.get(sg));
1345 ColourSchemeI colourScheme = sg.getColourScheme();
1346 if (colourScheme != null)
1348 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1349 if (groupColourScheme.conservationApplied())
1351 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1353 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1356 setUserColourScheme(colourScheme, userColours,
1361 jGroup.setColour(colourScheme.getSchemeName());
1364 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1366 jGroup.setColour("AnnotationColourGradient");
1367 jGroup.setAnnotationColours(constructAnnotationColours(
1368 (jalview.schemes.AnnotationColourGradient) colourScheme,
1369 userColours, object));
1371 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1374 setUserColourScheme(colourScheme, userColours, object));
1378 jGroup.setColour(colourScheme.getSchemeName());
1381 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1384 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1385 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1386 jGroup.setDisplayText(sg.getDisplayText());
1387 jGroup.setColourText(sg.getColourText());
1388 jGroup.setTextCol1(sg.textColour.getRGB());
1389 jGroup.setTextCol2(sg.textColour2.getRGB());
1390 jGroup.setTextColThreshold(sg.thresholdTextColour);
1391 jGroup.setShowUnconserved(sg.getShowNonconserved());
1392 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1393 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1394 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1395 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1396 for (SequenceI seq : sg.getSequences())
1398 // jGroup.addSeq(seqHash(seq));
1399 jGroup.getSeq().add(seqHash(seq));
1403 //jms.setJGroup(groups);
1405 for (JGroup grp : groups)
1407 object.getJGroup().add(grp);
1412 // /////////SAVE VIEWPORT
1413 Viewport view = new Viewport();
1414 view.setTitle(ap.alignFrame.getTitle());
1415 view.setSequenceSetId(
1416 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1417 view.setId(av.getViewId());
1418 if (av.getCodingComplement() != null)
1420 view.setComplementId(av.getCodingComplement().getViewId());
1422 view.setViewName(av.getViewName());
1423 view.setGatheredViews(av.isGatherViewsHere());
1425 Rectangle size = ap.av.getExplodedGeometry();
1426 Rectangle position = size;
1429 size = ap.alignFrame.getBounds();
1430 if (av.getCodingComplement() != null)
1432 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1440 view.setXpos(position.x);
1441 view.setYpos(position.y);
1443 view.setWidth(size.width);
1444 view.setHeight(size.height);
1446 view.setStartRes(vpRanges.getStartRes());
1447 view.setStartSeq(vpRanges.getStartSeq());
1449 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1451 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1452 userColours, object));
1455 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1457 AnnotationColourScheme ac = constructAnnotationColours(
1458 (jalview.schemes.AnnotationColourGradient) av
1459 .getGlobalColourScheme(),
1460 userColours, object);
1462 view.setAnnotationColours(ac);
1463 view.setBgColour("AnnotationColourGradient");
1467 view.setBgColour(ColourSchemeProperty
1468 .getColourName(av.getGlobalColourScheme()));
1471 ResidueShaderI vcs = av.getResidueShading();
1472 ColourSchemeI cs = av.getGlobalColourScheme();
1476 if (vcs.conservationApplied())
1478 view.setConsThreshold(vcs.getConservationInc());
1479 if (cs instanceof jalview.schemes.UserColourScheme)
1481 view.setBgColour(setUserColourScheme(cs, userColours, object));
1484 view.setPidThreshold(vcs.getThreshold());
1487 view.setConservationSelected(av.getConservationSelected());
1488 view.setPidSelected(av.getAbovePIDThreshold());
1489 final Font font = av.getFont();
1490 view.setFontName(font.getName());
1491 view.setFontSize(font.getSize());
1492 view.setFontStyle(font.getStyle());
1493 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1494 view.setRenderGaps(av.isRenderGaps());
1495 view.setShowAnnotation(av.isShowAnnotation());
1496 view.setShowBoxes(av.getShowBoxes());
1497 view.setShowColourText(av.getColourText());
1498 view.setShowFullId(av.getShowJVSuffix());
1499 view.setRightAlignIds(av.isRightAlignIds());
1500 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1501 view.setShowText(av.getShowText());
1502 view.setShowUnconserved(av.getShowUnconserved());
1503 view.setWrapAlignment(av.getWrapAlignment());
1504 view.setTextCol1(av.getTextColour().getRGB());
1505 view.setTextCol2(av.getTextColour2().getRGB());
1506 view.setTextColThreshold(av.getThresholdTextColour());
1507 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1508 view.setShowSequenceLogo(av.isShowSequenceLogo());
1509 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1510 view.setShowGroupConsensus(av.isShowGroupConsensus());
1511 view.setShowGroupConservation(av.isShowGroupConservation());
1512 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1513 view.setShowDbRefTooltip(av.isShowDBRefs());
1514 view.setFollowHighlight(av.isFollowHighlight());
1515 view.setFollowSelection(av.followSelection);
1516 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1517 view.setShowComplementFeatures(av.isShowComplementFeatures());
1518 view.setShowComplementFeaturesOnTop(
1519 av.isShowComplementFeaturesOnTop());
1520 if (av.getFeaturesDisplayed() != null)
1522 FeatureSettings fs = new FeatureSettings();
1524 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1525 .getFeatureRenderer();
1526 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1528 Vector<String> settingsAdded = new Vector<>();
1529 if (renderOrder != null)
1531 for (String featureType : renderOrder)
1533 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1534 setting.setType(featureType);
1537 * save any filter for the feature type
1539 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1540 if (filter != null) {
1541 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1542 FeatureMatcherI firstFilter = filters.next();
1543 setting.setMatcherSet(Jalview2XML.marshalFilter(
1544 firstFilter, filters, filter.isAnded()));
1548 * save colour scheme for the feature type
1550 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1551 if (!fcol.isSimpleColour())
1553 setting.setColour(fcol.getMaxColour().getRGB());
1554 setting.setMincolour(fcol.getMinColour().getRGB());
1555 setting.setMin(fcol.getMin());
1556 setting.setMax(fcol.getMax());
1557 setting.setColourByLabel(fcol.isColourByLabel());
1558 if (fcol.isColourByAttribute())
1560 String[] attName = fcol.getAttributeName();
1561 setting.getAttributeName().add(attName[0]);
1562 if (attName.length > 1)
1564 setting.getAttributeName().add(attName[1]);
1567 setting.setAutoScale(fcol.isAutoScaled());
1568 setting.setThreshold(fcol.getThreshold());
1569 Color noColour = fcol.getNoColour();
1570 if (noColour == null)
1572 setting.setNoValueColour(NoValueColour.NONE);
1574 else if (noColour.equals(fcol.getMaxColour()))
1576 setting.setNoValueColour(NoValueColour.MAX);
1580 setting.setNoValueColour(NoValueColour.MIN);
1582 // -1 = No threshold, 0 = Below, 1 = Above
1583 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1584 : (fcol.isBelowThreshold() ? 0 : -1));
1588 setting.setColour(fcol.getColour().getRGB());
1592 av.getFeaturesDisplayed().isVisible(featureType));
1594 .getOrder(featureType);
1597 setting.setOrder(rorder);
1599 /// fs.addSetting(setting);
1600 fs.getSetting().add(setting);
1601 settingsAdded.addElement(featureType);
1605 // is groups actually supposed to be a map here ?
1606 Iterator<String> en = fr.getFeatureGroups().iterator();
1607 Vector<String> groupsAdded = new Vector<>();
1608 while (en.hasNext())
1610 String grp = en.next();
1611 if (groupsAdded.contains(grp))
1615 Group g = new Group();
1617 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1620 fs.getGroup().add(g);
1621 groupsAdded.addElement(grp);
1623 // jms.setFeatureSettings(fs);
1624 object.setFeatureSettings(fs);
1627 if (av.hasHiddenColumns())
1629 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1630 .getHiddenColumns();
1633 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1637 Iterator<int[]> hiddenRegions = hidden.iterator();
1638 while (hiddenRegions.hasNext())
1640 int[] region = hiddenRegions.next();
1641 HiddenColumns hc = new HiddenColumns();
1642 hc.setStart(region[0]);
1643 hc.setEnd(region[1]);
1644 // view.addHiddenColumns(hc);
1645 view.getHiddenColumns().add(hc);
1649 if (calcIdSet.size() > 0)
1651 for (String calcId : calcIdSet)
1653 if (calcId.trim().length() > 0)
1655 CalcIdParam cidp = createCalcIdParam(calcId, av);
1656 // Some calcIds have no parameters.
1659 // view.addCalcIdParam(cidp);
1660 view.getCalcIdParam().add(cidp);
1666 // jms.addViewport(view);
1667 object.getViewport().add(view);
1669 // object.setJalviewModelSequence(jms);
1670 // object.getVamsasModel().addSequenceSet(vamsasSet);
1671 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1673 if (jout != null && fileName != null)
1675 // We may not want to write the object to disk,
1676 // eg we can copy the alignViewport to a new view object
1677 // using save and then load
1680 fileName = fileName.replace('\\', '/');
1681 System.out.println("Writing jar entry " + fileName);
1682 JarEntry entry = new JarEntry(fileName);
1683 jout.putNextEntry(entry);
1684 PrintWriter pout = new PrintWriter(
1685 new OutputStreamWriter(jout, UTF_8));
1686 JAXBContext jaxbContext = JAXBContext
1687 .newInstance(JalviewModel.class);
1688 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1690 // output pretty printed
1691 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1692 jaxbMarshaller.marshal(
1693 new ObjectFactory().createJalviewModel(object), pout);
1695 // jaxbMarshaller.marshal(object, pout);
1696 // marshaller.marshal(object);
1699 } catch (Exception ex)
1701 // TODO: raise error in GUI if marshalling failed.
1702 System.err.println("Error writing Jalview project");
1703 ex.printStackTrace();
1710 * Writes PCA viewer attributes and computed values to an XML model object and
1711 * adds it to the JalviewModel. Any exceptions are reported by logging.
1713 protected void savePCA(PCAPanel panel, JalviewModel object)
1717 PcaViewer viewer = new PcaViewer();
1718 viewer.setHeight(panel.getHeight());
1719 viewer.setWidth(panel.getWidth());
1720 viewer.setXpos(panel.getX());
1721 viewer.setYpos(panel.getY());
1722 viewer.setTitle(panel.getTitle());
1723 PCAModel pcaModel = panel.getPcaModel();
1724 viewer.setScoreModelName(pcaModel.getScoreModelName());
1725 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1726 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1727 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1729 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1730 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1731 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1732 SeqPointMin spmin = new SeqPointMin();
1733 spmin.setXPos(spMin[0]);
1734 spmin.setYPos(spMin[1]);
1735 spmin.setZPos(spMin[2]);
1736 viewer.setSeqPointMin(spmin);
1737 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1738 SeqPointMax spmax = new SeqPointMax();
1739 spmax.setXPos(spMax[0]);
1740 spmax.setYPos(spMax[1]);
1741 spmax.setZPos(spMax[2]);
1742 viewer.setSeqPointMax(spmax);
1743 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1744 viewer.setLinkToAllViews(
1745 panel.getRotatableCanvas().isApplyToAllViews());
1746 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1747 viewer.setIncludeGaps(sp.includeGaps());
1748 viewer.setMatchGaps(sp.matchGaps());
1749 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1750 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1753 * sequence points on display
1755 for (jalview.datamodel.SequencePoint spt : pcaModel
1756 .getSequencePoints())
1758 SequencePoint point = new SequencePoint();
1759 point.setSequenceRef(seqHash(spt.getSequence()));
1760 point.setXPos(spt.coord.x);
1761 point.setYPos(spt.coord.y);
1762 point.setZPos(spt.coord.z);
1763 viewer.getSequencePoint().add(point);
1767 * (end points of) axes on display
1769 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1772 Axis axis = new Axis();
1776 viewer.getAxis().add(axis);
1780 * raw PCA data (note we are not restoring PCA inputs here -
1781 * alignment view, score model, similarity parameters)
1783 PcaDataType data = new PcaDataType();
1784 viewer.setPcaData(data);
1785 PCA pca = pcaModel.getPcaData();
1787 DoubleMatrix pm = new DoubleMatrix();
1788 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1789 data.setPairwiseMatrix(pm);
1791 DoubleMatrix tm = new DoubleMatrix();
1792 saveDoubleMatrix(pca.getTridiagonal(), tm);
1793 data.setTridiagonalMatrix(tm);
1795 DoubleMatrix eigenMatrix = new DoubleMatrix();
1796 data.setEigenMatrix(eigenMatrix);
1797 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1799 object.getPcaViewer().add(viewer);
1800 } catch (Throwable t)
1802 Cache.log.error("Error saving PCA: " + t.getMessage());
1807 * Stores values from a matrix into an XML element, including (if present) the
1812 * @see #loadDoubleMatrix(DoubleMatrix)
1814 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1816 xmlMatrix.setRows(m.height());
1817 xmlMatrix.setColumns(m.width());
1818 for (int i = 0; i < m.height(); i++)
1820 DoubleVector row = new DoubleVector();
1821 for (int j = 0; j < m.width(); j++)
1823 row.getV().add(m.getValue(i, j));
1825 xmlMatrix.getRow().add(row);
1827 if (m.getD() != null)
1829 DoubleVector dVector = new DoubleVector();
1830 for (double d : m.getD())
1832 dVector.getV().add(d);
1834 xmlMatrix.setD(dVector);
1836 if (m.getE() != null)
1838 DoubleVector eVector = new DoubleVector();
1839 for (double e : m.getE())
1841 eVector.getV().add(e);
1843 xmlMatrix.setE(eVector);
1848 * Loads XML matrix data into a new Matrix object, including the D and/or E
1849 * vectors (if present)
1853 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1855 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1857 int rows = mData.getRows();
1858 double[][] vals = new double[rows][];
1860 for (int i = 0; i < rows; i++)
1862 List<Double> dVector = mData.getRow().get(i).getV();
1863 vals[i] = new double[dVector.size()];
1865 for (Double d : dVector)
1871 MatrixI m = new Matrix(vals);
1873 if (mData.getD() != null)
1875 List<Double> dVector = mData.getD().getV();
1876 double[] vec = new double[dVector.size()];
1878 for (Double d : dVector)
1884 if (mData.getE() != null)
1886 List<Double> dVector = mData.getE().getV();
1887 double[] vec = new double[dVector.size()];
1889 for (Double d : dVector)
1900 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1901 * for each viewer, with
1903 * <li>viewer geometry (position, size, split pane divider location)</li>
1904 * <li>index of the selected structure in the viewer (currently shows gapped
1906 * <li>the id of the annotation holding RNA secondary structure</li>
1907 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1909 * Varna viewer state is also written out (in native Varna XML) to separate
1910 * project jar entries. A separate entry is written for each RNA structure
1911 * displayed, with the naming convention
1913 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1921 * @param storeDataset
1923 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1924 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1925 boolean storeDataset)
1927 if (Desktop.desktop == null)
1931 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1932 for (int f = frames.length - 1; f > -1; f--)
1934 if (frames[f] instanceof AppVarna)
1936 AppVarna varna = (AppVarna) frames[f];
1938 * link the sequence to every viewer that is showing it and is linked to
1939 * its alignment panel
1941 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1943 String viewId = varna.getViewId();
1944 RnaViewer rna = new RnaViewer();
1945 rna.setViewId(viewId);
1946 rna.setTitle(varna.getTitle());
1947 rna.setXpos(varna.getX());
1948 rna.setYpos(varna.getY());
1949 rna.setWidth(varna.getWidth());
1950 rna.setHeight(varna.getHeight());
1951 rna.setDividerLocation(varna.getDividerLocation());
1952 rna.setSelectedRna(varna.getSelectedIndex());
1953 // jseq.addRnaViewer(rna);
1954 jseq.getRnaViewer().add(rna);
1957 * Store each Varna panel's state once in the project per sequence.
1958 * First time through only (storeDataset==false)
1960 // boolean storeSessions = false;
1961 // String sequenceViewId = viewId + seqsToIds.get(jds);
1962 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1964 // viewIds.add(sequenceViewId);
1965 // storeSessions = true;
1967 for (RnaModel model : varna.getModels())
1969 if (model.seq == jds)
1972 * VARNA saves each view (sequence or alignment secondary
1973 * structure, gapped or trimmed) as a separate XML file
1975 String jarEntryName = rnaSessions.get(model);
1976 if (jarEntryName == null)
1979 String varnaStateFile = varna.getStateInfo(model.rna);
1980 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1981 copyFileToJar(jout, varnaStateFile, jarEntryName);
1982 rnaSessions.put(model, jarEntryName);
1984 SecondaryStructure ss = new SecondaryStructure();
1985 String annotationId = varna.getAnnotation(jds).annotationId;
1986 ss.setAnnotationId(annotationId);
1987 ss.setViewerState(jarEntryName);
1988 ss.setGapped(model.gapped);
1989 ss.setTitle(model.title);
1990 // rna.addSecondaryStructure(ss);
1991 rna.getSecondaryStructure().add(ss);
2000 * Copy the contents of a file to a new entry added to the output jar
2004 * @param jarEntryName
2006 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2007 String jarEntryName)
2009 DataInputStream dis = null;
2012 File file = new File(infilePath);
2013 if (file.exists() && jout != null)
2015 dis = new DataInputStream(new FileInputStream(file));
2016 byte[] data = new byte[(int) file.length()];
2017 dis.readFully(data);
2018 writeJarEntry(jout, jarEntryName, data);
2020 } catch (Exception ex)
2022 ex.printStackTrace();
2030 } catch (IOException e)
2039 * Write the data to a new entry of given name in the output jar file
2042 * @param jarEntryName
2044 * @throws IOException
2046 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2047 byte[] data) throws IOException
2051 jarEntryName = jarEntryName.replace('\\','/');
2052 System.out.println("Writing jar entry " + jarEntryName);
2053 jout.putNextEntry(new JarEntry(jarEntryName));
2054 DataOutputStream dout = new DataOutputStream(jout);
2055 dout.write(data, 0, data.length);
2062 * Save the state of a structure viewer
2067 * the archive XML element under which to save the state
2070 * @param matchedFile
2074 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2075 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2076 String matchedFile, StructureViewerBase viewFrame)
2078 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2081 * Look for any bindings for this viewer to the PDB file of interest
2082 * (including part matches excluding chain id)
2084 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2086 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2087 final String pdbId = pdbentry.getId();
2088 if (!pdbId.equals(entry.getId())
2089 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2090 .startsWith(pdbId.toLowerCase())))
2093 * not interested in a binding to a different PDB entry here
2097 if (matchedFile == null)
2099 matchedFile = pdbentry.getFile();
2101 else if (!matchedFile.equals(pdbentry.getFile()))
2104 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2105 + pdbentry.getFile());
2109 // can get at it if the ID
2110 // match is ambiguous (e.g.
2113 for (int smap = 0; smap < viewFrame.getBinding()
2114 .getSequence()[peid].length; smap++)
2116 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2117 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2119 StructureState state = new StructureState();
2120 state.setVisible(true);
2121 state.setXpos(viewFrame.getX());
2122 state.setYpos(viewFrame.getY());
2123 state.setWidth(viewFrame.getWidth());
2124 state.setHeight(viewFrame.getHeight());
2125 final String viewId = viewFrame.getViewId();
2126 state.setViewId(viewId);
2127 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2128 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2129 state.setColourByJmol(viewFrame.isColouredByViewer());
2130 state.setType(viewFrame.getViewerType().toString());
2131 // pdb.addStructureState(state);
2132 pdb.getStructureState().add(state);
2140 * Populates the AnnotationColourScheme xml for save. This captures the
2141 * settings of the options in the 'Colour by Annotation' dialog.
2144 * @param userColours
2148 private AnnotationColourScheme constructAnnotationColours(
2149 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2152 AnnotationColourScheme ac = new AnnotationColourScheme();
2153 ac.setAboveThreshold(acg.getAboveThreshold());
2154 ac.setThreshold(acg.getAnnotationThreshold());
2155 // 2.10.2 save annotationId (unique) not annotation label
2156 ac.setAnnotation(acg.getAnnotation().annotationId);
2157 if (acg.getBaseColour() instanceof UserColourScheme)
2160 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2165 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2168 ac.setMaxColour(acg.getMaxColour().getRGB());
2169 ac.setMinColour(acg.getMinColour().getRGB());
2170 ac.setPerSequence(acg.isSeqAssociated());
2171 ac.setPredefinedColours(acg.isPredefinedColours());
2175 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2176 IdentityHashMap<SequenceGroup, String> groupRefs,
2177 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2178 SequenceSet vamsasSet)
2181 for (int i = 0; i < aa.length; i++)
2183 Annotation an = new Annotation();
2185 AlignmentAnnotation annotation = aa[i];
2186 if (annotation.annotationId != null)
2188 annotationIds.put(annotation.annotationId, annotation);
2191 an.setId(annotation.annotationId);
2193 an.setVisible(annotation.visible);
2195 an.setDescription(annotation.description);
2197 if (annotation.sequenceRef != null)
2199 // 2.9 JAL-1781 xref on sequence id rather than name
2200 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2202 if (annotation.groupRef != null)
2204 String groupIdr = groupRefs.get(annotation.groupRef);
2205 if (groupIdr == null)
2207 // make a locally unique String
2208 groupRefs.put(annotation.groupRef,
2209 groupIdr = ("" + System.currentTimeMillis()
2210 + annotation.groupRef.getName()
2211 + groupRefs.size()));
2213 an.setGroupRef(groupIdr.toString());
2216 // store all visualization attributes for annotation
2217 an.setGraphHeight(annotation.graphHeight);
2218 an.setCentreColLabels(annotation.centreColLabels);
2219 an.setScaleColLabels(annotation.scaleColLabel);
2220 an.setShowAllColLabels(annotation.showAllColLabels);
2221 an.setBelowAlignment(annotation.belowAlignment);
2223 if (annotation.graph > 0)
2226 an.setGraphType(annotation.graph);
2227 an.setGraphGroup(annotation.graphGroup);
2228 if (annotation.getThreshold() != null)
2230 ThresholdLine line = new ThresholdLine();
2231 line.setLabel(annotation.getThreshold().label);
2232 line.setValue(annotation.getThreshold().value);
2233 line.setColour(annotation.getThreshold().colour.getRGB());
2234 an.setThresholdLine(line);
2242 an.setLabel(annotation.label);
2244 if (annotation == av.getAlignmentQualityAnnot()
2245 || annotation == av.getAlignmentConservationAnnotation()
2246 || annotation == av.getAlignmentConsensusAnnotation()
2247 || annotation.autoCalculated)
2249 // new way of indicating autocalculated annotation -
2250 an.setAutoCalculated(annotation.autoCalculated);
2252 if (annotation.hasScore())
2254 an.setScore(annotation.getScore());
2257 if (annotation.getCalcId() != null)
2259 calcIdSet.add(annotation.getCalcId());
2260 an.setCalcId(annotation.getCalcId());
2262 if (annotation.hasProperties())
2264 for (String pr : annotation.getProperties())
2266 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2268 prop.setValue(annotation.getProperty(pr));
2269 // an.addProperty(prop);
2270 an.getProperty().add(prop);
2274 AnnotationElement ae;
2275 if (annotation.annotations != null)
2277 an.setScoreOnly(false);
2278 for (int a = 0; a < annotation.annotations.length; a++)
2280 if ((annotation == null) || (annotation.annotations[a] == null))
2285 ae = new AnnotationElement();
2286 if (annotation.annotations[a].description != null)
2288 ae.setDescription(annotation.annotations[a].description);
2290 if (annotation.annotations[a].displayCharacter != null)
2292 ae.setDisplayCharacter(
2293 annotation.annotations[a].displayCharacter);
2296 if (!Float.isNaN(annotation.annotations[a].value))
2298 ae.setValue(annotation.annotations[a].value);
2302 if (annotation.annotations[a].secondaryStructure > ' ')
2304 ae.setSecondaryStructure(
2305 annotation.annotations[a].secondaryStructure + "");
2308 if (annotation.annotations[a].colour != null
2309 && annotation.annotations[a].colour != java.awt.Color.black)
2311 ae.setColour(annotation.annotations[a].colour.getRGB());
2314 // an.addAnnotationElement(ae);
2315 an.getAnnotationElement().add(ae);
2316 if (annotation.autoCalculated)
2318 // only write one non-null entry into the annotation row -
2319 // sufficient to get the visualization attributes necessary to
2327 an.setScoreOnly(true);
2329 if (!storeDS || (storeDS && !annotation.autoCalculated))
2331 // skip autocalculated annotation - these are only provided for
2333 // vamsasSet.addAnnotation(an);
2334 vamsasSet.getAnnotation().add(an);
2340 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2342 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2343 if (settings != null)
2345 CalcIdParam vCalcIdParam = new CalcIdParam();
2346 vCalcIdParam.setCalcId(calcId);
2347 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2348 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2349 // generic URI allowing a third party to resolve another instance of the
2350 // service used for this calculation
2351 for (String url : settings.getServiceURLs())
2353 // vCalcIdParam.addServiceURL(urls);
2354 vCalcIdParam.getServiceURL().add(url);
2356 vCalcIdParam.setVersion("1.0");
2357 if (settings.getPreset() != null)
2359 WsParamSetI setting = settings.getPreset();
2360 vCalcIdParam.setName(setting.getName());
2361 vCalcIdParam.setDescription(setting.getDescription());
2365 vCalcIdParam.setName("");
2366 vCalcIdParam.setDescription("Last used parameters");
2368 // need to be able to recover 1) settings 2) user-defined presets or
2369 // recreate settings from preset 3) predefined settings provided by
2370 // service - or settings that can be transferred (or discarded)
2371 vCalcIdParam.setParameters(
2372 settings.getWsParamFile().replace("\n", "|\\n|"));
2373 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2374 // todo - decide if updateImmediately is needed for any projects.
2376 return vCalcIdParam;
2381 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2384 if (calcIdParam.getVersion().equals("1.0"))
2386 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2387 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2388 .getPreferredServiceFor(calcIds);
2389 if (service != null)
2391 WsParamSetI parmSet = null;
2394 parmSet = service.getParamStore().parseServiceParameterFile(
2395 calcIdParam.getName(), calcIdParam.getDescription(),
2397 calcIdParam.getParameters().replace("|\\n|", "\n"));
2398 } catch (IOException x)
2400 warn("Couldn't parse parameter data for "
2401 + calcIdParam.getCalcId(), x);
2404 List<ArgumentI> argList = null;
2405 if (calcIdParam.getName().length() > 0)
2407 parmSet = service.getParamStore()
2408 .getPreset(calcIdParam.getName());
2409 if (parmSet != null)
2411 // TODO : check we have a good match with settings in AACon -
2412 // otherwise we'll need to create a new preset
2417 argList = parmSet.getArguments();
2420 AAConSettings settings = new AAConSettings(
2421 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2422 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2423 calcIdParam.isNeedsUpdate());
2428 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2432 throw new Error(MessageManager.formatMessage(
2433 "error.unsupported_version_calcIdparam", new Object[]
2434 { calcIdParam.toString() }));
2438 * External mapping between jalview objects and objects yielding a valid and
2439 * unique object ID string. This is null for normal Jalview project IO, but
2440 * non-null when a jalview project is being read or written as part of a
2443 IdentityHashMap jv2vobj = null;
2446 * Construct a unique ID for jvobj using either existing bindings or if none
2447 * exist, the result of the hashcode call for the object.
2450 * jalview data object
2451 * @return unique ID for referring to jvobj
2453 private String makeHashCode(Object jvobj, String altCode)
2455 if (jv2vobj != null)
2457 Object id = jv2vobj.get(jvobj);
2460 return id.toString();
2462 // check string ID mappings
2463 if (jvids2vobj != null && jvobj instanceof String)
2465 id = jvids2vobj.get(jvobj);
2469 return id.toString();
2471 // give up and warn that something has gone wrong
2472 warn("Cannot find ID for object in external mapping : " + jvobj);
2478 * return local jalview object mapped to ID, if it exists
2482 * @return null or object bound to idcode
2484 private Object retrieveExistingObj(String idcode)
2486 if (idcode != null && vobj2jv != null)
2488 return vobj2jv.get(idcode);
2494 * binding from ID strings from external mapping table to jalview data model
2497 private Hashtable vobj2jv;
2499 private Sequence createVamsasSequence(String id, SequenceI jds)
2501 return createVamsasSequence(true, id, jds, null);
2504 private Sequence createVamsasSequence(boolean recurse, String id,
2505 SequenceI jds, SequenceI parentseq)
2507 Sequence vamsasSeq = new Sequence();
2508 vamsasSeq.setId(id);
2509 vamsasSeq.setName(jds.getName());
2510 vamsasSeq.setSequence(jds.getSequenceAsString());
2511 vamsasSeq.setDescription(jds.getDescription());
2512 List<DBRefEntry> dbrefs = null;
2513 if (jds.getDatasetSequence() != null)
2515 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2519 // seqId==dsseqid so we can tell which sequences really are
2520 // dataset sequences only
2521 vamsasSeq.setDsseqid(id);
2522 dbrefs = jds.getDBRefs();
2523 if (parentseq == null)
2530 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2534 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2536 DBRef dbref = new DBRef();
2537 DBRefEntry ref = dbrefs.get(d);
2538 dbref.setSource(ref.getSource());
2539 dbref.setVersion(ref.getVersion());
2540 dbref.setAccessionId(ref.getAccessionId());
2541 if (ref instanceof GeneLocus)
2543 dbref.setLocus(true);
2547 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2549 dbref.setMapping(mp);
2551 vamsasSeq.getDBRef().add(dbref);
2557 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2558 SequenceI parentseq, SequenceI jds, boolean recurse)
2561 if (jmp.getMap() != null)
2565 jalview.util.MapList mlst = jmp.getMap();
2566 List<int[]> r = mlst.getFromRanges();
2567 for (int[] range : r)
2569 MapListFrom mfrom = new MapListFrom();
2570 mfrom.setStart(range[0]);
2571 mfrom.setEnd(range[1]);
2572 // mp.addMapListFrom(mfrom);
2573 mp.getMapListFrom().add(mfrom);
2575 r = mlst.getToRanges();
2576 for (int[] range : r)
2578 MapListTo mto = new MapListTo();
2579 mto.setStart(range[0]);
2580 mto.setEnd(range[1]);
2581 // mp.addMapListTo(mto);
2582 mp.getMapListTo().add(mto);
2584 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2585 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2586 if (jmp.getTo() != null)
2588 // MappingChoice mpc = new MappingChoice();
2590 // check/create ID for the sequence referenced by getTo()
2593 SequenceI ps = null;
2594 if (parentseq != jmp.getTo()
2595 && parentseq.getDatasetSequence() != jmp.getTo())
2597 // chaining dbref rather than a handshaking one
2598 jmpid = seqHash(ps = jmp.getTo());
2602 jmpid = seqHash(ps = parentseq);
2604 // mpc.setDseqFor(jmpid);
2605 mp.setDseqFor(jmpid);
2606 if (!seqRefIds.containsKey(jmpid))
2608 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2609 seqRefIds.put(jmpid, ps);
2613 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2616 // mp.setMappingChoice(mpc);
2622 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2623 List<UserColourScheme> userColours, JalviewModel jm)
2626 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2627 boolean newucs = false;
2628 if (!userColours.contains(ucs))
2630 userColours.add(ucs);
2633 id = "ucs" + userColours.indexOf(ucs);
2636 // actually create the scheme's entry in the XML model
2637 java.awt.Color[] colours = ucs.getColours();
2638 UserColours uc = new UserColours();
2639 // UserColourScheme jbucs = new UserColourScheme();
2640 JalviewUserColours jbucs = new JalviewUserColours();
2642 for (int i = 0; i < colours.length; i++)
2644 Colour col = new Colour();
2645 col.setName(ResidueProperties.aa[i]);
2646 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2647 // jbucs.addColour(col);
2648 jbucs.getColour().add(col);
2650 if (ucs.getLowerCaseColours() != null)
2652 colours = ucs.getLowerCaseColours();
2653 for (int i = 0; i < colours.length; i++)
2655 Colour col = new Colour();
2656 col.setName(ResidueProperties.aa[i].toLowerCase());
2657 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2658 // jbucs.addColour(col);
2659 jbucs.getColour().add(col);
2664 uc.setUserColourScheme(jbucs);
2665 // jm.addUserColours(uc);
2666 jm.getUserColours().add(uc);
2672 jalview.schemes.UserColourScheme getUserColourScheme(
2673 JalviewModel jm, String id)
2675 List<UserColours> uc = jm.getUserColours();
2676 UserColours colours = null;
2678 for (int i = 0; i < uc.length; i++)
2680 if (uc[i].getId().equals(id))
2687 for (UserColours c : uc)
2689 if (c.getId().equals(id))
2696 java.awt.Color[] newColours = new java.awt.Color[24];
2698 for (int i = 0; i < 24; i++)
2700 newColours[i] = new java.awt.Color(Integer.parseInt(
2701 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2702 colours.getUserColourScheme().getColour().get(i).getRGB(),
2706 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2709 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2711 newColours = new java.awt.Color[23];
2712 for (int i = 0; i < 23; i++)
2714 newColours[i] = new java.awt.Color(Integer.parseInt(
2715 colours.getUserColourScheme().getColour().get(i + 24)
2719 ucs.setLowerCaseColours(newColours);
2726 * contains last error message (if any) encountered by XML loader.
2728 String errorMessage = null;
2731 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2732 * exceptions are raised during project XML parsing
2734 public boolean attemptversion1parse = false;
2737 * Load a jalview project archive from a jar file
2740 * - HTTP URL or filename
2742 public AlignFrame loadJalviewAlign(final Object file)
2745 jalview.gui.AlignFrame af = null;
2749 // create list to store references for any new Jmol viewers created
2750 newStructureViewers = new Vector<>();
2751 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2752 // Workaround is to make sure caller implements the JarInputStreamProvider
2754 // so we can re-open the jar input stream for each entry.
2756 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2757 af = loadJalviewAlign(jprovider);
2760 af.setMenusForViewport();
2762 } catch (MalformedURLException e)
2764 errorMessage = "Invalid URL format for '" + file + "'";
2770 SwingUtilities.invokeAndWait(new Runnable()
2775 setLoadingFinishedForNewStructureViewers();
2778 } catch (Exception x)
2780 System.err.println("Error loading alignment: " + x.getMessage());
2786 @SuppressWarnings("unused")
2787 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2789 // BH 2018 allow for bytes already attached to File object
2791 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2792 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2795 errorMessage = null;
2796 uniqueSetSuffix = null;
2798 viewportsAdded.clear();
2799 frefedSequence = null;
2801 if (file.startsWith("http://")) {
2802 url = new URL(file);
2804 final URL _url = url;
2805 return new jarInputStreamProvider() {
2808 public JarInputStream getJarInputStream() throws IOException {
2809 if (bytes != null) {
2810 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2811 return new JarInputStream(new ByteArrayInputStream(bytes));
2814 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2815 return new JarInputStream(_url.openStream());
2817 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2818 return new JarInputStream(new FileInputStream(file));
2823 public String getFilename() {
2827 } catch (IOException e) {
2828 e.printStackTrace();
2834 * Recover jalview session from a jalview project archive. Caller may
2835 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2836 * themselves. Any null fields will be initialised with default values,
2837 * non-null fields are left alone.
2842 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2844 errorMessage = null;
2845 if (uniqueSetSuffix == null)
2847 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2849 if (seqRefIds == null)
2853 AlignFrame af = null, _af = null;
2854 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2855 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2856 final String file = jprovider.getFilename();
2859 JarInputStream jin = null;
2860 JarEntry jarentry = null;
2865 jin = jprovider.getJarInputStream();
2866 for (int i = 0; i < entryCount; i++)
2868 jarentry = jin.getNextJarEntry();
2871 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2873 JAXBContext jc = JAXBContext
2874 .newInstance("jalview.xml.binding.jalview");
2875 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2876 .createXMLStreamReader(jin);
2877 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2878 JAXBElement<JalviewModel> jbe = um
2879 .unmarshal(streamReader, JalviewModel.class);
2880 JalviewModel object = jbe.getValue();
2882 if (true) // !skipViewport(object))
2884 _af = loadFromObject(object, file, true, jprovider);
2885 if (_af != null && object.getViewport().size() > 0)
2886 // getJalviewModelSequence().getViewportCount() > 0)
2890 // store a reference to the first view
2893 if (_af.getViewport().isGatherViewsHere())
2895 // if this is a gathered view, keep its reference since
2896 // after gathering views, only this frame will remain
2898 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2901 // Save dataset to register mappings once all resolved
2902 importedDatasets.put(
2903 af.getViewport().getAlignment().getDataset(),
2904 af.getViewport().getAlignment().getDataset());
2909 else if (jarentry != null)
2911 // Some other file here.
2914 } while (jarentry != null);
2915 resolveFrefedSequences();
2916 } catch (IOException ex)
2918 ex.printStackTrace();
2919 errorMessage = "Couldn't locate Jalview XML file : " + file;
2921 "Exception whilst loading jalview XML file : " + ex + "\n");
2922 } catch (Exception ex)
2924 System.err.println("Parsing as Jalview Version 2 file failed.");
2925 ex.printStackTrace(System.err);
2926 if (attemptversion1parse)
2928 // used to attempt to parse as V1 castor-generated xml
2930 if (Desktop.instance != null)
2932 Desktop.instance.stopLoading();
2936 System.out.println("Successfully loaded archive file");
2939 ex.printStackTrace();
2942 "Exception whilst loading jalview XML file : " + ex + "\n");
2943 } catch (OutOfMemoryError e)
2945 // Don't use the OOM Window here
2946 errorMessage = "Out of memory loading jalview XML file";
2947 System.err.println("Out of memory whilst loading jalview XML file");
2948 e.printStackTrace();
2952 * Regather multiple views (with the same sequence set id) to the frame (if
2953 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2954 * views instead of separate frames. Note this doesn't restore a state where
2955 * some expanded views in turn have tabbed views - the last "first tab" read
2956 * in will play the role of gatherer for all.
2958 for (AlignFrame fr : gatherToThisFrame.values())
2960 Desktop.instance.gatherViews(fr);
2963 restoreSplitFrames();
2964 for (AlignmentI ds : importedDatasets.keySet())
2966 if (ds.getCodonFrames() != null)
2968 StructureSelectionManager
2969 .getStructureSelectionManager(Desktop.instance)
2970 .registerMappings(ds.getCodonFrames());
2973 if (errorMessage != null)
2978 if (Desktop.instance != null)
2980 Desktop.instance.stopLoading();
2987 * Try to reconstruct and display SplitFrame windows, where each contains
2988 * complementary dna and protein alignments. Done by pairing up AlignFrame
2989 * objects (created earlier) which have complementary viewport ids associated.
2991 protected void restoreSplitFrames()
2993 List<SplitFrame> gatherTo = new ArrayList<>();
2994 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2995 Map<String, AlignFrame> dna = new HashMap<>();
2998 * Identify the DNA alignments
3000 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3003 AlignFrame af = candidate.getValue();
3004 if (af.getViewport().getAlignment().isNucleotide())
3006 dna.put(candidate.getKey().getId(), af);
3011 * Try to match up the protein complements
3013 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3016 AlignFrame af = candidate.getValue();
3017 if (!af.getViewport().getAlignment().isNucleotide())
3019 String complementId = candidate.getKey().getComplementId();
3020 // only non-null complements should be in the Map
3021 if (complementId != null && dna.containsKey(complementId))
3023 final AlignFrame dnaFrame = dna.get(complementId);
3024 SplitFrame sf = createSplitFrame(dnaFrame, af);
3025 addedToSplitFrames.add(dnaFrame);
3026 addedToSplitFrames.add(af);
3027 dnaFrame.setMenusForViewport();
3028 af.setMenusForViewport();
3029 if (af.getViewport().isGatherViewsHere())
3038 * Open any that we failed to pair up (which shouldn't happen!) as
3039 * standalone AlignFrame's.
3041 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3044 AlignFrame af = candidate.getValue();
3045 if (!addedToSplitFrames.contains(af))
3047 Viewport view = candidate.getKey();
3048 Desktop.addInternalFrame(af, view.getTitle(),
3049 safeInt(view.getWidth()), safeInt(view.getHeight()));
3050 af.setMenusForViewport();
3051 System.err.println("Failed to restore view " + view.getTitle()
3052 + " to split frame");
3057 * Gather back into tabbed views as flagged.
3059 for (SplitFrame sf : gatherTo)
3061 Desktop.instance.gatherViews(sf);
3064 splitFrameCandidates.clear();
3068 * Construct and display one SplitFrame holding DNA and protein alignments.
3071 * @param proteinFrame
3074 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3075 AlignFrame proteinFrame)
3077 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3078 String title = MessageManager.getString("label.linked_view_title");
3079 int width = (int) dnaFrame.getBounds().getWidth();
3080 int height = (int) (dnaFrame.getBounds().getHeight()
3081 + proteinFrame.getBounds().getHeight() + 50);
3084 * SplitFrame location is saved to both enclosed frames
3086 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3087 Desktop.addInternalFrame(splitFrame, title, width, height);
3090 * And compute cDNA consensus (couldn't do earlier with consensus as
3091 * mappings were not yet present)
3093 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3099 * check errorMessage for a valid error message and raise an error box in the
3100 * GUI or write the current errorMessage to stderr and then clear the error
3103 protected void reportErrors()
3105 reportErrors(false);
3108 protected void reportErrors(final boolean saving)
3110 if (errorMessage != null)
3112 final String finalErrorMessage = errorMessage;
3115 javax.swing.SwingUtilities.invokeLater(new Runnable()
3120 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3122 "Error " + (saving ? "saving" : "loading")
3124 JvOptionPane.WARNING_MESSAGE);
3130 System.err.println("Problem loading Jalview file: " + errorMessage);
3133 errorMessage = null;
3136 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3139 * when set, local views will be updated from view stored in JalviewXML
3140 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3141 * sync if this is set to true.
3143 private final boolean updateLocalViews = false;
3146 * Returns the path to a temporary file holding the PDB file for the given PDB
3147 * id. The first time of asking, searches for a file of that name in the
3148 * Jalview project jar, and copies it to a new temporary file. Any repeat
3149 * requests just return the path to the file previously created.
3155 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3158 if (alreadyLoadedPDB.containsKey(pdbId))
3160 return alreadyLoadedPDB.get(pdbId).toString();
3163 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3165 if (tempFile != null)
3167 alreadyLoadedPDB.put(pdbId, tempFile);
3173 * Copies the jar entry of given name to a new temporary file and returns the
3174 * path to the file, or null if the entry is not found.
3177 * @param jarEntryName
3179 * a prefix for the temporary file name, must be at least three
3181 * @param suffixModel
3182 * null or original file - so new file can be given the same suffix
3186 protected String copyJarEntry(jarInputStreamProvider jprovider,
3187 String jarEntryName, String prefix, String suffixModel)
3189 BufferedReader in = null;
3190 PrintWriter out = null;
3191 String suffix = ".tmp";
3192 if (suffixModel == null)
3194 suffixModel = jarEntryName;
3196 int sfpos = suffixModel.lastIndexOf(".");
3197 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3199 suffix = "." + suffixModel.substring(sfpos + 1);
3203 JarInputStream jin = jprovider.getJarInputStream();
3205 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3206 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3207 * FileInputStream(jprovider)); }
3210 JarEntry entry = null;
3213 entry = jin.getNextJarEntry();
3214 } while (entry != null && !entry.getName().equals(jarEntryName));
3217 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3218 File outFile = File.createTempFile(prefix, suffix);
3219 outFile.deleteOnExit();
3220 out = new PrintWriter(new FileOutputStream(outFile));
3223 while ((data = in.readLine()) != null)
3228 String t = outFile.getAbsolutePath();
3233 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3235 } catch (Exception ex)
3237 ex.printStackTrace();
3245 } catch (IOException e)
3259 private class JvAnnotRow
3261 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3268 * persisted version of annotation row from which to take vis properties
3270 public jalview.datamodel.AlignmentAnnotation template;
3273 * original position of the annotation row in the alignment
3279 * Load alignment frame from jalview XML DOM object
3281 * @param jalviewModel
3284 * filename source string
3285 * @param loadTreesAndStructures
3286 * when false only create Viewport
3288 * data source provider
3289 * @return alignment frame created from view stored in DOM
3291 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3292 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3294 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3295 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3297 // JalviewModelSequence jms = object.getJalviewModelSequence();
3299 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3301 Viewport view = (jalviewModel.getViewport().size() > 0)
3302 ? jalviewModel.getViewport().get(0)
3305 // ////////////////////////////////
3306 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3309 // If we just load in the same jar file again, the sequenceSetId
3310 // will be the same, and we end up with multiple references
3311 // to the same sequenceSet. We must modify this id on load
3312 // so that each load of the file gives a unique id
3315 * used to resolve correct alignment dataset for alignments with multiple
3318 String uniqueSeqSetId = null;
3319 String viewId = null;
3322 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3323 viewId = (view.getId() == null ? null
3324 : view.getId() + uniqueSetSuffix);
3327 // ////////////////////////////////
3330 List<SequenceI> hiddenSeqs = null;
3332 List<SequenceI> tmpseqs = new ArrayList<>();
3334 boolean multipleView = false;
3335 SequenceI referenceseqForView = null;
3336 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3337 List<JSeq> jseqs = jalviewModel.getJSeq();
3338 int vi = 0; // counter in vamsasSeq array
3339 for (int i = 0; i < jseqs.size(); i++)
3341 JSeq jseq = jseqs.get(i);
3342 String seqId = jseq.getId();
3344 SequenceI tmpSeq = seqRefIds.get(seqId);
3347 if (!incompleteSeqs.containsKey(seqId))
3349 // may not need this check, but keep it for at least 2.9,1 release
3350 if (tmpSeq.getStart() != jseq.getStart()
3351 || tmpSeq.getEnd() != jseq.getEnd())
3354 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3355 tmpSeq.getName(), tmpSeq.getStart(),
3356 tmpSeq.getEnd(), jseq.getStart(),
3362 incompleteSeqs.remove(seqId);
3364 if (vamsasSeqs.size() > vi
3365 && vamsasSeqs.get(vi).getId().equals(seqId))
3367 // most likely we are reading a dataset XML document so
3368 // update from vamsasSeq section of XML for this sequence
3369 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3370 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3371 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3376 // reading multiple views, so vamsasSeq set is a subset of JSeq
3377 multipleView = true;
3379 tmpSeq.setStart(jseq.getStart());
3380 tmpSeq.setEnd(jseq.getEnd());
3381 tmpseqs.add(tmpSeq);
3385 Sequence vamsasSeq = vamsasSeqs.get(vi);
3386 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3387 vamsasSeq.getSequence());
3388 tmpSeq.setDescription(vamsasSeq.getDescription());
3389 tmpSeq.setStart(jseq.getStart());
3390 tmpSeq.setEnd(jseq.getEnd());
3391 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3392 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3393 tmpseqs.add(tmpSeq);
3397 if (safeBoolean(jseq.isViewreference()))
3399 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3402 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3404 if (hiddenSeqs == null)
3406 hiddenSeqs = new ArrayList<>();
3409 hiddenSeqs.add(tmpSeq);
3414 // Create the alignment object from the sequence set
3415 // ///////////////////////////////
3416 SequenceI[] orderedSeqs = tmpseqs
3417 .toArray(new SequenceI[tmpseqs.size()]);
3419 AlignmentI al = null;
3420 // so we must create or recover the dataset alignment before going further
3421 // ///////////////////////////////
3422 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3424 // older jalview projects do not have a dataset - so creat alignment and
3426 al = new Alignment(orderedSeqs);
3427 al.setDataset(null);
3431 boolean isdsal = jalviewModel.getViewport().isEmpty();
3434 // we are importing a dataset record, so
3435 // recover reference to an alignment already materialsed as dataset
3436 al = getDatasetFor(vamsasSet.getDatasetId());
3440 // materialse the alignment
3441 al = new Alignment(orderedSeqs);
3445 addDatasetRef(vamsasSet.getDatasetId(), al);
3448 // finally, verify all data in vamsasSet is actually present in al
3449 // passing on flag indicating if it is actually a stored dataset
3450 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3453 if (referenceseqForView != null)
3455 al.setSeqrep(referenceseqForView);
3457 // / Add the alignment properties
3458 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3460 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3462 al.setProperty(ssp.getKey(), ssp.getValue());
3465 // ///////////////////////////////
3467 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3470 // load sequence features, database references and any associated PDB
3471 // structures for the alignment
3473 // prior to 2.10, this part would only be executed the first time a
3474 // sequence was encountered, but not afterwards.
3475 // now, for 2.10 projects, this is also done if the xml doc includes
3476 // dataset sequences not actually present in any particular view.
3478 for (int i = 0; i < vamsasSeqs.size(); i++)
3480 JSeq jseq = jseqs.get(i);
3481 if (jseq.getFeatures().size() > 0)
3483 List<Feature> features = jseq.getFeatures();
3484 for (int f = 0; f < features.size(); f++)
3486 Feature feat = features.get(f);
3487 SequenceFeature sf = new SequenceFeature(feat.getType(),
3488 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3489 safeFloat(feat.getScore()), feat.getFeatureGroup());
3490 sf.setStatus(feat.getStatus());
3493 * load any feature attributes - include map-valued attributes
3495 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3496 for (int od = 0; od < feat.getOtherData().size(); od++)
3498 OtherData keyValue = feat.getOtherData().get(od);
3499 String attributeName = keyValue.getKey();
3500 String attributeValue = keyValue.getValue();
3501 if (attributeName.startsWith("LINK"))
3503 sf.addLink(attributeValue);
3507 String subAttribute = keyValue.getKey2();
3508 if (subAttribute == null)
3510 // simple string-valued attribute
3511 sf.setValue(attributeName, attributeValue);
3515 // attribute 'key' has sub-attribute 'key2'
3516 if (!mapAttributes.containsKey(attributeName))
3518 mapAttributes.put(attributeName, new HashMap<>());
3520 mapAttributes.get(attributeName).put(subAttribute,
3525 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3528 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3531 // adds feature to datasequence's feature set (since Jalview 2.10)
3532 al.getSequenceAt(i).addSequenceFeature(sf);
3535 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3537 // adds dbrefs to datasequence's set (since Jalview 2.10)
3539 al.getSequenceAt(i).getDatasetSequence() == null
3540 ? al.getSequenceAt(i)
3541 : al.getSequenceAt(i).getDatasetSequence(),
3544 if (jseq.getPdbids().size() > 0)
3546 List<Pdbids> ids = jseq.getPdbids();
3547 for (int p = 0; p < ids.size(); p++)
3549 Pdbids pdbid = ids.get(p);
3550 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3551 entry.setId(pdbid.getId());
3552 if (pdbid.getType() != null)
3554 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3556 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3560 entry.setType(PDBEntry.Type.FILE);
3563 // jprovider is null when executing 'New View'
3564 if (pdbid.getFile() != null && jprovider != null)
3566 if (!pdbloaded.containsKey(pdbid.getFile()))
3568 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3573 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3577 if (pdbid.getPdbentryItem() != null)
3579 for (PdbentryItem item : pdbid.getPdbentryItem())
3581 for (Property pr : item.getProperty())
3583 entry.setProperty(pr.getName(), pr.getValue());
3588 for (Property prop : pdbid.getProperty())
3590 entry.setProperty(prop.getName(), prop.getValue());
3592 StructureSelectionManager
3593 .getStructureSelectionManager(Desktop.instance)
3594 .registerPDBEntry(entry);
3595 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3596 if (al.getSequenceAt(i).getDatasetSequence() != null)
3598 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3602 al.getSequenceAt(i).addPDBId(entry);
3607 } // end !multipleview
3609 // ///////////////////////////////
3610 // LOAD SEQUENCE MAPPINGS
3612 if (vamsasSet.getAlcodonFrame().size() > 0)
3614 // TODO Potentially this should only be done once for all views of an
3616 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3617 for (int i = 0; i < alc.size(); i++)
3619 AlignedCodonFrame cf = new AlignedCodonFrame();
3620 if (alc.get(i).getAlcodMap().size() > 0)
3622 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3623 for (int m = 0; m < maps.size(); m++)
3625 AlcodMap map = maps.get(m);
3626 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3628 jalview.datamodel.Mapping mapping = null;
3629 // attach to dna sequence reference.
3630 if (map.getMapping() != null)
3632 mapping = addMapping(map.getMapping());
3633 if (dnaseq != null && mapping.getTo() != null)
3635 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3641 newAlcodMapRef(map.getDnasq(), cf, mapping));
3645 al.addCodonFrame(cf);
3650 // ////////////////////////////////
3652 List<JvAnnotRow> autoAlan = new ArrayList<>();
3655 * store any annotations which forward reference a group's ID
3657 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3659 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3661 List<Annotation> an = vamsasSet.getAnnotation();
3663 for (int i = 0; i < an.size(); i++)
3665 Annotation annotation = an.get(i);
3668 * test if annotation is automatically calculated for this view only
3670 boolean autoForView = false;
3671 if (annotation.getLabel().equals("Quality")
3672 || annotation.getLabel().equals("Conservation")
3673 || annotation.getLabel().equals("Consensus"))
3675 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3677 // JAXB has no has() test; schema defaults value to false
3678 // if (!annotation.hasAutoCalculated())
3680 // annotation.setAutoCalculated(true);
3683 if (autoForView || annotation.isAutoCalculated())
3685 // remove ID - we don't recover annotation from other views for
3686 // view-specific annotation
3687 annotation.setId(null);
3690 // set visibility for other annotation in this view
3691 String annotationId = annotation.getId();
3692 if (annotationId != null && annotationIds.containsKey(annotationId))
3694 AlignmentAnnotation jda = annotationIds.get(annotationId);
3695 // in principle Visible should always be true for annotation displayed
3696 // in multiple views
3697 if (annotation.isVisible() != null)
3699 jda.visible = annotation.isVisible();
3702 al.addAnnotation(jda);
3706 // Construct new annotation from model.
3707 List<AnnotationElement> ae = annotation.getAnnotationElement();
3708 jalview.datamodel.Annotation[] anot = null;
3709 java.awt.Color firstColour = null;
3711 if (!annotation.isScoreOnly())
3713 anot = new jalview.datamodel.Annotation[al.getWidth()];
3714 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3716 AnnotationElement annElement = ae.get(aa);
3717 anpos = annElement.getPosition();
3719 if (anpos >= anot.length)
3724 float value = safeFloat(annElement.getValue());
3725 anot[anpos] = new jalview.datamodel.Annotation(
3726 annElement.getDisplayCharacter(),
3727 annElement.getDescription(),
3728 (annElement.getSecondaryStructure() == null
3729 || annElement.getSecondaryStructure()
3733 .getSecondaryStructure()
3736 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3737 if (firstColour == null)
3739 firstColour = anot[anpos].colour;
3743 jalview.datamodel.AlignmentAnnotation jaa = null;
3745 if (annotation.isGraph())
3747 float llim = 0, hlim = 0;
3748 // if (autoForView || an[i].isAutoCalculated()) {
3751 jaa = new jalview.datamodel.AlignmentAnnotation(
3752 annotation.getLabel(), annotation.getDescription(), anot,
3753 llim, hlim, safeInt(annotation.getGraphType()));
3755 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3756 jaa._linecolour = firstColour;
3757 if (annotation.getThresholdLine() != null)
3759 jaa.setThreshold(new jalview.datamodel.GraphLine(
3760 safeFloat(annotation.getThresholdLine().getValue()),
3761 annotation.getThresholdLine().getLabel(),
3762 new java.awt.Color(safeInt(
3763 annotation.getThresholdLine().getColour()))));
3765 if (autoForView || annotation.isAutoCalculated())
3767 // Hardwire the symbol display line to ensure that labels for
3768 // histograms are displayed
3774 jaa = new jalview.datamodel.AlignmentAnnotation(
3775 annotation.getLabel(), annotation.getDescription(), anot);
3776 jaa._linecolour = firstColour;
3778 // register new annotation
3779 if (annotation.getId() != null)
3781 annotationIds.put(annotation.getId(), jaa);
3782 jaa.annotationId = annotation.getId();
3784 // recover sequence association
3785 String sequenceRef = annotation.getSequenceRef();
3786 if (sequenceRef != null)
3788 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3789 SequenceI sequence = seqRefIds.get(sequenceRef);
3790 if (sequence == null)
3792 // in pre-2.9 projects sequence ref is to sequence name
3793 sequence = al.findName(sequenceRef);
3795 if (sequence != null)
3797 jaa.createSequenceMapping(sequence, 1, true);
3798 sequence.addAlignmentAnnotation(jaa);
3801 // and make a note of any group association
3802 if (annotation.getGroupRef() != null
3803 && annotation.getGroupRef().length() > 0)
3805 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3806 .get(annotation.getGroupRef());
3809 aal = new ArrayList<>();
3810 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3815 if (annotation.getScore() != null)
3817 jaa.setScore(annotation.getScore().doubleValue());
3819 if (annotation.isVisible() != null)
3821 jaa.visible = annotation.isVisible().booleanValue();
3824 if (annotation.isCentreColLabels() != null)
3826 jaa.centreColLabels = annotation.isCentreColLabels()
3830 if (annotation.isScaleColLabels() != null)
3832 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3834 if (annotation.isAutoCalculated())
3836 // newer files have an 'autoCalculated' flag and store calculation
3837 // state in viewport properties
3838 jaa.autoCalculated = true; // means annotation will be marked for
3839 // update at end of load.
3841 if (annotation.getGraphHeight() != null)
3843 jaa.graphHeight = annotation.getGraphHeight().intValue();
3845 jaa.belowAlignment = annotation.isBelowAlignment();
3846 jaa.setCalcId(annotation.getCalcId());
3847 if (annotation.getProperty().size() > 0)
3849 for (Annotation.Property prop : annotation
3852 jaa.setProperty(prop.getName(), prop.getValue());
3855 if (jaa.autoCalculated)
3857 autoAlan.add(new JvAnnotRow(i, jaa));
3860 // if (!autoForView)
3862 // add autocalculated group annotation and any user created annotation
3864 al.addAnnotation(jaa);
3868 // ///////////////////////
3870 // Create alignment markup and styles for this view
3871 if (jalviewModel.getJGroup().size() > 0)
3873 List<JGroup> groups = jalviewModel.getJGroup();
3874 boolean addAnnotSchemeGroup = false;
3875 for (int i = 0; i < groups.size(); i++)
3877 JGroup jGroup = groups.get(i);
3878 ColourSchemeI cs = null;
3879 if (jGroup.getColour() != null)
3881 if (jGroup.getColour().startsWith("ucs"))
3883 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3885 else if (jGroup.getColour().equals("AnnotationColourGradient")
3886 && jGroup.getAnnotationColours() != null)
3888 addAnnotSchemeGroup = true;
3892 cs = ColourSchemeProperty.getColourScheme(null, al,
3893 jGroup.getColour());
3896 int pidThreshold = safeInt(jGroup.getPidThreshold());
3898 Vector<SequenceI> seqs = new Vector<>();
3900 for (int s = 0; s < jGroup.getSeq().size(); s++)
3902 String seqId = jGroup.getSeq().get(s);
3903 SequenceI ts = seqRefIds.get(seqId);
3907 seqs.addElement(ts);
3911 if (seqs.size() < 1)
3916 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3917 safeBoolean(jGroup.isDisplayBoxes()),
3918 safeBoolean(jGroup.isDisplayText()),
3919 safeBoolean(jGroup.isColourText()),
3920 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3921 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3922 sg.getGroupColourScheme()
3923 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3924 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3926 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3927 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3928 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3929 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3930 // attributes with a default in the schema are never null
3931 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3932 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3933 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3934 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3935 if (jGroup.getConsThreshold() != null
3936 && jGroup.getConsThreshold().intValue() != 0)
3938 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3941 c.verdict(false, 25);
3942 sg.cs.setConservation(c);
3945 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3947 // re-instate unique group/annotation row reference
3948 List<AlignmentAnnotation> jaal = groupAnnotRefs
3949 .get(jGroup.getId());
3952 for (AlignmentAnnotation jaa : jaal)
3955 if (jaa.autoCalculated)
3957 // match up and try to set group autocalc alignment row for this
3959 if (jaa.label.startsWith("Consensus for "))
3961 sg.setConsensus(jaa);
3963 // match up and try to set group autocalc alignment row for this
3965 if (jaa.label.startsWith("Conservation for "))
3967 sg.setConservationRow(jaa);
3974 if (addAnnotSchemeGroup)
3976 // reconstruct the annotation colourscheme
3977 sg.setColourScheme(constructAnnotationColour(
3978 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3984 // only dataset in this model, so just return.
3987 // ///////////////////////////////
3990 AlignFrame af = null;
3991 AlignViewport av = null;
3992 // now check to see if we really need to create a new viewport.
3993 if (multipleView && viewportsAdded.size() == 0)
3995 // We recovered an alignment for which a viewport already exists.
3996 // TODO: fix up any settings necessary for overlaying stored state onto
3997 // state recovered from another document. (may not be necessary).
3998 // we may need a binding from a viewport in memory to one recovered from
4000 // and then recover its containing af to allow the settings to be applied.
4001 // TODO: fix for vamsas demo
4003 "About to recover a viewport for existing alignment: Sequence set ID is "
4005 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4006 if (seqsetobj != null)
4008 if (seqsetobj instanceof String)
4010 uniqueSeqSetId = (String) seqsetobj;
4012 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4018 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4024 * indicate that annotation colours are applied across all groups (pre
4025 * Jalview 2.8.1 behaviour)
4027 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4028 jalviewModel.getVersion());
4030 AlignmentPanel ap = null;
4031 boolean isnewview = true;
4034 // Check to see if this alignment already has a view id == viewId
4035 jalview.gui.AlignmentPanel views[] = Desktop
4036 .getAlignmentPanels(uniqueSeqSetId);
4037 if (views != null && views.length > 0)
4039 for (int v = 0; v < views.length; v++)
4041 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4043 // recover the existing alignpanel, alignframe, viewport
4044 af = views[v].alignFrame;
4047 // TODO: could even skip resetting view settings if we don't want to
4048 // change the local settings from other jalview processes
4057 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4058 uniqueSeqSetId, viewId, autoAlan);
4059 av = af.getViewport();
4064 * Load any trees, PDB structures and viewers
4066 * Not done if flag is false (when this method is used for New View)
4068 if (loadTreesAndStructures)
4070 loadTrees(jalviewModel, view, af, av, ap);
4071 loadPCAViewers(jalviewModel, ap);
4072 loadPDBStructures(jprovider, jseqs, af, ap);
4073 loadRnaViewers(jprovider, jseqs, ap);
4075 // and finally return.
4080 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4081 * panel is restored from separate jar entries, two (gapped and trimmed) per
4082 * sequence and secondary structure.
4084 * Currently each viewer shows just one sequence and structure (gapped and
4085 * trimmed), however this method is designed to support multiple sequences or
4086 * structures in viewers if wanted in future.
4092 private void loadRnaViewers(jarInputStreamProvider jprovider,
4093 List<JSeq> jseqs, AlignmentPanel ap)
4096 * scan the sequences for references to viewers; create each one the first
4097 * time it is referenced, add Rna models to existing viewers
4099 for (JSeq jseq : jseqs)
4101 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4103 RnaViewer viewer = jseq.getRnaViewer().get(i);
4104 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4107 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4109 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4110 SequenceI seq = seqRefIds.get(jseq.getId());
4111 AlignmentAnnotation ann = this.annotationIds
4112 .get(ss.getAnnotationId());
4115 * add the structure to the Varna display (with session state copied
4116 * from the jar to a temporary file)
4118 boolean gapped = safeBoolean(ss.isGapped());
4119 String rnaTitle = ss.getTitle();
4120 String sessionState = ss.getViewerState();
4121 String tempStateFile = copyJarEntry(jprovider, sessionState,
4123 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4124 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4126 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4132 * Locate and return an already instantiated matching AppVarna, or create one
4136 * @param viewIdSuffix
4140 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4141 String viewIdSuffix, AlignmentPanel ap)
4144 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4145 * if load is repeated
4147 String postLoadId = viewer.getViewId() + viewIdSuffix;
4148 for (JInternalFrame frame : getAllFrames())
4150 if (frame instanceof AppVarna)
4152 AppVarna varna = (AppVarna) frame;
4153 if (postLoadId.equals(varna.getViewId()))
4155 // this viewer is already instantiated
4156 // could in future here add ap as another 'parent' of the
4157 // AppVarna window; currently just 1-to-many
4164 * viewer not found - make it
4166 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4167 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4168 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4169 safeInt(viewer.getDividerLocation()));
4170 AppVarna varna = new AppVarna(model, ap);
4176 * Load any saved trees
4184 protected void loadTrees(JalviewModel jm, Viewport view,
4185 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4187 // TODO result of automated refactoring - are all these parameters needed?
4190 for (int t = 0; t < jm.getTree().size(); t++)
4193 Tree tree = jm.getTree().get(t);
4195 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4198 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4199 tree.getTitle(), safeInt(tree.getWidth()),
4200 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4201 safeInt(tree.getYpos()));
4202 if (tree.getId() != null)
4204 // perhaps bind the tree id to something ?
4209 // update local tree attributes ?
4210 // TODO: should check if tp has been manipulated by user - if so its
4211 // settings shouldn't be modified
4212 tp.setTitle(tree.getTitle());
4213 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4214 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4215 safeInt(tree.getHeight())));
4216 tp.setViewport(av); // af.viewport;
4217 // TODO: verify 'associate with all views' works still
4218 tp.getTreeCanvas().setViewport(av); // af.viewport;
4219 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4221 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4224 warn("There was a problem recovering stored Newick tree: \n"
4225 + tree.getNewick());
4229 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4230 tp.fitToWindow_actionPerformed(null);
4232 if (tree.getFontName() != null)
4235 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4236 safeInt(tree.getFontSize())));
4241 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4242 safeInt(view.getFontSize())));
4245 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4246 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4247 tp.showDistances(safeBoolean(tree.isShowDistances()));
4249 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4251 if (safeBoolean(tree.isCurrentTree()))
4253 af.getViewport().setCurrentTree(tp.getTree());
4257 } catch (Exception ex)
4259 ex.printStackTrace();
4264 * Load and link any saved structure viewers.
4271 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4272 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4275 * Run through all PDB ids on the alignment, and collect mappings between
4276 * distinct view ids and all sequences referring to that view.
4278 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4280 for (int i = 0; i < jseqs.size(); i++)
4282 JSeq jseq = jseqs.get(i);
4283 if (jseq.getPdbids().size() > 0)
4285 List<Pdbids> ids = jseq.getPdbids();
4286 for (int p = 0; p < ids.size(); p++)
4288 Pdbids pdbid = ids.get(p);
4289 final int structureStateCount = pdbid.getStructureState().size();
4290 for (int s = 0; s < structureStateCount; s++)
4292 // check to see if we haven't already created this structure view
4293 final StructureState structureState = pdbid
4294 .getStructureState().get(s);
4295 String sviewid = (structureState.getViewId() == null) ? null
4296 : structureState.getViewId() + uniqueSetSuffix;
4297 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4298 // Originally : pdbid.getFile()
4299 // : TODO: verify external PDB file recovery still works in normal
4300 // jalview project load
4302 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4303 jpdb.setId(pdbid.getId());
4305 int x = safeInt(structureState.getXpos());
4306 int y = safeInt(structureState.getYpos());
4307 int width = safeInt(structureState.getWidth());
4308 int height = safeInt(structureState.getHeight());
4310 // Probably don't need to do this anymore...
4311 // Desktop.desktop.getComponentAt(x, y);
4312 // TODO: NOW: check that this recovers the PDB file correctly.
4313 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4315 jalview.datamodel.SequenceI seq = seqRefIds
4316 .get(jseq.getId() + "");
4317 if (sviewid == null)
4319 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4322 if (!structureViewers.containsKey(sviewid))
4324 structureViewers.put(sviewid,
4325 new StructureViewerModel(x, y, width, height, false,
4326 false, true, structureState.getViewId(),
4327 structureState.getType()));
4328 // Legacy pre-2.7 conversion JAL-823 :
4329 // do not assume any view has to be linked for colour by
4333 // assemble String[] { pdb files }, String[] { id for each
4334 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4335 // seqs_file 2}, boolean[] {
4336 // linkAlignPanel,superposeWithAlignpanel}} from hash
4337 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4338 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4339 || structureState.isAlignwithAlignPanel());
4342 * Default colour by linked panel to false if not specified (e.g.
4343 * for pre-2.7 projects)
4345 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4346 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4347 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4350 * Default colour by viewer to true if not specified (e.g. for
4353 boolean colourByViewer = jmoldat.isColourByViewer();
4354 colourByViewer &= structureState.isColourByJmol();
4355 jmoldat.setColourByViewer(colourByViewer);
4357 if (jmoldat.getStateData().length() < structureState
4358 .getValue()/*Content()*/.length())
4360 jmoldat.setStateData(structureState.getValue());// Content());
4362 if (pdbid.getFile() != null)
4364 File mapkey = new File(pdbid.getFile());
4365 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4366 if (seqstrmaps == null)
4368 jmoldat.getFileData().put(mapkey,
4369 seqstrmaps = jmoldat.new StructureData(pdbFile,
4372 if (!seqstrmaps.getSeqList().contains(seq))
4374 seqstrmaps.getSeqList().add(seq);
4380 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");
4387 // Instantiate the associated structure views
4388 for (Entry<String, StructureViewerModel> entry : structureViewers
4393 createOrLinkStructureViewer(entry, af, ap, jprovider);
4394 } catch (Exception e)
4397 "Error loading structure viewer: " + e.getMessage());
4398 // failed - try the next one
4410 protected void createOrLinkStructureViewer(
4411 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4412 AlignmentPanel ap, jarInputStreamProvider jprovider)
4414 final StructureViewerModel stateData = viewerData.getValue();
4417 * Search for any viewer windows already open from other alignment views
4418 * that exactly match the stored structure state
4420 StructureViewerBase comp = findMatchingViewer(viewerData);
4424 linkStructureViewer(ap, comp, stateData);
4429 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4430 * "viewer_"+stateData.viewId
4432 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4434 createChimeraViewer(viewerData, af, jprovider);
4439 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4441 createJmolViewer(viewerData, af, jprovider);
4446 * Create a new Chimera viewer.
4452 protected void createChimeraViewer(
4453 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4454 jarInputStreamProvider jprovider)
4456 StructureViewerModel data = viewerData.getValue();
4457 String chimeraSessionFile = data.getStateData();
4460 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4462 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4463 * 'uniquified' sviewid used to reconstruct the viewer here
4465 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4466 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4469 Set<Entry<File, StructureData>> fileData = data.getFileData()
4471 List<PDBEntry> pdbs = new ArrayList<>();
4472 List<SequenceI[]> allseqs = new ArrayList<>();
4473 for (Entry<File, StructureData> pdb : fileData)
4475 String filePath = pdb.getValue().getFilePath();
4476 String pdbId = pdb.getValue().getPdbId();
4477 // pdbs.add(new PDBEntry(filePath, pdbId));
4478 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4479 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4480 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4484 boolean colourByChimera = data.isColourByViewer();
4485 boolean colourBySequence = data.isColourWithAlignPanel();
4487 // TODO use StructureViewer as a factory here, see JAL-1761
4488 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4489 final SequenceI[][] seqsArray = allseqs
4490 .toArray(new SequenceI[allseqs.size()][]);
4491 String newViewId = viewerData.getKey();
4493 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4494 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4495 colourBySequence, newViewId);
4496 cvf.setSize(data.getWidth(), data.getHeight());
4497 cvf.setLocation(data.getX(), data.getY());
4501 * Create a new Jmol window. First parse the Jmol state to translate filenames
4502 * loaded into the view, and record the order in which files are shown in the
4503 * Jmol view, so we can add the sequence mappings in same order.
4509 protected void createJmolViewer(
4510 final Entry<String, StructureViewerModel> viewerData,
4511 AlignFrame af, jarInputStreamProvider jprovider)
4513 final StructureViewerModel svattrib = viewerData.getValue();
4514 String state = svattrib.getStateData();
4517 * Pre-2.9: state element value is the Jmol state string
4519 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4522 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4524 state = readJarEntry(jprovider,
4525 getViewerJarEntryName(svattrib.getViewId()));
4528 List<String> pdbfilenames = new ArrayList<>();
4529 List<SequenceI[]> seqmaps = new ArrayList<>();
4530 List<String> pdbids = new ArrayList<>();
4531 StringBuilder newFileLoc = new StringBuilder(64);
4532 int cp = 0, ncp, ecp;
4533 Map<File, StructureData> oldFiles = svattrib.getFileData();
4534 while ((ncp = state.indexOf("load ", cp)) > -1)
4538 // look for next filename in load statement
4539 newFileLoc.append(state.substring(cp,
4540 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4541 String oldfilenam = state.substring(ncp,
4542 ecp = state.indexOf("\"", ncp));
4543 // recover the new mapping data for this old filename
4544 // have to normalize filename - since Jmol and jalview do
4546 // translation differently.
4547 StructureData filedat = oldFiles.get(new File(oldfilenam));
4548 if (filedat == null)
4550 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4551 filedat = oldFiles.get(new File(reformatedOldFilename));
4553 newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath()));
4554 pdbfilenames.add(filedat.getFilePath());
4555 pdbids.add(filedat.getPdbId());
4556 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4557 newFileLoc.append("\"");
4558 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4559 // look for next file statement.
4560 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4564 // just append rest of state
4565 newFileLoc.append(state.substring(cp));
4569 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4570 newFileLoc = new StringBuilder(state);
4571 newFileLoc.append("; load append ");
4572 for (File id : oldFiles.keySet())
4574 // add this and any other pdb files that should be present in
4576 StructureData filedat = oldFiles.get(id);
4577 newFileLoc.append(filedat.getFilePath());
4578 pdbfilenames.add(filedat.getFilePath());
4579 pdbids.add(filedat.getPdbId());
4580 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4581 newFileLoc.append(" \"");
4582 newFileLoc.append(filedat.getFilePath());
4583 newFileLoc.append("\"");
4586 newFileLoc.append(";");
4589 if (newFileLoc.length() == 0)
4593 int histbug = newFileLoc.indexOf("history = ");
4597 * change "history = [true|false];" to "history = [1|0];"
4600 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4601 String val = (diff == -1) ? null
4602 : newFileLoc.substring(histbug, diff);
4603 if (val != null && val.length() >= 4)
4605 if (val.contains("e")) // eh? what can it be?
4607 if (val.trim().equals("true"))
4615 newFileLoc.replace(histbug, diff, val);
4620 final String[] pdbf = pdbfilenames
4621 .toArray(new String[pdbfilenames.size()]);
4622 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4623 final SequenceI[][] sq = seqmaps
4624 .toArray(new SequenceI[seqmaps.size()][]);
4625 final String fileloc = newFileLoc.toString();
4626 final String sviewid = viewerData.getKey();
4627 final AlignFrame alf = af;
4628 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4629 svattrib.getWidth(), svattrib.getHeight());
4632 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4637 JalviewStructureDisplayI sview = null;
4640 sview = new StructureViewer(
4641 alf.alignPanel.getStructureSelectionManager())
4642 .createView(StructureViewer.ViewerType.JMOL,
4643 pdbf, id, sq, alf.alignPanel, svattrib,
4644 fileloc, rect, sviewid);
4645 addNewStructureViewer(sview);
4646 } catch (OutOfMemoryError ex)
4648 new OOMWarning("restoring structure view for PDB id " + id,
4649 (OutOfMemoryError) ex.getCause());
4650 if (sview != null && sview.isVisible())
4652 sview.closeViewer(false);
4653 sview.setVisible(false);
4659 } catch (InvocationTargetException ex)
4661 warn("Unexpected error when opening Jmol view.", ex);
4663 } catch (InterruptedException e)
4665 // e.printStackTrace();
4671 * Generates a name for the entry in the project jar file to hold state
4672 * information for a structure viewer
4677 protected String getViewerJarEntryName(String viewId)
4679 return VIEWER_PREFIX + viewId;
4683 * Returns any open frame that matches given structure viewer data. The match
4684 * is based on the unique viewId, or (for older project versions) the frame's
4690 protected StructureViewerBase findMatchingViewer(
4691 Entry<String, StructureViewerModel> viewerData)
4693 final String sviewid = viewerData.getKey();
4694 final StructureViewerModel svattrib = viewerData.getValue();
4695 StructureViewerBase comp = null;
4696 JInternalFrame[] frames = getAllFrames();
4697 for (JInternalFrame frame : frames)
4699 if (frame instanceof StructureViewerBase)
4702 * Post jalview 2.4 schema includes structure view id
4704 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4707 comp = (StructureViewerBase) frame;
4708 break; // break added in 2.9
4711 * Otherwise test for matching position and size of viewer frame
4713 else if (frame.getX() == svattrib.getX()
4714 && frame.getY() == svattrib.getY()
4715 && frame.getHeight() == svattrib.getHeight()
4716 && frame.getWidth() == svattrib.getWidth())
4718 comp = (StructureViewerBase) frame;
4719 // no break in faint hope of an exact match on viewId
4727 * Link an AlignmentPanel to an existing structure viewer.
4732 * @param useinViewerSuperpos
4733 * @param usetoColourbyseq
4734 * @param viewerColouring
4736 protected void linkStructureViewer(AlignmentPanel ap,
4737 StructureViewerBase viewer, StructureViewerModel stateData)
4739 // NOTE: if the jalview project is part of a shared session then
4740 // view synchronization should/could be done here.
4742 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4743 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4744 final boolean viewerColouring = stateData.isColourByViewer();
4745 Map<File, StructureData> oldFiles = stateData.getFileData();
4748 * Add mapping for sequences in this view to an already open viewer
4750 final AAStructureBindingModel binding = viewer.getBinding();
4751 for (File id : oldFiles.keySet())
4753 // add this and any other pdb files that should be present in the
4755 StructureData filedat = oldFiles.get(id);
4756 String pdbFile = filedat.getFilePath();
4757 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4758 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4760 binding.addSequenceForStructFile(pdbFile, seq);
4762 // and add the AlignmentPanel's reference to the view panel
4763 viewer.addAlignmentPanel(ap);
4764 if (useinViewerSuperpos)
4766 viewer.useAlignmentPanelForSuperposition(ap);
4770 viewer.excludeAlignmentPanelForSuperposition(ap);
4772 if (usetoColourbyseq)
4774 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4778 viewer.excludeAlignmentPanelForColourbyseq(ap);
4783 * Get all frames within the Desktop.
4787 protected JInternalFrame[] getAllFrames()
4789 JInternalFrame[] frames = null;
4790 // TODO is this necessary - is it safe - risk of hanging?
4795 frames = Desktop.desktop.getAllFrames();
4796 } catch (ArrayIndexOutOfBoundsException e)
4798 // occasional No such child exceptions are thrown here...
4802 } catch (InterruptedException f)
4806 } while (frames == null);
4811 * Answers true if 'version' is equal to or later than 'supported', where each
4812 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4813 * changes. Development and test values for 'version' are leniently treated
4817 * - minimum version we are comparing against
4819 * - version of data being processsed
4822 public static boolean isVersionStringLaterThan(String supported,
4825 if (supported == null || version == null
4826 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4827 || version.equalsIgnoreCase("Test")
4828 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4830 System.err.println("Assuming project file with "
4831 + (version == null ? "null" : version)
4832 + " is compatible with Jalview version " + supported);
4837 return StringUtils.compareVersions(version, supported, "b") >= 0;
4841 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4843 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4845 if (newStructureViewers != null)
4847 sview.getBinding().setFinishedLoadingFromArchive(false);
4848 newStructureViewers.add(sview);
4852 protected void setLoadingFinishedForNewStructureViewers()
4854 if (newStructureViewers != null)
4856 for (JalviewStructureDisplayI sview : newStructureViewers)
4858 sview.getBinding().setFinishedLoadingFromArchive(true);
4860 newStructureViewers.clear();
4861 newStructureViewers = null;
4865 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4866 List<SequenceI> hiddenSeqs, AlignmentI al,
4867 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4868 String viewId, List<JvAnnotRow> autoAlan)
4870 AlignFrame af = null;
4871 af = new AlignFrame(al, safeInt(view.getWidth()),
4872 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4876 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4877 // System.out.println("Jalview2XML AF " + e);
4878 // super.processKeyEvent(e);
4885 af.setFileName(file, FileFormat.Jalview);
4887 final AlignViewport viewport = af.getViewport();
4888 for (int i = 0; i < JSEQ.size(); i++)
4890 int colour = safeInt(JSEQ.get(i).getColour());
4891 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4897 viewport.setColourByReferenceSeq(true);
4898 viewport.setDisplayReferenceSeq(true);
4901 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4903 if (view.getSequenceSetId() != null)
4905 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4907 viewport.setSequenceSetId(uniqueSeqSetId);
4910 // propagate shared settings to this new view
4911 viewport.setHistoryList(av.getHistoryList());
4912 viewport.setRedoList(av.getRedoList());
4916 viewportsAdded.put(uniqueSeqSetId, viewport);
4918 // TODO: check if this method can be called repeatedly without
4919 // side-effects if alignpanel already registered.
4920 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4922 // apply Hidden regions to view.
4923 if (hiddenSeqs != null)
4925 for (int s = 0; s < JSEQ.size(); s++)
4927 SequenceGroup hidden = new SequenceGroup();
4928 boolean isRepresentative = false;
4929 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4931 isRepresentative = true;
4932 SequenceI sequenceToHide = al
4933 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4934 hidden.addSequence(sequenceToHide, false);
4935 // remove from hiddenSeqs list so we don't try to hide it twice
4936 hiddenSeqs.remove(sequenceToHide);
4938 if (isRepresentative)
4940 SequenceI representativeSequence = al.getSequenceAt(s);
4941 hidden.addSequence(representativeSequence, false);
4942 viewport.hideRepSequences(representativeSequence, hidden);
4946 SequenceI[] hseqs = hiddenSeqs
4947 .toArray(new SequenceI[hiddenSeqs.size()]);
4948 viewport.hideSequence(hseqs);
4951 // recover view properties and display parameters
4953 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4954 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4955 final int pidThreshold = safeInt(view.getPidThreshold());
4956 viewport.setThreshold(pidThreshold);
4958 viewport.setColourText(safeBoolean(view.isShowColourText()));
4961 .setConservationSelected(
4962 safeBoolean(view.isConservationSelected()));
4963 viewport.setIncrement(safeInt(view.getConsThreshold()));
4964 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4965 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4966 viewport.setFont(new Font(view.getFontName(),
4967 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4969 ViewStyleI vs = viewport.getViewStyle();
4970 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4971 viewport.setViewStyle(vs);
4972 // TODO: allow custom charWidth/Heights to be restored by updating them
4973 // after setting font - which means set above to false
4974 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4975 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4976 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4978 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4980 viewport.setShowText(safeBoolean(view.isShowText()));
4982 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4983 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4984 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4985 viewport.setShowUnconserved(view.isShowUnconserved());
4986 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4988 if (view.getViewName() != null)
4990 viewport.setViewName(view.getViewName());
4991 af.setInitialTabVisible();
4993 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4994 safeInt(view.getWidth()), safeInt(view.getHeight()));
4995 // startSeq set in af.alignPanel.updateLayout below
4996 af.alignPanel.updateLayout();
4997 ColourSchemeI cs = null;
4998 // apply colourschemes
4999 if (view.getBgColour() != null)
5001 if (view.getBgColour().startsWith("ucs"))
5003 cs = getUserColourScheme(jm, view.getBgColour());
5005 else if (view.getBgColour().startsWith("Annotation"))
5007 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5008 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5015 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5016 view.getBgColour());
5021 * turn off 'alignment colour applies to all groups'
5022 * while restoring global colour scheme
5024 viewport.setColourAppliesToAllGroups(false);
5025 viewport.setGlobalColourScheme(cs);
5026 viewport.getResidueShading().setThreshold(pidThreshold,
5027 view.isIgnoreGapsinConsensus());
5028 viewport.getResidueShading()
5029 .setConsensus(viewport.getSequenceConsensusHash());
5030 if (safeBoolean(view.isConservationSelected()) && cs != null)
5032 viewport.getResidueShading()
5033 .setConservationInc(safeInt(view.getConsThreshold()));
5035 af.changeColour(cs);
5036 viewport.setColourAppliesToAllGroups(true);
5039 .setShowSequenceFeatures(
5040 safeBoolean(view.isShowSequenceFeatures()));
5042 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5043 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5044 viewport.setFollowHighlight(view.isFollowHighlight());
5045 viewport.followSelection = view.isFollowSelection();
5046 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5047 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5048 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5049 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5050 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5051 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5052 viewport.setShowGroupConservation(view.isShowGroupConservation());
5053 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5054 viewport.setShowComplementFeaturesOnTop(
5055 view.isShowComplementFeaturesOnTop());
5057 // recover feature settings
5058 if (jm.getFeatureSettings() != null)
5060 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5061 .getFeatureRenderer();
5062 FeaturesDisplayed fdi;
5063 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5064 String[] renderOrder = new String[jm.getFeatureSettings()
5065 .getSetting().size()];
5066 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5067 Map<String, Float> featureOrder = new Hashtable<>();
5069 for (int fs = 0; fs < jm.getFeatureSettings()
5070 .getSetting().size(); fs++)
5072 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5073 String featureType = setting.getType();
5076 * restore feature filters (if any)
5078 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5080 if (filters != null)
5082 FeatureMatcherSetI filter = Jalview2XML
5083 .parseFilter(featureType, filters);
5084 if (!filter.isEmpty())
5086 fr.setFeatureFilter(featureType, filter);
5091 * restore feature colour scheme
5093 Color maxColour = new Color(setting.getColour());
5094 if (setting.getMincolour() != null)
5097 * minColour is always set unless a simple colour
5098 * (including for colour by label though it doesn't use it)
5100 Color minColour = new Color(setting.getMincolour().intValue());
5101 Color noValueColour = minColour;
5102 NoValueColour noColour = setting.getNoValueColour();
5103 if (noColour == NoValueColour.NONE)
5105 noValueColour = null;
5107 else if (noColour == NoValueColour.MAX)
5109 noValueColour = maxColour;
5111 float min = safeFloat(safeFloat(setting.getMin()));
5112 float max = setting.getMax() == null ? 1f
5113 : setting.getMax().floatValue();
5114 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5116 noValueColour, min, max);
5117 if (setting.getAttributeName().size() > 0)
5119 gc.setAttributeName(setting.getAttributeName().toArray(
5120 new String[setting.getAttributeName().size()]));
5122 if (setting.getThreshold() != null)
5124 gc.setThreshold(setting.getThreshold().floatValue());
5125 int threshstate = safeInt(setting.getThreshstate());
5126 // -1 = None, 0 = Below, 1 = Above threshold
5127 if (threshstate == 0)
5129 gc.setBelowThreshold(true);
5131 else if (threshstate == 1)
5133 gc.setAboveThreshold(true);
5136 gc.setAutoScaled(true); // default
5137 if (setting.isAutoScale() != null)
5139 gc.setAutoScaled(setting.isAutoScale());
5141 if (setting.isColourByLabel() != null)
5143 gc.setColourByLabel(setting.isColourByLabel());
5145 // and put in the feature colour table.
5146 featureColours.put(featureType, gc);
5150 featureColours.put(featureType,
5151 new FeatureColour(maxColour));
5153 renderOrder[fs] = featureType;
5154 if (setting.getOrder() != null)
5156 featureOrder.put(featureType, setting.getOrder().floatValue());
5160 featureOrder.put(featureType, Float.valueOf(
5161 fs / jm.getFeatureSettings().getSetting().size()));
5163 if (safeBoolean(setting.isDisplay()))
5165 fdi.setVisible(featureType);
5168 Map<String, Boolean> fgtable = new Hashtable<>();
5169 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5171 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5172 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5174 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5175 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5176 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5177 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5178 fgtable, featureColours, 1.0f, featureOrder);
5179 fr.transferSettings(frs);
5182 if (view.getHiddenColumns().size() > 0)
5184 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5186 final HiddenColumns hc = view.getHiddenColumns().get(c);
5187 viewport.hideColumns(safeInt(hc.getStart()),
5188 safeInt(hc.getEnd()) /* +1 */);
5191 if (view.getCalcIdParam() != null)
5193 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5195 if (calcIdParam != null)
5197 if (recoverCalcIdParam(calcIdParam, viewport))
5202 warn("Couldn't recover parameters for "
5203 + calcIdParam.getCalcId());
5208 af.setMenusFromViewport(viewport);
5209 af.setTitle(view.getTitle());
5210 // TODO: we don't need to do this if the viewport is aready visible.
5212 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5213 * has a 'cdna/protein complement' view, in which case save it in order to
5214 * populate a SplitFrame once all views have been read in.
5216 String complementaryViewId = view.getComplementId();
5217 if (complementaryViewId == null)
5219 Dimension dim = Platform.getDimIfEmbedded(af,
5220 safeInt(view.getWidth()), safeInt(view.getHeight()));
5221 Desktop.addInternalFrame(af, view.getTitle(), dim.width, dim.height);
5222 // recompute any autoannotation
5223 af.alignPanel.updateAnnotation(false, true);
5224 reorderAutoannotation(af, al, autoAlan);
5225 af.alignPanel.alignmentChanged();
5229 splitFrameCandidates.put(view, af);
5235 * Reads saved data to restore Colour by Annotation settings
5237 * @param viewAnnColour
5241 * @param checkGroupAnnColour
5244 private ColourSchemeI constructAnnotationColour(
5245 AnnotationColourScheme viewAnnColour, AlignFrame af,
5246 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5248 boolean propagateAnnColour = false;
5249 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5251 if (checkGroupAnnColour && al.getGroups() != null
5252 && al.getGroups().size() > 0)
5254 // pre 2.8.1 behaviour
5255 // check to see if we should transfer annotation colours
5256 propagateAnnColour = true;
5257 for (SequenceGroup sg : al.getGroups())
5259 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5261 propagateAnnColour = false;
5267 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5269 String annotationId = viewAnnColour.getAnnotation();
5270 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5273 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5275 if (matchedAnnotation == null
5276 && annAlignment.getAlignmentAnnotation() != null)
5278 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5281 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5283 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5288 if (matchedAnnotation == null)
5290 System.err.println("Failed to match annotation colour scheme for "
5294 if (matchedAnnotation.getThreshold() == null)
5296 matchedAnnotation.setThreshold(
5297 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5298 "Threshold", Color.black));
5301 AnnotationColourGradient cs = null;
5302 if (viewAnnColour.getColourScheme().equals("None"))
5304 cs = new AnnotationColourGradient(matchedAnnotation,
5305 new Color(safeInt(viewAnnColour.getMinColour())),
5306 new Color(safeInt(viewAnnColour.getMaxColour())),
5307 safeInt(viewAnnColour.getAboveThreshold()));
5309 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5311 cs = new AnnotationColourGradient(matchedAnnotation,
5312 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5313 safeInt(viewAnnColour.getAboveThreshold()));
5317 cs = new AnnotationColourGradient(matchedAnnotation,
5318 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5319 viewAnnColour.getColourScheme()),
5320 safeInt(viewAnnColour.getAboveThreshold()));
5323 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5324 boolean useOriginalColours = safeBoolean(
5325 viewAnnColour.isPredefinedColours());
5326 cs.setSeqAssociated(perSequenceOnly);
5327 cs.setPredefinedColours(useOriginalColours);
5329 if (propagateAnnColour && al.getGroups() != null)
5331 // Also use these settings for all the groups
5332 for (int g = 0; g < al.getGroups().size(); g++)
5334 SequenceGroup sg = al.getGroups().get(g);
5335 if (sg.getGroupColourScheme() == null)
5340 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5341 matchedAnnotation, sg.getColourScheme(),
5342 safeInt(viewAnnColour.getAboveThreshold()));
5343 sg.setColourScheme(groupScheme);
5344 groupScheme.setSeqAssociated(perSequenceOnly);
5345 groupScheme.setPredefinedColours(useOriginalColours);
5351 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5352 List<JvAnnotRow> autoAlan)
5354 // copy over visualization settings for autocalculated annotation in the
5356 if (al.getAlignmentAnnotation() != null)
5359 * Kludge for magic autoannotation names (see JAL-811)
5361 String[] magicNames = new String[] { "Consensus", "Quality",
5363 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5364 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5365 for (String nm : magicNames)
5367 visan.put(nm, nullAnnot);
5369 for (JvAnnotRow auan : autoAlan)
5371 visan.put(auan.template.label
5372 + (auan.template.getCalcId() == null ? ""
5373 : "\t" + auan.template.getCalcId()),
5376 int hSize = al.getAlignmentAnnotation().length;
5377 List<JvAnnotRow> reorder = new ArrayList<>();
5378 // work through any autoCalculated annotation already on the view
5379 // removing it if it should be placed in a different location on the
5380 // annotation panel.
5381 List<String> remains = new ArrayList<>(visan.keySet());
5382 for (int h = 0; h < hSize; h++)
5384 jalview.datamodel.AlignmentAnnotation jalan = al
5385 .getAlignmentAnnotation()[h];
5386 if (jalan.autoCalculated)
5389 JvAnnotRow valan = visan.get(k = jalan.label);
5390 if (jalan.getCalcId() != null)
5392 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5397 // delete the auto calculated row from the alignment
5398 al.deleteAnnotation(jalan, false);
5402 if (valan != nullAnnot)
5404 if (jalan != valan.template)
5406 // newly created autoannotation row instance
5407 // so keep a reference to the visible annotation row
5408 // and copy over all relevant attributes
5409 if (valan.template.graphHeight >= 0)
5412 jalan.graphHeight = valan.template.graphHeight;
5414 jalan.visible = valan.template.visible;
5416 reorder.add(new JvAnnotRow(valan.order, jalan));
5421 // Add any (possibly stale) autocalculated rows that were not appended to
5422 // the view during construction
5423 for (String other : remains)
5425 JvAnnotRow othera = visan.get(other);
5426 if (othera != nullAnnot && othera.template.getCalcId() != null
5427 && othera.template.getCalcId().length() > 0)
5429 reorder.add(othera);
5432 // now put the automatic annotation in its correct place
5433 int s = 0, srt[] = new int[reorder.size()];
5434 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5435 for (JvAnnotRow jvar : reorder)
5438 srt[s++] = jvar.order;
5441 jalview.util.QuickSort.sort(srt, rws);
5442 // and re-insert the annotation at its correct position
5443 for (JvAnnotRow jvar : rws)
5445 al.addAnnotation(jvar.template, jvar.order);
5447 af.alignPanel.adjustAnnotationHeight();
5451 Hashtable skipList = null;
5454 * TODO remove this method
5457 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5458 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5459 * throw new Error("Implementation Error. No skipList defined for this
5460 * Jalview2XML instance."); } return (AlignFrame)
5461 * skipList.get(view.getSequenceSetId()); }
5465 * Check if the Jalview view contained in object should be skipped or not.
5468 * @return true if view's sequenceSetId is a key in skipList
5470 private boolean skipViewport(JalviewModel object)
5472 if (skipList == null)
5476 String id = object.getViewport().get(0).getSequenceSetId();
5477 if (skipList.containsKey(id))
5479 if (Cache.log != null && Cache.log.isDebugEnabled())
5481 Cache.log.debug("Skipping seuqence set id " + id);
5488 public void addToSkipList(AlignFrame af)
5490 if (skipList == null)
5492 skipList = new Hashtable();
5494 skipList.put(af.getViewport().getSequenceSetId(), af);
5497 public void clearSkipList()
5499 if (skipList != null)
5506 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5507 boolean ignoreUnrefed, String uniqueSeqSetId)
5509 jalview.datamodel.AlignmentI ds = getDatasetFor(
5510 vamsasSet.getDatasetId());
5511 AlignmentI xtant_ds = ds;
5512 if (xtant_ds == null)
5514 // good chance we are about to create a new dataset, but check if we've
5515 // seen some of the dataset sequence IDs before.
5516 // TODO: skip this check if we are working with project generated by
5517 // version 2.11 or later
5518 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5519 if (xtant_ds != null)
5522 addDatasetRef(vamsasSet.getDatasetId(), ds);
5525 Vector dseqs = null;
5528 // recovering an alignment View
5529 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5530 if (seqSetDS != null)
5532 if (ds != null && ds != seqSetDS)
5534 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5535 + " - CDS/Protein crossreference data may be lost");
5536 if (xtant_ds != null)
5538 // This can only happen if the unique sequence set ID was bound to a
5539 // dataset that did not contain any of the sequences in the view
5540 // currently being restored.
5541 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.");
5545 addDatasetRef(vamsasSet.getDatasetId(), ds);
5550 // try even harder to restore dataset
5551 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5552 // create a list of new dataset sequences
5553 dseqs = new Vector();
5555 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5557 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5558 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5560 // create a new dataset
5563 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5564 dseqs.copyInto(dsseqs);
5565 ds = new jalview.datamodel.Alignment(dsseqs);
5566 debug("Created new dataset " + vamsasSet.getDatasetId()
5567 + " for alignment " + System.identityHashCode(al));
5568 addDatasetRef(vamsasSet.getDatasetId(), ds);
5570 // set the dataset for the newly imported alignment.
5571 if (al.getDataset() == null && !ignoreUnrefed)
5574 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5575 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5577 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5581 * XML dataset sequence ID to materialised dataset reference
5583 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5586 * @return the first materialised dataset reference containing a dataset
5587 * sequence referenced in the given view
5589 * - sequences from the view
5591 AlignmentI checkIfHasDataset(List<Sequence> list)
5593 for (Sequence restoredSeq : list)
5595 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5596 if (datasetFor != null)
5605 * Register ds as the containing dataset for the dataset sequences referenced
5606 * by sequences in list
5609 * - sequences in a view
5612 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5614 for (Sequence restoredSeq : list)
5616 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5617 if (prevDS != null && prevDS != ds)
5619 warn("Dataset sequence appears in many datasets: "
5620 + restoredSeq.getDsseqid());
5621 // TODO: try to merge!
5628 * sequence definition to create/merge dataset sequence for
5632 * vector to add new dataset sequence to
5633 * @param ignoreUnrefed
5634 * - when true, don't create new sequences from vamsasSeq if it's id
5635 * doesn't already have an asssociated Jalview sequence.
5637 * - used to reorder the sequence in the alignment according to the
5638 * vamsasSeq array ordering, to preserve ordering of dataset
5640 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5641 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5643 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5645 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5646 boolean reorder = false;
5647 SequenceI dsq = null;
5648 if (sq != null && sq.getDatasetSequence() != null)
5650 dsq = sq.getDatasetSequence();
5656 if (sq == null && ignoreUnrefed)
5660 String sqid = vamsasSeq.getDsseqid();
5663 // need to create or add a new dataset sequence reference to this sequence
5666 dsq = seqRefIds.get(sqid);
5671 // make a new dataset sequence
5672 dsq = sq.createDatasetSequence();
5675 // make up a new dataset reference for this sequence
5676 sqid = seqHash(dsq);
5678 dsq.setVamsasId(uniqueSetSuffix + sqid);
5679 seqRefIds.put(sqid, dsq);
5684 dseqs.addElement(dsq);
5689 ds.addSequence(dsq);
5695 { // make this dataset sequence sq's dataset sequence
5696 sq.setDatasetSequence(dsq);
5697 // and update the current dataset alignment
5702 if (!dseqs.contains(dsq))
5709 if (ds.findIndex(dsq) < 0)
5711 ds.addSequence(dsq);
5718 // TODO: refactor this as a merge dataset sequence function
5719 // now check that sq (the dataset sequence) sequence really is the union of
5720 // all references to it
5721 // boolean pre = sq.getStart() < dsq.getStart();
5722 // boolean post = sq.getEnd() > dsq.getEnd();
5726 // StringBuffer sb = new StringBuffer();
5727 String newres = jalview.analysis.AlignSeq.extractGaps(
5728 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5729 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5730 && newres.length() > dsq.getLength())
5732 // Update with the longer sequence.
5736 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5737 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5738 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5739 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5741 dsq.setSequence(newres);
5743 // TODO: merges will never happen if we 'know' we have the real dataset
5744 // sequence - this should be detected when id==dssid
5746 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5747 // + (pre ? "prepended" : "") + " "
5748 // + (post ? "appended" : ""));
5753 // sequence refs are identical. We may need to update the existing dataset
5754 // alignment with this one, though.
5755 if (ds != null && dseqs == null)
5757 int opos = ds.findIndex(dsq);
5758 SequenceI tseq = null;
5759 if (opos != -1 && vseqpos != opos)
5761 // remove from old position
5762 ds.deleteSequence(dsq);
5764 if (vseqpos < ds.getHeight())
5766 if (vseqpos != opos)
5768 // save sequence at destination position
5769 tseq = ds.getSequenceAt(vseqpos);
5770 ds.replaceSequenceAt(vseqpos, dsq);
5771 ds.addSequence(tseq);
5776 ds.addSequence(dsq);
5783 * TODO use AlignmentI here and in related methods - needs
5784 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5786 Hashtable<String, AlignmentI> datasetIds = null;
5788 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5790 private AlignmentI getDatasetFor(String datasetId)
5792 if (datasetIds == null)
5794 datasetIds = new Hashtable<>();
5797 if (datasetIds.containsKey(datasetId))
5799 return datasetIds.get(datasetId);
5804 private void addDatasetRef(String datasetId, AlignmentI dataset)
5806 if (datasetIds == null)
5808 datasetIds = new Hashtable<>();
5810 datasetIds.put(datasetId, dataset);
5814 * make a new dataset ID for this jalview dataset alignment
5819 private String getDatasetIdRef(AlignmentI dataset)
5821 if (dataset.getDataset() != null)
5823 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5825 String datasetId = makeHashCode(dataset, null);
5826 if (datasetId == null)
5828 // make a new datasetId and record it
5829 if (dataset2Ids == null)
5831 dataset2Ids = new IdentityHashMap<>();
5835 datasetId = dataset2Ids.get(dataset);
5837 if (datasetId == null)
5839 datasetId = "ds" + dataset2Ids.size() + 1;
5840 dataset2Ids.put(dataset, datasetId);
5847 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5848 * constructed as a special subclass GeneLocus.
5850 * @param datasetSequence
5853 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5855 for (int d = 0; d < sequence.getDBRef().size(); d++)
5857 DBRef dr = sequence.getDBRef().get(d);
5861 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5862 dr.getAccessionId());
5866 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5867 dr.getAccessionId());
5869 if (dr.getMapping() != null)
5871 entry.setMap(addMapping(dr.getMapping()));
5873 datasetSequence.addDBRef(entry);
5877 private jalview.datamodel.Mapping addMapping(Mapping m)
5879 SequenceI dsto = null;
5880 // Mapping m = dr.getMapping();
5881 int fr[] = new int[m.getMapListFrom().size() * 2];
5882 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5883 for (int _i = 0; from.hasNext(); _i += 2)
5885 MapListFrom mf = from.next();
5886 fr[_i] = mf.getStart();
5887 fr[_i + 1] = mf.getEnd();
5889 int fto[] = new int[m.getMapListTo().size() * 2];
5890 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5891 for (int _i = 0; to.hasNext(); _i += 2)
5893 MapListTo mf = to.next();
5894 fto[_i] = mf.getStart();
5895 fto[_i + 1] = mf.getEnd();
5897 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5898 fto, m.getMapFromUnit().intValue(),
5899 m.getMapToUnit().intValue());
5902 * (optional) choice of dseqFor or Sequence
5904 if (m.getDseqFor() != null)
5906 String dsfor = m.getDseqFor();
5907 if (seqRefIds.containsKey(dsfor))
5912 jmap.setTo(seqRefIds.get(dsfor));
5916 frefedSequence.add(newMappingRef(dsfor, jmap));
5919 else if (m.getSequence() != null)
5922 * local sequence definition
5924 Sequence ms = m.getSequence();
5925 SequenceI djs = null;
5926 String sqid = ms.getDsseqid();
5927 if (sqid != null && sqid.length() > 0)
5930 * recover dataset sequence
5932 djs = seqRefIds.get(sqid);
5937 "Warning - making up dataset sequence id for DbRef sequence map reference");
5938 sqid = ((Object) ms).toString(); // make up a new hascode for
5939 // undefined dataset sequence hash
5940 // (unlikely to happen)
5946 * make a new dataset sequence and add it to refIds hash
5948 djs = new jalview.datamodel.Sequence(ms.getName(),
5950 djs.setStart(jmap.getMap().getToLowest());
5951 djs.setEnd(jmap.getMap().getToHighest());
5952 djs.setVamsasId(uniqueSetSuffix + sqid);
5954 incompleteSeqs.put(sqid, djs);
5955 seqRefIds.put(sqid, djs);
5958 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5967 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5968 * view as XML (but not to file), and then reloading it
5973 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5976 JalviewModel jm = saveState(ap, null, null, null);
5979 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5980 ap.getAlignment().getDataset());
5982 uniqueSetSuffix = "";
5983 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5984 jm.getViewport().get(0).setId(null);
5985 // we don't overwrite the view we just copied
5987 if (this.frefedSequence == null)
5989 frefedSequence = new Vector<>();
5992 viewportsAdded.clear();
5994 AlignFrame af = loadFromObject(jm, null, false, null);
5995 af.getAlignPanels().clear();
5996 af.closeMenuItem_actionPerformed(true);
5999 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6000 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6001 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6002 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6003 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6006 return af.alignPanel;
6009 private Hashtable jvids2vobj;
6011 private void warn(String msg)
6016 private void warn(String msg, Exception e)
6018 if (Cache.log != null)
6022 Cache.log.warn(msg, e);
6026 Cache.log.warn(msg);
6031 System.err.println("Warning: " + msg);
6034 e.printStackTrace();
6039 private void debug(String string)
6041 debug(string, null);
6044 private void debug(String msg, Exception e)
6046 if (Cache.log != null)
6050 Cache.log.debug(msg, e);
6054 Cache.log.debug(msg);
6059 System.err.println("Warning: " + msg);
6062 e.printStackTrace();
6068 * set the object to ID mapping tables used to write/recover objects and XML
6069 * ID strings for the jalview project. If external tables are provided then
6070 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6071 * object goes out of scope. - also populates the datasetIds hashtable with
6072 * alignment objects containing dataset sequences
6075 * Map from ID strings to jalview datamodel
6077 * Map from jalview datamodel to ID strings
6081 public void setObjectMappingTables(Hashtable vobj2jv,
6082 IdentityHashMap jv2vobj)
6084 this.jv2vobj = jv2vobj;
6085 this.vobj2jv = vobj2jv;
6086 Iterator ds = jv2vobj.keySet().iterator();
6088 while (ds.hasNext())
6090 Object jvobj = ds.next();
6091 id = jv2vobj.get(jvobj).toString();
6092 if (jvobj instanceof jalview.datamodel.Alignment)
6094 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6096 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6099 else if (jvobj instanceof jalview.datamodel.Sequence)
6101 // register sequence object so the XML parser can recover it.
6102 if (seqRefIds == null)
6104 seqRefIds = new HashMap<>();
6106 if (seqsToIds == null)
6108 seqsToIds = new IdentityHashMap<>();
6110 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6111 seqsToIds.put((SequenceI) jvobj, id);
6113 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6116 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6117 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6118 if (jvann.annotationId == null)
6120 jvann.annotationId = anid;
6122 if (!jvann.annotationId.equals(anid))
6124 // TODO verify that this is the correct behaviour
6125 this.warn("Overriding Annotation ID for " + anid
6126 + " from different id : " + jvann.annotationId);
6127 jvann.annotationId = anid;
6130 else if (jvobj instanceof String)
6132 if (jvids2vobj == null)
6134 jvids2vobj = new Hashtable();
6135 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6140 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6146 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6147 * objects created from the project archive. If string is null (default for
6148 * construction) then suffix will be set automatically.
6152 public void setUniqueSetSuffix(String string)
6154 uniqueSetSuffix = string;
6159 * uses skipList2 as the skipList for skipping views on sequence sets
6160 * associated with keys in the skipList
6164 public void setSkipList(Hashtable skipList2)
6166 skipList = skipList2;
6170 * Reads the jar entry of given name and returns its contents, or null if the
6171 * entry is not found.
6174 * @param jarEntryName
6177 protected String readJarEntry(jarInputStreamProvider jprovider,
6178 String jarEntryName)
6180 String result = null;
6181 BufferedReader in = null;
6186 * Reopen the jar input stream and traverse its entries to find a matching
6189 JarInputStream jin = jprovider.getJarInputStream();
6190 JarEntry entry = null;
6193 entry = jin.getNextJarEntry();
6194 } while (entry != null && !entry.getName().equals(jarEntryName));
6198 StringBuilder out = new StringBuilder(256);
6199 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6202 while ((data = in.readLine()) != null)
6206 result = out.toString();
6210 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6212 } catch (Exception ex)
6214 ex.printStackTrace();
6222 } catch (IOException e)
6233 * Returns an incrementing counter (0, 1, 2...)
6237 private synchronized int nextCounter()
6243 * Loads any saved PCA viewers
6248 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6252 List<PcaViewer> pcaviewers = model.getPcaViewer();
6253 for (PcaViewer viewer : pcaviewers)
6255 String modelName = viewer.getScoreModelName();
6256 SimilarityParamsI params = new SimilarityParams(
6257 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6258 viewer.isIncludeGaps(),
6259 viewer.isDenominateByShortestLength());
6262 * create the panel (without computing the PCA)
6264 PCAPanel panel = new PCAPanel(ap, modelName, params);
6266 panel.setTitle(viewer.getTitle());
6267 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6268 viewer.getWidth(), viewer.getHeight()));
6270 boolean showLabels = viewer.isShowLabels();
6271 panel.setShowLabels(showLabels);
6272 panel.getRotatableCanvas().setShowLabels(showLabels);
6273 panel.getRotatableCanvas()
6274 .setBgColour(new Color(viewer.getBgColour()));
6275 panel.getRotatableCanvas()
6276 .setApplyToAllViews(viewer.isLinkToAllViews());
6279 * load PCA output data
6281 ScoreModelI scoreModel = ScoreModels.getInstance()
6282 .getScoreModel(modelName, ap);
6283 PCA pca = new PCA(null, scoreModel, params);
6284 PcaDataType pcaData = viewer.getPcaData();
6286 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6287 pca.setPairwiseScores(pairwise);
6289 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6290 pca.setTridiagonal(triDiag);
6292 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6293 pca.setEigenmatrix(result);
6295 panel.getPcaModel().setPCA(pca);
6298 * we haven't saved the input data! (JAL-2647 to do)
6300 panel.setInputData(null);
6303 * add the sequence points for the PCA display
6305 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6306 for (SequencePoint sp : viewer.getSequencePoint())
6308 String seqId = sp.getSequenceRef();
6309 SequenceI seq = seqRefIds.get(seqId);
6312 throw new IllegalStateException(
6313 "Unmatched seqref for PCA: " + seqId);
6315 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6316 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6318 seqPoints.add(seqPoint);
6320 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6323 * set min-max ranges and scale after setPoints (which recomputes them)
6325 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6326 SeqPointMin spMin = viewer.getSeqPointMin();
6327 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6329 SeqPointMax spMax = viewer.getSeqPointMax();
6330 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6332 panel.getRotatableCanvas().setSeqMinMax(min, max);
6334 // todo: hold points list in PCAModel only
6335 panel.getPcaModel().setSequencePoints(seqPoints);
6337 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6338 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6339 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6341 // is this duplication needed?
6342 panel.setTop(seqPoints.size() - 1);
6343 panel.getPcaModel().setTop(seqPoints.size() - 1);
6346 * add the axes' end points for the display
6348 for (int i = 0; i < 3; i++)
6350 Axis axis = viewer.getAxis().get(i);
6351 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6352 axis.getXPos(), axis.getYPos(), axis.getZPos());
6354 PCAPanel.addToDesktop(panel, modelName);
6356 } catch (Exception ex)
6358 Cache.log.error("Error loading PCA: " + ex.toString());
6363 * Populates an XML model of the feature colour scheme for one feature type
6365 * @param featureType
6369 public static Colour marshalColour(
6370 String featureType, FeatureColourI fcol)
6372 Colour col = new Colour();
6373 if (fcol.isSimpleColour())
6375 col.setRGB(Format.getHexString(fcol.getColour()));
6379 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6380 col.setMin(fcol.getMin());
6381 col.setMax(fcol.getMax());
6382 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6383 col.setAutoScale(fcol.isAutoScaled());
6384 col.setThreshold(fcol.getThreshold());
6385 col.setColourByLabel(fcol.isColourByLabel());
6386 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6387 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6388 : ThresholdType.NONE));
6389 if (fcol.isColourByAttribute())
6391 final String[] attName = fcol.getAttributeName();
6392 col.getAttributeName().add(attName[0]);
6393 if (attName.length > 1)
6395 col.getAttributeName().add(attName[1]);
6398 Color noColour = fcol.getNoColour();
6399 if (noColour == null)
6401 col.setNoValueColour(NoValueColour.NONE);
6403 else if (noColour == fcol.getMaxColour())
6405 col.setNoValueColour(NoValueColour.MAX);
6409 col.setNoValueColour(NoValueColour.MIN);
6412 col.setName(featureType);
6417 * Populates an XML model of the feature filter(s) for one feature type
6419 * @param firstMatcher
6420 * the first (or only) match condition)
6422 * remaining match conditions (if any)
6424 * if true, conditions are and-ed, else or-ed
6426 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6427 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6430 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6432 if (filters.hasNext())
6437 CompoundMatcher compound = new CompoundMatcher();
6438 compound.setAnd(and);
6439 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6440 firstMatcher, Collections.emptyIterator(), and);
6441 // compound.addMatcherSet(matcher1);
6442 compound.getMatcherSet().add(matcher1);
6443 FeatureMatcherI nextMatcher = filters.next();
6444 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6445 nextMatcher, filters, and);
6446 // compound.addMatcherSet(matcher2);
6447 compound.getMatcherSet().add(matcher2);
6448 result.setCompoundMatcher(compound);
6453 * single condition matcher
6455 // MatchCondition matcherModel = new MatchCondition();
6456 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6457 matcherModel.setCondition(
6458 firstMatcher.getMatcher().getCondition().getStableName());
6459 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6460 if (firstMatcher.isByAttribute())
6462 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6463 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6464 String[] attName = firstMatcher.getAttribute();
6465 matcherModel.getAttributeName().add(attName[0]); // attribute
6466 if (attName.length > 1)
6468 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6471 else if (firstMatcher.isByLabel())
6473 matcherModel.setBy(FilterBy.BY_LABEL);
6475 else if (firstMatcher.isByScore())
6477 matcherModel.setBy(FilterBy.BY_SCORE);
6479 result.setMatchCondition(matcherModel);
6486 * Loads one XML model of a feature filter to a Jalview object
6488 * @param featureType
6489 * @param matcherSetModel
6492 public static FeatureMatcherSetI parseFilter(
6494 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6496 FeatureMatcherSetI result = new FeatureMatcherSet();
6499 parseFilterConditions(result, matcherSetModel, true);
6500 } catch (IllegalStateException e)
6502 // mixing AND and OR conditions perhaps
6504 String.format("Error reading filter conditions for '%s': %s",
6505 featureType, e.getMessage()));
6506 // return as much as was parsed up to the error
6513 * Adds feature match conditions to matcherSet as unmarshalled from XML
6514 * (possibly recursively for compound conditions)
6517 * @param matcherSetModel
6519 * if true, multiple conditions are AND-ed, else they are OR-ed
6520 * @throws IllegalStateException
6521 * if AND and OR conditions are mixed
6523 protected static void parseFilterConditions(
6524 FeatureMatcherSetI matcherSet,
6525 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6528 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6529 .getMatchCondition();
6535 FilterBy filterBy = mc.getBy();
6536 Condition cond = Condition.fromString(mc.getCondition());
6537 String pattern = mc.getValue();
6538 FeatureMatcherI matchCondition = null;
6539 if (filterBy == FilterBy.BY_LABEL)
6541 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6543 else if (filterBy == FilterBy.BY_SCORE)
6545 matchCondition = FeatureMatcher.byScore(cond, pattern);
6548 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6550 final List<String> attributeName = mc.getAttributeName();
6551 String[] attNames = attributeName
6552 .toArray(new String[attributeName.size()]);
6553 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6558 * note this throws IllegalStateException if AND-ing to a
6559 * previously OR-ed compound condition, or vice versa
6563 matcherSet.and(matchCondition);
6567 matcherSet.or(matchCondition);
6573 * compound condition
6575 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6576 .getCompoundMatcher().getMatcherSet();
6577 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6578 if (matchers.size() == 2)
6580 parseFilterConditions(matcherSet, matchers.get(0), anded);
6581 parseFilterConditions(matcherSet, matchers.get(1), anded);
6585 System.err.println("Malformed compound filter condition");
6591 * Loads one XML model of a feature colour to a Jalview object
6593 * @param colourModel
6596 public static FeatureColourI parseColour(Colour colourModel)
6598 FeatureColourI colour = null;
6600 if (colourModel.getMax() != null)
6602 Color mincol = null;
6603 Color maxcol = null;
6604 Color noValueColour = null;
6608 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6609 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6610 } catch (Exception e)
6612 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6615 NoValueColour noCol = colourModel.getNoValueColour();
6616 if (noCol == NoValueColour.MIN)
6618 noValueColour = mincol;
6620 else if (noCol == NoValueColour.MAX)
6622 noValueColour = maxcol;
6625 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6626 safeFloat(colourModel.getMin()),
6627 safeFloat(colourModel.getMax()));
6628 final List<String> attributeName = colourModel.getAttributeName();
6629 String[] attributes = attributeName
6630 .toArray(new String[attributeName.size()]);
6631 if (attributes != null && attributes.length > 0)
6633 colour.setAttributeName(attributes);
6635 if (colourModel.isAutoScale() != null)
6637 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6639 if (colourModel.isColourByLabel() != null)
6641 colour.setColourByLabel(
6642 colourModel.isColourByLabel().booleanValue());
6644 if (colourModel.getThreshold() != null)
6646 colour.setThreshold(colourModel.getThreshold().floatValue());
6648 ThresholdType ttyp = colourModel.getThreshType();
6649 if (ttyp == ThresholdType.ABOVE)
6651 colour.setAboveThreshold(true);
6653 else if (ttyp == ThresholdType.BELOW)
6655 colour.setBelowThreshold(true);
6660 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6661 colour = new FeatureColour(color);