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 JInternalFrame frame = (JInternalFrame) SwingUtilities
1457 .getAncestorOfClass(JInternalFrame.class, ov);
1458 overview.setTitle(frame.getTitle());
1459 Rectangle bounds = frame.getBounds();
1460 overview.setXpos(bounds.x);
1461 overview.setYpos(bounds.y);
1462 overview.setWidth(bounds.width);
1463 overview.setHeight(bounds.height);
1464 overview.setShowHidden(ov.isShowHiddenRegions());
1465 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1466 overview.setResidueColour(ov.getCanvas().getResidueColour().getRGB());
1467 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1468 view.setOverview(overview);
1470 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1472 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1473 userColours, object));
1476 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1478 AnnotationColourScheme ac = constructAnnotationColours(
1479 (jalview.schemes.AnnotationColourGradient) av
1480 .getGlobalColourScheme(),
1481 userColours, object);
1483 view.setAnnotationColours(ac);
1484 view.setBgColour("AnnotationColourGradient");
1488 view.setBgColour(ColourSchemeProperty
1489 .getColourName(av.getGlobalColourScheme()));
1492 ResidueShaderI vcs = av.getResidueShading();
1493 ColourSchemeI cs = av.getGlobalColourScheme();
1497 if (vcs.conservationApplied())
1499 view.setConsThreshold(vcs.getConservationInc());
1500 if (cs instanceof jalview.schemes.UserColourScheme)
1502 view.setBgColour(setUserColourScheme(cs, userColours, object));
1505 view.setPidThreshold(vcs.getThreshold());
1508 view.setConservationSelected(av.getConservationSelected());
1509 view.setPidSelected(av.getAbovePIDThreshold());
1510 final Font font = av.getFont();
1511 view.setFontName(font.getName());
1512 view.setFontSize(font.getSize());
1513 view.setFontStyle(font.getStyle());
1514 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1515 view.setRenderGaps(av.isRenderGaps());
1516 view.setShowAnnotation(av.isShowAnnotation());
1517 view.setShowBoxes(av.getShowBoxes());
1518 view.setShowColourText(av.getColourText());
1519 view.setShowFullId(av.getShowJVSuffix());
1520 view.setRightAlignIds(av.isRightAlignIds());
1521 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1522 view.setShowText(av.getShowText());
1523 view.setShowUnconserved(av.getShowUnconserved());
1524 view.setWrapAlignment(av.getWrapAlignment());
1525 view.setTextCol1(av.getTextColour().getRGB());
1526 view.setTextCol2(av.getTextColour2().getRGB());
1527 view.setTextColThreshold(av.getThresholdTextColour());
1528 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1529 view.setShowSequenceLogo(av.isShowSequenceLogo());
1530 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1531 view.setShowGroupConsensus(av.isShowGroupConsensus());
1532 view.setShowGroupConservation(av.isShowGroupConservation());
1533 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1534 view.setShowDbRefTooltip(av.isShowDBRefs());
1535 view.setFollowHighlight(av.isFollowHighlight());
1536 view.setFollowSelection(av.followSelection);
1537 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1538 view.setShowComplementFeatures(av.isShowComplementFeatures());
1539 view.setShowComplementFeaturesOnTop(
1540 av.isShowComplementFeaturesOnTop());
1541 if (av.getFeaturesDisplayed() != null)
1543 FeatureSettings fs = new FeatureSettings();
1545 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1546 .getFeatureRenderer();
1547 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1549 Vector<String> settingsAdded = new Vector<>();
1550 if (renderOrder != null)
1552 for (String featureType : renderOrder)
1554 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1555 setting.setType(featureType);
1558 * save any filter for the feature type
1560 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1561 if (filter != null) {
1562 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1563 FeatureMatcherI firstFilter = filters.next();
1564 setting.setMatcherSet(Jalview2XML.marshalFilter(
1565 firstFilter, filters, filter.isAnded()));
1569 * save colour scheme for the feature type
1571 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1572 if (!fcol.isSimpleColour())
1574 setting.setColour(fcol.getMaxColour().getRGB());
1575 setting.setMincolour(fcol.getMinColour().getRGB());
1576 setting.setMin(fcol.getMin());
1577 setting.setMax(fcol.getMax());
1578 setting.setColourByLabel(fcol.isColourByLabel());
1579 if (fcol.isColourByAttribute())
1581 String[] attName = fcol.getAttributeName();
1582 setting.getAttributeName().add(attName[0]);
1583 if (attName.length > 1)
1585 setting.getAttributeName().add(attName[1]);
1588 setting.setAutoScale(fcol.isAutoScaled());
1589 setting.setThreshold(fcol.getThreshold());
1590 Color noColour = fcol.getNoColour();
1591 if (noColour == null)
1593 setting.setNoValueColour(NoValueColour.NONE);
1595 else if (noColour.equals(fcol.getMaxColour()))
1597 setting.setNoValueColour(NoValueColour.MAX);
1601 setting.setNoValueColour(NoValueColour.MIN);
1603 // -1 = No threshold, 0 = Below, 1 = Above
1604 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1605 : (fcol.isBelowThreshold() ? 0 : -1));
1609 setting.setColour(fcol.getColour().getRGB());
1613 av.getFeaturesDisplayed().isVisible(featureType));
1615 .getOrder(featureType);
1618 setting.setOrder(rorder);
1620 /// fs.addSetting(setting);
1621 fs.getSetting().add(setting);
1622 settingsAdded.addElement(featureType);
1626 // is groups actually supposed to be a map here ?
1627 Iterator<String> en = fr.getFeatureGroups().iterator();
1628 Vector<String> groupsAdded = new Vector<>();
1629 while (en.hasNext())
1631 String grp = en.next();
1632 if (groupsAdded.contains(grp))
1636 Group g = new Group();
1638 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1641 fs.getGroup().add(g);
1642 groupsAdded.addElement(grp);
1644 // jms.setFeatureSettings(fs);
1645 object.setFeatureSettings(fs);
1648 if (av.hasHiddenColumns())
1650 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1651 .getHiddenColumns();
1654 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1658 Iterator<int[]> hiddenRegions = hidden.iterator();
1659 while (hiddenRegions.hasNext())
1661 int[] region = hiddenRegions.next();
1662 HiddenColumns hc = new HiddenColumns();
1663 hc.setStart(region[0]);
1664 hc.setEnd(region[1]);
1665 // view.addHiddenColumns(hc);
1666 view.getHiddenColumns().add(hc);
1670 if (calcIdSet.size() > 0)
1672 for (String calcId : calcIdSet)
1674 if (calcId.trim().length() > 0)
1676 CalcIdParam cidp = createCalcIdParam(calcId, av);
1677 // Some calcIds have no parameters.
1680 // view.addCalcIdParam(cidp);
1681 view.getCalcIdParam().add(cidp);
1687 // jms.addViewport(view);
1688 object.getViewport().add(view);
1690 // object.setJalviewModelSequence(jms);
1691 // object.getVamsasModel().addSequenceSet(vamsasSet);
1692 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1694 if (jout != null && fileName != null)
1696 // We may not want to write the object to disk,
1697 // eg we can copy the alignViewport to a new view object
1698 // using save and then load
1701 fileName = fileName.replace('\\', '/');
1702 System.out.println("Writing jar entry " + fileName);
1703 JarEntry entry = new JarEntry(fileName);
1704 jout.putNextEntry(entry);
1705 PrintWriter pout = new PrintWriter(
1706 new OutputStreamWriter(jout, UTF_8));
1707 JAXBContext jaxbContext = JAXBContext
1708 .newInstance(JalviewModel.class);
1709 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1711 // output pretty printed
1712 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1713 jaxbMarshaller.marshal(
1714 new ObjectFactory().createJalviewModel(object), pout);
1716 // jaxbMarshaller.marshal(object, pout);
1717 // marshaller.marshal(object);
1720 } catch (Exception ex)
1722 // TODO: raise error in GUI if marshalling failed.
1723 System.err.println("Error writing Jalview project");
1724 ex.printStackTrace();
1731 * Writes PCA viewer attributes and computed values to an XML model object and
1732 * adds it to the JalviewModel. Any exceptions are reported by logging.
1734 protected void savePCA(PCAPanel panel, JalviewModel object)
1738 PcaViewer viewer = new PcaViewer();
1739 viewer.setHeight(panel.getHeight());
1740 viewer.setWidth(panel.getWidth());
1741 viewer.setXpos(panel.getX());
1742 viewer.setYpos(panel.getY());
1743 viewer.setTitle(panel.getTitle());
1744 PCAModel pcaModel = panel.getPcaModel();
1745 viewer.setScoreModelName(pcaModel.getScoreModelName());
1746 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1747 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1748 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1750 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1751 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1752 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1753 SeqPointMin spmin = new SeqPointMin();
1754 spmin.setXPos(spMin[0]);
1755 spmin.setYPos(spMin[1]);
1756 spmin.setZPos(spMin[2]);
1757 viewer.setSeqPointMin(spmin);
1758 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1759 SeqPointMax spmax = new SeqPointMax();
1760 spmax.setXPos(spMax[0]);
1761 spmax.setYPos(spMax[1]);
1762 spmax.setZPos(spMax[2]);
1763 viewer.setSeqPointMax(spmax);
1764 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1765 viewer.setLinkToAllViews(
1766 panel.getRotatableCanvas().isApplyToAllViews());
1767 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1768 viewer.setIncludeGaps(sp.includeGaps());
1769 viewer.setMatchGaps(sp.matchGaps());
1770 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1771 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1774 * sequence points on display
1776 for (jalview.datamodel.SequencePoint spt : pcaModel
1777 .getSequencePoints())
1779 SequencePoint point = new SequencePoint();
1780 point.setSequenceRef(seqHash(spt.getSequence()));
1781 point.setXPos(spt.coord.x);
1782 point.setYPos(spt.coord.y);
1783 point.setZPos(spt.coord.z);
1784 viewer.getSequencePoint().add(point);
1788 * (end points of) axes on display
1790 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1793 Axis axis = new Axis();
1797 viewer.getAxis().add(axis);
1801 * raw PCA data (note we are not restoring PCA inputs here -
1802 * alignment view, score model, similarity parameters)
1804 PcaDataType data = new PcaDataType();
1805 viewer.setPcaData(data);
1806 PCA pca = pcaModel.getPcaData();
1808 DoubleMatrix pm = new DoubleMatrix();
1809 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1810 data.setPairwiseMatrix(pm);
1812 DoubleMatrix tm = new DoubleMatrix();
1813 saveDoubleMatrix(pca.getTridiagonal(), tm);
1814 data.setTridiagonalMatrix(tm);
1816 DoubleMatrix eigenMatrix = new DoubleMatrix();
1817 data.setEigenMatrix(eigenMatrix);
1818 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1820 object.getPcaViewer().add(viewer);
1821 } catch (Throwable t)
1823 Cache.log.error("Error saving PCA: " + t.getMessage());
1828 * Stores values from a matrix into an XML element, including (if present) the
1833 * @see #loadDoubleMatrix(DoubleMatrix)
1835 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1837 xmlMatrix.setRows(m.height());
1838 xmlMatrix.setColumns(m.width());
1839 for (int i = 0; i < m.height(); i++)
1841 DoubleVector row = new DoubleVector();
1842 for (int j = 0; j < m.width(); j++)
1844 row.getV().add(m.getValue(i, j));
1846 xmlMatrix.getRow().add(row);
1848 if (m.getD() != null)
1850 DoubleVector dVector = new DoubleVector();
1851 for (double d : m.getD())
1853 dVector.getV().add(d);
1855 xmlMatrix.setD(dVector);
1857 if (m.getE() != null)
1859 DoubleVector eVector = new DoubleVector();
1860 for (double e : m.getE())
1862 eVector.getV().add(e);
1864 xmlMatrix.setE(eVector);
1869 * Loads XML matrix data into a new Matrix object, including the D and/or E
1870 * vectors (if present)
1874 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1876 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1878 int rows = mData.getRows();
1879 double[][] vals = new double[rows][];
1881 for (int i = 0; i < rows; i++)
1883 List<Double> dVector = mData.getRow().get(i).getV();
1884 vals[i] = new double[dVector.size()];
1886 for (Double d : dVector)
1892 MatrixI m = new Matrix(vals);
1894 if (mData.getD() != null)
1896 List<Double> dVector = mData.getD().getV();
1897 double[] vec = new double[dVector.size()];
1899 for (Double d : dVector)
1905 if (mData.getE() != null)
1907 List<Double> dVector = mData.getE().getV();
1908 double[] vec = new double[dVector.size()];
1910 for (Double d : dVector)
1921 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1922 * for each viewer, with
1924 * <li>viewer geometry (position, size, split pane divider location)</li>
1925 * <li>index of the selected structure in the viewer (currently shows gapped
1927 * <li>the id of the annotation holding RNA secondary structure</li>
1928 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1930 * Varna viewer state is also written out (in native Varna XML) to separate
1931 * project jar entries. A separate entry is written for each RNA structure
1932 * displayed, with the naming convention
1934 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1942 * @param storeDataset
1944 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1945 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1946 boolean storeDataset)
1948 if (Desktop.desktop == null)
1952 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1953 for (int f = frames.length - 1; f > -1; f--)
1955 if (frames[f] instanceof AppVarna)
1957 AppVarna varna = (AppVarna) frames[f];
1959 * link the sequence to every viewer that is showing it and is linked to
1960 * its alignment panel
1962 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1964 String viewId = varna.getViewId();
1965 RnaViewer rna = new RnaViewer();
1966 rna.setViewId(viewId);
1967 rna.setTitle(varna.getTitle());
1968 rna.setXpos(varna.getX());
1969 rna.setYpos(varna.getY());
1970 rna.setWidth(varna.getWidth());
1971 rna.setHeight(varna.getHeight());
1972 rna.setDividerLocation(varna.getDividerLocation());
1973 rna.setSelectedRna(varna.getSelectedIndex());
1974 // jseq.addRnaViewer(rna);
1975 jseq.getRnaViewer().add(rna);
1978 * Store each Varna panel's state once in the project per sequence.
1979 * First time through only (storeDataset==false)
1981 // boolean storeSessions = false;
1982 // String sequenceViewId = viewId + seqsToIds.get(jds);
1983 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1985 // viewIds.add(sequenceViewId);
1986 // storeSessions = true;
1988 for (RnaModel model : varna.getModels())
1990 if (model.seq == jds)
1993 * VARNA saves each view (sequence or alignment secondary
1994 * structure, gapped or trimmed) as a separate XML file
1996 String jarEntryName = rnaSessions.get(model);
1997 if (jarEntryName == null)
2000 String varnaStateFile = varna.getStateInfo(model.rna);
2001 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2002 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2003 rnaSessions.put(model, jarEntryName);
2005 SecondaryStructure ss = new SecondaryStructure();
2006 String annotationId = varna.getAnnotation(jds).annotationId;
2007 ss.setAnnotationId(annotationId);
2008 ss.setViewerState(jarEntryName);
2009 ss.setGapped(model.gapped);
2010 ss.setTitle(model.title);
2011 // rna.addSecondaryStructure(ss);
2012 rna.getSecondaryStructure().add(ss);
2021 * Copy the contents of a file to a new entry added to the output jar
2025 * @param jarEntryName
2027 * additional identifying info to log to the console
2029 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2030 String jarEntryName, String msg)
2032 try (InputStream is = new FileInputStream(infilePath))
2034 File file = new File(infilePath);
2035 if (file.exists() && jout != null)
2038 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2039 jout.putNextEntry(new JarEntry(jarEntryName));
2042 // dis = new DataInputStream(new FileInputStream(file));
2043 // byte[] data = new byte[(int) file.length()];
2044 // dis.readFully(data);
2045 // writeJarEntry(jout, jarEntryName, data);
2047 } catch (Exception ex)
2049 ex.printStackTrace();
2054 * Copies input to output, in 4K buffers; handles any data (text or binary)
2058 * @throws IOException
2060 protected void copyAll(InputStream in, OutputStream out)
2063 byte[] buffer = new byte[4096];
2065 while ((bytesRead = in.read(buffer)) != -1)
2067 out.write(buffer, 0, bytesRead);
2072 * Save the state of a structure viewer
2077 * the archive XML element under which to save the state
2080 * @param matchedFile
2084 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2085 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2086 String matchedFile, StructureViewerBase viewFrame)
2088 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2091 * Look for any bindings for this viewer to the PDB file of interest
2092 * (including part matches excluding chain id)
2094 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2096 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2097 final String pdbId = pdbentry.getId();
2098 if (!pdbId.equals(entry.getId())
2099 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2100 .startsWith(pdbId.toLowerCase())))
2103 * not interested in a binding to a different PDB entry here
2107 if (matchedFile == null)
2109 matchedFile = pdbentry.getFile();
2111 else if (!matchedFile.equals(pdbentry.getFile()))
2114 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2115 + pdbentry.getFile());
2119 // can get at it if the ID
2120 // match is ambiguous (e.g.
2123 for (int smap = 0; smap < viewFrame.getBinding()
2124 .getSequence()[peid].length; smap++)
2126 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2127 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2129 StructureState state = new StructureState();
2130 state.setVisible(true);
2131 state.setXpos(viewFrame.getX());
2132 state.setYpos(viewFrame.getY());
2133 state.setWidth(viewFrame.getWidth());
2134 state.setHeight(viewFrame.getHeight());
2135 final String viewId = viewFrame.getViewId();
2136 state.setViewId(viewId);
2137 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2138 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2139 state.setColourByJmol(viewFrame.isColouredByViewer());
2140 state.setType(viewFrame.getViewerType().toString());
2141 // pdb.addStructureState(state);
2142 pdb.getStructureState().add(state);
2150 * Populates the AnnotationColourScheme xml for save. This captures the
2151 * settings of the options in the 'Colour by Annotation' dialog.
2154 * @param userColours
2158 private AnnotationColourScheme constructAnnotationColours(
2159 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2162 AnnotationColourScheme ac = new AnnotationColourScheme();
2163 ac.setAboveThreshold(acg.getAboveThreshold());
2164 ac.setThreshold(acg.getAnnotationThreshold());
2165 // 2.10.2 save annotationId (unique) not annotation label
2166 ac.setAnnotation(acg.getAnnotation().annotationId);
2167 if (acg.getBaseColour() instanceof UserColourScheme)
2170 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2175 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2178 ac.setMaxColour(acg.getMaxColour().getRGB());
2179 ac.setMinColour(acg.getMinColour().getRGB());
2180 ac.setPerSequence(acg.isSeqAssociated());
2181 ac.setPredefinedColours(acg.isPredefinedColours());
2185 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2186 IdentityHashMap<SequenceGroup, String> groupRefs,
2187 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2188 SequenceSet vamsasSet)
2191 for (int i = 0; i < aa.length; i++)
2193 Annotation an = new Annotation();
2195 AlignmentAnnotation annotation = aa[i];
2196 if (annotation.annotationId != null)
2198 annotationIds.put(annotation.annotationId, annotation);
2201 an.setId(annotation.annotationId);
2203 an.setVisible(annotation.visible);
2205 an.setDescription(annotation.description);
2207 if (annotation.sequenceRef != null)
2209 // 2.9 JAL-1781 xref on sequence id rather than name
2210 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2212 if (annotation.groupRef != null)
2214 String groupIdr = groupRefs.get(annotation.groupRef);
2215 if (groupIdr == null)
2217 // make a locally unique String
2218 groupRefs.put(annotation.groupRef,
2219 groupIdr = ("" + System.currentTimeMillis()
2220 + annotation.groupRef.getName()
2221 + groupRefs.size()));
2223 an.setGroupRef(groupIdr.toString());
2226 // store all visualization attributes for annotation
2227 an.setGraphHeight(annotation.graphHeight);
2228 an.setCentreColLabels(annotation.centreColLabels);
2229 an.setScaleColLabels(annotation.scaleColLabel);
2230 an.setShowAllColLabels(annotation.showAllColLabels);
2231 an.setBelowAlignment(annotation.belowAlignment);
2233 if (annotation.graph > 0)
2236 an.setGraphType(annotation.graph);
2237 an.setGraphGroup(annotation.graphGroup);
2238 if (annotation.getThreshold() != null)
2240 ThresholdLine line = new ThresholdLine();
2241 line.setLabel(annotation.getThreshold().label);
2242 line.setValue(annotation.getThreshold().value);
2243 line.setColour(annotation.getThreshold().colour.getRGB());
2244 an.setThresholdLine(line);
2252 an.setLabel(annotation.label);
2254 if (annotation == av.getAlignmentQualityAnnot()
2255 || annotation == av.getAlignmentConservationAnnotation()
2256 || annotation == av.getAlignmentConsensusAnnotation()
2257 || annotation.autoCalculated)
2259 // new way of indicating autocalculated annotation -
2260 an.setAutoCalculated(annotation.autoCalculated);
2262 if (annotation.hasScore())
2264 an.setScore(annotation.getScore());
2267 if (annotation.getCalcId() != null)
2269 calcIdSet.add(annotation.getCalcId());
2270 an.setCalcId(annotation.getCalcId());
2272 if (annotation.hasProperties())
2274 for (String pr : annotation.getProperties())
2276 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2278 prop.setValue(annotation.getProperty(pr));
2279 // an.addProperty(prop);
2280 an.getProperty().add(prop);
2284 AnnotationElement ae;
2285 if (annotation.annotations != null)
2287 an.setScoreOnly(false);
2288 for (int a = 0; a < annotation.annotations.length; a++)
2290 if ((annotation == null) || (annotation.annotations[a] == null))
2295 ae = new AnnotationElement();
2296 if (annotation.annotations[a].description != null)
2298 ae.setDescription(annotation.annotations[a].description);
2300 if (annotation.annotations[a].displayCharacter != null)
2302 ae.setDisplayCharacter(
2303 annotation.annotations[a].displayCharacter);
2306 if (!Float.isNaN(annotation.annotations[a].value))
2308 ae.setValue(annotation.annotations[a].value);
2312 if (annotation.annotations[a].secondaryStructure > ' ')
2314 ae.setSecondaryStructure(
2315 annotation.annotations[a].secondaryStructure + "");
2318 if (annotation.annotations[a].colour != null
2319 && annotation.annotations[a].colour != java.awt.Color.black)
2321 ae.setColour(annotation.annotations[a].colour.getRGB());
2324 // an.addAnnotationElement(ae);
2325 an.getAnnotationElement().add(ae);
2326 if (annotation.autoCalculated)
2328 // only write one non-null entry into the annotation row -
2329 // sufficient to get the visualization attributes necessary to
2337 an.setScoreOnly(true);
2339 if (!storeDS || (storeDS && !annotation.autoCalculated))
2341 // skip autocalculated annotation - these are only provided for
2343 // vamsasSet.addAnnotation(an);
2344 vamsasSet.getAnnotation().add(an);
2350 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2352 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2353 if (settings != null)
2355 CalcIdParam vCalcIdParam = new CalcIdParam();
2356 vCalcIdParam.setCalcId(calcId);
2357 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2358 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2359 // generic URI allowing a third party to resolve another instance of the
2360 // service used for this calculation
2361 for (String url : settings.getServiceURLs())
2363 // vCalcIdParam.addServiceURL(urls);
2364 vCalcIdParam.getServiceURL().add(url);
2366 vCalcIdParam.setVersion("1.0");
2367 if (settings.getPreset() != null)
2369 WsParamSetI setting = settings.getPreset();
2370 vCalcIdParam.setName(setting.getName());
2371 vCalcIdParam.setDescription(setting.getDescription());
2375 vCalcIdParam.setName("");
2376 vCalcIdParam.setDescription("Last used parameters");
2378 // need to be able to recover 1) settings 2) user-defined presets or
2379 // recreate settings from preset 3) predefined settings provided by
2380 // service - or settings that can be transferred (or discarded)
2381 vCalcIdParam.setParameters(
2382 settings.getWsParamFile().replace("\n", "|\\n|"));
2383 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2384 // todo - decide if updateImmediately is needed for any projects.
2386 return vCalcIdParam;
2391 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2394 if (calcIdParam.getVersion().equals("1.0"))
2396 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2397 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2398 .getPreferredServiceFor(calcIds);
2399 if (service != null)
2401 WsParamSetI parmSet = null;
2404 parmSet = service.getParamStore().parseServiceParameterFile(
2405 calcIdParam.getName(), calcIdParam.getDescription(),
2407 calcIdParam.getParameters().replace("|\\n|", "\n"));
2408 } catch (IOException x)
2410 warn("Couldn't parse parameter data for "
2411 + calcIdParam.getCalcId(), x);
2414 List<ArgumentI> argList = null;
2415 if (calcIdParam.getName().length() > 0)
2417 parmSet = service.getParamStore()
2418 .getPreset(calcIdParam.getName());
2419 if (parmSet != null)
2421 // TODO : check we have a good match with settings in AACon -
2422 // otherwise we'll need to create a new preset
2427 argList = parmSet.getArguments();
2430 AAConSettings settings = new AAConSettings(
2431 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2432 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2433 calcIdParam.isNeedsUpdate());
2438 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2442 throw new Error(MessageManager.formatMessage(
2443 "error.unsupported_version_calcIdparam", new Object[]
2444 { calcIdParam.toString() }));
2448 * External mapping between jalview objects and objects yielding a valid and
2449 * unique object ID string. This is null for normal Jalview project IO, but
2450 * non-null when a jalview project is being read or written as part of a
2453 IdentityHashMap jv2vobj = null;
2456 * Construct a unique ID for jvobj using either existing bindings or if none
2457 * exist, the result of the hashcode call for the object.
2460 * jalview data object
2461 * @return unique ID for referring to jvobj
2463 private String makeHashCode(Object jvobj, String altCode)
2465 if (jv2vobj != null)
2467 Object id = jv2vobj.get(jvobj);
2470 return id.toString();
2472 // check string ID mappings
2473 if (jvids2vobj != null && jvobj instanceof String)
2475 id = jvids2vobj.get(jvobj);
2479 return id.toString();
2481 // give up and warn that something has gone wrong
2482 warn("Cannot find ID for object in external mapping : " + jvobj);
2488 * return local jalview object mapped to ID, if it exists
2492 * @return null or object bound to idcode
2494 private Object retrieveExistingObj(String idcode)
2496 if (idcode != null && vobj2jv != null)
2498 return vobj2jv.get(idcode);
2504 * binding from ID strings from external mapping table to jalview data model
2507 private Hashtable vobj2jv;
2509 private Sequence createVamsasSequence(String id, SequenceI jds)
2511 return createVamsasSequence(true, id, jds, null);
2514 private Sequence createVamsasSequence(boolean recurse, String id,
2515 SequenceI jds, SequenceI parentseq)
2517 Sequence vamsasSeq = new Sequence();
2518 vamsasSeq.setId(id);
2519 vamsasSeq.setName(jds.getName());
2520 vamsasSeq.setSequence(jds.getSequenceAsString());
2521 vamsasSeq.setDescription(jds.getDescription());
2522 List<DBRefEntry> dbrefs = null;
2523 if (jds.getDatasetSequence() != null)
2525 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2529 // seqId==dsseqid so we can tell which sequences really are
2530 // dataset sequences only
2531 vamsasSeq.setDsseqid(id);
2532 dbrefs = jds.getDBRefs();
2533 if (parentseq == null)
2540 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2544 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2546 DBRef dbref = new DBRef();
2547 DBRefEntry ref = dbrefs.get(d);
2548 dbref.setSource(ref.getSource());
2549 dbref.setVersion(ref.getVersion());
2550 dbref.setAccessionId(ref.getAccessionId());
2551 if (ref instanceof GeneLocus)
2553 dbref.setLocus(true);
2557 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2559 dbref.setMapping(mp);
2561 vamsasSeq.getDBRef().add(dbref);
2567 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2568 SequenceI parentseq, SequenceI jds, boolean recurse)
2571 if (jmp.getMap() != null)
2575 jalview.util.MapList mlst = jmp.getMap();
2576 List<int[]> r = mlst.getFromRanges();
2577 for (int[] range : r)
2579 MapListFrom mfrom = new MapListFrom();
2580 mfrom.setStart(range[0]);
2581 mfrom.setEnd(range[1]);
2582 // mp.addMapListFrom(mfrom);
2583 mp.getMapListFrom().add(mfrom);
2585 r = mlst.getToRanges();
2586 for (int[] range : r)
2588 MapListTo mto = new MapListTo();
2589 mto.setStart(range[0]);
2590 mto.setEnd(range[1]);
2591 // mp.addMapListTo(mto);
2592 mp.getMapListTo().add(mto);
2594 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2595 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2596 if (jmp.getTo() != null)
2598 // MappingChoice mpc = new MappingChoice();
2600 // check/create ID for the sequence referenced by getTo()
2603 SequenceI ps = null;
2604 if (parentseq != jmp.getTo()
2605 && parentseq.getDatasetSequence() != jmp.getTo())
2607 // chaining dbref rather than a handshaking one
2608 jmpid = seqHash(ps = jmp.getTo());
2612 jmpid = seqHash(ps = parentseq);
2614 // mpc.setDseqFor(jmpid);
2615 mp.setDseqFor(jmpid);
2616 if (!seqRefIds.containsKey(jmpid))
2618 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2619 seqRefIds.put(jmpid, ps);
2623 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2626 // mp.setMappingChoice(mpc);
2632 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2633 List<UserColourScheme> userColours, JalviewModel jm)
2636 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2637 boolean newucs = false;
2638 if (!userColours.contains(ucs))
2640 userColours.add(ucs);
2643 id = "ucs" + userColours.indexOf(ucs);
2646 // actually create the scheme's entry in the XML model
2647 java.awt.Color[] colours = ucs.getColours();
2648 UserColours uc = new UserColours();
2649 // UserColourScheme jbucs = new UserColourScheme();
2650 JalviewUserColours jbucs = new JalviewUserColours();
2652 for (int i = 0; i < colours.length; i++)
2654 Colour col = new Colour();
2655 col.setName(ResidueProperties.aa[i]);
2656 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2657 // jbucs.addColour(col);
2658 jbucs.getColour().add(col);
2660 if (ucs.getLowerCaseColours() != null)
2662 colours = ucs.getLowerCaseColours();
2663 for (int i = 0; i < colours.length; i++)
2665 Colour col = new Colour();
2666 col.setName(ResidueProperties.aa[i].toLowerCase());
2667 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2668 // jbucs.addColour(col);
2669 jbucs.getColour().add(col);
2674 uc.setUserColourScheme(jbucs);
2675 // jm.addUserColours(uc);
2676 jm.getUserColours().add(uc);
2682 jalview.schemes.UserColourScheme getUserColourScheme(
2683 JalviewModel jm, String id)
2685 List<UserColours> uc = jm.getUserColours();
2686 UserColours colours = null;
2688 for (int i = 0; i < uc.length; i++)
2690 if (uc[i].getId().equals(id))
2697 for (UserColours c : uc)
2699 if (c.getId().equals(id))
2706 java.awt.Color[] newColours = new java.awt.Color[24];
2708 for (int i = 0; i < 24; i++)
2710 newColours[i] = new java.awt.Color(Integer.parseInt(
2711 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2712 colours.getUserColourScheme().getColour().get(i).getRGB(),
2716 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2719 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2721 newColours = new java.awt.Color[23];
2722 for (int i = 0; i < 23; i++)
2724 newColours[i] = new java.awt.Color(Integer.parseInt(
2725 colours.getUserColourScheme().getColour().get(i + 24)
2729 ucs.setLowerCaseColours(newColours);
2736 * contains last error message (if any) encountered by XML loader.
2738 String errorMessage = null;
2741 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2742 * exceptions are raised during project XML parsing
2744 public boolean attemptversion1parse = false;
2747 * Load a jalview project archive from a jar file
2750 * - HTTP URL or filename
2752 public AlignFrame loadJalviewAlign(final Object file)
2755 jalview.gui.AlignFrame af = null;
2759 // create list to store references for any new Jmol viewers created
2760 newStructureViewers = new Vector<>();
2761 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2762 // Workaround is to make sure caller implements the JarInputStreamProvider
2764 // so we can re-open the jar input stream for each entry.
2766 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2767 af = loadJalviewAlign(jprovider);
2770 af.setMenusForViewport();
2772 } catch (MalformedURLException e)
2774 errorMessage = "Invalid URL format for '" + file + "'";
2780 SwingUtilities.invokeAndWait(new Runnable()
2785 setLoadingFinishedForNewStructureViewers();
2788 } catch (Exception x)
2790 System.err.println("Error loading alignment: " + x.getMessage());
2796 @SuppressWarnings("unused")
2797 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2799 // BH 2018 allow for bytes already attached to File object
2801 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2802 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2805 errorMessage = null;
2806 uniqueSetSuffix = null;
2808 viewportsAdded.clear();
2809 frefedSequence = null;
2811 if (file.startsWith("http://")) {
2812 url = new URL(file);
2814 final URL _url = url;
2815 return new jarInputStreamProvider() {
2818 public JarInputStream getJarInputStream() throws IOException {
2819 if (bytes != null) {
2820 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2821 return new JarInputStream(new ByteArrayInputStream(bytes));
2824 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2825 return new JarInputStream(_url.openStream());
2827 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2828 return new JarInputStream(new FileInputStream(file));
2833 public String getFilename() {
2837 } catch (IOException e) {
2838 e.printStackTrace();
2844 * Recover jalview session from a jalview project archive. Caller may
2845 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2846 * themselves. Any null fields will be initialised with default values,
2847 * non-null fields are left alone.
2852 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2854 errorMessage = null;
2855 if (uniqueSetSuffix == null)
2857 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2859 if (seqRefIds == null)
2863 AlignFrame af = null, _af = null;
2864 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2865 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2866 final String file = jprovider.getFilename();
2869 JarInputStream jin = null;
2870 JarEntry jarentry = null;
2875 jin = jprovider.getJarInputStream();
2876 for (int i = 0; i < entryCount; i++)
2878 jarentry = jin.getNextJarEntry();
2881 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2883 JAXBContext jc = JAXBContext
2884 .newInstance("jalview.xml.binding.jalview");
2885 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2886 .createXMLStreamReader(jin);
2887 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2888 JAXBElement<JalviewModel> jbe = um
2889 .unmarshal(streamReader, JalviewModel.class);
2890 JalviewModel object = jbe.getValue();
2892 if (true) // !skipViewport(object))
2894 _af = loadFromObject(object, file, true, jprovider);
2895 if (_af != null && object.getViewport().size() > 0)
2896 // getJalviewModelSequence().getViewportCount() > 0)
2900 // store a reference to the first view
2903 if (_af.getViewport().isGatherViewsHere())
2905 // if this is a gathered view, keep its reference since
2906 // after gathering views, only this frame will remain
2908 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2911 // Save dataset to register mappings once all resolved
2912 importedDatasets.put(
2913 af.getViewport().getAlignment().getDataset(),
2914 af.getViewport().getAlignment().getDataset());
2919 else if (jarentry != null)
2921 // Some other file here.
2924 } while (jarentry != null);
2925 resolveFrefedSequences();
2926 } catch (IOException ex)
2928 ex.printStackTrace();
2929 errorMessage = "Couldn't locate Jalview XML file : " + file;
2931 "Exception whilst loading jalview XML file : " + ex + "\n");
2932 } catch (Exception ex)
2934 System.err.println("Parsing as Jalview Version 2 file failed.");
2935 ex.printStackTrace(System.err);
2936 if (attemptversion1parse)
2938 // used to attempt to parse as V1 castor-generated xml
2940 if (Desktop.instance != null)
2942 Desktop.instance.stopLoading();
2946 System.out.println("Successfully loaded archive file");
2949 ex.printStackTrace();
2952 "Exception whilst loading jalview XML file : " + ex + "\n");
2953 } catch (OutOfMemoryError e)
2955 // Don't use the OOM Window here
2956 errorMessage = "Out of memory loading jalview XML file";
2957 System.err.println("Out of memory whilst loading jalview XML file");
2958 e.printStackTrace();
2962 * Regather multiple views (with the same sequence set id) to the frame (if
2963 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2964 * views instead of separate frames. Note this doesn't restore a state where
2965 * some expanded views in turn have tabbed views - the last "first tab" read
2966 * in will play the role of gatherer for all.
2968 for (AlignFrame fr : gatherToThisFrame.values())
2970 Desktop.instance.gatherViews(fr);
2973 restoreSplitFrames();
2974 for (AlignmentI ds : importedDatasets.keySet())
2976 if (ds.getCodonFrames() != null)
2978 StructureSelectionManager
2979 .getStructureSelectionManager(Desktop.instance)
2980 .registerMappings(ds.getCodonFrames());
2983 if (errorMessage != null)
2988 if (Desktop.instance != null)
2990 Desktop.instance.stopLoading();
2997 * Try to reconstruct and display SplitFrame windows, where each contains
2998 * complementary dna and protein alignments. Done by pairing up AlignFrame
2999 * objects (created earlier) which have complementary viewport ids associated.
3001 protected void restoreSplitFrames()
3003 List<SplitFrame> gatherTo = new ArrayList<>();
3004 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3005 Map<String, AlignFrame> dna = new HashMap<>();
3008 * Identify the DNA alignments
3010 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3013 AlignFrame af = candidate.getValue();
3014 if (af.getViewport().getAlignment().isNucleotide())
3016 dna.put(candidate.getKey().getId(), af);
3021 * Try to match up the protein complements
3023 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3026 AlignFrame af = candidate.getValue();
3027 if (!af.getViewport().getAlignment().isNucleotide())
3029 String complementId = candidate.getKey().getComplementId();
3030 // only non-null complements should be in the Map
3031 if (complementId != null && dna.containsKey(complementId))
3033 final AlignFrame dnaFrame = dna.get(complementId);
3034 SplitFrame sf = createSplitFrame(dnaFrame, af);
3035 addedToSplitFrames.add(dnaFrame);
3036 addedToSplitFrames.add(af);
3037 dnaFrame.setMenusForViewport();
3038 af.setMenusForViewport();
3039 if (af.getViewport().isGatherViewsHere())
3048 * Open any that we failed to pair up (which shouldn't happen!) as
3049 * standalone AlignFrame's.
3051 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3054 AlignFrame af = candidate.getValue();
3055 if (!addedToSplitFrames.contains(af))
3057 Viewport view = candidate.getKey();
3058 Desktop.addInternalFrame(af, view.getTitle(),
3059 safeInt(view.getWidth()), safeInt(view.getHeight()));
3060 af.setMenusForViewport();
3061 System.err.println("Failed to restore view " + view.getTitle()
3062 + " to split frame");
3067 * Gather back into tabbed views as flagged.
3069 for (SplitFrame sf : gatherTo)
3071 Desktop.instance.gatherViews(sf);
3074 splitFrameCandidates.clear();
3078 * Construct and display one SplitFrame holding DNA and protein alignments.
3081 * @param proteinFrame
3084 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3085 AlignFrame proteinFrame)
3087 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3088 String title = MessageManager.getString("label.linked_view_title");
3089 int width = (int) dnaFrame.getBounds().getWidth();
3090 int height = (int) (dnaFrame.getBounds().getHeight()
3091 + proteinFrame.getBounds().getHeight() + 50);
3094 * SplitFrame location is saved to both enclosed frames
3096 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3097 Desktop.addInternalFrame(splitFrame, title, width, height);
3100 * And compute cDNA consensus (couldn't do earlier with consensus as
3101 * mappings were not yet present)
3103 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3109 * check errorMessage for a valid error message and raise an error box in the
3110 * GUI or write the current errorMessage to stderr and then clear the error
3113 protected void reportErrors()
3115 reportErrors(false);
3118 protected void reportErrors(final boolean saving)
3120 if (errorMessage != null)
3122 final String finalErrorMessage = errorMessage;
3125 javax.swing.SwingUtilities.invokeLater(new Runnable()
3130 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3132 "Error " + (saving ? "saving" : "loading")
3134 JvOptionPane.WARNING_MESSAGE);
3140 System.err.println("Problem loading Jalview file: " + errorMessage);
3143 errorMessage = null;
3146 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3149 * when set, local views will be updated from view stored in JalviewXML
3150 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3151 * sync if this is set to true.
3153 private final boolean updateLocalViews = false;
3156 * Returns the path to a temporary file holding the PDB file for the given PDB
3157 * id. The first time of asking, searches for a file of that name in the
3158 * Jalview project jar, and copies it to a new temporary file. Any repeat
3159 * requests just return the path to the file previously created.
3165 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3168 if (alreadyLoadedPDB.containsKey(pdbId))
3170 return alreadyLoadedPDB.get(pdbId).toString();
3173 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3175 if (tempFile != null)
3177 alreadyLoadedPDB.put(pdbId, tempFile);
3183 * Copies the jar entry of given name to a new temporary file and returns the
3184 * path to the file, or null if the entry is not found.
3187 * @param jarEntryName
3189 * a prefix for the temporary file name, must be at least three
3191 * @param suffixModel
3192 * null or original file - so new file can be given the same suffix
3196 protected String copyJarEntry(jarInputStreamProvider jprovider,
3197 String jarEntryName, String prefix, String suffixModel)
3199 String suffix = ".tmp";
3200 if (suffixModel == null)
3202 suffixModel = jarEntryName;
3204 int sfpos = suffixModel.lastIndexOf(".");
3205 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3207 suffix = "." + suffixModel.substring(sfpos + 1);
3210 try (JarInputStream jin = jprovider.getJarInputStream())
3212 JarEntry entry = null;
3215 entry = jin.getNextJarEntry();
3216 } while (entry != null && !entry.getName().equals(jarEntryName));
3220 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3221 File outFile = File.createTempFile(prefix, suffix);
3222 outFile.deleteOnExit();
3223 try (OutputStream os = new FileOutputStream(outFile))
3227 String t = outFile.getAbsolutePath();
3232 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3234 } catch (Exception ex)
3236 ex.printStackTrace();
3242 private class JvAnnotRow
3244 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3251 * persisted version of annotation row from which to take vis properties
3253 public jalview.datamodel.AlignmentAnnotation template;
3256 * original position of the annotation row in the alignment
3262 * Load alignment frame from jalview XML DOM object
3264 * @param jalviewModel
3267 * filename source string
3268 * @param loadTreesAndStructures
3269 * when false only create Viewport
3271 * data source provider
3272 * @return alignment frame created from view stored in DOM
3274 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3275 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3277 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3278 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3280 // JalviewModelSequence jms = object.getJalviewModelSequence();
3282 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3284 Viewport view = (jalviewModel.getViewport().size() > 0)
3285 ? jalviewModel.getViewport().get(0)
3288 // ////////////////////////////////
3289 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3292 // If we just load in the same jar file again, the sequenceSetId
3293 // will be the same, and we end up with multiple references
3294 // to the same sequenceSet. We must modify this id on load
3295 // so that each load of the file gives a unique id
3298 * used to resolve correct alignment dataset for alignments with multiple
3301 String uniqueSeqSetId = null;
3302 String viewId = null;
3305 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3306 viewId = (view.getId() == null ? null
3307 : view.getId() + uniqueSetSuffix);
3310 // ////////////////////////////////
3313 List<SequenceI> hiddenSeqs = null;
3315 List<SequenceI> tmpseqs = new ArrayList<>();
3317 boolean multipleView = false;
3318 SequenceI referenceseqForView = null;
3319 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3320 List<JSeq> jseqs = jalviewModel.getJSeq();
3321 int vi = 0; // counter in vamsasSeq array
3322 for (int i = 0; i < jseqs.size(); i++)
3324 JSeq jseq = jseqs.get(i);
3325 String seqId = jseq.getId();
3327 SequenceI tmpSeq = seqRefIds.get(seqId);
3330 if (!incompleteSeqs.containsKey(seqId))
3332 // may not need this check, but keep it for at least 2.9,1 release
3333 if (tmpSeq.getStart() != jseq.getStart()
3334 || tmpSeq.getEnd() != jseq.getEnd())
3337 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3338 tmpSeq.getName(), tmpSeq.getStart(),
3339 tmpSeq.getEnd(), jseq.getStart(),
3345 incompleteSeqs.remove(seqId);
3347 if (vamsasSeqs.size() > vi
3348 && vamsasSeqs.get(vi).getId().equals(seqId))
3350 // most likely we are reading a dataset XML document so
3351 // update from vamsasSeq section of XML for this sequence
3352 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3353 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3354 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3359 // reading multiple views, so vamsasSeq set is a subset of JSeq
3360 multipleView = true;
3362 tmpSeq.setStart(jseq.getStart());
3363 tmpSeq.setEnd(jseq.getEnd());
3364 tmpseqs.add(tmpSeq);
3368 Sequence vamsasSeq = vamsasSeqs.get(vi);
3369 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3370 vamsasSeq.getSequence());
3371 tmpSeq.setDescription(vamsasSeq.getDescription());
3372 tmpSeq.setStart(jseq.getStart());
3373 tmpSeq.setEnd(jseq.getEnd());
3374 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3375 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3376 tmpseqs.add(tmpSeq);
3380 if (safeBoolean(jseq.isViewreference()))
3382 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3385 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3387 if (hiddenSeqs == null)
3389 hiddenSeqs = new ArrayList<>();
3392 hiddenSeqs.add(tmpSeq);
3397 // Create the alignment object from the sequence set
3398 // ///////////////////////////////
3399 SequenceI[] orderedSeqs = tmpseqs
3400 .toArray(new SequenceI[tmpseqs.size()]);
3402 AlignmentI al = null;
3403 // so we must create or recover the dataset alignment before going further
3404 // ///////////////////////////////
3405 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3407 // older jalview projects do not have a dataset - so creat alignment and
3409 al = new Alignment(orderedSeqs);
3410 al.setDataset(null);
3414 boolean isdsal = jalviewModel.getViewport().isEmpty();
3417 // we are importing a dataset record, so
3418 // recover reference to an alignment already materialsed as dataset
3419 al = getDatasetFor(vamsasSet.getDatasetId());
3423 // materialse the alignment
3424 al = new Alignment(orderedSeqs);
3428 addDatasetRef(vamsasSet.getDatasetId(), al);
3431 // finally, verify all data in vamsasSet is actually present in al
3432 // passing on flag indicating if it is actually a stored dataset
3433 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3436 if (referenceseqForView != null)
3438 al.setSeqrep(referenceseqForView);
3440 // / Add the alignment properties
3441 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3443 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3445 al.setProperty(ssp.getKey(), ssp.getValue());
3448 // ///////////////////////////////
3450 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3453 // load sequence features, database references and any associated PDB
3454 // structures for the alignment
3456 // prior to 2.10, this part would only be executed the first time a
3457 // sequence was encountered, but not afterwards.
3458 // now, for 2.10 projects, this is also done if the xml doc includes
3459 // dataset sequences not actually present in any particular view.
3461 for (int i = 0; i < vamsasSeqs.size(); i++)
3463 JSeq jseq = jseqs.get(i);
3464 if (jseq.getFeatures().size() > 0)
3466 List<Feature> features = jseq.getFeatures();
3467 for (int f = 0; f < features.size(); f++)
3469 Feature feat = features.get(f);
3470 SequenceFeature sf = new SequenceFeature(feat.getType(),
3471 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3472 safeFloat(feat.getScore()), feat.getFeatureGroup());
3473 sf.setStatus(feat.getStatus());
3476 * load any feature attributes - include map-valued attributes
3478 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3479 for (int od = 0; od < feat.getOtherData().size(); od++)
3481 OtherData keyValue = feat.getOtherData().get(od);
3482 String attributeName = keyValue.getKey();
3483 String attributeValue = keyValue.getValue();
3484 if (attributeName.startsWith("LINK"))
3486 sf.addLink(attributeValue);
3490 String subAttribute = keyValue.getKey2();
3491 if (subAttribute == null)
3493 // simple string-valued attribute
3494 sf.setValue(attributeName, attributeValue);
3498 // attribute 'key' has sub-attribute 'key2'
3499 if (!mapAttributes.containsKey(attributeName))
3501 mapAttributes.put(attributeName, new HashMap<>());
3503 mapAttributes.get(attributeName).put(subAttribute,
3508 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3511 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3514 // adds feature to datasequence's feature set (since Jalview 2.10)
3515 al.getSequenceAt(i).addSequenceFeature(sf);
3518 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3520 // adds dbrefs to datasequence's set (since Jalview 2.10)
3522 al.getSequenceAt(i).getDatasetSequence() == null
3523 ? al.getSequenceAt(i)
3524 : al.getSequenceAt(i).getDatasetSequence(),
3527 if (jseq.getPdbids().size() > 0)
3529 List<Pdbids> ids = jseq.getPdbids();
3530 for (int p = 0; p < ids.size(); p++)
3532 Pdbids pdbid = ids.get(p);
3533 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3534 entry.setId(pdbid.getId());
3535 if (pdbid.getType() != null)
3537 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3539 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3543 entry.setType(PDBEntry.Type.FILE);
3546 // jprovider is null when executing 'New View'
3547 if (pdbid.getFile() != null && jprovider != null)
3549 if (!pdbloaded.containsKey(pdbid.getFile()))
3551 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3556 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3560 if (pdbid.getPdbentryItem() != null)
3562 for (PdbentryItem item : pdbid.getPdbentryItem())
3564 for (Property pr : item.getProperty())
3566 entry.setProperty(pr.getName(), pr.getValue());
3571 for (Property prop : pdbid.getProperty())
3573 entry.setProperty(prop.getName(), prop.getValue());
3575 StructureSelectionManager
3576 .getStructureSelectionManager(Desktop.instance)
3577 .registerPDBEntry(entry);
3578 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3579 if (al.getSequenceAt(i).getDatasetSequence() != null)
3581 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3585 al.getSequenceAt(i).addPDBId(entry);
3590 } // end !multipleview
3592 // ///////////////////////////////
3593 // LOAD SEQUENCE MAPPINGS
3595 if (vamsasSet.getAlcodonFrame().size() > 0)
3597 // TODO Potentially this should only be done once for all views of an
3599 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3600 for (int i = 0; i < alc.size(); i++)
3602 AlignedCodonFrame cf = new AlignedCodonFrame();
3603 if (alc.get(i).getAlcodMap().size() > 0)
3605 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3606 for (int m = 0; m < maps.size(); m++)
3608 AlcodMap map = maps.get(m);
3609 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3611 jalview.datamodel.Mapping mapping = null;
3612 // attach to dna sequence reference.
3613 if (map.getMapping() != null)
3615 mapping = addMapping(map.getMapping());
3616 if (dnaseq != null && mapping.getTo() != null)
3618 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3624 newAlcodMapRef(map.getDnasq(), cf, mapping));
3628 al.addCodonFrame(cf);
3633 // ////////////////////////////////
3635 List<JvAnnotRow> autoAlan = new ArrayList<>();
3638 * store any annotations which forward reference a group's ID
3640 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3642 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3644 List<Annotation> an = vamsasSet.getAnnotation();
3646 for (int i = 0; i < an.size(); i++)
3648 Annotation annotation = an.get(i);
3651 * test if annotation is automatically calculated for this view only
3653 boolean autoForView = false;
3654 if (annotation.getLabel().equals("Quality")
3655 || annotation.getLabel().equals("Conservation")
3656 || annotation.getLabel().equals("Consensus"))
3658 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3660 // JAXB has no has() test; schema defaults value to false
3661 // if (!annotation.hasAutoCalculated())
3663 // annotation.setAutoCalculated(true);
3666 if (autoForView || annotation.isAutoCalculated())
3668 // remove ID - we don't recover annotation from other views for
3669 // view-specific annotation
3670 annotation.setId(null);
3673 // set visibility for other annotation in this view
3674 String annotationId = annotation.getId();
3675 if (annotationId != null && annotationIds.containsKey(annotationId))
3677 AlignmentAnnotation jda = annotationIds.get(annotationId);
3678 // in principle Visible should always be true for annotation displayed
3679 // in multiple views
3680 if (annotation.isVisible() != null)
3682 jda.visible = annotation.isVisible();
3685 al.addAnnotation(jda);
3689 // Construct new annotation from model.
3690 List<AnnotationElement> ae = annotation.getAnnotationElement();
3691 jalview.datamodel.Annotation[] anot = null;
3692 java.awt.Color firstColour = null;
3694 if (!annotation.isScoreOnly())
3696 anot = new jalview.datamodel.Annotation[al.getWidth()];
3697 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3699 AnnotationElement annElement = ae.get(aa);
3700 anpos = annElement.getPosition();
3702 if (anpos >= anot.length)
3707 float value = safeFloat(annElement.getValue());
3708 anot[anpos] = new jalview.datamodel.Annotation(
3709 annElement.getDisplayCharacter(),
3710 annElement.getDescription(),
3711 (annElement.getSecondaryStructure() == null
3712 || annElement.getSecondaryStructure()
3716 .getSecondaryStructure()
3719 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3720 if (firstColour == null)
3722 firstColour = anot[anpos].colour;
3726 jalview.datamodel.AlignmentAnnotation jaa = null;
3728 if (annotation.isGraph())
3730 float llim = 0, hlim = 0;
3731 // if (autoForView || an[i].isAutoCalculated()) {
3734 jaa = new jalview.datamodel.AlignmentAnnotation(
3735 annotation.getLabel(), annotation.getDescription(), anot,
3736 llim, hlim, safeInt(annotation.getGraphType()));
3738 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3739 jaa._linecolour = firstColour;
3740 if (annotation.getThresholdLine() != null)
3742 jaa.setThreshold(new jalview.datamodel.GraphLine(
3743 safeFloat(annotation.getThresholdLine().getValue()),
3744 annotation.getThresholdLine().getLabel(),
3745 new java.awt.Color(safeInt(
3746 annotation.getThresholdLine().getColour()))));
3748 if (autoForView || annotation.isAutoCalculated())
3750 // Hardwire the symbol display line to ensure that labels for
3751 // histograms are displayed
3757 jaa = new jalview.datamodel.AlignmentAnnotation(
3758 annotation.getLabel(), annotation.getDescription(), anot);
3759 jaa._linecolour = firstColour;
3761 // register new annotation
3762 if (annotation.getId() != null)
3764 annotationIds.put(annotation.getId(), jaa);
3765 jaa.annotationId = annotation.getId();
3767 // recover sequence association
3768 String sequenceRef = annotation.getSequenceRef();
3769 if (sequenceRef != null)
3771 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3772 SequenceI sequence = seqRefIds.get(sequenceRef);
3773 if (sequence == null)
3775 // in pre-2.9 projects sequence ref is to sequence name
3776 sequence = al.findName(sequenceRef);
3778 if (sequence != null)
3780 jaa.createSequenceMapping(sequence, 1, true);
3781 sequence.addAlignmentAnnotation(jaa);
3784 // and make a note of any group association
3785 if (annotation.getGroupRef() != null
3786 && annotation.getGroupRef().length() > 0)
3788 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3789 .get(annotation.getGroupRef());
3792 aal = new ArrayList<>();
3793 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3798 if (annotation.getScore() != null)
3800 jaa.setScore(annotation.getScore().doubleValue());
3802 if (annotation.isVisible() != null)
3804 jaa.visible = annotation.isVisible().booleanValue();
3807 if (annotation.isCentreColLabels() != null)
3809 jaa.centreColLabels = annotation.isCentreColLabels()
3813 if (annotation.isScaleColLabels() != null)
3815 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3817 if (annotation.isAutoCalculated())
3819 // newer files have an 'autoCalculated' flag and store calculation
3820 // state in viewport properties
3821 jaa.autoCalculated = true; // means annotation will be marked for
3822 // update at end of load.
3824 if (annotation.getGraphHeight() != null)
3826 jaa.graphHeight = annotation.getGraphHeight().intValue();
3828 jaa.belowAlignment = annotation.isBelowAlignment();
3829 jaa.setCalcId(annotation.getCalcId());
3830 if (annotation.getProperty().size() > 0)
3832 for (Annotation.Property prop : annotation
3835 jaa.setProperty(prop.getName(), prop.getValue());
3838 if (jaa.autoCalculated)
3840 autoAlan.add(new JvAnnotRow(i, jaa));
3843 // if (!autoForView)
3845 // add autocalculated group annotation and any user created annotation
3847 al.addAnnotation(jaa);
3851 // ///////////////////////
3853 // Create alignment markup and styles for this view
3854 if (jalviewModel.getJGroup().size() > 0)
3856 List<JGroup> groups = jalviewModel.getJGroup();
3857 boolean addAnnotSchemeGroup = false;
3858 for (int i = 0; i < groups.size(); i++)
3860 JGroup jGroup = groups.get(i);
3861 ColourSchemeI cs = null;
3862 if (jGroup.getColour() != null)
3864 if (jGroup.getColour().startsWith("ucs"))
3866 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3868 else if (jGroup.getColour().equals("AnnotationColourGradient")
3869 && jGroup.getAnnotationColours() != null)
3871 addAnnotSchemeGroup = true;
3875 cs = ColourSchemeProperty.getColourScheme(null, al,
3876 jGroup.getColour());
3879 int pidThreshold = safeInt(jGroup.getPidThreshold());
3881 Vector<SequenceI> seqs = new Vector<>();
3883 for (int s = 0; s < jGroup.getSeq().size(); s++)
3885 String seqId = jGroup.getSeq().get(s);
3886 SequenceI ts = seqRefIds.get(seqId);
3890 seqs.addElement(ts);
3894 if (seqs.size() < 1)
3899 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3900 safeBoolean(jGroup.isDisplayBoxes()),
3901 safeBoolean(jGroup.isDisplayText()),
3902 safeBoolean(jGroup.isColourText()),
3903 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3904 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3905 sg.getGroupColourScheme()
3906 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3907 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3909 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3910 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3911 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3912 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3913 // attributes with a default in the schema are never null
3914 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3915 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3916 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3917 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3918 if (jGroup.getConsThreshold() != null
3919 && jGroup.getConsThreshold().intValue() != 0)
3921 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3924 c.verdict(false, 25);
3925 sg.cs.setConservation(c);
3928 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3930 // re-instate unique group/annotation row reference
3931 List<AlignmentAnnotation> jaal = groupAnnotRefs
3932 .get(jGroup.getId());
3935 for (AlignmentAnnotation jaa : jaal)
3938 if (jaa.autoCalculated)
3940 // match up and try to set group autocalc alignment row for this
3942 if (jaa.label.startsWith("Consensus for "))
3944 sg.setConsensus(jaa);
3946 // match up and try to set group autocalc alignment row for this
3948 if (jaa.label.startsWith("Conservation for "))
3950 sg.setConservationRow(jaa);
3957 if (addAnnotSchemeGroup)
3959 // reconstruct the annotation colourscheme
3960 sg.setColourScheme(constructAnnotationColour(
3961 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3967 // only dataset in this model, so just return.
3970 // ///////////////////////////////
3973 AlignFrame af = null;
3974 AlignViewport av = null;
3975 // now check to see if we really need to create a new viewport.
3976 if (multipleView && viewportsAdded.size() == 0)
3978 // We recovered an alignment for which a viewport already exists.
3979 // TODO: fix up any settings necessary for overlaying stored state onto
3980 // state recovered from another document. (may not be necessary).
3981 // we may need a binding from a viewport in memory to one recovered from
3983 // and then recover its containing af to allow the settings to be applied.
3984 // TODO: fix for vamsas demo
3986 "About to recover a viewport for existing alignment: Sequence set ID is "
3988 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3989 if (seqsetobj != null)
3991 if (seqsetobj instanceof String)
3993 uniqueSeqSetId = (String) seqsetobj;
3995 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4001 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4007 * indicate that annotation colours are applied across all groups (pre
4008 * Jalview 2.8.1 behaviour)
4010 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4011 jalviewModel.getVersion());
4013 AlignmentPanel ap = null;
4014 boolean isnewview = true;
4017 // Check to see if this alignment already has a view id == viewId
4018 jalview.gui.AlignmentPanel views[] = Desktop
4019 .getAlignmentPanels(uniqueSeqSetId);
4020 if (views != null && views.length > 0)
4022 for (int v = 0; v < views.length; v++)
4024 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4026 // recover the existing alignpanel, alignframe, viewport
4027 af = views[v].alignFrame;
4030 // TODO: could even skip resetting view settings if we don't want to
4031 // change the local settings from other jalview processes
4040 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4041 uniqueSeqSetId, viewId, autoAlan);
4042 av = af.getViewport();
4047 * Load any trees, PDB structures and viewers, Overview
4049 * Not done if flag is false (when this method is used for New View)
4051 if (loadTreesAndStructures)
4053 loadTrees(jalviewModel, view, af, av, ap);
4054 loadPCAViewers(jalviewModel, ap);
4055 loadPDBStructures(jprovider, jseqs, af, ap);
4056 loadRnaViewers(jprovider, jseqs, ap);
4057 loadOverview(view, af);
4059 // and finally return.
4064 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4065 * and geometry as saved
4070 protected void loadOverview(Viewport view, AlignFrame af)
4072 Overview overview = view.getOverview();
4073 if (overview != null)
4075 OverviewPanel overviewPanel = af
4076 .openOverviewPanel(overview.isShowHidden());
4077 JInternalFrame frame = (JInternalFrame) SwingUtilities
4078 .getAncestorOfClass(JInternalFrame.class, overviewPanel);
4079 frame.setTitle(overview.getTitle());
4080 frame.setBounds(overview.getXpos(), overview.getYpos(),
4081 overview.getWidth(), overview.getHeight());
4082 Color gap = new Color(overview.getGapColour());
4083 Color residue = new Color(overview.getResidueColour());
4084 Color hidden = new Color(overview.getHiddenColour());
4085 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4090 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4091 * panel is restored from separate jar entries, two (gapped and trimmed) per
4092 * sequence and secondary structure.
4094 * Currently each viewer shows just one sequence and structure (gapped and
4095 * trimmed), however this method is designed to support multiple sequences or
4096 * structures in viewers if wanted in future.
4102 private void loadRnaViewers(jarInputStreamProvider jprovider,
4103 List<JSeq> jseqs, AlignmentPanel ap)
4106 * scan the sequences for references to viewers; create each one the first
4107 * time it is referenced, add Rna models to existing viewers
4109 for (JSeq jseq : jseqs)
4111 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4113 RnaViewer viewer = jseq.getRnaViewer().get(i);
4114 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4117 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4119 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4120 SequenceI seq = seqRefIds.get(jseq.getId());
4121 AlignmentAnnotation ann = this.annotationIds
4122 .get(ss.getAnnotationId());
4125 * add the structure to the Varna display (with session state copied
4126 * from the jar to a temporary file)
4128 boolean gapped = safeBoolean(ss.isGapped());
4129 String rnaTitle = ss.getTitle();
4130 String sessionState = ss.getViewerState();
4131 String tempStateFile = copyJarEntry(jprovider, sessionState,
4133 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4134 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4136 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4142 * Locate and return an already instantiated matching AppVarna, or create one
4146 * @param viewIdSuffix
4150 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4151 String viewIdSuffix, AlignmentPanel ap)
4154 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4155 * if load is repeated
4157 String postLoadId = viewer.getViewId() + viewIdSuffix;
4158 for (JInternalFrame frame : getAllFrames())
4160 if (frame instanceof AppVarna)
4162 AppVarna varna = (AppVarna) frame;
4163 if (postLoadId.equals(varna.getViewId()))
4165 // this viewer is already instantiated
4166 // could in future here add ap as another 'parent' of the
4167 // AppVarna window; currently just 1-to-many
4174 * viewer not found - make it
4176 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4177 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4178 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4179 safeInt(viewer.getDividerLocation()));
4180 AppVarna varna = new AppVarna(model, ap);
4186 * Load any saved trees
4194 protected void loadTrees(JalviewModel jm, Viewport view,
4195 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4197 // TODO result of automated refactoring - are all these parameters needed?
4200 for (int t = 0; t < jm.getTree().size(); t++)
4203 Tree tree = jm.getTree().get(t);
4205 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4208 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4209 tree.getTitle(), safeInt(tree.getWidth()),
4210 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4211 safeInt(tree.getYpos()));
4212 if (tree.getId() != null)
4214 // perhaps bind the tree id to something ?
4219 // update local tree attributes ?
4220 // TODO: should check if tp has been manipulated by user - if so its
4221 // settings shouldn't be modified
4222 tp.setTitle(tree.getTitle());
4223 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4224 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4225 safeInt(tree.getHeight())));
4226 tp.setViewport(av); // af.viewport;
4227 // TODO: verify 'associate with all views' works still
4228 tp.getTreeCanvas().setViewport(av); // af.viewport;
4229 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4231 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4234 warn("There was a problem recovering stored Newick tree: \n"
4235 + tree.getNewick());
4239 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4240 tp.fitToWindow_actionPerformed(null);
4242 if (tree.getFontName() != null)
4245 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4246 safeInt(tree.getFontSize())));
4251 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4252 safeInt(view.getFontSize())));
4255 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4256 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4257 tp.showDistances(safeBoolean(tree.isShowDistances()));
4259 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4261 if (safeBoolean(tree.isCurrentTree()))
4263 af.getViewport().setCurrentTree(tp.getTree());
4267 } catch (Exception ex)
4269 ex.printStackTrace();
4274 * Load and link any saved structure viewers.
4281 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4282 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4285 * Run through all PDB ids on the alignment, and collect mappings between
4286 * distinct view ids and all sequences referring to that view.
4288 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4290 for (int i = 0; i < jseqs.size(); i++)
4292 JSeq jseq = jseqs.get(i);
4293 if (jseq.getPdbids().size() > 0)
4295 List<Pdbids> ids = jseq.getPdbids();
4296 for (int p = 0; p < ids.size(); p++)
4298 Pdbids pdbid = ids.get(p);
4299 final int structureStateCount = pdbid.getStructureState().size();
4300 for (int s = 0; s < structureStateCount; s++)
4302 // check to see if we haven't already created this structure view
4303 final StructureState structureState = pdbid
4304 .getStructureState().get(s);
4305 String sviewid = (structureState.getViewId() == null) ? null
4306 : structureState.getViewId() + uniqueSetSuffix;
4307 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4308 // Originally : pdbid.getFile()
4309 // : TODO: verify external PDB file recovery still works in normal
4310 // jalview project load
4312 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4313 jpdb.setId(pdbid.getId());
4315 int x = safeInt(structureState.getXpos());
4316 int y = safeInt(structureState.getYpos());
4317 int width = safeInt(structureState.getWidth());
4318 int height = safeInt(structureState.getHeight());
4320 // Probably don't need to do this anymore...
4321 // Desktop.desktop.getComponentAt(x, y);
4322 // TODO: NOW: check that this recovers the PDB file correctly.
4323 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4325 jalview.datamodel.SequenceI seq = seqRefIds
4326 .get(jseq.getId() + "");
4327 if (sviewid == null)
4329 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4332 if (!structureViewers.containsKey(sviewid))
4334 String viewerType = structureState.getType();
4335 if (viewerType == null) // pre Jalview 2.9
4337 viewerType = ViewerType.JMOL.toString();
4339 structureViewers.put(sviewid,
4340 new StructureViewerModel(x, y, width, height, false,
4341 false, true, structureState.getViewId(),
4343 // Legacy pre-2.7 conversion JAL-823 :
4344 // do not assume any view has to be linked for colour by
4348 // assemble String[] { pdb files }, String[] { id for each
4349 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4350 // seqs_file 2}, boolean[] {
4351 // linkAlignPanel,superposeWithAlignpanel}} from hash
4352 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4353 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4354 || structureState.isAlignwithAlignPanel());
4357 * Default colour by linked panel to false if not specified (e.g.
4358 * for pre-2.7 projects)
4360 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4361 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4362 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4365 * Default colour by viewer to true if not specified (e.g. for
4368 boolean colourByViewer = jmoldat.isColourByViewer();
4369 colourByViewer &= structureState.isColourByJmol();
4370 jmoldat.setColourByViewer(colourByViewer);
4372 if (jmoldat.getStateData().length() < structureState
4373 .getValue()/*Content()*/.length())
4375 jmoldat.setStateData(structureState.getValue());// Content());
4377 if (pdbid.getFile() != null)
4379 File mapkey = new File(pdbid.getFile());
4380 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4381 if (seqstrmaps == null)
4383 jmoldat.getFileData().put(mapkey,
4384 seqstrmaps = jmoldat.new StructureData(pdbFile,
4387 if (!seqstrmaps.getSeqList().contains(seq))
4389 seqstrmaps.getSeqList().add(seq);
4395 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");
4402 // Instantiate the associated structure views
4403 for (Entry<String, StructureViewerModel> entry : structureViewers
4408 createOrLinkStructureViewer(entry, af, ap, jprovider);
4409 } catch (Exception e)
4412 "Error loading structure viewer: " + e.getMessage());
4413 // failed - try the next one
4425 protected void createOrLinkStructureViewer(
4426 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4427 AlignmentPanel ap, jarInputStreamProvider jprovider)
4429 final StructureViewerModel stateData = viewerData.getValue();
4432 * Search for any viewer windows already open from other alignment views
4433 * that exactly match the stored structure state
4435 StructureViewerBase comp = findMatchingViewer(viewerData);
4439 linkStructureViewer(ap, comp, stateData);
4443 String type = stateData.getType();
4446 ViewerType viewerType = ViewerType.valueOf(type);
4447 createStructureViewer(viewerType, viewerData, af, jprovider);
4448 } catch (IllegalArgumentException | NullPointerException e)
4450 // TODO JAL-3619 show error dialog / offer an alternative viewer
4452 "Invalid structure viewer type: " + type);
4457 * Generates a name for the entry in the project jar file to hold state
4458 * information for a structure viewer
4463 protected String getViewerJarEntryName(String viewId)
4465 return VIEWER_PREFIX + viewId;
4469 * Returns any open frame that matches given structure viewer data. The match
4470 * is based on the unique viewId, or (for older project versions) the frame's
4476 protected StructureViewerBase findMatchingViewer(
4477 Entry<String, StructureViewerModel> viewerData)
4479 final String sviewid = viewerData.getKey();
4480 final StructureViewerModel svattrib = viewerData.getValue();
4481 StructureViewerBase comp = null;
4482 JInternalFrame[] frames = getAllFrames();
4483 for (JInternalFrame frame : frames)
4485 if (frame instanceof StructureViewerBase)
4488 * Post jalview 2.4 schema includes structure view id
4490 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4493 comp = (StructureViewerBase) frame;
4494 break; // break added in 2.9
4497 * Otherwise test for matching position and size of viewer frame
4499 else if (frame.getX() == svattrib.getX()
4500 && frame.getY() == svattrib.getY()
4501 && frame.getHeight() == svattrib.getHeight()
4502 && frame.getWidth() == svattrib.getWidth())
4504 comp = (StructureViewerBase) frame;
4505 // no break in faint hope of an exact match on viewId
4513 * Link an AlignmentPanel to an existing structure viewer.
4518 * @param useinViewerSuperpos
4519 * @param usetoColourbyseq
4520 * @param viewerColouring
4522 protected void linkStructureViewer(AlignmentPanel ap,
4523 StructureViewerBase viewer, StructureViewerModel stateData)
4525 // NOTE: if the jalview project is part of a shared session then
4526 // view synchronization should/could be done here.
4528 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4529 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4530 final boolean viewerColouring = stateData.isColourByViewer();
4531 Map<File, StructureData> oldFiles = stateData.getFileData();
4534 * Add mapping for sequences in this view to an already open viewer
4536 final AAStructureBindingModel binding = viewer.getBinding();
4537 for (File id : oldFiles.keySet())
4539 // add this and any other pdb files that should be present in the
4541 StructureData filedat = oldFiles.get(id);
4542 String pdbFile = filedat.getFilePath();
4543 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4544 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4546 binding.addSequenceForStructFile(pdbFile, seq);
4548 // and add the AlignmentPanel's reference to the view panel
4549 viewer.addAlignmentPanel(ap);
4550 if (useinViewerSuperpos)
4552 viewer.useAlignmentPanelForSuperposition(ap);
4556 viewer.excludeAlignmentPanelForSuperposition(ap);
4558 if (usetoColourbyseq)
4560 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4564 viewer.excludeAlignmentPanelForColourbyseq(ap);
4569 * Get all frames within the Desktop.
4573 protected JInternalFrame[] getAllFrames()
4575 JInternalFrame[] frames = null;
4576 // TODO is this necessary - is it safe - risk of hanging?
4581 frames = Desktop.desktop.getAllFrames();
4582 } catch (ArrayIndexOutOfBoundsException e)
4584 // occasional No such child exceptions are thrown here...
4588 } catch (InterruptedException f)
4592 } while (frames == null);
4597 * Answers true if 'version' is equal to or later than 'supported', where each
4598 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4599 * changes. Development and test values for 'version' are leniently treated
4603 * - minimum version we are comparing against
4605 * - version of data being processsed
4608 public static boolean isVersionStringLaterThan(String supported,
4611 if (supported == null || version == null
4612 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4613 || version.equalsIgnoreCase("Test")
4614 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4616 System.err.println("Assuming project file with "
4617 + (version == null ? "null" : version)
4618 + " is compatible with Jalview version " + supported);
4623 return StringUtils.compareVersions(version, supported, "b") >= 0;
4627 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4629 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4631 if (newStructureViewers != null)
4633 sview.getBinding().setFinishedLoadingFromArchive(false);
4634 newStructureViewers.add(sview);
4638 protected void setLoadingFinishedForNewStructureViewers()
4640 if (newStructureViewers != null)
4642 for (JalviewStructureDisplayI sview : newStructureViewers)
4644 sview.getBinding().setFinishedLoadingFromArchive(true);
4646 newStructureViewers.clear();
4647 newStructureViewers = null;
4651 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4652 List<SequenceI> hiddenSeqs, AlignmentI al,
4653 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4654 String viewId, List<JvAnnotRow> autoAlan)
4656 AlignFrame af = null;
4657 af = new AlignFrame(al, safeInt(view.getWidth()),
4658 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4662 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4663 // System.out.println("Jalview2XML AF " + e);
4664 // super.processKeyEvent(e);
4671 af.setFileName(file, FileFormat.Jalview);
4673 final AlignViewport viewport = af.getViewport();
4674 for (int i = 0; i < JSEQ.size(); i++)
4676 int colour = safeInt(JSEQ.get(i).getColour());
4677 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4683 viewport.setColourByReferenceSeq(true);
4684 viewport.setDisplayReferenceSeq(true);
4687 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4689 if (view.getSequenceSetId() != null)
4691 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4693 viewport.setSequenceSetId(uniqueSeqSetId);
4696 // propagate shared settings to this new view
4697 viewport.setHistoryList(av.getHistoryList());
4698 viewport.setRedoList(av.getRedoList());
4702 viewportsAdded.put(uniqueSeqSetId, viewport);
4704 // TODO: check if this method can be called repeatedly without
4705 // side-effects if alignpanel already registered.
4706 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4708 // apply Hidden regions to view.
4709 if (hiddenSeqs != null)
4711 for (int s = 0; s < JSEQ.size(); s++)
4713 SequenceGroup hidden = new SequenceGroup();
4714 boolean isRepresentative = false;
4715 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4717 isRepresentative = true;
4718 SequenceI sequenceToHide = al
4719 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4720 hidden.addSequence(sequenceToHide, false);
4721 // remove from hiddenSeqs list so we don't try to hide it twice
4722 hiddenSeqs.remove(sequenceToHide);
4724 if (isRepresentative)
4726 SequenceI representativeSequence = al.getSequenceAt(s);
4727 hidden.addSequence(representativeSequence, false);
4728 viewport.hideRepSequences(representativeSequence, hidden);
4732 SequenceI[] hseqs = hiddenSeqs
4733 .toArray(new SequenceI[hiddenSeqs.size()]);
4734 viewport.hideSequence(hseqs);
4737 // recover view properties and display parameters
4739 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4740 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4741 final int pidThreshold = safeInt(view.getPidThreshold());
4742 viewport.setThreshold(pidThreshold);
4744 viewport.setColourText(safeBoolean(view.isShowColourText()));
4747 .setConservationSelected(
4748 safeBoolean(view.isConservationSelected()));
4749 viewport.setIncrement(safeInt(view.getConsThreshold()));
4750 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4751 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4752 viewport.setFont(new Font(view.getFontName(),
4753 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4755 ViewStyleI vs = viewport.getViewStyle();
4756 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4757 viewport.setViewStyle(vs);
4758 // TODO: allow custom charWidth/Heights to be restored by updating them
4759 // after setting font - which means set above to false
4760 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4761 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4762 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4764 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4766 viewport.setShowText(safeBoolean(view.isShowText()));
4768 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4769 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4770 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4771 viewport.setShowUnconserved(view.isShowUnconserved());
4772 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4774 if (view.getViewName() != null)
4776 viewport.setViewName(view.getViewName());
4777 af.setInitialTabVisible();
4779 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4780 safeInt(view.getWidth()), safeInt(view.getHeight()));
4781 // startSeq set in af.alignPanel.updateLayout below
4782 af.alignPanel.updateLayout();
4783 ColourSchemeI cs = null;
4784 // apply colourschemes
4785 if (view.getBgColour() != null)
4787 if (view.getBgColour().startsWith("ucs"))
4789 cs = getUserColourScheme(jm, view.getBgColour());
4791 else if (view.getBgColour().startsWith("Annotation"))
4793 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4794 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4801 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4802 view.getBgColour());
4807 * turn off 'alignment colour applies to all groups'
4808 * while restoring global colour scheme
4810 viewport.setColourAppliesToAllGroups(false);
4811 viewport.setGlobalColourScheme(cs);
4812 viewport.getResidueShading().setThreshold(pidThreshold,
4813 view.isIgnoreGapsinConsensus());
4814 viewport.getResidueShading()
4815 .setConsensus(viewport.getSequenceConsensusHash());
4816 if (safeBoolean(view.isConservationSelected()) && cs != null)
4818 viewport.getResidueShading()
4819 .setConservationInc(safeInt(view.getConsThreshold()));
4821 af.changeColour(cs);
4822 viewport.setColourAppliesToAllGroups(true);
4825 .setShowSequenceFeatures(
4826 safeBoolean(view.isShowSequenceFeatures()));
4828 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4829 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4830 viewport.setFollowHighlight(view.isFollowHighlight());
4831 viewport.followSelection = view.isFollowSelection();
4832 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4833 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4834 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4835 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4836 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4837 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4838 viewport.setShowGroupConservation(view.isShowGroupConservation());
4839 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4840 viewport.setShowComplementFeaturesOnTop(
4841 view.isShowComplementFeaturesOnTop());
4843 // recover feature settings
4844 if (jm.getFeatureSettings() != null)
4846 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4847 .getFeatureRenderer();
4848 FeaturesDisplayed fdi;
4849 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4850 String[] renderOrder = new String[jm.getFeatureSettings()
4851 .getSetting().size()];
4852 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4853 Map<String, Float> featureOrder = new Hashtable<>();
4855 for (int fs = 0; fs < jm.getFeatureSettings()
4856 .getSetting().size(); fs++)
4858 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4859 String featureType = setting.getType();
4862 * restore feature filters (if any)
4864 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4866 if (filters != null)
4868 FeatureMatcherSetI filter = Jalview2XML
4869 .parseFilter(featureType, filters);
4870 if (!filter.isEmpty())
4872 fr.setFeatureFilter(featureType, filter);
4877 * restore feature colour scheme
4879 Color maxColour = new Color(setting.getColour());
4880 if (setting.getMincolour() != null)
4883 * minColour is always set unless a simple colour
4884 * (including for colour by label though it doesn't use it)
4886 Color minColour = new Color(setting.getMincolour().intValue());
4887 Color noValueColour = minColour;
4888 NoValueColour noColour = setting.getNoValueColour();
4889 if (noColour == NoValueColour.NONE)
4891 noValueColour = null;
4893 else if (noColour == NoValueColour.MAX)
4895 noValueColour = maxColour;
4897 float min = safeFloat(safeFloat(setting.getMin()));
4898 float max = setting.getMax() == null ? 1f
4899 : setting.getMax().floatValue();
4900 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4902 noValueColour, min, max);
4903 if (setting.getAttributeName().size() > 0)
4905 gc.setAttributeName(setting.getAttributeName().toArray(
4906 new String[setting.getAttributeName().size()]));
4908 if (setting.getThreshold() != null)
4910 gc.setThreshold(setting.getThreshold().floatValue());
4911 int threshstate = safeInt(setting.getThreshstate());
4912 // -1 = None, 0 = Below, 1 = Above threshold
4913 if (threshstate == 0)
4915 gc.setBelowThreshold(true);
4917 else if (threshstate == 1)
4919 gc.setAboveThreshold(true);
4922 gc.setAutoScaled(true); // default
4923 if (setting.isAutoScale() != null)
4925 gc.setAutoScaled(setting.isAutoScale());
4927 if (setting.isColourByLabel() != null)
4929 gc.setColourByLabel(setting.isColourByLabel());
4931 // and put in the feature colour table.
4932 featureColours.put(featureType, gc);
4936 featureColours.put(featureType,
4937 new FeatureColour(maxColour));
4939 renderOrder[fs] = featureType;
4940 if (setting.getOrder() != null)
4942 featureOrder.put(featureType, setting.getOrder().floatValue());
4946 featureOrder.put(featureType, Float.valueOf(
4947 fs / jm.getFeatureSettings().getSetting().size()));
4949 if (safeBoolean(setting.isDisplay()))
4951 fdi.setVisible(featureType);
4954 Map<String, Boolean> fgtable = new Hashtable<>();
4955 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4957 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4958 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4960 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4961 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4962 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4963 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4964 fgtable, featureColours, 1.0f, featureOrder);
4965 fr.transferSettings(frs);
4968 if (view.getHiddenColumns().size() > 0)
4970 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4972 final HiddenColumns hc = view.getHiddenColumns().get(c);
4973 viewport.hideColumns(safeInt(hc.getStart()),
4974 safeInt(hc.getEnd()) /* +1 */);
4977 if (view.getCalcIdParam() != null)
4979 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4981 if (calcIdParam != null)
4983 if (recoverCalcIdParam(calcIdParam, viewport))
4988 warn("Couldn't recover parameters for "
4989 + calcIdParam.getCalcId());
4994 af.setMenusFromViewport(viewport);
4995 af.setTitle(view.getTitle());
4996 // TODO: we don't need to do this if the viewport is aready visible.
4998 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4999 * has a 'cdna/protein complement' view, in which case save it in order to
5000 * populate a SplitFrame once all views have been read in.
5002 String complementaryViewId = view.getComplementId();
5003 if (complementaryViewId == null)
5005 Desktop.addInternalFrame(af, view.getTitle(),
5006 safeInt(view.getWidth()), safeInt(view.getHeight()));
5007 // recompute any autoannotation
5008 af.alignPanel.updateAnnotation(false, true);
5009 reorderAutoannotation(af, al, autoAlan);
5010 af.alignPanel.alignmentChanged();
5014 splitFrameCandidates.put(view, af);
5021 * Reads saved data to restore Colour by Annotation settings
5023 * @param viewAnnColour
5027 * @param checkGroupAnnColour
5030 private ColourSchemeI constructAnnotationColour(
5031 AnnotationColourScheme viewAnnColour, AlignFrame af,
5032 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5034 boolean propagateAnnColour = false;
5035 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5037 if (checkGroupAnnColour && al.getGroups() != null
5038 && al.getGroups().size() > 0)
5040 // pre 2.8.1 behaviour
5041 // check to see if we should transfer annotation colours
5042 propagateAnnColour = true;
5043 for (SequenceGroup sg : al.getGroups())
5045 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5047 propagateAnnColour = false;
5053 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5055 String annotationId = viewAnnColour.getAnnotation();
5056 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5059 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5061 if (matchedAnnotation == null
5062 && annAlignment.getAlignmentAnnotation() != null)
5064 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5067 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5069 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5074 if (matchedAnnotation == null)
5076 System.err.println("Failed to match annotation colour scheme for "
5080 if (matchedAnnotation.getThreshold() == null)
5082 matchedAnnotation.setThreshold(
5083 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5084 "Threshold", Color.black));
5087 AnnotationColourGradient cs = null;
5088 if (viewAnnColour.getColourScheme().equals("None"))
5090 cs = new AnnotationColourGradient(matchedAnnotation,
5091 new Color(safeInt(viewAnnColour.getMinColour())),
5092 new Color(safeInt(viewAnnColour.getMaxColour())),
5093 safeInt(viewAnnColour.getAboveThreshold()));
5095 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5097 cs = new AnnotationColourGradient(matchedAnnotation,
5098 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5099 safeInt(viewAnnColour.getAboveThreshold()));
5103 cs = new AnnotationColourGradient(matchedAnnotation,
5104 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5105 viewAnnColour.getColourScheme()),
5106 safeInt(viewAnnColour.getAboveThreshold()));
5109 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5110 boolean useOriginalColours = safeBoolean(
5111 viewAnnColour.isPredefinedColours());
5112 cs.setSeqAssociated(perSequenceOnly);
5113 cs.setPredefinedColours(useOriginalColours);
5115 if (propagateAnnColour && al.getGroups() != null)
5117 // Also use these settings for all the groups
5118 for (int g = 0; g < al.getGroups().size(); g++)
5120 SequenceGroup sg = al.getGroups().get(g);
5121 if (sg.getGroupColourScheme() == null)
5126 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5127 matchedAnnotation, sg.getColourScheme(),
5128 safeInt(viewAnnColour.getAboveThreshold()));
5129 sg.setColourScheme(groupScheme);
5130 groupScheme.setSeqAssociated(perSequenceOnly);
5131 groupScheme.setPredefinedColours(useOriginalColours);
5137 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5138 List<JvAnnotRow> autoAlan)
5140 // copy over visualization settings for autocalculated annotation in the
5142 if (al.getAlignmentAnnotation() != null)
5145 * Kludge for magic autoannotation names (see JAL-811)
5147 String[] magicNames = new String[] { "Consensus", "Quality",
5149 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5150 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5151 for (String nm : magicNames)
5153 visan.put(nm, nullAnnot);
5155 for (JvAnnotRow auan : autoAlan)
5157 visan.put(auan.template.label
5158 + (auan.template.getCalcId() == null ? ""
5159 : "\t" + auan.template.getCalcId()),
5162 int hSize = al.getAlignmentAnnotation().length;
5163 List<JvAnnotRow> reorder = new ArrayList<>();
5164 // work through any autoCalculated annotation already on the view
5165 // removing it if it should be placed in a different location on the
5166 // annotation panel.
5167 List<String> remains = new ArrayList<>(visan.keySet());
5168 for (int h = 0; h < hSize; h++)
5170 jalview.datamodel.AlignmentAnnotation jalan = al
5171 .getAlignmentAnnotation()[h];
5172 if (jalan.autoCalculated)
5175 JvAnnotRow valan = visan.get(k = jalan.label);
5176 if (jalan.getCalcId() != null)
5178 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5183 // delete the auto calculated row from the alignment
5184 al.deleteAnnotation(jalan, false);
5188 if (valan != nullAnnot)
5190 if (jalan != valan.template)
5192 // newly created autoannotation row instance
5193 // so keep a reference to the visible annotation row
5194 // and copy over all relevant attributes
5195 if (valan.template.graphHeight >= 0)
5198 jalan.graphHeight = valan.template.graphHeight;
5200 jalan.visible = valan.template.visible;
5202 reorder.add(new JvAnnotRow(valan.order, jalan));
5207 // Add any (possibly stale) autocalculated rows that were not appended to
5208 // the view during construction
5209 for (String other : remains)
5211 JvAnnotRow othera = visan.get(other);
5212 if (othera != nullAnnot && othera.template.getCalcId() != null
5213 && othera.template.getCalcId().length() > 0)
5215 reorder.add(othera);
5218 // now put the automatic annotation in its correct place
5219 int s = 0, srt[] = new int[reorder.size()];
5220 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5221 for (JvAnnotRow jvar : reorder)
5224 srt[s++] = jvar.order;
5227 jalview.util.QuickSort.sort(srt, rws);
5228 // and re-insert the annotation at its correct position
5229 for (JvAnnotRow jvar : rws)
5231 al.addAnnotation(jvar.template, jvar.order);
5233 af.alignPanel.adjustAnnotationHeight();
5237 Hashtable skipList = null;
5240 * TODO remove this method
5243 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5244 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5245 * throw new Error("Implementation Error. No skipList defined for this
5246 * Jalview2XML instance."); } return (AlignFrame)
5247 * skipList.get(view.getSequenceSetId()); }
5251 * Check if the Jalview view contained in object should be skipped or not.
5254 * @return true if view's sequenceSetId is a key in skipList
5256 private boolean skipViewport(JalviewModel object)
5258 if (skipList == null)
5262 String id = object.getViewport().get(0).getSequenceSetId();
5263 if (skipList.containsKey(id))
5265 if (Cache.log != null && Cache.log.isDebugEnabled())
5267 Cache.log.debug("Skipping seuqence set id " + id);
5274 public void addToSkipList(AlignFrame af)
5276 if (skipList == null)
5278 skipList = new Hashtable();
5280 skipList.put(af.getViewport().getSequenceSetId(), af);
5283 public void clearSkipList()
5285 if (skipList != null)
5292 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5293 boolean ignoreUnrefed, String uniqueSeqSetId)
5295 jalview.datamodel.AlignmentI ds = getDatasetFor(
5296 vamsasSet.getDatasetId());
5297 AlignmentI xtant_ds = ds;
5298 if (xtant_ds == null)
5300 // good chance we are about to create a new dataset, but check if we've
5301 // seen some of the dataset sequence IDs before.
5302 // TODO: skip this check if we are working with project generated by
5303 // version 2.11 or later
5304 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5305 if (xtant_ds != null)
5308 addDatasetRef(vamsasSet.getDatasetId(), ds);
5311 Vector<SequenceI> dseqs = null;
5314 // recovering an alignment View
5315 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5316 if (seqSetDS != null)
5318 if (ds != null && ds != seqSetDS)
5320 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5321 + " - CDS/Protein crossreference data may be lost");
5322 if (xtant_ds != null)
5324 // This can only happen if the unique sequence set ID was bound to a
5325 // dataset that did not contain any of the sequences in the view
5326 // currently being restored.
5327 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.");
5331 addDatasetRef(vamsasSet.getDatasetId(), ds);
5336 // try even harder to restore dataset
5337 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5338 // create a list of new dataset sequences
5339 dseqs = new Vector<>();
5341 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5343 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5344 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5346 // create a new dataset
5349 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5350 dseqs.copyInto(dsseqs);
5351 ds = new jalview.datamodel.Alignment(dsseqs);
5352 debug("Created new dataset " + vamsasSet.getDatasetId()
5353 + " for alignment " + System.identityHashCode(al));
5354 addDatasetRef(vamsasSet.getDatasetId(), ds);
5356 // set the dataset for the newly imported alignment.
5357 if (al.getDataset() == null && !ignoreUnrefed)
5360 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5361 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5363 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5367 * XML dataset sequence ID to materialised dataset reference
5369 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5372 * @return the first materialised dataset reference containing a dataset
5373 * sequence referenced in the given view
5375 * - sequences from the view
5377 AlignmentI checkIfHasDataset(List<Sequence> list)
5379 for (Sequence restoredSeq : list)
5381 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5382 if (datasetFor != null)
5391 * Register ds as the containing dataset for the dataset sequences referenced
5392 * by sequences in list
5395 * - sequences in a view
5398 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5400 for (Sequence restoredSeq : list)
5402 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5403 if (prevDS != null && prevDS != ds)
5405 warn("Dataset sequence appears in many datasets: "
5406 + restoredSeq.getDsseqid());
5407 // TODO: try to merge!
5414 * sequence definition to create/merge dataset sequence for
5418 * vector to add new dataset sequence to
5419 * @param ignoreUnrefed
5420 * - when true, don't create new sequences from vamsasSeq if it's id
5421 * doesn't already have an asssociated Jalview sequence.
5423 * - used to reorder the sequence in the alignment according to the
5424 * vamsasSeq array ordering, to preserve ordering of dataset
5426 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5427 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5430 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5432 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5433 boolean reorder = false;
5434 SequenceI dsq = null;
5435 if (sq != null && sq.getDatasetSequence() != null)
5437 dsq = sq.getDatasetSequence();
5443 if (sq == null && ignoreUnrefed)
5447 String sqid = vamsasSeq.getDsseqid();
5450 // need to create or add a new dataset sequence reference to this sequence
5453 dsq = seqRefIds.get(sqid);
5458 // make a new dataset sequence
5459 dsq = sq.createDatasetSequence();
5462 // make up a new dataset reference for this sequence
5463 sqid = seqHash(dsq);
5465 dsq.setVamsasId(uniqueSetSuffix + sqid);
5466 seqRefIds.put(sqid, dsq);
5471 dseqs.addElement(dsq);
5476 ds.addSequence(dsq);
5482 { // make this dataset sequence sq's dataset sequence
5483 sq.setDatasetSequence(dsq);
5484 // and update the current dataset alignment
5489 if (!dseqs.contains(dsq))
5496 if (ds.findIndex(dsq) < 0)
5498 ds.addSequence(dsq);
5505 // TODO: refactor this as a merge dataset sequence function
5506 // now check that sq (the dataset sequence) sequence really is the union of
5507 // all references to it
5508 // boolean pre = sq.getStart() < dsq.getStart();
5509 // boolean post = sq.getEnd() > dsq.getEnd();
5513 // StringBuffer sb = new StringBuffer();
5514 String newres = jalview.analysis.AlignSeq.extractGaps(
5515 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5516 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5517 && newres.length() > dsq.getLength())
5519 // Update with the longer sequence.
5523 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5524 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5525 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5526 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5528 dsq.setSequence(newres);
5530 // TODO: merges will never happen if we 'know' we have the real dataset
5531 // sequence - this should be detected when id==dssid
5533 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5534 // + (pre ? "prepended" : "") + " "
5535 // + (post ? "appended" : ""));
5540 // sequence refs are identical. We may need to update the existing dataset
5541 // alignment with this one, though.
5542 if (ds != null && dseqs == null)
5544 int opos = ds.findIndex(dsq);
5545 SequenceI tseq = null;
5546 if (opos != -1 && vseqpos != opos)
5548 // remove from old position
5549 ds.deleteSequence(dsq);
5551 if (vseqpos < ds.getHeight())
5553 if (vseqpos != opos)
5555 // save sequence at destination position
5556 tseq = ds.getSequenceAt(vseqpos);
5557 ds.replaceSequenceAt(vseqpos, dsq);
5558 ds.addSequence(tseq);
5563 ds.addSequence(dsq);
5570 * TODO use AlignmentI here and in related methods - needs
5571 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5573 Hashtable<String, AlignmentI> datasetIds = null;
5575 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5577 private AlignmentI getDatasetFor(String datasetId)
5579 if (datasetIds == null)
5581 datasetIds = new Hashtable<>();
5584 if (datasetIds.containsKey(datasetId))
5586 return datasetIds.get(datasetId);
5591 private void addDatasetRef(String datasetId, AlignmentI dataset)
5593 if (datasetIds == null)
5595 datasetIds = new Hashtable<>();
5597 datasetIds.put(datasetId, dataset);
5601 * make a new dataset ID for this jalview dataset alignment
5606 private String getDatasetIdRef(AlignmentI dataset)
5608 if (dataset.getDataset() != null)
5610 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5612 String datasetId = makeHashCode(dataset, null);
5613 if (datasetId == null)
5615 // make a new datasetId and record it
5616 if (dataset2Ids == null)
5618 dataset2Ids = new IdentityHashMap<>();
5622 datasetId = dataset2Ids.get(dataset);
5624 if (datasetId == null)
5626 datasetId = "ds" + dataset2Ids.size() + 1;
5627 dataset2Ids.put(dataset, datasetId);
5634 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5635 * constructed as a special subclass GeneLocus.
5637 * @param datasetSequence
5640 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5642 for (int d = 0; d < sequence.getDBRef().size(); d++)
5644 DBRef dr = sequence.getDBRef().get(d);
5648 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5649 dr.getAccessionId());
5653 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5654 dr.getAccessionId());
5656 if (dr.getMapping() != null)
5658 entry.setMap(addMapping(dr.getMapping()));
5660 datasetSequence.addDBRef(entry);
5664 private jalview.datamodel.Mapping addMapping(Mapping m)
5666 SequenceI dsto = null;
5667 // Mapping m = dr.getMapping();
5668 int fr[] = new int[m.getMapListFrom().size() * 2];
5669 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5670 for (int _i = 0; from.hasNext(); _i += 2)
5672 MapListFrom mf = from.next();
5673 fr[_i] = mf.getStart();
5674 fr[_i + 1] = mf.getEnd();
5676 int fto[] = new int[m.getMapListTo().size() * 2];
5677 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5678 for (int _i = 0; to.hasNext(); _i += 2)
5680 MapListTo mf = to.next();
5681 fto[_i] = mf.getStart();
5682 fto[_i + 1] = mf.getEnd();
5684 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5685 fto, m.getMapFromUnit().intValue(),
5686 m.getMapToUnit().intValue());
5689 * (optional) choice of dseqFor or Sequence
5691 if (m.getDseqFor() != null)
5693 String dsfor = m.getDseqFor();
5694 if (seqRefIds.containsKey(dsfor))
5699 jmap.setTo(seqRefIds.get(dsfor));
5703 frefedSequence.add(newMappingRef(dsfor, jmap));
5706 else if (m.getSequence() != null)
5709 * local sequence definition
5711 Sequence ms = m.getSequence();
5712 SequenceI djs = null;
5713 String sqid = ms.getDsseqid();
5714 if (sqid != null && sqid.length() > 0)
5717 * recover dataset sequence
5719 djs = seqRefIds.get(sqid);
5724 "Warning - making up dataset sequence id for DbRef sequence map reference");
5725 sqid = ((Object) ms).toString(); // make up a new hascode for
5726 // undefined dataset sequence hash
5727 // (unlikely to happen)
5733 * make a new dataset sequence and add it to refIds hash
5735 djs = new jalview.datamodel.Sequence(ms.getName(),
5737 djs.setStart(jmap.getMap().getToLowest());
5738 djs.setEnd(jmap.getMap().getToHighest());
5739 djs.setVamsasId(uniqueSetSuffix + sqid);
5741 incompleteSeqs.put(sqid, djs);
5742 seqRefIds.put(sqid, djs);
5745 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5754 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5755 * view as XML (but not to file), and then reloading it
5760 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5763 JalviewModel jm = saveState(ap, null, null, null);
5766 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5767 ap.getAlignment().getDataset());
5769 uniqueSetSuffix = "";
5770 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5771 jm.getViewport().get(0).setId(null);
5772 // we don't overwrite the view we just copied
5774 if (this.frefedSequence == null)
5776 frefedSequence = new Vector<>();
5779 viewportsAdded.clear();
5781 AlignFrame af = loadFromObject(jm, null, false, null);
5782 af.getAlignPanels().clear();
5783 af.closeMenuItem_actionPerformed(true);
5786 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5787 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5788 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5789 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5790 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5793 return af.alignPanel;
5796 private Hashtable jvids2vobj;
5798 private void warn(String msg)
5803 private void warn(String msg, Exception e)
5805 if (Cache.log != null)
5809 Cache.log.warn(msg, e);
5813 Cache.log.warn(msg);
5818 System.err.println("Warning: " + msg);
5821 e.printStackTrace();
5826 private void debug(String string)
5828 debug(string, null);
5831 private void debug(String msg, Exception e)
5833 if (Cache.log != null)
5837 Cache.log.debug(msg, e);
5841 Cache.log.debug(msg);
5846 System.err.println("Warning: " + msg);
5849 e.printStackTrace();
5855 * set the object to ID mapping tables used to write/recover objects and XML
5856 * ID strings for the jalview project. If external tables are provided then
5857 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5858 * object goes out of scope. - also populates the datasetIds hashtable with
5859 * alignment objects containing dataset sequences
5862 * Map from ID strings to jalview datamodel
5864 * Map from jalview datamodel to ID strings
5868 public void setObjectMappingTables(Hashtable vobj2jv,
5869 IdentityHashMap jv2vobj)
5871 this.jv2vobj = jv2vobj;
5872 this.vobj2jv = vobj2jv;
5873 Iterator ds = jv2vobj.keySet().iterator();
5875 while (ds.hasNext())
5877 Object jvobj = ds.next();
5878 id = jv2vobj.get(jvobj).toString();
5879 if (jvobj instanceof jalview.datamodel.Alignment)
5881 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5883 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5886 else if (jvobj instanceof jalview.datamodel.Sequence)
5888 // register sequence object so the XML parser can recover it.
5889 if (seqRefIds == null)
5891 seqRefIds = new HashMap<>();
5893 if (seqsToIds == null)
5895 seqsToIds = new IdentityHashMap<>();
5897 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5898 seqsToIds.put((SequenceI) jvobj, id);
5900 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5903 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5904 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5905 if (jvann.annotationId == null)
5907 jvann.annotationId = anid;
5909 if (!jvann.annotationId.equals(anid))
5911 // TODO verify that this is the correct behaviour
5912 this.warn("Overriding Annotation ID for " + anid
5913 + " from different id : " + jvann.annotationId);
5914 jvann.annotationId = anid;
5917 else if (jvobj instanceof String)
5919 if (jvids2vobj == null)
5921 jvids2vobj = new Hashtable();
5922 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5927 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5933 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5934 * objects created from the project archive. If string is null (default for
5935 * construction) then suffix will be set automatically.
5939 public void setUniqueSetSuffix(String string)
5941 uniqueSetSuffix = string;
5946 * uses skipList2 as the skipList for skipping views on sequence sets
5947 * associated with keys in the skipList
5951 public void setSkipList(Hashtable skipList2)
5953 skipList = skipList2;
5957 * Reads the jar entry of given name and returns its contents, or null if the
5958 * entry is not found.
5961 * @param jarEntryName
5964 protected String readJarEntry(jarInputStreamProvider jprovider,
5965 String jarEntryName)
5967 String result = null;
5968 BufferedReader in = null;
5973 * Reopen the jar input stream and traverse its entries to find a matching
5976 JarInputStream jin = jprovider.getJarInputStream();
5977 JarEntry entry = null;
5980 entry = jin.getNextJarEntry();
5981 } while (entry != null && !entry.getName().equals(jarEntryName));
5985 StringBuilder out = new StringBuilder(256);
5986 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5989 while ((data = in.readLine()) != null)
5993 result = out.toString();
5997 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5999 } catch (Exception ex)
6001 ex.printStackTrace();
6009 } catch (IOException e)
6020 * Returns an incrementing counter (0, 1, 2...)
6024 private synchronized int nextCounter()
6030 * Loads any saved PCA viewers
6035 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6039 List<PcaViewer> pcaviewers = model.getPcaViewer();
6040 for (PcaViewer viewer : pcaviewers)
6042 String modelName = viewer.getScoreModelName();
6043 SimilarityParamsI params = new SimilarityParams(
6044 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6045 viewer.isIncludeGaps(),
6046 viewer.isDenominateByShortestLength());
6049 * create the panel (without computing the PCA)
6051 PCAPanel panel = new PCAPanel(ap, modelName, params);
6053 panel.setTitle(viewer.getTitle());
6054 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6055 viewer.getWidth(), viewer.getHeight()));
6057 boolean showLabels = viewer.isShowLabels();
6058 panel.setShowLabels(showLabels);
6059 panel.getRotatableCanvas().setShowLabels(showLabels);
6060 panel.getRotatableCanvas()
6061 .setBgColour(new Color(viewer.getBgColour()));
6062 panel.getRotatableCanvas()
6063 .setApplyToAllViews(viewer.isLinkToAllViews());
6066 * load PCA output data
6068 ScoreModelI scoreModel = ScoreModels.getInstance()
6069 .getScoreModel(modelName, ap);
6070 PCA pca = new PCA(null, scoreModel, params);
6071 PcaDataType pcaData = viewer.getPcaData();
6073 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6074 pca.setPairwiseScores(pairwise);
6076 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6077 pca.setTridiagonal(triDiag);
6079 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6080 pca.setEigenmatrix(result);
6082 panel.getPcaModel().setPCA(pca);
6085 * we haven't saved the input data! (JAL-2647 to do)
6087 panel.setInputData(null);
6090 * add the sequence points for the PCA display
6092 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6093 for (SequencePoint sp : viewer.getSequencePoint())
6095 String seqId = sp.getSequenceRef();
6096 SequenceI seq = seqRefIds.get(seqId);
6099 throw new IllegalStateException(
6100 "Unmatched seqref for PCA: " + seqId);
6102 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6103 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6105 seqPoints.add(seqPoint);
6107 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6110 * set min-max ranges and scale after setPoints (which recomputes them)
6112 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6113 SeqPointMin spMin = viewer.getSeqPointMin();
6114 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6116 SeqPointMax spMax = viewer.getSeqPointMax();
6117 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6119 panel.getRotatableCanvas().setSeqMinMax(min, max);
6121 // todo: hold points list in PCAModel only
6122 panel.getPcaModel().setSequencePoints(seqPoints);
6124 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6125 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6126 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6128 // is this duplication needed?
6129 panel.setTop(seqPoints.size() - 1);
6130 panel.getPcaModel().setTop(seqPoints.size() - 1);
6133 * add the axes' end points for the display
6135 for (int i = 0; i < 3; i++)
6137 Axis axis = viewer.getAxis().get(i);
6138 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6139 axis.getXPos(), axis.getYPos(), axis.getZPos());
6142 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6143 "label.calc_title", "PCA", modelName), 475, 450);
6145 } catch (Exception ex)
6147 Cache.log.error("Error loading PCA: " + ex.toString());
6152 * Creates a new structure viewer window
6159 protected void createStructureViewer(
6160 ViewerType viewerType, final Entry<String, StructureViewerModel> viewerData,
6161 AlignFrame af, jarInputStreamProvider jprovider)
6163 final StructureViewerModel viewerModel = viewerData.getValue();
6164 String sessionFilePath = null;
6166 if (viewerType == ViewerType.JMOL)
6168 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6172 String viewerJarEntryName = getViewerJarEntryName(
6173 viewerModel.getViewId());
6174 sessionFilePath = copyJarEntry(jprovider,
6176 "viewerSession", ".tmp");
6178 final String sessionPath = sessionFilePath;
6179 final String sviewid = viewerData.getKey();
6182 SwingUtilities.invokeAndWait(new Runnable()
6187 JalviewStructureDisplayI sview = null;
6190 sview = StructureViewer.createView(viewerType, af.alignPanel,
6191 viewerModel, sessionPath, sviewid);
6192 addNewStructureViewer(sview);
6193 } catch (OutOfMemoryError ex)
6195 new OOMWarning("Restoring structure view for "
6197 (OutOfMemoryError) ex.getCause());
6198 if (sview != null && sview.isVisible())
6200 sview.closeViewer(false);
6201 sview.setVisible(false);
6207 } catch (InvocationTargetException | InterruptedException ex)
6209 warn("Unexpected error when opening " + viewerType
6210 + " structure viewer", ex);
6215 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6216 * the path of the file. "load file" commands are rewritten to change the
6217 * original PDB file names to those created as the Jalview project is loaded.
6223 private String rewriteJmolSession(StructureViewerModel svattrib,
6224 jarInputStreamProvider jprovider)
6226 String state = svattrib.getStateData(); // Jalview < 2.9
6227 if (state == null || state.isEmpty()) // Jalview >= 2.9
6229 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6230 state = readJarEntry(jprovider, jarEntryName);
6232 // TODO or simpler? for each key in oldFiles,
6233 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6234 // (allowing for different path escapings)
6235 StringBuilder rewritten = new StringBuilder(state.length());
6236 int cp = 0, ncp, ecp;
6237 Map<File, StructureData> oldFiles = svattrib.getFileData();
6238 while ((ncp = state.indexOf("load ", cp)) > -1)
6242 // look for next filename in load statement
6243 rewritten.append(state.substring(cp,
6244 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6245 String oldfilenam = state.substring(ncp,
6246 ecp = state.indexOf("\"", ncp));
6247 // recover the new mapping data for this old filename
6248 // have to normalize filename - since Jmol and jalview do
6249 // filename translation differently.
6250 StructureData filedat = oldFiles.get(new File(oldfilenam));
6251 if (filedat == null)
6253 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6254 filedat = oldFiles.get(new File(reformatedOldFilename));
6257 .append(Platform.escapeBackslashes(filedat.getFilePath()));
6258 rewritten.append("\"");
6259 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6260 // look for next file statement.
6261 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6265 // just append rest of state
6266 rewritten.append(state.substring(cp));
6270 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6271 rewritten = new StringBuilder(state);
6272 rewritten.append("; load append ");
6273 for (File id : oldFiles.keySet())
6275 // add pdb files that should be present in the viewer
6276 StructureData filedat = oldFiles.get(id);
6277 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6279 rewritten.append(";");
6282 if (rewritten.length() == 0)
6286 final String history = "history = ";
6287 int historyIndex = rewritten.indexOf(history);
6288 if (historyIndex > -1)
6291 * change "history = [true|false];" to "history = [1|0];"
6293 historyIndex += history.length();
6294 String val = rewritten.substring(historyIndex, historyIndex + 5);
6295 if (val.startsWith("true"))
6297 rewritten.replace(historyIndex, historyIndex + 4, "1");
6299 else if (val.startsWith("false"))
6301 rewritten.replace(historyIndex, historyIndex + 5, "0");
6307 File tmp = File.createTempFile("viewerSession", ".tmp");
6308 try (OutputStream os = new FileOutputStream(tmp))
6310 InputStream is = new ByteArrayInputStream(
6311 rewritten.toString().getBytes());
6313 return tmp.getAbsolutePath();
6315 } catch (IOException e)
6317 Cache.log.error("Error restoring Jmol session: " + e.toString());
6323 * Populates an XML model of the feature colour scheme for one feature type
6325 * @param featureType
6329 public static Colour marshalColour(
6330 String featureType, FeatureColourI fcol)
6332 Colour col = new Colour();
6333 if (fcol.isSimpleColour())
6335 col.setRGB(Format.getHexString(fcol.getColour()));
6339 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6340 col.setMin(fcol.getMin());
6341 col.setMax(fcol.getMax());
6342 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6343 col.setAutoScale(fcol.isAutoScaled());
6344 col.setThreshold(fcol.getThreshold());
6345 col.setColourByLabel(fcol.isColourByLabel());
6346 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6347 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6348 : ThresholdType.NONE));
6349 if (fcol.isColourByAttribute())
6351 final String[] attName = fcol.getAttributeName();
6352 col.getAttributeName().add(attName[0]);
6353 if (attName.length > 1)
6355 col.getAttributeName().add(attName[1]);
6358 Color noColour = fcol.getNoColour();
6359 if (noColour == null)
6361 col.setNoValueColour(NoValueColour.NONE);
6363 else if (noColour == fcol.getMaxColour())
6365 col.setNoValueColour(NoValueColour.MAX);
6369 col.setNoValueColour(NoValueColour.MIN);
6372 col.setName(featureType);
6377 * Populates an XML model of the feature filter(s) for one feature type
6379 * @param firstMatcher
6380 * the first (or only) match condition)
6382 * remaining match conditions (if any)
6384 * if true, conditions are and-ed, else or-ed
6386 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6387 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6390 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6392 if (filters.hasNext())
6397 CompoundMatcher compound = new CompoundMatcher();
6398 compound.setAnd(and);
6399 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6400 firstMatcher, Collections.emptyIterator(), and);
6401 // compound.addMatcherSet(matcher1);
6402 compound.getMatcherSet().add(matcher1);
6403 FeatureMatcherI nextMatcher = filters.next();
6404 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6405 nextMatcher, filters, and);
6406 // compound.addMatcherSet(matcher2);
6407 compound.getMatcherSet().add(matcher2);
6408 result.setCompoundMatcher(compound);
6413 * single condition matcher
6415 // MatchCondition matcherModel = new MatchCondition();
6416 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6417 matcherModel.setCondition(
6418 firstMatcher.getMatcher().getCondition().getStableName());
6419 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6420 if (firstMatcher.isByAttribute())
6422 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6423 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6424 String[] attName = firstMatcher.getAttribute();
6425 matcherModel.getAttributeName().add(attName[0]); // attribute
6426 if (attName.length > 1)
6428 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6431 else if (firstMatcher.isByLabel())
6433 matcherModel.setBy(FilterBy.BY_LABEL);
6435 else if (firstMatcher.isByScore())
6437 matcherModel.setBy(FilterBy.BY_SCORE);
6439 result.setMatchCondition(matcherModel);
6446 * Loads one XML model of a feature filter to a Jalview object
6448 * @param featureType
6449 * @param matcherSetModel
6452 public static FeatureMatcherSetI parseFilter(
6454 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6456 FeatureMatcherSetI result = new FeatureMatcherSet();
6459 parseFilterConditions(result, matcherSetModel, true);
6460 } catch (IllegalStateException e)
6462 // mixing AND and OR conditions perhaps
6464 String.format("Error reading filter conditions for '%s': %s",
6465 featureType, e.getMessage()));
6466 // return as much as was parsed up to the error
6473 * Adds feature match conditions to matcherSet as unmarshalled from XML
6474 * (possibly recursively for compound conditions)
6477 * @param matcherSetModel
6479 * if true, multiple conditions are AND-ed, else they are OR-ed
6480 * @throws IllegalStateException
6481 * if AND and OR conditions are mixed
6483 protected static void parseFilterConditions(
6484 FeatureMatcherSetI matcherSet,
6485 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6488 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6489 .getMatchCondition();
6495 FilterBy filterBy = mc.getBy();
6496 Condition cond = Condition.fromString(mc.getCondition());
6497 String pattern = mc.getValue();
6498 FeatureMatcherI matchCondition = null;
6499 if (filterBy == FilterBy.BY_LABEL)
6501 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6503 else if (filterBy == FilterBy.BY_SCORE)
6505 matchCondition = FeatureMatcher.byScore(cond, pattern);
6508 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6510 final List<String> attributeName = mc.getAttributeName();
6511 String[] attNames = attributeName
6512 .toArray(new String[attributeName.size()]);
6513 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6518 * note this throws IllegalStateException if AND-ing to a
6519 * previously OR-ed compound condition, or vice versa
6523 matcherSet.and(matchCondition);
6527 matcherSet.or(matchCondition);
6533 * compound condition
6535 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6536 .getCompoundMatcher().getMatcherSet();
6537 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6538 if (matchers.size() == 2)
6540 parseFilterConditions(matcherSet, matchers.get(0), anded);
6541 parseFilterConditions(matcherSet, matchers.get(1), anded);
6545 System.err.println("Malformed compound filter condition");
6551 * Loads one XML model of a feature colour to a Jalview object
6553 * @param colourModel
6556 public static FeatureColourI parseColour(Colour colourModel)
6558 FeatureColourI colour = null;
6560 if (colourModel.getMax() != null)
6562 Color mincol = null;
6563 Color maxcol = null;
6564 Color noValueColour = null;
6568 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6569 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6570 } catch (Exception e)
6572 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6575 NoValueColour noCol = colourModel.getNoValueColour();
6576 if (noCol == NoValueColour.MIN)
6578 noValueColour = mincol;
6580 else if (noCol == NoValueColour.MAX)
6582 noValueColour = maxcol;
6585 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6586 safeFloat(colourModel.getMin()),
6587 safeFloat(colourModel.getMax()));
6588 final List<String> attributeName = colourModel.getAttributeName();
6589 String[] attributes = attributeName
6590 .toArray(new String[attributeName.size()]);
6591 if (attributes != null && attributes.length > 0)
6593 colour.setAttributeName(attributes);
6595 if (colourModel.isAutoScale() != null)
6597 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6599 if (colourModel.isColourByLabel() != null)
6601 colour.setColourByLabel(
6602 colourModel.isColourByLabel().booleanValue());
6604 if (colourModel.getThreshold() != null)
6606 colour.setThreshold(colourModel.getThreshold().floatValue());
6608 ThresholdType ttyp = colourModel.getThreshType();
6609 if (ttyp == ThresholdType.ABOVE)
6611 colour.setAboveThreshold(true);
6613 else if (ttyp == ThresholdType.BELOW)
6615 colour.setBelowThreshold(true);
6620 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6621 colour = new FeatureColour(color);