2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Enumeration;
49 import java.util.GregorianCalendar;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Hashtable;
53 import java.util.IdentityHashMap;
54 import java.util.Iterator;
55 import java.util.LinkedHashMap;
56 import java.util.List;
58 import java.util.Map.Entry;
60 import java.util.Vector;
61 import java.util.jar.JarEntry;
62 import java.util.jar.JarInputStream;
63 import java.util.jar.JarOutputStream;
65 import javax.swing.JInternalFrame;
66 import javax.swing.SwingUtilities;
67 import javax.xml.bind.JAXBContext;
68 import javax.xml.bind.JAXBElement;
69 import javax.xml.bind.Marshaller;
70 import javax.xml.datatype.DatatypeConfigurationException;
71 import javax.xml.datatype.DatatypeFactory;
72 import javax.xml.datatype.XMLGregorianCalendar;
73 import javax.xml.stream.XMLInputFactory;
74 import javax.xml.stream.XMLStreamReader;
76 import jalview.analysis.Conservation;
77 import jalview.analysis.PCA;
78 import jalview.analysis.scoremodels.ScoreModels;
79 import jalview.analysis.scoremodels.SimilarityParams;
80 import jalview.api.FeatureColourI;
81 import jalview.api.ViewStyleI;
82 import jalview.api.analysis.ScoreModelI;
83 import jalview.api.analysis.SimilarityParamsI;
84 import jalview.api.structures.JalviewStructureDisplayI;
85 import jalview.bin.Cache;
86 import jalview.datamodel.AlignedCodonFrame;
87 import jalview.datamodel.Alignment;
88 import jalview.datamodel.AlignmentAnnotation;
89 import jalview.datamodel.AlignmentI;
90 import jalview.datamodel.DBRefEntry;
91 import jalview.datamodel.GeneLocus;
92 import jalview.datamodel.GraphLine;
93 import jalview.datamodel.PDBEntry;
94 import jalview.datamodel.Point;
95 import jalview.datamodel.RnaViewerModel;
96 import jalview.datamodel.SequenceFeature;
97 import jalview.datamodel.SequenceGroup;
98 import jalview.datamodel.SequenceI;
99 import jalview.datamodel.StructureViewerModel;
100 import jalview.datamodel.StructureViewerModel.StructureData;
101 import jalview.datamodel.features.FeatureMatcher;
102 import jalview.datamodel.features.FeatureMatcherI;
103 import jalview.datamodel.features.FeatureMatcherSet;
104 import jalview.datamodel.features.FeatureMatcherSetI;
105 import jalview.ext.varna.RnaModel;
106 import jalview.gui.AlignFrame;
107 import jalview.gui.AlignViewport;
108 import jalview.gui.AlignmentPanel;
109 import jalview.gui.AppVarna;
110 import jalview.gui.Desktop;
111 import jalview.gui.JvOptionPane;
112 import jalview.gui.OOMWarning;
113 import jalview.gui.OverviewPanel;
114 import jalview.gui.PCAPanel;
115 import jalview.gui.PaintRefresher;
116 import jalview.gui.SplitFrame;
117 import jalview.gui.StructureViewer;
118 import jalview.gui.StructureViewer.ViewerType;
119 import jalview.gui.StructureViewerBase;
120 import jalview.gui.TreePanel;
121 import jalview.io.BackupFiles;
122 import jalview.io.DataSourceType;
123 import jalview.io.FileFormat;
124 import jalview.io.NewickFile;
125 import jalview.math.Matrix;
126 import jalview.math.MatrixI;
127 import jalview.renderer.ResidueShaderI;
128 import jalview.schemes.AnnotationColourGradient;
129 import jalview.schemes.ColourSchemeI;
130 import jalview.schemes.ColourSchemeProperty;
131 import jalview.schemes.FeatureColour;
132 import jalview.schemes.ResidueProperties;
133 import jalview.schemes.UserColourScheme;
134 import jalview.structure.StructureSelectionManager;
135 import jalview.structures.models.AAStructureBindingModel;
136 import jalview.util.Format;
137 import jalview.util.MessageManager;
138 import jalview.util.Platform;
139 import jalview.util.StringUtils;
140 import jalview.util.jarInputStreamProvider;
141 import jalview.util.matcher.Condition;
142 import jalview.viewmodel.AlignmentViewport;
143 import jalview.viewmodel.PCAModel;
144 import jalview.viewmodel.ViewportRanges;
145 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
146 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
147 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
148 import jalview.ws.jws2.Jws2Discoverer;
149 import jalview.ws.jws2.dm.AAConSettings;
150 import jalview.ws.jws2.jabaws2.Jws2Instance;
151 import jalview.ws.params.ArgumentI;
152 import jalview.ws.params.AutoCalcSetting;
153 import jalview.ws.params.WsParamSetI;
154 import jalview.xml.binding.jalview.AlcodonFrame;
155 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
156 import jalview.xml.binding.jalview.Annotation;
157 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
158 import jalview.xml.binding.jalview.AnnotationColourScheme;
159 import jalview.xml.binding.jalview.AnnotationElement;
160 import jalview.xml.binding.jalview.DoubleMatrix;
161 import jalview.xml.binding.jalview.DoubleVector;
162 import jalview.xml.binding.jalview.Feature;
163 import jalview.xml.binding.jalview.Feature.OtherData;
164 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
165 import jalview.xml.binding.jalview.FilterBy;
166 import jalview.xml.binding.jalview.JalviewModel;
167 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
168 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
169 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
170 import jalview.xml.binding.jalview.JalviewModel.JGroup;
171 import jalview.xml.binding.jalview.JalviewModel.JSeq;
172 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
173 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
176 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
177 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
178 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
181 import jalview.xml.binding.jalview.JalviewModel.Tree;
182 import jalview.xml.binding.jalview.JalviewModel.UserColours;
183 import jalview.xml.binding.jalview.JalviewModel.Viewport;
184 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
185 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
187 import jalview.xml.binding.jalview.JalviewUserColours;
188 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
189 import jalview.xml.binding.jalview.MapListType.MapListFrom;
190 import jalview.xml.binding.jalview.MapListType.MapListTo;
191 import jalview.xml.binding.jalview.Mapping;
192 import jalview.xml.binding.jalview.NoValueColour;
193 import jalview.xml.binding.jalview.ObjectFactory;
194 import jalview.xml.binding.jalview.PcaDataType;
195 import jalview.xml.binding.jalview.Pdbentry.Property;
196 import jalview.xml.binding.jalview.Sequence;
197 import jalview.xml.binding.jalview.Sequence.DBRef;
198 import jalview.xml.binding.jalview.SequenceSet;
199 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
200 import jalview.xml.binding.jalview.ThresholdType;
201 import jalview.xml.binding.jalview.VAMSAS;
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 = saveStructureViewer(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 String viewerType = viewFrame.getViewerType().toString();
1101 if (!storeDS && !viewIds.contains(viewId))
1103 viewIds.add(viewId);
1104 File viewerState = viewFrame.saveSession();
1105 if (viewerState != null)
1107 copyFileToJar(jout, viewerState.getPath(),
1108 getViewerJarEntryName(viewId), viewerType);
1112 Cache.log.error("Failed to save viewer state for "
1120 if (matchedFile != null || entry.getFile() != null)
1122 if (entry.getFile() != null)
1125 matchedFile = entry.getFile();
1127 pdb.setFile(matchedFile); // entry.getFile());
1128 if (pdbfiles == null)
1130 pdbfiles = new ArrayList<>();
1133 if (!pdbfiles.contains(pdbId))
1135 pdbfiles.add(pdbId);
1136 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1140 Enumeration<String> props = entry.getProperties();
1141 if (props.hasMoreElements())
1143 // PdbentryItem item = new PdbentryItem();
1144 while (props.hasMoreElements())
1146 Property prop = new Property();
1147 String key = props.nextElement();
1149 prop.setValue(entry.getProperty(key).toString());
1150 // item.addProperty(prop);
1151 pdb.getProperty().add(prop);
1153 // pdb.addPdbentryItem(item);
1156 // jseq.addPdbids(pdb);
1157 jseq.getPdbids().add(pdb);
1161 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1163 // jms.addJSeq(jseq);
1164 object.getJSeq().add(jseq);
1167 if (!storeDS && av.hasHiddenRows())
1169 jal = av.getAlignment();
1173 if (storeDS && jal.getCodonFrames() != null)
1175 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1176 for (AlignedCodonFrame acf : jac)
1178 AlcodonFrame alc = new AlcodonFrame();
1179 if (acf.getProtMappings() != null
1180 && acf.getProtMappings().length > 0)
1182 boolean hasMap = false;
1183 SequenceI[] dnas = acf.getdnaSeqs();
1184 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1185 for (int m = 0; m < pmaps.length; m++)
1187 AlcodMap alcmap = new AlcodMap();
1188 alcmap.setDnasq(seqHash(dnas[m]));
1190 createVamsasMapping(pmaps[m], dnas[m], null, false));
1191 // alc.addAlcodMap(alcmap);
1192 alc.getAlcodMap().add(alcmap);
1197 // vamsasSet.addAlcodonFrame(alc);
1198 vamsasSet.getAlcodonFrame().add(alc);
1201 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1203 // AlcodonFrame alc = new AlcodonFrame();
1204 // vamsasSet.addAlcodonFrame(alc);
1205 // for (int p = 0; p < acf.aaWidth; p++)
1207 // Alcodon cmap = new Alcodon();
1208 // if (acf.codons[p] != null)
1210 // // Null codons indicate a gapped column in the translated peptide
1212 // cmap.setPos1(acf.codons[p][0]);
1213 // cmap.setPos2(acf.codons[p][1]);
1214 // cmap.setPos3(acf.codons[p][2]);
1216 // alc.addAlcodon(cmap);
1218 // if (acf.getProtMappings() != null
1219 // && acf.getProtMappings().length > 0)
1221 // SequenceI[] dnas = acf.getdnaSeqs();
1222 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1223 // for (int m = 0; m < pmaps.length; m++)
1225 // AlcodMap alcmap = new AlcodMap();
1226 // alcmap.setDnasq(seqHash(dnas[m]));
1227 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1229 // alc.addAlcodMap(alcmap);
1236 // /////////////////////////////////
1237 if (!storeDS && av.getCurrentTree() != null)
1239 // FIND ANY ASSOCIATED TREES
1240 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1241 if (Desktop.desktop != null)
1243 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1245 for (int t = 0; t < frames.length; t++)
1247 if (frames[t] instanceof TreePanel)
1249 TreePanel tp = (TreePanel) frames[t];
1251 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1253 JalviewModel.Tree tree = new JalviewModel.Tree();
1254 tree.setTitle(tp.getTitle());
1255 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1256 tree.setNewick(tp.getTree().print());
1257 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1259 tree.setFitToWindow(tp.fitToWindow.getState());
1260 tree.setFontName(tp.getTreeFont().getName());
1261 tree.setFontSize(tp.getTreeFont().getSize());
1262 tree.setFontStyle(tp.getTreeFont().getStyle());
1263 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1265 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1266 tree.setShowDistances(tp.distanceMenu.getState());
1268 tree.setHeight(tp.getHeight());
1269 tree.setWidth(tp.getWidth());
1270 tree.setXpos(tp.getX());
1271 tree.setYpos(tp.getY());
1272 tree.setId(makeHashCode(tp, null));
1273 tree.setLinkToAllViews(
1274 tp.getTreeCanvas().isApplyToAllViews());
1276 // jms.addTree(tree);
1277 object.getTree().add(tree);
1287 if (!storeDS && Desktop.desktop != null)
1289 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1291 if (frame instanceof PCAPanel)
1293 PCAPanel panel = (PCAPanel) frame;
1294 if (panel.getAlignViewport().getAlignment() == jal)
1296 savePCA(panel, object);
1304 * store forward refs from an annotationRow to any groups
1306 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1309 for (SequenceI sq : jal.getSequences())
1311 // Store annotation on dataset sequences only
1312 AlignmentAnnotation[] aa = sq.getAnnotation();
1313 if (aa != null && aa.length > 0)
1315 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1322 if (jal.getAlignmentAnnotation() != null)
1324 // Store the annotation shown on the alignment.
1325 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1326 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1331 if (jal.getGroups() != null)
1333 JGroup[] groups = new JGroup[jal.getGroups().size()];
1335 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1337 JGroup jGroup = new JGroup();
1338 groups[++i] = jGroup;
1340 jGroup.setStart(sg.getStartRes());
1341 jGroup.setEnd(sg.getEndRes());
1342 jGroup.setName(sg.getName());
1343 if (groupRefs.containsKey(sg))
1345 // group has references so set its ID field
1346 jGroup.setId(groupRefs.get(sg));
1348 ColourSchemeI colourScheme = sg.getColourScheme();
1349 if (colourScheme != null)
1351 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1352 if (groupColourScheme.conservationApplied())
1354 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1356 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1359 setUserColourScheme(colourScheme, userColours,
1364 jGroup.setColour(colourScheme.getSchemeName());
1367 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1369 jGroup.setColour("AnnotationColourGradient");
1370 jGroup.setAnnotationColours(constructAnnotationColours(
1371 (jalview.schemes.AnnotationColourGradient) colourScheme,
1372 userColours, object));
1374 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1377 setUserColourScheme(colourScheme, userColours, object));
1381 jGroup.setColour(colourScheme.getSchemeName());
1384 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1387 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1388 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1389 jGroup.setDisplayText(sg.getDisplayText());
1390 jGroup.setColourText(sg.getColourText());
1391 jGroup.setTextCol1(sg.textColour.getRGB());
1392 jGroup.setTextCol2(sg.textColour2.getRGB());
1393 jGroup.setTextColThreshold(sg.thresholdTextColour);
1394 jGroup.setShowUnconserved(sg.getShowNonconserved());
1395 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1396 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1397 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1398 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1399 for (SequenceI seq : sg.getSequences())
1401 // jGroup.addSeq(seqHash(seq));
1402 jGroup.getSeq().add(seqHash(seq));
1406 //jms.setJGroup(groups);
1408 for (JGroup grp : groups)
1410 object.getJGroup().add(grp);
1415 // /////////SAVE VIEWPORT
1416 Viewport view = new Viewport();
1417 view.setTitle(ap.alignFrame.getTitle());
1418 view.setSequenceSetId(
1419 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1420 view.setId(av.getViewId());
1421 if (av.getCodingComplement() != null)
1423 view.setComplementId(av.getCodingComplement().getViewId());
1425 view.setViewName(av.getViewName());
1426 view.setGatheredViews(av.isGatherViewsHere());
1428 Rectangle size = ap.av.getExplodedGeometry();
1429 Rectangle position = size;
1432 size = ap.alignFrame.getBounds();
1433 if (av.getCodingComplement() != null)
1435 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1443 view.setXpos(position.x);
1444 view.setYpos(position.y);
1446 view.setWidth(size.width);
1447 view.setHeight(size.height);
1449 view.setStartRes(vpRanges.getStartRes());
1450 view.setStartSeq(vpRanges.getStartSeq());
1452 OverviewPanel ov = ap.getOverviewPanel();
1455 Overview overview = new Overview();
1456 overview.setTitle(ov.getTitle());
1457 Rectangle bounds = ov.getFrameBounds();
1458 overview.setXpos(bounds.x);
1459 overview.setYpos(bounds.y);
1460 overview.setWidth(bounds.width);
1461 overview.setHeight(bounds.height);
1462 overview.setShowHidden(ov.isShowHiddenRegions());
1463 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1464 overview.setResidueColour(ov.getCanvas().getResidueColour().getRGB());
1465 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1466 view.setOverview(overview);
1468 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1470 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1471 userColours, object));
1474 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1476 AnnotationColourScheme ac = constructAnnotationColours(
1477 (jalview.schemes.AnnotationColourGradient) av
1478 .getGlobalColourScheme(),
1479 userColours, object);
1481 view.setAnnotationColours(ac);
1482 view.setBgColour("AnnotationColourGradient");
1486 view.setBgColour(ColourSchemeProperty
1487 .getColourName(av.getGlobalColourScheme()));
1490 ResidueShaderI vcs = av.getResidueShading();
1491 ColourSchemeI cs = av.getGlobalColourScheme();
1495 if (vcs.conservationApplied())
1497 view.setConsThreshold(vcs.getConservationInc());
1498 if (cs instanceof jalview.schemes.UserColourScheme)
1500 view.setBgColour(setUserColourScheme(cs, userColours, object));
1503 view.setPidThreshold(vcs.getThreshold());
1506 view.setConservationSelected(av.getConservationSelected());
1507 view.setPidSelected(av.getAbovePIDThreshold());
1508 final Font font = av.getFont();
1509 view.setFontName(font.getName());
1510 view.setFontSize(font.getSize());
1511 view.setFontStyle(font.getStyle());
1512 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1513 view.setRenderGaps(av.isRenderGaps());
1514 view.setShowAnnotation(av.isShowAnnotation());
1515 view.setShowBoxes(av.getShowBoxes());
1516 view.setShowColourText(av.getColourText());
1517 view.setShowFullId(av.getShowJVSuffix());
1518 view.setRightAlignIds(av.isRightAlignIds());
1519 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1520 view.setShowText(av.getShowText());
1521 view.setShowUnconserved(av.getShowUnconserved());
1522 view.setWrapAlignment(av.getWrapAlignment());
1523 view.setTextCol1(av.getTextColour().getRGB());
1524 view.setTextCol2(av.getTextColour2().getRGB());
1525 view.setTextColThreshold(av.getThresholdTextColour());
1526 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1527 view.setShowSequenceLogo(av.isShowSequenceLogo());
1528 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1529 view.setShowGroupConsensus(av.isShowGroupConsensus());
1530 view.setShowGroupConservation(av.isShowGroupConservation());
1531 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1532 view.setShowDbRefTooltip(av.isShowDBRefs());
1533 view.setFollowHighlight(av.isFollowHighlight());
1534 view.setFollowSelection(av.followSelection);
1535 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1536 view.setShowComplementFeatures(av.isShowComplementFeatures());
1537 view.setShowComplementFeaturesOnTop(
1538 av.isShowComplementFeaturesOnTop());
1539 if (av.getFeaturesDisplayed() != null)
1541 FeatureSettings fs = new FeatureSettings();
1543 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1544 .getFeatureRenderer();
1545 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1547 Vector<String> settingsAdded = new Vector<>();
1548 if (renderOrder != null)
1550 for (String featureType : renderOrder)
1552 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1553 setting.setType(featureType);
1556 * save any filter for the feature type
1558 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1559 if (filter != null) {
1560 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1561 FeatureMatcherI firstFilter = filters.next();
1562 setting.setMatcherSet(Jalview2XML.marshalFilter(
1563 firstFilter, filters, filter.isAnded()));
1567 * save colour scheme for the feature type
1569 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1570 if (!fcol.isSimpleColour())
1572 setting.setColour(fcol.getMaxColour().getRGB());
1573 setting.setMincolour(fcol.getMinColour().getRGB());
1574 setting.setMin(fcol.getMin());
1575 setting.setMax(fcol.getMax());
1576 setting.setColourByLabel(fcol.isColourByLabel());
1577 if (fcol.isColourByAttribute())
1579 String[] attName = fcol.getAttributeName();
1580 setting.getAttributeName().add(attName[0]);
1581 if (attName.length > 1)
1583 setting.getAttributeName().add(attName[1]);
1586 setting.setAutoScale(fcol.isAutoScaled());
1587 setting.setThreshold(fcol.getThreshold());
1588 Color noColour = fcol.getNoColour();
1589 if (noColour == null)
1591 setting.setNoValueColour(NoValueColour.NONE);
1593 else if (noColour.equals(fcol.getMaxColour()))
1595 setting.setNoValueColour(NoValueColour.MAX);
1599 setting.setNoValueColour(NoValueColour.MIN);
1601 // -1 = No threshold, 0 = Below, 1 = Above
1602 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1603 : (fcol.isBelowThreshold() ? 0 : -1));
1607 setting.setColour(fcol.getColour().getRGB());
1611 av.getFeaturesDisplayed().isVisible(featureType));
1613 .getOrder(featureType);
1616 setting.setOrder(rorder);
1618 /// fs.addSetting(setting);
1619 fs.getSetting().add(setting);
1620 settingsAdded.addElement(featureType);
1624 // is groups actually supposed to be a map here ?
1625 Iterator<String> en = fr.getFeatureGroups().iterator();
1626 Vector<String> groupsAdded = new Vector<>();
1627 while (en.hasNext())
1629 String grp = en.next();
1630 if (groupsAdded.contains(grp))
1634 Group g = new Group();
1636 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1639 fs.getGroup().add(g);
1640 groupsAdded.addElement(grp);
1642 // jms.setFeatureSettings(fs);
1643 object.setFeatureSettings(fs);
1646 if (av.hasHiddenColumns())
1648 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1649 .getHiddenColumns();
1652 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1656 Iterator<int[]> hiddenRegions = hidden.iterator();
1657 while (hiddenRegions.hasNext())
1659 int[] region = hiddenRegions.next();
1660 HiddenColumns hc = new HiddenColumns();
1661 hc.setStart(region[0]);
1662 hc.setEnd(region[1]);
1663 // view.addHiddenColumns(hc);
1664 view.getHiddenColumns().add(hc);
1668 if (calcIdSet.size() > 0)
1670 for (String calcId : calcIdSet)
1672 if (calcId.trim().length() > 0)
1674 CalcIdParam cidp = createCalcIdParam(calcId, av);
1675 // Some calcIds have no parameters.
1678 // view.addCalcIdParam(cidp);
1679 view.getCalcIdParam().add(cidp);
1685 // jms.addViewport(view);
1686 object.getViewport().add(view);
1688 // object.setJalviewModelSequence(jms);
1689 // object.getVamsasModel().addSequenceSet(vamsasSet);
1690 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1692 if (jout != null && fileName != null)
1694 // We may not want to write the object to disk,
1695 // eg we can copy the alignViewport to a new view object
1696 // using save and then load
1699 fileName = fileName.replace('\\', '/');
1700 System.out.println("Writing jar entry " + fileName);
1701 JarEntry entry = new JarEntry(fileName);
1702 jout.putNextEntry(entry);
1703 PrintWriter pout = new PrintWriter(
1704 new OutputStreamWriter(jout, UTF_8));
1705 JAXBContext jaxbContext = JAXBContext
1706 .newInstance(JalviewModel.class);
1707 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1709 // output pretty printed
1710 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1711 jaxbMarshaller.marshal(
1712 new ObjectFactory().createJalviewModel(object), pout);
1714 // jaxbMarshaller.marshal(object, pout);
1715 // marshaller.marshal(object);
1718 } catch (Exception ex)
1720 // TODO: raise error in GUI if marshalling failed.
1721 System.err.println("Error writing Jalview project");
1722 ex.printStackTrace();
1729 * Writes PCA viewer attributes and computed values to an XML model object and
1730 * adds it to the JalviewModel. Any exceptions are reported by logging.
1732 protected void savePCA(PCAPanel panel, JalviewModel object)
1736 PcaViewer viewer = new PcaViewer();
1737 viewer.setHeight(panel.getHeight());
1738 viewer.setWidth(panel.getWidth());
1739 viewer.setXpos(panel.getX());
1740 viewer.setYpos(panel.getY());
1741 viewer.setTitle(panel.getTitle());
1742 PCAModel pcaModel = panel.getPcaModel();
1743 viewer.setScoreModelName(pcaModel.getScoreModelName());
1744 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1745 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1746 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1748 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1749 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1750 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1751 SeqPointMin spmin = new SeqPointMin();
1752 spmin.setXPos(spMin[0]);
1753 spmin.setYPos(spMin[1]);
1754 spmin.setZPos(spMin[2]);
1755 viewer.setSeqPointMin(spmin);
1756 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1757 SeqPointMax spmax = new SeqPointMax();
1758 spmax.setXPos(spMax[0]);
1759 spmax.setYPos(spMax[1]);
1760 spmax.setZPos(spMax[2]);
1761 viewer.setSeqPointMax(spmax);
1762 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1763 viewer.setLinkToAllViews(
1764 panel.getRotatableCanvas().isApplyToAllViews());
1765 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1766 viewer.setIncludeGaps(sp.includeGaps());
1767 viewer.setMatchGaps(sp.matchGaps());
1768 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1769 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1772 * sequence points on display
1774 for (jalview.datamodel.SequencePoint spt : pcaModel
1775 .getSequencePoints())
1777 SequencePoint point = new SequencePoint();
1778 point.setSequenceRef(seqHash(spt.getSequence()));
1779 point.setXPos(spt.coord.x);
1780 point.setYPos(spt.coord.y);
1781 point.setZPos(spt.coord.z);
1782 viewer.getSequencePoint().add(point);
1786 * (end points of) axes on display
1788 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1791 Axis axis = new Axis();
1795 viewer.getAxis().add(axis);
1799 * raw PCA data (note we are not restoring PCA inputs here -
1800 * alignment view, score model, similarity parameters)
1802 PcaDataType data = new PcaDataType();
1803 viewer.setPcaData(data);
1804 PCA pca = pcaModel.getPcaData();
1806 DoubleMatrix pm = new DoubleMatrix();
1807 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1808 data.setPairwiseMatrix(pm);
1810 DoubleMatrix tm = new DoubleMatrix();
1811 saveDoubleMatrix(pca.getTridiagonal(), tm);
1812 data.setTridiagonalMatrix(tm);
1814 DoubleMatrix eigenMatrix = new DoubleMatrix();
1815 data.setEigenMatrix(eigenMatrix);
1816 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1818 object.getPcaViewer().add(viewer);
1819 } catch (Throwable t)
1821 Cache.log.error("Error saving PCA: " + t.getMessage());
1826 * Stores values from a matrix into an XML element, including (if present) the
1831 * @see #loadDoubleMatrix(DoubleMatrix)
1833 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1835 xmlMatrix.setRows(m.height());
1836 xmlMatrix.setColumns(m.width());
1837 for (int i = 0; i < m.height(); i++)
1839 DoubleVector row = new DoubleVector();
1840 for (int j = 0; j < m.width(); j++)
1842 row.getV().add(m.getValue(i, j));
1844 xmlMatrix.getRow().add(row);
1846 if (m.getD() != null)
1848 DoubleVector dVector = new DoubleVector();
1849 for (double d : m.getD())
1851 dVector.getV().add(d);
1853 xmlMatrix.setD(dVector);
1855 if (m.getE() != null)
1857 DoubleVector eVector = new DoubleVector();
1858 for (double e : m.getE())
1860 eVector.getV().add(e);
1862 xmlMatrix.setE(eVector);
1867 * Loads XML matrix data into a new Matrix object, including the D and/or E
1868 * vectors (if present)
1872 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1874 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1876 int rows = mData.getRows();
1877 double[][] vals = new double[rows][];
1879 for (int i = 0; i < rows; i++)
1881 List<Double> dVector = mData.getRow().get(i).getV();
1882 vals[i] = new double[dVector.size()];
1884 for (Double d : dVector)
1890 MatrixI m = new Matrix(vals);
1892 if (mData.getD() != null)
1894 List<Double> dVector = mData.getD().getV();
1895 double[] vec = new double[dVector.size()];
1897 for (Double d : dVector)
1903 if (mData.getE() != null)
1905 List<Double> dVector = mData.getE().getV();
1906 double[] vec = new double[dVector.size()];
1908 for (Double d : dVector)
1919 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1920 * for each viewer, with
1922 * <li>viewer geometry (position, size, split pane divider location)</li>
1923 * <li>index of the selected structure in the viewer (currently shows gapped
1925 * <li>the id of the annotation holding RNA secondary structure</li>
1926 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1928 * Varna viewer state is also written out (in native Varna XML) to separate
1929 * project jar entries. A separate entry is written for each RNA structure
1930 * displayed, with the naming convention
1932 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1940 * @param storeDataset
1942 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1943 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1944 boolean storeDataset)
1946 if (Desktop.desktop == null)
1950 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1951 for (int f = frames.length - 1; f > -1; f--)
1953 if (frames[f] instanceof AppVarna)
1955 AppVarna varna = (AppVarna) frames[f];
1957 * link the sequence to every viewer that is showing it and is linked to
1958 * its alignment panel
1960 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1962 String viewId = varna.getViewId();
1963 RnaViewer rna = new RnaViewer();
1964 rna.setViewId(viewId);
1965 rna.setTitle(varna.getTitle());
1966 rna.setXpos(varna.getX());
1967 rna.setYpos(varna.getY());
1968 rna.setWidth(varna.getWidth());
1969 rna.setHeight(varna.getHeight());
1970 rna.setDividerLocation(varna.getDividerLocation());
1971 rna.setSelectedRna(varna.getSelectedIndex());
1972 // jseq.addRnaViewer(rna);
1973 jseq.getRnaViewer().add(rna);
1976 * Store each Varna panel's state once in the project per sequence.
1977 * First time through only (storeDataset==false)
1979 // boolean storeSessions = false;
1980 // String sequenceViewId = viewId + seqsToIds.get(jds);
1981 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1983 // viewIds.add(sequenceViewId);
1984 // storeSessions = true;
1986 for (RnaModel model : varna.getModels())
1988 if (model.seq == jds)
1991 * VARNA saves each view (sequence or alignment secondary
1992 * structure, gapped or trimmed) as a separate XML file
1994 String jarEntryName = rnaSessions.get(model);
1995 if (jarEntryName == null)
1998 String varnaStateFile = varna.getStateInfo(model.rna);
1999 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2000 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2001 rnaSessions.put(model, jarEntryName);
2003 SecondaryStructure ss = new SecondaryStructure();
2004 String annotationId = varna.getAnnotation(jds).annotationId;
2005 ss.setAnnotationId(annotationId);
2006 ss.setViewerState(jarEntryName);
2007 ss.setGapped(model.gapped);
2008 ss.setTitle(model.title);
2009 // rna.addSecondaryStructure(ss);
2010 rna.getSecondaryStructure().add(ss);
2019 * Copy the contents of a file to a new entry added to the output jar
2023 * @param jarEntryName
2025 * additional identifying info to log to the console
2027 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2028 String jarEntryName, String msg)
2030 try (InputStream is = new FileInputStream(infilePath))
2032 File file = new File(infilePath);
2033 if (file.exists() && jout != null)
2036 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2037 jout.putNextEntry(new JarEntry(jarEntryName));
2040 // dis = new DataInputStream(new FileInputStream(file));
2041 // byte[] data = new byte[(int) file.length()];
2042 // dis.readFully(data);
2043 // writeJarEntry(jout, jarEntryName, data);
2045 } catch (Exception ex)
2047 ex.printStackTrace();
2052 * Copies input to output, in 4K buffers; handles any data (text or binary)
2056 * @throws IOException
2058 protected void copyAll(InputStream in, OutputStream out)
2061 byte[] buffer = new byte[4096];
2063 while ((bytesRead = in.read(buffer)) != -1)
2065 out.write(buffer, 0, bytesRead);
2070 * Save the state of a structure viewer
2075 * the archive XML element under which to save the state
2078 * @param matchedFile
2082 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2083 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2084 String matchedFile, StructureViewerBase viewFrame)
2086 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2089 * Look for any bindings for this viewer to the PDB file of interest
2090 * (including part matches excluding chain id)
2092 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2094 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2095 final String pdbId = pdbentry.getId();
2096 if (!pdbId.equals(entry.getId())
2097 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2098 .startsWith(pdbId.toLowerCase())))
2101 * not interested in a binding to a different PDB entry here
2105 if (matchedFile == null)
2107 matchedFile = pdbentry.getFile();
2109 else if (!matchedFile.equals(pdbentry.getFile()))
2112 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2113 + pdbentry.getFile());
2117 // can get at it if the ID
2118 // match is ambiguous (e.g.
2121 for (int smap = 0; smap < viewFrame.getBinding()
2122 .getSequence()[peid].length; smap++)
2124 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2125 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2127 StructureState state = new StructureState();
2128 state.setVisible(true);
2129 state.setXpos(viewFrame.getX());
2130 state.setYpos(viewFrame.getY());
2131 state.setWidth(viewFrame.getWidth());
2132 state.setHeight(viewFrame.getHeight());
2133 final String viewId = viewFrame.getViewId();
2134 state.setViewId(viewId);
2135 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2136 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2137 state.setColourByJmol(viewFrame.isColouredByViewer());
2138 state.setType(viewFrame.getViewerType().toString());
2139 // pdb.addStructureState(state);
2140 pdb.getStructureState().add(state);
2148 * Populates the AnnotationColourScheme xml for save. This captures the
2149 * settings of the options in the 'Colour by Annotation' dialog.
2152 * @param userColours
2156 private AnnotationColourScheme constructAnnotationColours(
2157 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2160 AnnotationColourScheme ac = new AnnotationColourScheme();
2161 ac.setAboveThreshold(acg.getAboveThreshold());
2162 ac.setThreshold(acg.getAnnotationThreshold());
2163 // 2.10.2 save annotationId (unique) not annotation label
2164 ac.setAnnotation(acg.getAnnotation().annotationId);
2165 if (acg.getBaseColour() instanceof UserColourScheme)
2168 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2173 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2176 ac.setMaxColour(acg.getMaxColour().getRGB());
2177 ac.setMinColour(acg.getMinColour().getRGB());
2178 ac.setPerSequence(acg.isSeqAssociated());
2179 ac.setPredefinedColours(acg.isPredefinedColours());
2183 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2184 IdentityHashMap<SequenceGroup, String> groupRefs,
2185 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2186 SequenceSet vamsasSet)
2189 for (int i = 0; i < aa.length; i++)
2191 Annotation an = new Annotation();
2193 AlignmentAnnotation annotation = aa[i];
2194 if (annotation.annotationId != null)
2196 annotationIds.put(annotation.annotationId, annotation);
2199 an.setId(annotation.annotationId);
2201 an.setVisible(annotation.visible);
2203 an.setDescription(annotation.description);
2205 if (annotation.sequenceRef != null)
2207 // 2.9 JAL-1781 xref on sequence id rather than name
2208 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2210 if (annotation.groupRef != null)
2212 String groupIdr = groupRefs.get(annotation.groupRef);
2213 if (groupIdr == null)
2215 // make a locally unique String
2216 groupRefs.put(annotation.groupRef,
2217 groupIdr = ("" + System.currentTimeMillis()
2218 + annotation.groupRef.getName()
2219 + groupRefs.size()));
2221 an.setGroupRef(groupIdr.toString());
2224 // store all visualization attributes for annotation
2225 an.setGraphHeight(annotation.graphHeight);
2226 an.setCentreColLabels(annotation.centreColLabels);
2227 an.setScaleColLabels(annotation.scaleColLabel);
2228 an.setShowAllColLabels(annotation.showAllColLabels);
2229 an.setBelowAlignment(annotation.belowAlignment);
2231 if (annotation.graph > 0)
2234 an.setGraphType(annotation.graph);
2235 an.setGraphGroup(annotation.graphGroup);
2236 if (annotation.getThreshold() != null)
2238 ThresholdLine line = new ThresholdLine();
2239 line.setLabel(annotation.getThreshold().label);
2240 line.setValue(annotation.getThreshold().value);
2241 line.setColour(annotation.getThreshold().colour.getRGB());
2242 an.setThresholdLine(line);
2250 an.setLabel(annotation.label);
2252 if (annotation == av.getAlignmentQualityAnnot()
2253 || annotation == av.getAlignmentConservationAnnotation()
2254 || annotation == av.getAlignmentConsensusAnnotation()
2255 || annotation.autoCalculated)
2257 // new way of indicating autocalculated annotation -
2258 an.setAutoCalculated(annotation.autoCalculated);
2260 if (annotation.hasScore())
2262 an.setScore(annotation.getScore());
2265 if (annotation.getCalcId() != null)
2267 calcIdSet.add(annotation.getCalcId());
2268 an.setCalcId(annotation.getCalcId());
2270 if (annotation.hasProperties())
2272 for (String pr : annotation.getProperties())
2274 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2276 prop.setValue(annotation.getProperty(pr));
2277 // an.addProperty(prop);
2278 an.getProperty().add(prop);
2282 AnnotationElement ae;
2283 if (annotation.annotations != null)
2285 an.setScoreOnly(false);
2286 for (int a = 0; a < annotation.annotations.length; a++)
2288 if ((annotation == null) || (annotation.annotations[a] == null))
2293 ae = new AnnotationElement();
2294 if (annotation.annotations[a].description != null)
2296 ae.setDescription(annotation.annotations[a].description);
2298 if (annotation.annotations[a].displayCharacter != null)
2300 ae.setDisplayCharacter(
2301 annotation.annotations[a].displayCharacter);
2304 if (!Float.isNaN(annotation.annotations[a].value))
2306 ae.setValue(annotation.annotations[a].value);
2310 if (annotation.annotations[a].secondaryStructure > ' ')
2312 ae.setSecondaryStructure(
2313 annotation.annotations[a].secondaryStructure + "");
2316 if (annotation.annotations[a].colour != null
2317 && annotation.annotations[a].colour != java.awt.Color.black)
2319 ae.setColour(annotation.annotations[a].colour.getRGB());
2322 // an.addAnnotationElement(ae);
2323 an.getAnnotationElement().add(ae);
2324 if (annotation.autoCalculated)
2326 // only write one non-null entry into the annotation row -
2327 // sufficient to get the visualization attributes necessary to
2335 an.setScoreOnly(true);
2337 if (!storeDS || (storeDS && !annotation.autoCalculated))
2339 // skip autocalculated annotation - these are only provided for
2341 // vamsasSet.addAnnotation(an);
2342 vamsasSet.getAnnotation().add(an);
2348 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2350 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2351 if (settings != null)
2353 CalcIdParam vCalcIdParam = new CalcIdParam();
2354 vCalcIdParam.setCalcId(calcId);
2355 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2356 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2357 // generic URI allowing a third party to resolve another instance of the
2358 // service used for this calculation
2359 for (String url : settings.getServiceURLs())
2361 // vCalcIdParam.addServiceURL(urls);
2362 vCalcIdParam.getServiceURL().add(url);
2364 vCalcIdParam.setVersion("1.0");
2365 if (settings.getPreset() != null)
2367 WsParamSetI setting = settings.getPreset();
2368 vCalcIdParam.setName(setting.getName());
2369 vCalcIdParam.setDescription(setting.getDescription());
2373 vCalcIdParam.setName("");
2374 vCalcIdParam.setDescription("Last used parameters");
2376 // need to be able to recover 1) settings 2) user-defined presets or
2377 // recreate settings from preset 3) predefined settings provided by
2378 // service - or settings that can be transferred (or discarded)
2379 vCalcIdParam.setParameters(
2380 settings.getWsParamFile().replace("\n", "|\\n|"));
2381 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2382 // todo - decide if updateImmediately is needed for any projects.
2384 return vCalcIdParam;
2389 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2392 if (calcIdParam.getVersion().equals("1.0"))
2394 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2395 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2396 .getPreferredServiceFor(calcIds);
2397 if (service != null)
2399 WsParamSetI parmSet = null;
2402 parmSet = service.getParamStore().parseServiceParameterFile(
2403 calcIdParam.getName(), calcIdParam.getDescription(),
2405 calcIdParam.getParameters().replace("|\\n|", "\n"));
2406 } catch (IOException x)
2408 warn("Couldn't parse parameter data for "
2409 + calcIdParam.getCalcId(), x);
2412 List<ArgumentI> argList = null;
2413 if (calcIdParam.getName().length() > 0)
2415 parmSet = service.getParamStore()
2416 .getPreset(calcIdParam.getName());
2417 if (parmSet != null)
2419 // TODO : check we have a good match with settings in AACon -
2420 // otherwise we'll need to create a new preset
2425 argList = parmSet.getArguments();
2428 AAConSettings settings = new AAConSettings(
2429 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2430 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2431 calcIdParam.isNeedsUpdate());
2436 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2440 throw new Error(MessageManager.formatMessage(
2441 "error.unsupported_version_calcIdparam", new Object[]
2442 { calcIdParam.toString() }));
2446 * External mapping between jalview objects and objects yielding a valid and
2447 * unique object ID string. This is null for normal Jalview project IO, but
2448 * non-null when a jalview project is being read or written as part of a
2451 IdentityHashMap jv2vobj = null;
2454 * Construct a unique ID for jvobj using either existing bindings or if none
2455 * exist, the result of the hashcode call for the object.
2458 * jalview data object
2459 * @return unique ID for referring to jvobj
2461 private String makeHashCode(Object jvobj, String altCode)
2463 if (jv2vobj != null)
2465 Object id = jv2vobj.get(jvobj);
2468 return id.toString();
2470 // check string ID mappings
2471 if (jvids2vobj != null && jvobj instanceof String)
2473 id = jvids2vobj.get(jvobj);
2477 return id.toString();
2479 // give up and warn that something has gone wrong
2480 warn("Cannot find ID for object in external mapping : " + jvobj);
2486 * return local jalview object mapped to ID, if it exists
2490 * @return null or object bound to idcode
2492 private Object retrieveExistingObj(String idcode)
2494 if (idcode != null && vobj2jv != null)
2496 return vobj2jv.get(idcode);
2502 * binding from ID strings from external mapping table to jalview data model
2505 private Hashtable vobj2jv;
2507 private Sequence createVamsasSequence(String id, SequenceI jds)
2509 return createVamsasSequence(true, id, jds, null);
2512 private Sequence createVamsasSequence(boolean recurse, String id,
2513 SequenceI jds, SequenceI parentseq)
2515 Sequence vamsasSeq = new Sequence();
2516 vamsasSeq.setId(id);
2517 vamsasSeq.setName(jds.getName());
2518 vamsasSeq.setSequence(jds.getSequenceAsString());
2519 vamsasSeq.setDescription(jds.getDescription());
2520 List<DBRefEntry> dbrefs = null;
2521 if (jds.getDatasetSequence() != null)
2523 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2527 // seqId==dsseqid so we can tell which sequences really are
2528 // dataset sequences only
2529 vamsasSeq.setDsseqid(id);
2530 dbrefs = jds.getDBRefs();
2531 if (parentseq == null)
2538 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2542 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2544 DBRef dbref = new DBRef();
2545 DBRefEntry ref = dbrefs.get(d);
2546 dbref.setSource(ref.getSource());
2547 dbref.setVersion(ref.getVersion());
2548 dbref.setAccessionId(ref.getAccessionId());
2549 if (ref instanceof GeneLocus)
2551 dbref.setLocus(true);
2555 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2557 dbref.setMapping(mp);
2559 vamsasSeq.getDBRef().add(dbref);
2565 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2566 SequenceI parentseq, SequenceI jds, boolean recurse)
2569 if (jmp.getMap() != null)
2573 jalview.util.MapList mlst = jmp.getMap();
2574 List<int[]> r = mlst.getFromRanges();
2575 for (int[] range : r)
2577 MapListFrom mfrom = new MapListFrom();
2578 mfrom.setStart(range[0]);
2579 mfrom.setEnd(range[1]);
2580 // mp.addMapListFrom(mfrom);
2581 mp.getMapListFrom().add(mfrom);
2583 r = mlst.getToRanges();
2584 for (int[] range : r)
2586 MapListTo mto = new MapListTo();
2587 mto.setStart(range[0]);
2588 mto.setEnd(range[1]);
2589 // mp.addMapListTo(mto);
2590 mp.getMapListTo().add(mto);
2592 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2593 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2594 if (jmp.getTo() != null)
2596 // MappingChoice mpc = new MappingChoice();
2598 // check/create ID for the sequence referenced by getTo()
2601 SequenceI ps = null;
2602 if (parentseq != jmp.getTo()
2603 && parentseq.getDatasetSequence() != jmp.getTo())
2605 // chaining dbref rather than a handshaking one
2606 jmpid = seqHash(ps = jmp.getTo());
2610 jmpid = seqHash(ps = parentseq);
2612 // mpc.setDseqFor(jmpid);
2613 mp.setDseqFor(jmpid);
2614 if (!seqRefIds.containsKey(jmpid))
2616 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2617 seqRefIds.put(jmpid, ps);
2621 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2624 // mp.setMappingChoice(mpc);
2630 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2631 List<UserColourScheme> userColours, JalviewModel jm)
2634 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2635 boolean newucs = false;
2636 if (!userColours.contains(ucs))
2638 userColours.add(ucs);
2641 id = "ucs" + userColours.indexOf(ucs);
2644 // actually create the scheme's entry in the XML model
2645 java.awt.Color[] colours = ucs.getColours();
2646 UserColours uc = new UserColours();
2647 // UserColourScheme jbucs = new UserColourScheme();
2648 JalviewUserColours jbucs = new JalviewUserColours();
2650 for (int i = 0; i < colours.length; i++)
2652 Colour col = new Colour();
2653 col.setName(ResidueProperties.aa[i]);
2654 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2655 // jbucs.addColour(col);
2656 jbucs.getColour().add(col);
2658 if (ucs.getLowerCaseColours() != null)
2660 colours = ucs.getLowerCaseColours();
2661 for (int i = 0; i < colours.length; i++)
2663 Colour col = new Colour();
2664 col.setName(ResidueProperties.aa[i].toLowerCase());
2665 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2666 // jbucs.addColour(col);
2667 jbucs.getColour().add(col);
2672 uc.setUserColourScheme(jbucs);
2673 // jm.addUserColours(uc);
2674 jm.getUserColours().add(uc);
2680 jalview.schemes.UserColourScheme getUserColourScheme(
2681 JalviewModel jm, String id)
2683 List<UserColours> uc = jm.getUserColours();
2684 UserColours colours = null;
2686 for (int i = 0; i < uc.length; i++)
2688 if (uc[i].getId().equals(id))
2695 for (UserColours c : uc)
2697 if (c.getId().equals(id))
2704 java.awt.Color[] newColours = new java.awt.Color[24];
2706 for (int i = 0; i < 24; i++)
2708 newColours[i] = new java.awt.Color(Integer.parseInt(
2709 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2710 colours.getUserColourScheme().getColour().get(i).getRGB(),
2714 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2717 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2719 newColours = new java.awt.Color[23];
2720 for (int i = 0; i < 23; i++)
2722 newColours[i] = new java.awt.Color(Integer.parseInt(
2723 colours.getUserColourScheme().getColour().get(i + 24)
2727 ucs.setLowerCaseColours(newColours);
2734 * contains last error message (if any) encountered by XML loader.
2736 String errorMessage = null;
2739 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2740 * exceptions are raised during project XML parsing
2742 public boolean attemptversion1parse = false;
2745 * Load a jalview project archive from a jar file
2748 * - HTTP URL or filename
2750 public AlignFrame loadJalviewAlign(final Object file)
2753 jalview.gui.AlignFrame af = null;
2757 // create list to store references for any new Jmol viewers created
2758 newStructureViewers = new Vector<>();
2759 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2760 // Workaround is to make sure caller implements the JarInputStreamProvider
2762 // so we can re-open the jar input stream for each entry.
2764 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2765 af = loadJalviewAlign(jprovider);
2768 af.setMenusForViewport();
2770 } catch (MalformedURLException e)
2772 errorMessage = "Invalid URL format for '" + file + "'";
2778 SwingUtilities.invokeAndWait(new Runnable()
2783 setLoadingFinishedForNewStructureViewers();
2786 } catch (Exception x)
2788 System.err.println("Error loading alignment: " + x.getMessage());
2794 @SuppressWarnings("unused")
2795 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2797 // BH 2018 allow for bytes already attached to File object
2799 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2800 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2803 errorMessage = null;
2804 uniqueSetSuffix = null;
2806 viewportsAdded.clear();
2807 frefedSequence = null;
2809 if (file.startsWith("http://")) {
2810 url = new URL(file);
2812 final URL _url = url;
2813 return new jarInputStreamProvider() {
2816 public JarInputStream getJarInputStream() throws IOException {
2817 if (bytes != null) {
2818 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2819 return new JarInputStream(new ByteArrayInputStream(bytes));
2822 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2823 return new JarInputStream(_url.openStream());
2825 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2826 return new JarInputStream(new FileInputStream(file));
2831 public String getFilename() {
2835 } catch (IOException e) {
2836 e.printStackTrace();
2842 * Recover jalview session from a jalview project archive. Caller may
2843 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2844 * themselves. Any null fields will be initialised with default values,
2845 * non-null fields are left alone.
2850 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2852 errorMessage = null;
2853 if (uniqueSetSuffix == null)
2855 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2857 if (seqRefIds == null)
2861 AlignFrame af = null, _af = null;
2862 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2863 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2864 final String file = jprovider.getFilename();
2867 JarInputStream jin = null;
2868 JarEntry jarentry = null;
2873 jin = jprovider.getJarInputStream();
2874 for (int i = 0; i < entryCount; i++)
2876 jarentry = jin.getNextJarEntry();
2879 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2881 JAXBContext jc = JAXBContext
2882 .newInstance("jalview.xml.binding.jalview");
2883 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2884 .createXMLStreamReader(jin);
2885 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2886 JAXBElement<JalviewModel> jbe = um
2887 .unmarshal(streamReader, JalviewModel.class);
2888 JalviewModel object = jbe.getValue();
2890 if (true) // !skipViewport(object))
2892 _af = loadFromObject(object, file, true, jprovider);
2893 if (_af != null && object.getViewport().size() > 0)
2894 // getJalviewModelSequence().getViewportCount() > 0)
2898 // store a reference to the first view
2901 if (_af.getViewport().isGatherViewsHere())
2903 // if this is a gathered view, keep its reference since
2904 // after gathering views, only this frame will remain
2906 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2909 // Save dataset to register mappings once all resolved
2910 importedDatasets.put(
2911 af.getViewport().getAlignment().getDataset(),
2912 af.getViewport().getAlignment().getDataset());
2917 else if (jarentry != null)
2919 // Some other file here.
2922 } while (jarentry != null);
2923 resolveFrefedSequences();
2924 } catch (IOException ex)
2926 ex.printStackTrace();
2927 errorMessage = "Couldn't locate Jalview XML file : " + file;
2929 "Exception whilst loading jalview XML file : " + ex + "\n");
2930 } catch (Exception ex)
2932 System.err.println("Parsing as Jalview Version 2 file failed.");
2933 ex.printStackTrace(System.err);
2934 if (attemptversion1parse)
2936 // used to attempt to parse as V1 castor-generated xml
2938 if (Desktop.instance != null)
2940 Desktop.instance.stopLoading();
2944 System.out.println("Successfully loaded archive file");
2947 ex.printStackTrace();
2950 "Exception whilst loading jalview XML file : " + ex + "\n");
2951 } catch (OutOfMemoryError e)
2953 // Don't use the OOM Window here
2954 errorMessage = "Out of memory loading jalview XML file";
2955 System.err.println("Out of memory whilst loading jalview XML file");
2956 e.printStackTrace();
2960 * Regather multiple views (with the same sequence set id) to the frame (if
2961 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2962 * views instead of separate frames. Note this doesn't restore a state where
2963 * some expanded views in turn have tabbed views - the last "first tab" read
2964 * in will play the role of gatherer for all.
2966 for (AlignFrame fr : gatherToThisFrame.values())
2968 Desktop.instance.gatherViews(fr);
2971 restoreSplitFrames();
2972 for (AlignmentI ds : importedDatasets.keySet())
2974 if (ds.getCodonFrames() != null)
2976 StructureSelectionManager
2977 .getStructureSelectionManager(Desktop.instance)
2978 .registerMappings(ds.getCodonFrames());
2981 if (errorMessage != null)
2986 if (Desktop.instance != null)
2988 Desktop.instance.stopLoading();
2995 * Try to reconstruct and display SplitFrame windows, where each contains
2996 * complementary dna and protein alignments. Done by pairing up AlignFrame
2997 * objects (created earlier) which have complementary viewport ids associated.
2999 protected void restoreSplitFrames()
3001 List<SplitFrame> gatherTo = new ArrayList<>();
3002 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3003 Map<String, AlignFrame> dna = new HashMap<>();
3006 * Identify the DNA alignments
3008 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3011 AlignFrame af = candidate.getValue();
3012 if (af.getViewport().getAlignment().isNucleotide())
3014 dna.put(candidate.getKey().getId(), af);
3019 * Try to match up the protein complements
3021 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3024 AlignFrame af = candidate.getValue();
3025 if (!af.getViewport().getAlignment().isNucleotide())
3027 String complementId = candidate.getKey().getComplementId();
3028 // only non-null complements should be in the Map
3029 if (complementId != null && dna.containsKey(complementId))
3031 final AlignFrame dnaFrame = dna.get(complementId);
3032 SplitFrame sf = createSplitFrame(dnaFrame, af);
3033 addedToSplitFrames.add(dnaFrame);
3034 addedToSplitFrames.add(af);
3035 dnaFrame.setMenusForViewport();
3036 af.setMenusForViewport();
3037 if (af.getViewport().isGatherViewsHere())
3046 * Open any that we failed to pair up (which shouldn't happen!) as
3047 * standalone AlignFrame's.
3049 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3052 AlignFrame af = candidate.getValue();
3053 if (!addedToSplitFrames.contains(af))
3055 Viewport view = candidate.getKey();
3056 Desktop.addInternalFrame(af, view.getTitle(),
3057 safeInt(view.getWidth()), safeInt(view.getHeight()));
3058 af.setMenusForViewport();
3059 System.err.println("Failed to restore view " + view.getTitle()
3060 + " to split frame");
3065 * Gather back into tabbed views as flagged.
3067 for (SplitFrame sf : gatherTo)
3069 Desktop.instance.gatherViews(sf);
3072 splitFrameCandidates.clear();
3076 * Construct and display one SplitFrame holding DNA and protein alignments.
3079 * @param proteinFrame
3082 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3083 AlignFrame proteinFrame)
3085 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3086 String title = MessageManager.getString("label.linked_view_title");
3087 int width = (int) dnaFrame.getBounds().getWidth();
3088 int height = (int) (dnaFrame.getBounds().getHeight()
3089 + proteinFrame.getBounds().getHeight() + 50);
3092 * SplitFrame location is saved to both enclosed frames
3094 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3095 Desktop.addInternalFrame(splitFrame, title, width, height);
3098 * And compute cDNA consensus (couldn't do earlier with consensus as
3099 * mappings were not yet present)
3101 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3107 * check errorMessage for a valid error message and raise an error box in the
3108 * GUI or write the current errorMessage to stderr and then clear the error
3111 protected void reportErrors()
3113 reportErrors(false);
3116 protected void reportErrors(final boolean saving)
3118 if (errorMessage != null)
3120 final String finalErrorMessage = errorMessage;
3123 javax.swing.SwingUtilities.invokeLater(new Runnable()
3128 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3130 "Error " + (saving ? "saving" : "loading")
3132 JvOptionPane.WARNING_MESSAGE);
3138 System.err.println("Problem loading Jalview file: " + errorMessage);
3141 errorMessage = null;
3144 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3147 * when set, local views will be updated from view stored in JalviewXML
3148 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3149 * sync if this is set to true.
3151 private final boolean updateLocalViews = false;
3154 * Returns the path to a temporary file holding the PDB file for the given PDB
3155 * id. The first time of asking, searches for a file of that name in the
3156 * Jalview project jar, and copies it to a new temporary file. Any repeat
3157 * requests just return the path to the file previously created.
3163 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3166 if (alreadyLoadedPDB.containsKey(pdbId))
3168 return alreadyLoadedPDB.get(pdbId).toString();
3171 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3173 if (tempFile != null)
3175 alreadyLoadedPDB.put(pdbId, tempFile);
3181 * Copies the jar entry of given name to a new temporary file and returns the
3182 * path to the file, or null if the entry is not found.
3185 * @param jarEntryName
3187 * a prefix for the temporary file name, must be at least three
3189 * @param suffixModel
3190 * null or original file - so new file can be given the same suffix
3194 protected String copyJarEntry(jarInputStreamProvider jprovider,
3195 String jarEntryName, String prefix, String suffixModel)
3197 String suffix = ".tmp";
3198 if (suffixModel == null)
3200 suffixModel = jarEntryName;
3202 int sfpos = suffixModel.lastIndexOf(".");
3203 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3205 suffix = "." + suffixModel.substring(sfpos + 1);
3208 try (JarInputStream jin = jprovider.getJarInputStream())
3210 JarEntry entry = null;
3213 entry = jin.getNextJarEntry();
3214 } while (entry != null && !entry.getName().equals(jarEntryName));
3218 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3219 File outFile = File.createTempFile(prefix, suffix);
3220 outFile.deleteOnExit();
3221 try (OutputStream os = new FileOutputStream(outFile))
3225 String t = outFile.getAbsolutePath();
3230 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3232 } catch (Exception ex)
3234 ex.printStackTrace();
3240 private class JvAnnotRow
3242 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3249 * persisted version of annotation row from which to take vis properties
3251 public jalview.datamodel.AlignmentAnnotation template;
3254 * original position of the annotation row in the alignment
3260 * Load alignment frame from jalview XML DOM object
3262 * @param jalviewModel
3265 * filename source string
3266 * @param loadTreesAndStructures
3267 * when false only create Viewport
3269 * data source provider
3270 * @return alignment frame created from view stored in DOM
3272 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3273 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3275 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3276 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3278 // JalviewModelSequence jms = object.getJalviewModelSequence();
3280 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3282 Viewport view = (jalviewModel.getViewport().size() > 0)
3283 ? jalviewModel.getViewport().get(0)
3286 // ////////////////////////////////
3287 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3290 // If we just load in the same jar file again, the sequenceSetId
3291 // will be the same, and we end up with multiple references
3292 // to the same sequenceSet. We must modify this id on load
3293 // so that each load of the file gives a unique id
3296 * used to resolve correct alignment dataset for alignments with multiple
3299 String uniqueSeqSetId = null;
3300 String viewId = null;
3303 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3304 viewId = (view.getId() == null ? null
3305 : view.getId() + uniqueSetSuffix);
3308 // ////////////////////////////////
3311 List<SequenceI> hiddenSeqs = null;
3313 List<SequenceI> tmpseqs = new ArrayList<>();
3315 boolean multipleView = false;
3316 SequenceI referenceseqForView = null;
3317 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3318 List<JSeq> jseqs = jalviewModel.getJSeq();
3319 int vi = 0; // counter in vamsasSeq array
3320 for (int i = 0; i < jseqs.size(); i++)
3322 JSeq jseq = jseqs.get(i);
3323 String seqId = jseq.getId();
3325 SequenceI tmpSeq = seqRefIds.get(seqId);
3328 if (!incompleteSeqs.containsKey(seqId))
3330 // may not need this check, but keep it for at least 2.9,1 release
3331 if (tmpSeq.getStart() != jseq.getStart()
3332 || tmpSeq.getEnd() != jseq.getEnd())
3335 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3336 tmpSeq.getName(), tmpSeq.getStart(),
3337 tmpSeq.getEnd(), jseq.getStart(),
3343 incompleteSeqs.remove(seqId);
3345 if (vamsasSeqs.size() > vi
3346 && vamsasSeqs.get(vi).getId().equals(seqId))
3348 // most likely we are reading a dataset XML document so
3349 // update from vamsasSeq section of XML for this sequence
3350 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3351 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3352 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3357 // reading multiple views, so vamsasSeq set is a subset of JSeq
3358 multipleView = true;
3360 tmpSeq.setStart(jseq.getStart());
3361 tmpSeq.setEnd(jseq.getEnd());
3362 tmpseqs.add(tmpSeq);
3366 Sequence vamsasSeq = vamsasSeqs.get(vi);
3367 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3368 vamsasSeq.getSequence());
3369 tmpSeq.setDescription(vamsasSeq.getDescription());
3370 tmpSeq.setStart(jseq.getStart());
3371 tmpSeq.setEnd(jseq.getEnd());
3372 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3373 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3374 tmpseqs.add(tmpSeq);
3378 if (safeBoolean(jseq.isViewreference()))
3380 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3383 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3385 if (hiddenSeqs == null)
3387 hiddenSeqs = new ArrayList<>();
3390 hiddenSeqs.add(tmpSeq);
3395 // Create the alignment object from the sequence set
3396 // ///////////////////////////////
3397 SequenceI[] orderedSeqs = tmpseqs
3398 .toArray(new SequenceI[tmpseqs.size()]);
3400 AlignmentI al = null;
3401 // so we must create or recover the dataset alignment before going further
3402 // ///////////////////////////////
3403 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3405 // older jalview projects do not have a dataset - so creat alignment and
3407 al = new Alignment(orderedSeqs);
3408 al.setDataset(null);
3412 boolean isdsal = jalviewModel.getViewport().isEmpty();
3415 // we are importing a dataset record, so
3416 // recover reference to an alignment already materialsed as dataset
3417 al = getDatasetFor(vamsasSet.getDatasetId());
3421 // materialse the alignment
3422 al = new Alignment(orderedSeqs);
3426 addDatasetRef(vamsasSet.getDatasetId(), al);
3429 // finally, verify all data in vamsasSet is actually present in al
3430 // passing on flag indicating if it is actually a stored dataset
3431 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3434 if (referenceseqForView != null)
3436 al.setSeqrep(referenceseqForView);
3438 // / Add the alignment properties
3439 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3441 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3443 al.setProperty(ssp.getKey(), ssp.getValue());
3446 // ///////////////////////////////
3448 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3451 // load sequence features, database references and any associated PDB
3452 // structures for the alignment
3454 // prior to 2.10, this part would only be executed the first time a
3455 // sequence was encountered, but not afterwards.
3456 // now, for 2.10 projects, this is also done if the xml doc includes
3457 // dataset sequences not actually present in any particular view.
3459 for (int i = 0; i < vamsasSeqs.size(); i++)
3461 JSeq jseq = jseqs.get(i);
3462 if (jseq.getFeatures().size() > 0)
3464 List<Feature> features = jseq.getFeatures();
3465 for (int f = 0; f < features.size(); f++)
3467 Feature feat = features.get(f);
3468 SequenceFeature sf = new SequenceFeature(feat.getType(),
3469 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3470 safeFloat(feat.getScore()), feat.getFeatureGroup());
3471 sf.setStatus(feat.getStatus());
3474 * load any feature attributes - include map-valued attributes
3476 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3477 for (int od = 0; od < feat.getOtherData().size(); od++)
3479 OtherData keyValue = feat.getOtherData().get(od);
3480 String attributeName = keyValue.getKey();
3481 String attributeValue = keyValue.getValue();
3482 if (attributeName.startsWith("LINK"))
3484 sf.addLink(attributeValue);
3488 String subAttribute = keyValue.getKey2();
3489 if (subAttribute == null)
3491 // simple string-valued attribute
3492 sf.setValue(attributeName, attributeValue);
3496 // attribute 'key' has sub-attribute 'key2'
3497 if (!mapAttributes.containsKey(attributeName))
3499 mapAttributes.put(attributeName, new HashMap<>());
3501 mapAttributes.get(attributeName).put(subAttribute,
3506 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3509 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3512 // adds feature to datasequence's feature set (since Jalview 2.10)
3513 al.getSequenceAt(i).addSequenceFeature(sf);
3516 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3518 // adds dbrefs to datasequence's set (since Jalview 2.10)
3520 al.getSequenceAt(i).getDatasetSequence() == null
3521 ? al.getSequenceAt(i)
3522 : al.getSequenceAt(i).getDatasetSequence(),
3525 if (jseq.getPdbids().size() > 0)
3527 List<Pdbids> ids = jseq.getPdbids();
3528 for (int p = 0; p < ids.size(); p++)
3530 Pdbids pdbid = ids.get(p);
3531 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3532 entry.setId(pdbid.getId());
3533 if (pdbid.getType() != null)
3535 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3537 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3541 entry.setType(PDBEntry.Type.FILE);
3544 // jprovider is null when executing 'New View'
3545 if (pdbid.getFile() != null && jprovider != null)
3547 if (!pdbloaded.containsKey(pdbid.getFile()))
3549 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3554 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3558 if (pdbid.getPdbentryItem() != null)
3560 for (PdbentryItem item : pdbid.getPdbentryItem())
3562 for (Property pr : item.getProperty())
3564 entry.setProperty(pr.getName(), pr.getValue());
3569 for (Property prop : pdbid.getProperty())
3571 entry.setProperty(prop.getName(), prop.getValue());
3573 StructureSelectionManager
3574 .getStructureSelectionManager(Desktop.instance)
3575 .registerPDBEntry(entry);
3576 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3577 if (al.getSequenceAt(i).getDatasetSequence() != null)
3579 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3583 al.getSequenceAt(i).addPDBId(entry);
3588 } // end !multipleview
3590 // ///////////////////////////////
3591 // LOAD SEQUENCE MAPPINGS
3593 if (vamsasSet.getAlcodonFrame().size() > 0)
3595 // TODO Potentially this should only be done once for all views of an
3597 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3598 for (int i = 0; i < alc.size(); i++)
3600 AlignedCodonFrame cf = new AlignedCodonFrame();
3601 if (alc.get(i).getAlcodMap().size() > 0)
3603 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3604 for (int m = 0; m < maps.size(); m++)
3606 AlcodMap map = maps.get(m);
3607 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3609 jalview.datamodel.Mapping mapping = null;
3610 // attach to dna sequence reference.
3611 if (map.getMapping() != null)
3613 mapping = addMapping(map.getMapping());
3614 if (dnaseq != null && mapping.getTo() != null)
3616 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3622 newAlcodMapRef(map.getDnasq(), cf, mapping));
3626 al.addCodonFrame(cf);
3631 // ////////////////////////////////
3633 List<JvAnnotRow> autoAlan = new ArrayList<>();
3636 * store any annotations which forward reference a group's ID
3638 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3640 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3642 List<Annotation> an = vamsasSet.getAnnotation();
3644 for (int i = 0; i < an.size(); i++)
3646 Annotation annotation = an.get(i);
3649 * test if annotation is automatically calculated for this view only
3651 boolean autoForView = false;
3652 if (annotation.getLabel().equals("Quality")
3653 || annotation.getLabel().equals("Conservation")
3654 || annotation.getLabel().equals("Consensus"))
3656 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3658 // JAXB has no has() test; schema defaults value to false
3659 // if (!annotation.hasAutoCalculated())
3661 // annotation.setAutoCalculated(true);
3664 if (autoForView || annotation.isAutoCalculated())
3666 // remove ID - we don't recover annotation from other views for
3667 // view-specific annotation
3668 annotation.setId(null);
3671 // set visibility for other annotation in this view
3672 String annotationId = annotation.getId();
3673 if (annotationId != null && annotationIds.containsKey(annotationId))
3675 AlignmentAnnotation jda = annotationIds.get(annotationId);
3676 // in principle Visible should always be true for annotation displayed
3677 // in multiple views
3678 if (annotation.isVisible() != null)
3680 jda.visible = annotation.isVisible();
3683 al.addAnnotation(jda);
3687 // Construct new annotation from model.
3688 List<AnnotationElement> ae = annotation.getAnnotationElement();
3689 jalview.datamodel.Annotation[] anot = null;
3690 java.awt.Color firstColour = null;
3692 if (!annotation.isScoreOnly())
3694 anot = new jalview.datamodel.Annotation[al.getWidth()];
3695 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3697 AnnotationElement annElement = ae.get(aa);
3698 anpos = annElement.getPosition();
3700 if (anpos >= anot.length)
3705 float value = safeFloat(annElement.getValue());
3706 anot[anpos] = new jalview.datamodel.Annotation(
3707 annElement.getDisplayCharacter(),
3708 annElement.getDescription(),
3709 (annElement.getSecondaryStructure() == null
3710 || annElement.getSecondaryStructure()
3714 .getSecondaryStructure()
3717 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3718 if (firstColour == null)
3720 firstColour = anot[anpos].colour;
3724 jalview.datamodel.AlignmentAnnotation jaa = null;
3726 if (annotation.isGraph())
3728 float llim = 0, hlim = 0;
3729 // if (autoForView || an[i].isAutoCalculated()) {
3732 jaa = new jalview.datamodel.AlignmentAnnotation(
3733 annotation.getLabel(), annotation.getDescription(), anot,
3734 llim, hlim, safeInt(annotation.getGraphType()));
3736 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3737 jaa._linecolour = firstColour;
3738 if (annotation.getThresholdLine() != null)
3740 jaa.setThreshold(new jalview.datamodel.GraphLine(
3741 safeFloat(annotation.getThresholdLine().getValue()),
3742 annotation.getThresholdLine().getLabel(),
3743 new java.awt.Color(safeInt(
3744 annotation.getThresholdLine().getColour()))));
3746 if (autoForView || annotation.isAutoCalculated())
3748 // Hardwire the symbol display line to ensure that labels for
3749 // histograms are displayed
3755 jaa = new jalview.datamodel.AlignmentAnnotation(
3756 annotation.getLabel(), annotation.getDescription(), anot);
3757 jaa._linecolour = firstColour;
3759 // register new annotation
3760 if (annotation.getId() != null)
3762 annotationIds.put(annotation.getId(), jaa);
3763 jaa.annotationId = annotation.getId();
3765 // recover sequence association
3766 String sequenceRef = annotation.getSequenceRef();
3767 if (sequenceRef != null)
3769 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3770 SequenceI sequence = seqRefIds.get(sequenceRef);
3771 if (sequence == null)
3773 // in pre-2.9 projects sequence ref is to sequence name
3774 sequence = al.findName(sequenceRef);
3776 if (sequence != null)
3778 jaa.createSequenceMapping(sequence, 1, true);
3779 sequence.addAlignmentAnnotation(jaa);
3782 // and make a note of any group association
3783 if (annotation.getGroupRef() != null
3784 && annotation.getGroupRef().length() > 0)
3786 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3787 .get(annotation.getGroupRef());
3790 aal = new ArrayList<>();
3791 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3796 if (annotation.getScore() != null)
3798 jaa.setScore(annotation.getScore().doubleValue());
3800 if (annotation.isVisible() != null)
3802 jaa.visible = annotation.isVisible().booleanValue();
3805 if (annotation.isCentreColLabels() != null)
3807 jaa.centreColLabels = annotation.isCentreColLabels()
3811 if (annotation.isScaleColLabels() != null)
3813 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3815 if (annotation.isAutoCalculated())
3817 // newer files have an 'autoCalculated' flag and store calculation
3818 // state in viewport properties
3819 jaa.autoCalculated = true; // means annotation will be marked for
3820 // update at end of load.
3822 if (annotation.getGraphHeight() != null)
3824 jaa.graphHeight = annotation.getGraphHeight().intValue();
3826 jaa.belowAlignment = annotation.isBelowAlignment();
3827 jaa.setCalcId(annotation.getCalcId());
3828 if (annotation.getProperty().size() > 0)
3830 for (Annotation.Property prop : annotation
3833 jaa.setProperty(prop.getName(), prop.getValue());
3836 if (jaa.autoCalculated)
3838 autoAlan.add(new JvAnnotRow(i, jaa));
3841 // if (!autoForView)
3843 // add autocalculated group annotation and any user created annotation
3845 al.addAnnotation(jaa);
3849 // ///////////////////////
3851 // Create alignment markup and styles for this view
3852 if (jalviewModel.getJGroup().size() > 0)
3854 List<JGroup> groups = jalviewModel.getJGroup();
3855 boolean addAnnotSchemeGroup = false;
3856 for (int i = 0; i < groups.size(); i++)
3858 JGroup jGroup = groups.get(i);
3859 ColourSchemeI cs = null;
3860 if (jGroup.getColour() != null)
3862 if (jGroup.getColour().startsWith("ucs"))
3864 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3866 else if (jGroup.getColour().equals("AnnotationColourGradient")
3867 && jGroup.getAnnotationColours() != null)
3869 addAnnotSchemeGroup = true;
3873 cs = ColourSchemeProperty.getColourScheme(null, al,
3874 jGroup.getColour());
3877 int pidThreshold = safeInt(jGroup.getPidThreshold());
3879 Vector<SequenceI> seqs = new Vector<>();
3881 for (int s = 0; s < jGroup.getSeq().size(); s++)
3883 String seqId = jGroup.getSeq().get(s);
3884 SequenceI ts = seqRefIds.get(seqId);
3888 seqs.addElement(ts);
3892 if (seqs.size() < 1)
3897 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3898 safeBoolean(jGroup.isDisplayBoxes()),
3899 safeBoolean(jGroup.isDisplayText()),
3900 safeBoolean(jGroup.isColourText()),
3901 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3902 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3903 sg.getGroupColourScheme()
3904 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3905 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3907 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3908 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3909 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3910 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3911 // attributes with a default in the schema are never null
3912 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3913 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3914 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3915 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3916 if (jGroup.getConsThreshold() != null
3917 && jGroup.getConsThreshold().intValue() != 0)
3919 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3922 c.verdict(false, 25);
3923 sg.cs.setConservation(c);
3926 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3928 // re-instate unique group/annotation row reference
3929 List<AlignmentAnnotation> jaal = groupAnnotRefs
3930 .get(jGroup.getId());
3933 for (AlignmentAnnotation jaa : jaal)
3936 if (jaa.autoCalculated)
3938 // match up and try to set group autocalc alignment row for this
3940 if (jaa.label.startsWith("Consensus for "))
3942 sg.setConsensus(jaa);
3944 // match up and try to set group autocalc alignment row for this
3946 if (jaa.label.startsWith("Conservation for "))
3948 sg.setConservationRow(jaa);
3955 if (addAnnotSchemeGroup)
3957 // reconstruct the annotation colourscheme
3958 sg.setColourScheme(constructAnnotationColour(
3959 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3965 // only dataset in this model, so just return.
3968 // ///////////////////////////////
3971 AlignFrame af = null;
3972 AlignViewport av = null;
3973 // now check to see if we really need to create a new viewport.
3974 if (multipleView && viewportsAdded.size() == 0)
3976 // We recovered an alignment for which a viewport already exists.
3977 // TODO: fix up any settings necessary for overlaying stored state onto
3978 // state recovered from another document. (may not be necessary).
3979 // we may need a binding from a viewport in memory to one recovered from
3981 // and then recover its containing af to allow the settings to be applied.
3982 // TODO: fix for vamsas demo
3984 "About to recover a viewport for existing alignment: Sequence set ID is "
3986 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3987 if (seqsetobj != null)
3989 if (seqsetobj instanceof String)
3991 uniqueSeqSetId = (String) seqsetobj;
3993 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3999 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4005 * indicate that annotation colours are applied across all groups (pre
4006 * Jalview 2.8.1 behaviour)
4008 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4009 jalviewModel.getVersion());
4011 AlignmentPanel ap = null;
4012 boolean isnewview = true;
4015 // Check to see if this alignment already has a view id == viewId
4016 jalview.gui.AlignmentPanel views[] = Desktop
4017 .getAlignmentPanels(uniqueSeqSetId);
4018 if (views != null && views.length > 0)
4020 for (int v = 0; v < views.length; v++)
4022 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4024 // recover the existing alignpanel, alignframe, viewport
4025 af = views[v].alignFrame;
4028 // TODO: could even skip resetting view settings if we don't want to
4029 // change the local settings from other jalview processes
4038 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4039 uniqueSeqSetId, viewId, autoAlan);
4040 av = af.getViewport();
4045 * Load any trees, PDB structures and viewers, Overview
4047 * Not done if flag is false (when this method is used for New View)
4049 if (loadTreesAndStructures)
4051 loadTrees(jalviewModel, view, af, av, ap);
4052 loadPCAViewers(jalviewModel, ap);
4053 loadPDBStructures(jprovider, jseqs, af, ap);
4054 loadRnaViewers(jprovider, jseqs, ap);
4055 loadOverview(view, af);
4057 // and finally return.
4062 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4063 * and geometry as saved
4068 protected void loadOverview(Viewport view, AlignFrame af)
4070 Overview overview = view.getOverview();
4071 if (overview != null)
4073 OverviewPanel overviewPanel = af
4074 .openOverviewPanel(overview.isShowHidden());
4075 overviewPanel.setTitle(overview.getTitle());
4076 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4077 overview.getWidth(), overview.getHeight());
4078 Color gap = new Color(overview.getGapColour());
4079 Color residue = new Color(overview.getResidueColour());
4080 Color hidden = new Color(overview.getHiddenColour());
4081 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4086 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4087 * panel is restored from separate jar entries, two (gapped and trimmed) per
4088 * sequence and secondary structure.
4090 * Currently each viewer shows just one sequence and structure (gapped and
4091 * trimmed), however this method is designed to support multiple sequences or
4092 * structures in viewers if wanted in future.
4098 private void loadRnaViewers(jarInputStreamProvider jprovider,
4099 List<JSeq> jseqs, AlignmentPanel ap)
4102 * scan the sequences for references to viewers; create each one the first
4103 * time it is referenced, add Rna models to existing viewers
4105 for (JSeq jseq : jseqs)
4107 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4109 RnaViewer viewer = jseq.getRnaViewer().get(i);
4110 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4113 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4115 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4116 SequenceI seq = seqRefIds.get(jseq.getId());
4117 AlignmentAnnotation ann = this.annotationIds
4118 .get(ss.getAnnotationId());
4121 * add the structure to the Varna display (with session state copied
4122 * from the jar to a temporary file)
4124 boolean gapped = safeBoolean(ss.isGapped());
4125 String rnaTitle = ss.getTitle();
4126 String sessionState = ss.getViewerState();
4127 String tempStateFile = copyJarEntry(jprovider, sessionState,
4129 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4130 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4132 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4138 * Locate and return an already instantiated matching AppVarna, or create one
4142 * @param viewIdSuffix
4146 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4147 String viewIdSuffix, AlignmentPanel ap)
4150 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4151 * if load is repeated
4153 String postLoadId = viewer.getViewId() + viewIdSuffix;
4154 for (JInternalFrame frame : getAllFrames())
4156 if (frame instanceof AppVarna)
4158 AppVarna varna = (AppVarna) frame;
4159 if (postLoadId.equals(varna.getViewId()))
4161 // this viewer is already instantiated
4162 // could in future here add ap as another 'parent' of the
4163 // AppVarna window; currently just 1-to-many
4170 * viewer not found - make it
4172 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4173 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4174 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4175 safeInt(viewer.getDividerLocation()));
4176 AppVarna varna = new AppVarna(model, ap);
4182 * Load any saved trees
4190 protected void loadTrees(JalviewModel jm, Viewport view,
4191 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4193 // TODO result of automated refactoring - are all these parameters needed?
4196 for (int t = 0; t < jm.getTree().size(); t++)
4199 Tree tree = jm.getTree().get(t);
4201 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4204 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4205 tree.getTitle(), safeInt(tree.getWidth()),
4206 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4207 safeInt(tree.getYpos()));
4208 if (tree.getId() != null)
4210 // perhaps bind the tree id to something ?
4215 // update local tree attributes ?
4216 // TODO: should check if tp has been manipulated by user - if so its
4217 // settings shouldn't be modified
4218 tp.setTitle(tree.getTitle());
4219 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4220 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4221 safeInt(tree.getHeight())));
4222 tp.setViewport(av); // af.viewport;
4223 // TODO: verify 'associate with all views' works still
4224 tp.getTreeCanvas().setViewport(av); // af.viewport;
4225 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4227 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4230 warn("There was a problem recovering stored Newick tree: \n"
4231 + tree.getNewick());
4235 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4236 tp.fitToWindow_actionPerformed(null);
4238 if (tree.getFontName() != null)
4241 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4242 safeInt(tree.getFontSize())));
4247 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4248 safeInt(view.getFontSize())));
4251 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4252 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4253 tp.showDistances(safeBoolean(tree.isShowDistances()));
4255 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4257 if (safeBoolean(tree.isCurrentTree()))
4259 af.getViewport().setCurrentTree(tp.getTree());
4263 } catch (Exception ex)
4265 ex.printStackTrace();
4270 * Load and link any saved structure viewers.
4277 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4278 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4281 * Run through all PDB ids on the alignment, and collect mappings between
4282 * distinct view ids and all sequences referring to that view.
4284 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4286 for (int i = 0; i < jseqs.size(); i++)
4288 JSeq jseq = jseqs.get(i);
4289 if (jseq.getPdbids().size() > 0)
4291 List<Pdbids> ids = jseq.getPdbids();
4292 for (int p = 0; p < ids.size(); p++)
4294 Pdbids pdbid = ids.get(p);
4295 final int structureStateCount = pdbid.getStructureState().size();
4296 for (int s = 0; s < structureStateCount; s++)
4298 // check to see if we haven't already created this structure view
4299 final StructureState structureState = pdbid
4300 .getStructureState().get(s);
4301 String sviewid = (structureState.getViewId() == null) ? null
4302 : structureState.getViewId() + uniqueSetSuffix;
4303 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4304 // Originally : pdbid.getFile()
4305 // : TODO: verify external PDB file recovery still works in normal
4306 // jalview project load
4308 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4309 jpdb.setId(pdbid.getId());
4311 int x = safeInt(structureState.getXpos());
4312 int y = safeInt(structureState.getYpos());
4313 int width = safeInt(structureState.getWidth());
4314 int height = safeInt(structureState.getHeight());
4316 // Probably don't need to do this anymore...
4317 // Desktop.desktop.getComponentAt(x, y);
4318 // TODO: NOW: check that this recovers the PDB file correctly.
4319 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4321 jalview.datamodel.SequenceI seq = seqRefIds
4322 .get(jseq.getId() + "");
4323 if (sviewid == null)
4325 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4328 if (!structureViewers.containsKey(sviewid))
4330 String viewerType = structureState.getType();
4331 if (viewerType == null) // pre Jalview 2.9
4333 viewerType = ViewerType.JMOL.toString();
4335 structureViewers.put(sviewid,
4336 new StructureViewerModel(x, y, width, height, false,
4337 false, true, structureState.getViewId(),
4339 // Legacy pre-2.7 conversion JAL-823 :
4340 // do not assume any view has to be linked for colour by
4344 // assemble String[] { pdb files }, String[] { id for each
4345 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4346 // seqs_file 2}, boolean[] {
4347 // linkAlignPanel,superposeWithAlignpanel}} from hash
4348 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4349 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4350 || structureState.isAlignwithAlignPanel());
4353 * Default colour by linked panel to false if not specified (e.g.
4354 * for pre-2.7 projects)
4356 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4357 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4358 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4361 * Default colour by viewer to true if not specified (e.g. for
4364 boolean colourByViewer = jmoldat.isColourByViewer();
4365 colourByViewer &= structureState.isColourByJmol();
4366 jmoldat.setColourByViewer(colourByViewer);
4368 if (jmoldat.getStateData().length() < structureState
4369 .getValue()/*Content()*/.length())
4371 jmoldat.setStateData(structureState.getValue());// Content());
4373 if (pdbid.getFile() != null)
4375 File mapkey = new File(pdbid.getFile());
4376 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4377 if (seqstrmaps == null)
4379 jmoldat.getFileData().put(mapkey,
4380 seqstrmaps = jmoldat.new StructureData(pdbFile,
4383 if (!seqstrmaps.getSeqList().contains(seq))
4385 seqstrmaps.getSeqList().add(seq);
4391 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");
4398 // Instantiate the associated structure views
4399 for (Entry<String, StructureViewerModel> entry : structureViewers
4404 createOrLinkStructureViewer(entry, af, ap, jprovider);
4405 } catch (Exception e)
4408 "Error loading structure viewer: " + e.getMessage());
4409 // failed - try the next one
4421 protected void createOrLinkStructureViewer(
4422 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4423 AlignmentPanel ap, jarInputStreamProvider jprovider)
4425 final StructureViewerModel stateData = viewerData.getValue();
4428 * Search for any viewer windows already open from other alignment views
4429 * that exactly match the stored structure state
4431 StructureViewerBase comp = findMatchingViewer(viewerData);
4435 linkStructureViewer(ap, comp, stateData);
4439 String type = stateData.getType();
4442 ViewerType viewerType = ViewerType.valueOf(type);
4443 createStructureViewer(viewerType, viewerData, af, jprovider);
4444 } catch (IllegalArgumentException | NullPointerException e)
4446 // TODO JAL-3619 show error dialog / offer an alternative viewer
4448 "Invalid structure viewer type: " + type);
4453 * Generates a name for the entry in the project jar file to hold state
4454 * information for a structure viewer
4459 protected String getViewerJarEntryName(String viewId)
4461 return VIEWER_PREFIX + viewId;
4465 * Returns any open frame that matches given structure viewer data. The match
4466 * is based on the unique viewId, or (for older project versions) the frame's
4472 protected StructureViewerBase findMatchingViewer(
4473 Entry<String, StructureViewerModel> viewerData)
4475 final String sviewid = viewerData.getKey();
4476 final StructureViewerModel svattrib = viewerData.getValue();
4477 StructureViewerBase comp = null;
4478 JInternalFrame[] frames = getAllFrames();
4479 for (JInternalFrame frame : frames)
4481 if (frame instanceof StructureViewerBase)
4484 * Post jalview 2.4 schema includes structure view id
4486 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4489 comp = (StructureViewerBase) frame;
4490 break; // break added in 2.9
4493 * Otherwise test for matching position and size of viewer frame
4495 else if (frame.getX() == svattrib.getX()
4496 && frame.getY() == svattrib.getY()
4497 && frame.getHeight() == svattrib.getHeight()
4498 && frame.getWidth() == svattrib.getWidth())
4500 comp = (StructureViewerBase) frame;
4501 // no break in faint hope of an exact match on viewId
4509 * Link an AlignmentPanel to an existing structure viewer.
4514 * @param useinViewerSuperpos
4515 * @param usetoColourbyseq
4516 * @param viewerColouring
4518 protected void linkStructureViewer(AlignmentPanel ap,
4519 StructureViewerBase viewer, StructureViewerModel stateData)
4521 // NOTE: if the jalview project is part of a shared session then
4522 // view synchronization should/could be done here.
4524 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4525 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4526 final boolean viewerColouring = stateData.isColourByViewer();
4527 Map<File, StructureData> oldFiles = stateData.getFileData();
4530 * Add mapping for sequences in this view to an already open viewer
4532 final AAStructureBindingModel binding = viewer.getBinding();
4533 for (File id : oldFiles.keySet())
4535 // add this and any other pdb files that should be present in the
4537 StructureData filedat = oldFiles.get(id);
4538 String pdbFile = filedat.getFilePath();
4539 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4540 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4542 binding.addSequenceForStructFile(pdbFile, seq);
4544 // and add the AlignmentPanel's reference to the view panel
4545 viewer.addAlignmentPanel(ap);
4546 if (useinViewerSuperpos)
4548 viewer.useAlignmentPanelForSuperposition(ap);
4552 viewer.excludeAlignmentPanelForSuperposition(ap);
4554 if (usetoColourbyseq)
4556 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4560 viewer.excludeAlignmentPanelForColourbyseq(ap);
4565 * Get all frames within the Desktop.
4569 protected JInternalFrame[] getAllFrames()
4571 JInternalFrame[] frames = null;
4572 // TODO is this necessary - is it safe - risk of hanging?
4577 frames = Desktop.desktop.getAllFrames();
4578 } catch (ArrayIndexOutOfBoundsException e)
4580 // occasional No such child exceptions are thrown here...
4584 } catch (InterruptedException f)
4588 } while (frames == null);
4593 * Answers true if 'version' is equal to or later than 'supported', where each
4594 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4595 * changes. Development and test values for 'version' are leniently treated
4599 * - minimum version we are comparing against
4601 * - version of data being processsed
4604 public static boolean isVersionStringLaterThan(String supported,
4607 if (supported == null || version == null
4608 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4609 || version.equalsIgnoreCase("Test")
4610 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4612 System.err.println("Assuming project file with "
4613 + (version == null ? "null" : version)
4614 + " is compatible with Jalview version " + supported);
4619 return StringUtils.compareVersions(version, supported, "b") >= 0;
4623 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4625 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4627 if (newStructureViewers != null)
4629 sview.getBinding().setFinishedLoadingFromArchive(false);
4630 newStructureViewers.add(sview);
4634 protected void setLoadingFinishedForNewStructureViewers()
4636 if (newStructureViewers != null)
4638 for (JalviewStructureDisplayI sview : newStructureViewers)
4640 sview.getBinding().setFinishedLoadingFromArchive(true);
4642 newStructureViewers.clear();
4643 newStructureViewers = null;
4647 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4648 List<SequenceI> hiddenSeqs, AlignmentI al,
4649 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4650 String viewId, List<JvAnnotRow> autoAlan)
4652 AlignFrame af = null;
4653 af = new AlignFrame(al, safeInt(view.getWidth()),
4654 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4658 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4659 // System.out.println("Jalview2XML AF " + e);
4660 // super.processKeyEvent(e);
4667 af.setFileName(file, FileFormat.Jalview);
4669 final AlignViewport viewport = af.getViewport();
4670 for (int i = 0; i < JSEQ.size(); i++)
4672 int colour = safeInt(JSEQ.get(i).getColour());
4673 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4679 viewport.setColourByReferenceSeq(true);
4680 viewport.setDisplayReferenceSeq(true);
4683 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4685 if (view.getSequenceSetId() != null)
4687 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4689 viewport.setSequenceSetId(uniqueSeqSetId);
4692 // propagate shared settings to this new view
4693 viewport.setHistoryList(av.getHistoryList());
4694 viewport.setRedoList(av.getRedoList());
4698 viewportsAdded.put(uniqueSeqSetId, viewport);
4700 // TODO: check if this method can be called repeatedly without
4701 // side-effects if alignpanel already registered.
4702 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4704 // apply Hidden regions to view.
4705 if (hiddenSeqs != null)
4707 for (int s = 0; s < JSEQ.size(); s++)
4709 SequenceGroup hidden = new SequenceGroup();
4710 boolean isRepresentative = false;
4711 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4713 isRepresentative = true;
4714 SequenceI sequenceToHide = al
4715 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4716 hidden.addSequence(sequenceToHide, false);
4717 // remove from hiddenSeqs list so we don't try to hide it twice
4718 hiddenSeqs.remove(sequenceToHide);
4720 if (isRepresentative)
4722 SequenceI representativeSequence = al.getSequenceAt(s);
4723 hidden.addSequence(representativeSequence, false);
4724 viewport.hideRepSequences(representativeSequence, hidden);
4728 SequenceI[] hseqs = hiddenSeqs
4729 .toArray(new SequenceI[hiddenSeqs.size()]);
4730 viewport.hideSequence(hseqs);
4733 // recover view properties and display parameters
4735 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4736 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4737 final int pidThreshold = safeInt(view.getPidThreshold());
4738 viewport.setThreshold(pidThreshold);
4740 viewport.setColourText(safeBoolean(view.isShowColourText()));
4743 .setConservationSelected(
4744 safeBoolean(view.isConservationSelected()));
4745 viewport.setIncrement(safeInt(view.getConsThreshold()));
4746 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4747 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4748 viewport.setFont(new Font(view.getFontName(),
4749 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4751 ViewStyleI vs = viewport.getViewStyle();
4752 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4753 viewport.setViewStyle(vs);
4754 // TODO: allow custom charWidth/Heights to be restored by updating them
4755 // after setting font - which means set above to false
4756 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4757 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4758 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4760 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4762 viewport.setShowText(safeBoolean(view.isShowText()));
4764 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4765 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4766 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4767 viewport.setShowUnconserved(view.isShowUnconserved());
4768 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4770 if (view.getViewName() != null)
4772 viewport.setViewName(view.getViewName());
4773 af.setInitialTabVisible();
4775 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4776 safeInt(view.getWidth()), safeInt(view.getHeight()));
4777 // startSeq set in af.alignPanel.updateLayout below
4778 af.alignPanel.updateLayout();
4779 ColourSchemeI cs = null;
4780 // apply colourschemes
4781 if (view.getBgColour() != null)
4783 if (view.getBgColour().startsWith("ucs"))
4785 cs = getUserColourScheme(jm, view.getBgColour());
4787 else if (view.getBgColour().startsWith("Annotation"))
4789 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4790 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4797 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4798 view.getBgColour());
4803 * turn off 'alignment colour applies to all groups'
4804 * while restoring global colour scheme
4806 viewport.setColourAppliesToAllGroups(false);
4807 viewport.setGlobalColourScheme(cs);
4808 viewport.getResidueShading().setThreshold(pidThreshold,
4809 view.isIgnoreGapsinConsensus());
4810 viewport.getResidueShading()
4811 .setConsensus(viewport.getSequenceConsensusHash());
4812 if (safeBoolean(view.isConservationSelected()) && cs != null)
4814 viewport.getResidueShading()
4815 .setConservationInc(safeInt(view.getConsThreshold()));
4817 af.changeColour(cs);
4818 viewport.setColourAppliesToAllGroups(true);
4821 .setShowSequenceFeatures(
4822 safeBoolean(view.isShowSequenceFeatures()));
4824 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4825 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4826 viewport.setFollowHighlight(view.isFollowHighlight());
4827 viewport.followSelection = view.isFollowSelection();
4828 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4829 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4830 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4831 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4832 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4833 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4834 viewport.setShowGroupConservation(view.isShowGroupConservation());
4835 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4836 viewport.setShowComplementFeaturesOnTop(
4837 view.isShowComplementFeaturesOnTop());
4839 // recover feature settings
4840 if (jm.getFeatureSettings() != null)
4842 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4843 .getFeatureRenderer();
4844 FeaturesDisplayed fdi;
4845 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4846 String[] renderOrder = new String[jm.getFeatureSettings()
4847 .getSetting().size()];
4848 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4849 Map<String, Float> featureOrder = new Hashtable<>();
4851 for (int fs = 0; fs < jm.getFeatureSettings()
4852 .getSetting().size(); fs++)
4854 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4855 String featureType = setting.getType();
4858 * restore feature filters (if any)
4860 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4862 if (filters != null)
4864 FeatureMatcherSetI filter = Jalview2XML
4865 .parseFilter(featureType, filters);
4866 if (!filter.isEmpty())
4868 fr.setFeatureFilter(featureType, filter);
4873 * restore feature colour scheme
4875 Color maxColour = new Color(setting.getColour());
4876 if (setting.getMincolour() != null)
4879 * minColour is always set unless a simple colour
4880 * (including for colour by label though it doesn't use it)
4882 Color minColour = new Color(setting.getMincolour().intValue());
4883 Color noValueColour = minColour;
4884 NoValueColour noColour = setting.getNoValueColour();
4885 if (noColour == NoValueColour.NONE)
4887 noValueColour = null;
4889 else if (noColour == NoValueColour.MAX)
4891 noValueColour = maxColour;
4893 float min = safeFloat(safeFloat(setting.getMin()));
4894 float max = setting.getMax() == null ? 1f
4895 : setting.getMax().floatValue();
4896 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4898 noValueColour, min, max);
4899 if (setting.getAttributeName().size() > 0)
4901 gc.setAttributeName(setting.getAttributeName().toArray(
4902 new String[setting.getAttributeName().size()]));
4904 if (setting.getThreshold() != null)
4906 gc.setThreshold(setting.getThreshold().floatValue());
4907 int threshstate = safeInt(setting.getThreshstate());
4908 // -1 = None, 0 = Below, 1 = Above threshold
4909 if (threshstate == 0)
4911 gc.setBelowThreshold(true);
4913 else if (threshstate == 1)
4915 gc.setAboveThreshold(true);
4918 gc.setAutoScaled(true); // default
4919 if (setting.isAutoScale() != null)
4921 gc.setAutoScaled(setting.isAutoScale());
4923 if (setting.isColourByLabel() != null)
4925 gc.setColourByLabel(setting.isColourByLabel());
4927 // and put in the feature colour table.
4928 featureColours.put(featureType, gc);
4932 featureColours.put(featureType,
4933 new FeatureColour(maxColour));
4935 renderOrder[fs] = featureType;
4936 if (setting.getOrder() != null)
4938 featureOrder.put(featureType, setting.getOrder().floatValue());
4942 featureOrder.put(featureType, Float.valueOf(
4943 fs / jm.getFeatureSettings().getSetting().size()));
4945 if (safeBoolean(setting.isDisplay()))
4947 fdi.setVisible(featureType);
4950 Map<String, Boolean> fgtable = new Hashtable<>();
4951 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4953 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4954 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4956 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4957 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4958 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4959 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4960 fgtable, featureColours, 1.0f, featureOrder);
4961 fr.transferSettings(frs);
4964 if (view.getHiddenColumns().size() > 0)
4966 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4968 final HiddenColumns hc = view.getHiddenColumns().get(c);
4969 viewport.hideColumns(safeInt(hc.getStart()),
4970 safeInt(hc.getEnd()) /* +1 */);
4973 if (view.getCalcIdParam() != null)
4975 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4977 if (calcIdParam != null)
4979 if (recoverCalcIdParam(calcIdParam, viewport))
4984 warn("Couldn't recover parameters for "
4985 + calcIdParam.getCalcId());
4990 af.setMenusFromViewport(viewport);
4991 af.setTitle(view.getTitle());
4992 // TODO: we don't need to do this if the viewport is aready visible.
4994 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4995 * has a 'cdna/protein complement' view, in which case save it in order to
4996 * populate a SplitFrame once all views have been read in.
4998 String complementaryViewId = view.getComplementId();
4999 if (complementaryViewId == null)
5001 Desktop.addInternalFrame(af, view.getTitle(),
5002 safeInt(view.getWidth()), safeInt(view.getHeight()));
5003 // recompute any autoannotation
5004 af.alignPanel.updateAnnotation(false, true);
5005 reorderAutoannotation(af, al, autoAlan);
5006 af.alignPanel.alignmentChanged();
5010 splitFrameCandidates.put(view, af);
5017 * Reads saved data to restore Colour by Annotation settings
5019 * @param viewAnnColour
5023 * @param checkGroupAnnColour
5026 private ColourSchemeI constructAnnotationColour(
5027 AnnotationColourScheme viewAnnColour, AlignFrame af,
5028 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5030 boolean propagateAnnColour = false;
5031 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5033 if (checkGroupAnnColour && al.getGroups() != null
5034 && al.getGroups().size() > 0)
5036 // pre 2.8.1 behaviour
5037 // check to see if we should transfer annotation colours
5038 propagateAnnColour = true;
5039 for (SequenceGroup sg : al.getGroups())
5041 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5043 propagateAnnColour = false;
5049 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5051 String annotationId = viewAnnColour.getAnnotation();
5052 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5055 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5057 if (matchedAnnotation == null
5058 && annAlignment.getAlignmentAnnotation() != null)
5060 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5063 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5065 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5070 if (matchedAnnotation == null)
5072 System.err.println("Failed to match annotation colour scheme for "
5076 if (matchedAnnotation.getThreshold() == null)
5078 matchedAnnotation.setThreshold(
5079 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5080 "Threshold", Color.black));
5083 AnnotationColourGradient cs = null;
5084 if (viewAnnColour.getColourScheme().equals("None"))
5086 cs = new AnnotationColourGradient(matchedAnnotation,
5087 new Color(safeInt(viewAnnColour.getMinColour())),
5088 new Color(safeInt(viewAnnColour.getMaxColour())),
5089 safeInt(viewAnnColour.getAboveThreshold()));
5091 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5093 cs = new AnnotationColourGradient(matchedAnnotation,
5094 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5095 safeInt(viewAnnColour.getAboveThreshold()));
5099 cs = new AnnotationColourGradient(matchedAnnotation,
5100 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5101 viewAnnColour.getColourScheme()),
5102 safeInt(viewAnnColour.getAboveThreshold()));
5105 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5106 boolean useOriginalColours = safeBoolean(
5107 viewAnnColour.isPredefinedColours());
5108 cs.setSeqAssociated(perSequenceOnly);
5109 cs.setPredefinedColours(useOriginalColours);
5111 if (propagateAnnColour && al.getGroups() != null)
5113 // Also use these settings for all the groups
5114 for (int g = 0; g < al.getGroups().size(); g++)
5116 SequenceGroup sg = al.getGroups().get(g);
5117 if (sg.getGroupColourScheme() == null)
5122 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5123 matchedAnnotation, sg.getColourScheme(),
5124 safeInt(viewAnnColour.getAboveThreshold()));
5125 sg.setColourScheme(groupScheme);
5126 groupScheme.setSeqAssociated(perSequenceOnly);
5127 groupScheme.setPredefinedColours(useOriginalColours);
5133 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5134 List<JvAnnotRow> autoAlan)
5136 // copy over visualization settings for autocalculated annotation in the
5138 if (al.getAlignmentAnnotation() != null)
5141 * Kludge for magic autoannotation names (see JAL-811)
5143 String[] magicNames = new String[] { "Consensus", "Quality",
5145 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5146 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5147 for (String nm : magicNames)
5149 visan.put(nm, nullAnnot);
5151 for (JvAnnotRow auan : autoAlan)
5153 visan.put(auan.template.label
5154 + (auan.template.getCalcId() == null ? ""
5155 : "\t" + auan.template.getCalcId()),
5158 int hSize = al.getAlignmentAnnotation().length;
5159 List<JvAnnotRow> reorder = new ArrayList<>();
5160 // work through any autoCalculated annotation already on the view
5161 // removing it if it should be placed in a different location on the
5162 // annotation panel.
5163 List<String> remains = new ArrayList<>(visan.keySet());
5164 for (int h = 0; h < hSize; h++)
5166 jalview.datamodel.AlignmentAnnotation jalan = al
5167 .getAlignmentAnnotation()[h];
5168 if (jalan.autoCalculated)
5171 JvAnnotRow valan = visan.get(k = jalan.label);
5172 if (jalan.getCalcId() != null)
5174 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5179 // delete the auto calculated row from the alignment
5180 al.deleteAnnotation(jalan, false);
5184 if (valan != nullAnnot)
5186 if (jalan != valan.template)
5188 // newly created autoannotation row instance
5189 // so keep a reference to the visible annotation row
5190 // and copy over all relevant attributes
5191 if (valan.template.graphHeight >= 0)
5194 jalan.graphHeight = valan.template.graphHeight;
5196 jalan.visible = valan.template.visible;
5198 reorder.add(new JvAnnotRow(valan.order, jalan));
5203 // Add any (possibly stale) autocalculated rows that were not appended to
5204 // the view during construction
5205 for (String other : remains)
5207 JvAnnotRow othera = visan.get(other);
5208 if (othera != nullAnnot && othera.template.getCalcId() != null
5209 && othera.template.getCalcId().length() > 0)
5211 reorder.add(othera);
5214 // now put the automatic annotation in its correct place
5215 int s = 0, srt[] = new int[reorder.size()];
5216 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5217 for (JvAnnotRow jvar : reorder)
5220 srt[s++] = jvar.order;
5223 jalview.util.QuickSort.sort(srt, rws);
5224 // and re-insert the annotation at its correct position
5225 for (JvAnnotRow jvar : rws)
5227 al.addAnnotation(jvar.template, jvar.order);
5229 af.alignPanel.adjustAnnotationHeight();
5233 Hashtable skipList = null;
5236 * TODO remove this method
5239 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5240 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5241 * throw new Error("Implementation Error. No skipList defined for this
5242 * Jalview2XML instance."); } return (AlignFrame)
5243 * skipList.get(view.getSequenceSetId()); }
5247 * Check if the Jalview view contained in object should be skipped or not.
5250 * @return true if view's sequenceSetId is a key in skipList
5252 private boolean skipViewport(JalviewModel object)
5254 if (skipList == null)
5258 String id = object.getViewport().get(0).getSequenceSetId();
5259 if (skipList.containsKey(id))
5261 if (Cache.log != null && Cache.log.isDebugEnabled())
5263 Cache.log.debug("Skipping seuqence set id " + id);
5270 public void addToSkipList(AlignFrame af)
5272 if (skipList == null)
5274 skipList = new Hashtable();
5276 skipList.put(af.getViewport().getSequenceSetId(), af);
5279 public void clearSkipList()
5281 if (skipList != null)
5288 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5289 boolean ignoreUnrefed, String uniqueSeqSetId)
5291 jalview.datamodel.AlignmentI ds = getDatasetFor(
5292 vamsasSet.getDatasetId());
5293 AlignmentI xtant_ds = ds;
5294 if (xtant_ds == null)
5296 // good chance we are about to create a new dataset, but check if we've
5297 // seen some of the dataset sequence IDs before.
5298 // TODO: skip this check if we are working with project generated by
5299 // version 2.11 or later
5300 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5301 if (xtant_ds != null)
5304 addDatasetRef(vamsasSet.getDatasetId(), ds);
5307 Vector<SequenceI> dseqs = null;
5310 // recovering an alignment View
5311 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5312 if (seqSetDS != null)
5314 if (ds != null && ds != seqSetDS)
5316 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5317 + " - CDS/Protein crossreference data may be lost");
5318 if (xtant_ds != null)
5320 // This can only happen if the unique sequence set ID was bound to a
5321 // dataset that did not contain any of the sequences in the view
5322 // currently being restored.
5323 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.");
5327 addDatasetRef(vamsasSet.getDatasetId(), ds);
5332 // try even harder to restore dataset
5333 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5334 // create a list of new dataset sequences
5335 dseqs = new Vector<>();
5337 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5339 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5340 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5342 // create a new dataset
5345 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5346 dseqs.copyInto(dsseqs);
5347 ds = new jalview.datamodel.Alignment(dsseqs);
5348 debug("Created new dataset " + vamsasSet.getDatasetId()
5349 + " for alignment " + System.identityHashCode(al));
5350 addDatasetRef(vamsasSet.getDatasetId(), ds);
5352 // set the dataset for the newly imported alignment.
5353 if (al.getDataset() == null && !ignoreUnrefed)
5356 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5357 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5359 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5363 * XML dataset sequence ID to materialised dataset reference
5365 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5368 * @return the first materialised dataset reference containing a dataset
5369 * sequence referenced in the given view
5371 * - sequences from the view
5373 AlignmentI checkIfHasDataset(List<Sequence> list)
5375 for (Sequence restoredSeq : list)
5377 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5378 if (datasetFor != null)
5387 * Register ds as the containing dataset for the dataset sequences referenced
5388 * by sequences in list
5391 * - sequences in a view
5394 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5396 for (Sequence restoredSeq : list)
5398 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5399 if (prevDS != null && prevDS != ds)
5401 warn("Dataset sequence appears in many datasets: "
5402 + restoredSeq.getDsseqid());
5403 // TODO: try to merge!
5410 * sequence definition to create/merge dataset sequence for
5414 * vector to add new dataset sequence to
5415 * @param ignoreUnrefed
5416 * - when true, don't create new sequences from vamsasSeq if it's id
5417 * doesn't already have an asssociated Jalview sequence.
5419 * - used to reorder the sequence in the alignment according to the
5420 * vamsasSeq array ordering, to preserve ordering of dataset
5422 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5423 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5426 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5428 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5429 boolean reorder = false;
5430 SequenceI dsq = null;
5431 if (sq != null && sq.getDatasetSequence() != null)
5433 dsq = sq.getDatasetSequence();
5439 if (sq == null && ignoreUnrefed)
5443 String sqid = vamsasSeq.getDsseqid();
5446 // need to create or add a new dataset sequence reference to this sequence
5449 dsq = seqRefIds.get(sqid);
5454 // make a new dataset sequence
5455 dsq = sq.createDatasetSequence();
5458 // make up a new dataset reference for this sequence
5459 sqid = seqHash(dsq);
5461 dsq.setVamsasId(uniqueSetSuffix + sqid);
5462 seqRefIds.put(sqid, dsq);
5467 dseqs.addElement(dsq);
5472 ds.addSequence(dsq);
5478 { // make this dataset sequence sq's dataset sequence
5479 sq.setDatasetSequence(dsq);
5480 // and update the current dataset alignment
5485 if (!dseqs.contains(dsq))
5492 if (ds.findIndex(dsq) < 0)
5494 ds.addSequence(dsq);
5501 // TODO: refactor this as a merge dataset sequence function
5502 // now check that sq (the dataset sequence) sequence really is the union of
5503 // all references to it
5504 // boolean pre = sq.getStart() < dsq.getStart();
5505 // boolean post = sq.getEnd() > dsq.getEnd();
5509 // StringBuffer sb = new StringBuffer();
5510 String newres = jalview.analysis.AlignSeq.extractGaps(
5511 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5512 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5513 && newres.length() > dsq.getLength())
5515 // Update with the longer sequence.
5519 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5520 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5521 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5522 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5524 dsq.setSequence(newres);
5526 // TODO: merges will never happen if we 'know' we have the real dataset
5527 // sequence - this should be detected when id==dssid
5529 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5530 // + (pre ? "prepended" : "") + " "
5531 // + (post ? "appended" : ""));
5536 // sequence refs are identical. We may need to update the existing dataset
5537 // alignment with this one, though.
5538 if (ds != null && dseqs == null)
5540 int opos = ds.findIndex(dsq);
5541 SequenceI tseq = null;
5542 if (opos != -1 && vseqpos != opos)
5544 // remove from old position
5545 ds.deleteSequence(dsq);
5547 if (vseqpos < ds.getHeight())
5549 if (vseqpos != opos)
5551 // save sequence at destination position
5552 tseq = ds.getSequenceAt(vseqpos);
5553 ds.replaceSequenceAt(vseqpos, dsq);
5554 ds.addSequence(tseq);
5559 ds.addSequence(dsq);
5566 * TODO use AlignmentI here and in related methods - needs
5567 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5569 Hashtable<String, AlignmentI> datasetIds = null;
5571 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5573 private AlignmentI getDatasetFor(String datasetId)
5575 if (datasetIds == null)
5577 datasetIds = new Hashtable<>();
5580 if (datasetIds.containsKey(datasetId))
5582 return datasetIds.get(datasetId);
5587 private void addDatasetRef(String datasetId, AlignmentI dataset)
5589 if (datasetIds == null)
5591 datasetIds = new Hashtable<>();
5593 datasetIds.put(datasetId, dataset);
5597 * make a new dataset ID for this jalview dataset alignment
5602 private String getDatasetIdRef(AlignmentI dataset)
5604 if (dataset.getDataset() != null)
5606 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5608 String datasetId = makeHashCode(dataset, null);
5609 if (datasetId == null)
5611 // make a new datasetId and record it
5612 if (dataset2Ids == null)
5614 dataset2Ids = new IdentityHashMap<>();
5618 datasetId = dataset2Ids.get(dataset);
5620 if (datasetId == null)
5622 datasetId = "ds" + dataset2Ids.size() + 1;
5623 dataset2Ids.put(dataset, datasetId);
5630 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5631 * constructed as a special subclass GeneLocus.
5633 * @param datasetSequence
5636 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5638 for (int d = 0; d < sequence.getDBRef().size(); d++)
5640 DBRef dr = sequence.getDBRef().get(d);
5644 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5645 dr.getAccessionId());
5649 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5650 dr.getAccessionId());
5652 if (dr.getMapping() != null)
5654 entry.setMap(addMapping(dr.getMapping()));
5656 datasetSequence.addDBRef(entry);
5660 private jalview.datamodel.Mapping addMapping(Mapping m)
5662 SequenceI dsto = null;
5663 // Mapping m = dr.getMapping();
5664 int fr[] = new int[m.getMapListFrom().size() * 2];
5665 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5666 for (int _i = 0; from.hasNext(); _i += 2)
5668 MapListFrom mf = from.next();
5669 fr[_i] = mf.getStart();
5670 fr[_i + 1] = mf.getEnd();
5672 int fto[] = new int[m.getMapListTo().size() * 2];
5673 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5674 for (int _i = 0; to.hasNext(); _i += 2)
5676 MapListTo mf = to.next();
5677 fto[_i] = mf.getStart();
5678 fto[_i + 1] = mf.getEnd();
5680 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5681 fto, m.getMapFromUnit().intValue(),
5682 m.getMapToUnit().intValue());
5685 * (optional) choice of dseqFor or Sequence
5687 if (m.getDseqFor() != null)
5689 String dsfor = m.getDseqFor();
5690 if (seqRefIds.containsKey(dsfor))
5695 jmap.setTo(seqRefIds.get(dsfor));
5699 frefedSequence.add(newMappingRef(dsfor, jmap));
5702 else if (m.getSequence() != null)
5705 * local sequence definition
5707 Sequence ms = m.getSequence();
5708 SequenceI djs = null;
5709 String sqid = ms.getDsseqid();
5710 if (sqid != null && sqid.length() > 0)
5713 * recover dataset sequence
5715 djs = seqRefIds.get(sqid);
5720 "Warning - making up dataset sequence id for DbRef sequence map reference");
5721 sqid = ((Object) ms).toString(); // make up a new hascode for
5722 // undefined dataset sequence hash
5723 // (unlikely to happen)
5729 * make a new dataset sequence and add it to refIds hash
5731 djs = new jalview.datamodel.Sequence(ms.getName(),
5733 djs.setStart(jmap.getMap().getToLowest());
5734 djs.setEnd(jmap.getMap().getToHighest());
5735 djs.setVamsasId(uniqueSetSuffix + sqid);
5737 incompleteSeqs.put(sqid, djs);
5738 seqRefIds.put(sqid, djs);
5741 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5750 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5751 * view as XML (but not to file), and then reloading it
5756 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5759 JalviewModel jm = saveState(ap, null, null, null);
5762 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5763 ap.getAlignment().getDataset());
5765 uniqueSetSuffix = "";
5766 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5767 jm.getViewport().get(0).setId(null);
5768 // we don't overwrite the view we just copied
5770 if (this.frefedSequence == null)
5772 frefedSequence = new Vector<>();
5775 viewportsAdded.clear();
5777 AlignFrame af = loadFromObject(jm, null, false, null);
5778 af.getAlignPanels().clear();
5779 af.closeMenuItem_actionPerformed(true);
5782 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5783 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5784 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5785 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5786 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5789 return af.alignPanel;
5792 private Hashtable jvids2vobj;
5794 private void warn(String msg)
5799 private void warn(String msg, Exception e)
5801 if (Cache.log != null)
5805 Cache.log.warn(msg, e);
5809 Cache.log.warn(msg);
5814 System.err.println("Warning: " + msg);
5817 e.printStackTrace();
5822 private void debug(String string)
5824 debug(string, null);
5827 private void debug(String msg, Exception e)
5829 if (Cache.log != null)
5833 Cache.log.debug(msg, e);
5837 Cache.log.debug(msg);
5842 System.err.println("Warning: " + msg);
5845 e.printStackTrace();
5851 * set the object to ID mapping tables used to write/recover objects and XML
5852 * ID strings for the jalview project. If external tables are provided then
5853 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5854 * object goes out of scope. - also populates the datasetIds hashtable with
5855 * alignment objects containing dataset sequences
5858 * Map from ID strings to jalview datamodel
5860 * Map from jalview datamodel to ID strings
5864 public void setObjectMappingTables(Hashtable vobj2jv,
5865 IdentityHashMap jv2vobj)
5867 this.jv2vobj = jv2vobj;
5868 this.vobj2jv = vobj2jv;
5869 Iterator ds = jv2vobj.keySet().iterator();
5871 while (ds.hasNext())
5873 Object jvobj = ds.next();
5874 id = jv2vobj.get(jvobj).toString();
5875 if (jvobj instanceof jalview.datamodel.Alignment)
5877 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5879 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5882 else if (jvobj instanceof jalview.datamodel.Sequence)
5884 // register sequence object so the XML parser can recover it.
5885 if (seqRefIds == null)
5887 seqRefIds = new HashMap<>();
5889 if (seqsToIds == null)
5891 seqsToIds = new IdentityHashMap<>();
5893 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5894 seqsToIds.put((SequenceI) jvobj, id);
5896 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5899 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5900 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5901 if (jvann.annotationId == null)
5903 jvann.annotationId = anid;
5905 if (!jvann.annotationId.equals(anid))
5907 // TODO verify that this is the correct behaviour
5908 this.warn("Overriding Annotation ID for " + anid
5909 + " from different id : " + jvann.annotationId);
5910 jvann.annotationId = anid;
5913 else if (jvobj instanceof String)
5915 if (jvids2vobj == null)
5917 jvids2vobj = new Hashtable();
5918 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5923 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5929 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5930 * objects created from the project archive. If string is null (default for
5931 * construction) then suffix will be set automatically.
5935 public void setUniqueSetSuffix(String string)
5937 uniqueSetSuffix = string;
5942 * uses skipList2 as the skipList for skipping views on sequence sets
5943 * associated with keys in the skipList
5947 public void setSkipList(Hashtable skipList2)
5949 skipList = skipList2;
5953 * Reads the jar entry of given name and returns its contents, or null if the
5954 * entry is not found.
5957 * @param jarEntryName
5960 protected String readJarEntry(jarInputStreamProvider jprovider,
5961 String jarEntryName)
5963 String result = null;
5964 BufferedReader in = null;
5969 * Reopen the jar input stream and traverse its entries to find a matching
5972 JarInputStream jin = jprovider.getJarInputStream();
5973 JarEntry entry = null;
5976 entry = jin.getNextJarEntry();
5977 } while (entry != null && !entry.getName().equals(jarEntryName));
5981 StringBuilder out = new StringBuilder(256);
5982 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5985 while ((data = in.readLine()) != null)
5989 result = out.toString();
5993 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5995 } catch (Exception ex)
5997 ex.printStackTrace();
6005 } catch (IOException e)
6016 * Returns an incrementing counter (0, 1, 2...)
6020 private synchronized int nextCounter()
6026 * Loads any saved PCA viewers
6031 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6035 List<PcaViewer> pcaviewers = model.getPcaViewer();
6036 for (PcaViewer viewer : pcaviewers)
6038 String modelName = viewer.getScoreModelName();
6039 SimilarityParamsI params = new SimilarityParams(
6040 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6041 viewer.isIncludeGaps(),
6042 viewer.isDenominateByShortestLength());
6045 * create the panel (without computing the PCA)
6047 PCAPanel panel = new PCAPanel(ap, modelName, params);
6049 panel.setTitle(viewer.getTitle());
6050 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6051 viewer.getWidth(), viewer.getHeight()));
6053 boolean showLabels = viewer.isShowLabels();
6054 panel.setShowLabels(showLabels);
6055 panel.getRotatableCanvas().setShowLabels(showLabels);
6056 panel.getRotatableCanvas()
6057 .setBgColour(new Color(viewer.getBgColour()));
6058 panel.getRotatableCanvas()
6059 .setApplyToAllViews(viewer.isLinkToAllViews());
6062 * load PCA output data
6064 ScoreModelI scoreModel = ScoreModels.getInstance()
6065 .getScoreModel(modelName, ap);
6066 PCA pca = new PCA(null, scoreModel, params);
6067 PcaDataType pcaData = viewer.getPcaData();
6069 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6070 pca.setPairwiseScores(pairwise);
6072 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6073 pca.setTridiagonal(triDiag);
6075 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6076 pca.setEigenmatrix(result);
6078 panel.getPcaModel().setPCA(pca);
6081 * we haven't saved the input data! (JAL-2647 to do)
6083 panel.setInputData(null);
6086 * add the sequence points for the PCA display
6088 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6089 for (SequencePoint sp : viewer.getSequencePoint())
6091 String seqId = sp.getSequenceRef();
6092 SequenceI seq = seqRefIds.get(seqId);
6095 throw new IllegalStateException(
6096 "Unmatched seqref for PCA: " + seqId);
6098 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6099 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6101 seqPoints.add(seqPoint);
6103 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6106 * set min-max ranges and scale after setPoints (which recomputes them)
6108 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6109 SeqPointMin spMin = viewer.getSeqPointMin();
6110 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6112 SeqPointMax spMax = viewer.getSeqPointMax();
6113 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6115 panel.getRotatableCanvas().setSeqMinMax(min, max);
6117 // todo: hold points list in PCAModel only
6118 panel.getPcaModel().setSequencePoints(seqPoints);
6120 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6121 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6122 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6124 // is this duplication needed?
6125 panel.setTop(seqPoints.size() - 1);
6126 panel.getPcaModel().setTop(seqPoints.size() - 1);
6129 * add the axes' end points for the display
6131 for (int i = 0; i < 3; i++)
6133 Axis axis = viewer.getAxis().get(i);
6134 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6135 axis.getXPos(), axis.getYPos(), axis.getZPos());
6138 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6139 "label.calc_title", "PCA", modelName), 475, 450);
6141 } catch (Exception ex)
6143 Cache.log.error("Error loading PCA: " + ex.toString());
6148 * Creates a new structure viewer window
6155 protected void createStructureViewer(
6156 ViewerType viewerType, final Entry<String, StructureViewerModel> viewerData,
6157 AlignFrame af, jarInputStreamProvider jprovider)
6159 final StructureViewerModel viewerModel = viewerData.getValue();
6160 String sessionFilePath = null;
6162 if (viewerType == ViewerType.JMOL)
6164 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6168 String viewerJarEntryName = getViewerJarEntryName(
6169 viewerModel.getViewId());
6170 sessionFilePath = copyJarEntry(jprovider,
6172 "viewerSession", ".tmp");
6174 final String sessionPath = sessionFilePath;
6175 final String sviewid = viewerData.getKey();
6178 SwingUtilities.invokeAndWait(new Runnable()
6183 JalviewStructureDisplayI sview = null;
6186 sview = StructureViewer.createView(viewerType, af.alignPanel,
6187 viewerModel, sessionPath, sviewid);
6188 addNewStructureViewer(sview);
6189 } catch (OutOfMemoryError ex)
6191 new OOMWarning("Restoring structure view for "
6193 (OutOfMemoryError) ex.getCause());
6194 if (sview != null && sview.isVisible())
6196 sview.closeViewer(false);
6197 sview.setVisible(false);
6203 } catch (InvocationTargetException | InterruptedException ex)
6205 warn("Unexpected error when opening " + viewerType
6206 + " structure viewer", ex);
6211 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6212 * the path of the file. "load file" commands are rewritten to change the
6213 * original PDB file names to those created as the Jalview project is loaded.
6219 private String rewriteJmolSession(StructureViewerModel svattrib,
6220 jarInputStreamProvider jprovider)
6222 String state = svattrib.getStateData(); // Jalview < 2.9
6223 if (state == null || state.isEmpty()) // Jalview >= 2.9
6225 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6226 state = readJarEntry(jprovider, jarEntryName);
6228 // TODO or simpler? for each key in oldFiles,
6229 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6230 // (allowing for different path escapings)
6231 StringBuilder rewritten = new StringBuilder(state.length());
6232 int cp = 0, ncp, ecp;
6233 Map<File, StructureData> oldFiles = svattrib.getFileData();
6234 while ((ncp = state.indexOf("load ", cp)) > -1)
6238 // look for next filename in load statement
6239 rewritten.append(state.substring(cp,
6240 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6241 String oldfilenam = state.substring(ncp,
6242 ecp = state.indexOf("\"", ncp));
6243 // recover the new mapping data for this old filename
6244 // have to normalize filename - since Jmol and jalview do
6245 // filename translation differently.
6246 StructureData filedat = oldFiles.get(new File(oldfilenam));
6247 if (filedat == null)
6249 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6250 filedat = oldFiles.get(new File(reformatedOldFilename));
6253 .append(Platform.escapeBackslashes(filedat.getFilePath()));
6254 rewritten.append("\"");
6255 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6256 // look for next file statement.
6257 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6261 // just append rest of state
6262 rewritten.append(state.substring(cp));
6266 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6267 rewritten = new StringBuilder(state);
6268 rewritten.append("; load append ");
6269 for (File id : oldFiles.keySet())
6271 // add pdb files that should be present in the viewer
6272 StructureData filedat = oldFiles.get(id);
6273 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6275 rewritten.append(";");
6278 if (rewritten.length() == 0)
6282 final String history = "history = ";
6283 int historyIndex = rewritten.indexOf(history);
6284 if (historyIndex > -1)
6287 * change "history = [true|false];" to "history = [1|0];"
6289 historyIndex += history.length();
6290 String val = rewritten.substring(historyIndex, historyIndex + 5);
6291 if (val.startsWith("true"))
6293 rewritten.replace(historyIndex, historyIndex + 4, "1");
6295 else if (val.startsWith("false"))
6297 rewritten.replace(historyIndex, historyIndex + 5, "0");
6303 File tmp = File.createTempFile("viewerSession", ".tmp");
6304 try (OutputStream os = new FileOutputStream(tmp))
6306 InputStream is = new ByteArrayInputStream(
6307 rewritten.toString().getBytes());
6309 return tmp.getAbsolutePath();
6311 } catch (IOException e)
6313 Cache.log.error("Error restoring Jmol session: " + e.toString());
6319 * Populates an XML model of the feature colour scheme for one feature type
6321 * @param featureType
6325 public static Colour marshalColour(
6326 String featureType, FeatureColourI fcol)
6328 Colour col = new Colour();
6329 if (fcol.isSimpleColour())
6331 col.setRGB(Format.getHexString(fcol.getColour()));
6335 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6336 col.setMin(fcol.getMin());
6337 col.setMax(fcol.getMax());
6338 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6339 col.setAutoScale(fcol.isAutoScaled());
6340 col.setThreshold(fcol.getThreshold());
6341 col.setColourByLabel(fcol.isColourByLabel());
6342 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6343 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6344 : ThresholdType.NONE));
6345 if (fcol.isColourByAttribute())
6347 final String[] attName = fcol.getAttributeName();
6348 col.getAttributeName().add(attName[0]);
6349 if (attName.length > 1)
6351 col.getAttributeName().add(attName[1]);
6354 Color noColour = fcol.getNoColour();
6355 if (noColour == null)
6357 col.setNoValueColour(NoValueColour.NONE);
6359 else if (noColour == fcol.getMaxColour())
6361 col.setNoValueColour(NoValueColour.MAX);
6365 col.setNoValueColour(NoValueColour.MIN);
6368 col.setName(featureType);
6373 * Populates an XML model of the feature filter(s) for one feature type
6375 * @param firstMatcher
6376 * the first (or only) match condition)
6378 * remaining match conditions (if any)
6380 * if true, conditions are and-ed, else or-ed
6382 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6383 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6386 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6388 if (filters.hasNext())
6393 CompoundMatcher compound = new CompoundMatcher();
6394 compound.setAnd(and);
6395 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6396 firstMatcher, Collections.emptyIterator(), and);
6397 // compound.addMatcherSet(matcher1);
6398 compound.getMatcherSet().add(matcher1);
6399 FeatureMatcherI nextMatcher = filters.next();
6400 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6401 nextMatcher, filters, and);
6402 // compound.addMatcherSet(matcher2);
6403 compound.getMatcherSet().add(matcher2);
6404 result.setCompoundMatcher(compound);
6409 * single condition matcher
6411 // MatchCondition matcherModel = new MatchCondition();
6412 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6413 matcherModel.setCondition(
6414 firstMatcher.getMatcher().getCondition().getStableName());
6415 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6416 if (firstMatcher.isByAttribute())
6418 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6419 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6420 String[] attName = firstMatcher.getAttribute();
6421 matcherModel.getAttributeName().add(attName[0]); // attribute
6422 if (attName.length > 1)
6424 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6427 else if (firstMatcher.isByLabel())
6429 matcherModel.setBy(FilterBy.BY_LABEL);
6431 else if (firstMatcher.isByScore())
6433 matcherModel.setBy(FilterBy.BY_SCORE);
6435 result.setMatchCondition(matcherModel);
6442 * Loads one XML model of a feature filter to a Jalview object
6444 * @param featureType
6445 * @param matcherSetModel
6448 public static FeatureMatcherSetI parseFilter(
6450 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6452 FeatureMatcherSetI result = new FeatureMatcherSet();
6455 parseFilterConditions(result, matcherSetModel, true);
6456 } catch (IllegalStateException e)
6458 // mixing AND and OR conditions perhaps
6460 String.format("Error reading filter conditions for '%s': %s",
6461 featureType, e.getMessage()));
6462 // return as much as was parsed up to the error
6469 * Adds feature match conditions to matcherSet as unmarshalled from XML
6470 * (possibly recursively for compound conditions)
6473 * @param matcherSetModel
6475 * if true, multiple conditions are AND-ed, else they are OR-ed
6476 * @throws IllegalStateException
6477 * if AND and OR conditions are mixed
6479 protected static void parseFilterConditions(
6480 FeatureMatcherSetI matcherSet,
6481 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6484 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6485 .getMatchCondition();
6491 FilterBy filterBy = mc.getBy();
6492 Condition cond = Condition.fromString(mc.getCondition());
6493 String pattern = mc.getValue();
6494 FeatureMatcherI matchCondition = null;
6495 if (filterBy == FilterBy.BY_LABEL)
6497 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6499 else if (filterBy == FilterBy.BY_SCORE)
6501 matchCondition = FeatureMatcher.byScore(cond, pattern);
6504 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6506 final List<String> attributeName = mc.getAttributeName();
6507 String[] attNames = attributeName
6508 .toArray(new String[attributeName.size()]);
6509 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6514 * note this throws IllegalStateException if AND-ing to a
6515 * previously OR-ed compound condition, or vice versa
6519 matcherSet.and(matchCondition);
6523 matcherSet.or(matchCondition);
6529 * compound condition
6531 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6532 .getCompoundMatcher().getMatcherSet();
6533 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6534 if (matchers.size() == 2)
6536 parseFilterConditions(matcherSet, matchers.get(0), anded);
6537 parseFilterConditions(matcherSet, matchers.get(1), anded);
6541 System.err.println("Malformed compound filter condition");
6547 * Loads one XML model of a feature colour to a Jalview object
6549 * @param colourModel
6552 public static FeatureColourI parseColour(Colour colourModel)
6554 FeatureColourI colour = null;
6556 if (colourModel.getMax() != null)
6558 Color mincol = null;
6559 Color maxcol = null;
6560 Color noValueColour = null;
6564 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6565 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6566 } catch (Exception e)
6568 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6571 NoValueColour noCol = colourModel.getNoValueColour();
6572 if (noCol == NoValueColour.MIN)
6574 noValueColour = mincol;
6576 else if (noCol == NoValueColour.MAX)
6578 noValueColour = maxcol;
6581 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6582 safeFloat(colourModel.getMin()),
6583 safeFloat(colourModel.getMax()));
6584 final List<String> attributeName = colourModel.getAttributeName();
6585 String[] attributes = attributeName
6586 .toArray(new String[attributeName.size()]);
6587 if (attributes != null && attributes.length > 0)
6589 colour.setAttributeName(attributes);
6591 if (colourModel.isAutoScale() != null)
6593 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6595 if (colourModel.isColourByLabel() != null)
6597 colour.setColourByLabel(
6598 colourModel.isColourByLabel().booleanValue());
6600 if (colourModel.getThreshold() != null)
6602 colour.setThreshold(colourModel.getThreshold().floatValue());
6604 ThresholdType ttyp = colourModel.getThreshType();
6605 if (ttyp == ThresholdType.ABOVE)
6607 colour.setAboveThreshold(true);
6609 else if (ttyp == ThresholdType.BELOW)
6611 colour.setBelowThreshold(true);
6616 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6617 colour = new FeatureColour(color);