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;
57 import java.util.Locale;
59 import java.util.Map.Entry;
61 import java.util.Vector;
62 import java.util.jar.JarEntry;
63 import java.util.jar.JarInputStream;
64 import java.util.jar.JarOutputStream;
66 import javax.swing.JInternalFrame;
67 import javax.swing.SwingUtilities;
68 import javax.xml.bind.JAXBContext;
69 import javax.xml.bind.JAXBElement;
70 import javax.xml.bind.Marshaller;
71 import javax.xml.datatype.DatatypeConfigurationException;
72 import javax.xml.datatype.DatatypeFactory;
73 import javax.xml.datatype.XMLGregorianCalendar;
74 import javax.xml.stream.XMLInputFactory;
75 import javax.xml.stream.XMLStreamReader;
77 import jalview.analysis.Conservation;
78 import jalview.analysis.PCA;
79 import jalview.analysis.scoremodels.ScoreModels;
80 import jalview.analysis.scoremodels.SimilarityParams;
81 import jalview.api.FeatureColourI;
82 import jalview.api.ViewStyleI;
83 import jalview.api.analysis.ScoreModelI;
84 import jalview.api.analysis.SimilarityParamsI;
85 import jalview.api.structures.JalviewStructureDisplayI;
86 import jalview.bin.Cache;
87 import jalview.datamodel.AlignedCodonFrame;
88 import jalview.datamodel.Alignment;
89 import jalview.datamodel.AlignmentAnnotation;
90 import jalview.datamodel.AlignmentI;
91 import jalview.datamodel.DBRefEntry;
92 import jalview.datamodel.GeneLocus;
93 import jalview.datamodel.GraphLine;
94 import jalview.datamodel.PDBEntry;
95 import jalview.datamodel.Point;
96 import jalview.datamodel.RnaViewerModel;
97 import jalview.datamodel.SequenceFeature;
98 import jalview.datamodel.SequenceGroup;
99 import jalview.datamodel.SequenceI;
100 import jalview.datamodel.StructureViewerModel;
101 import jalview.datamodel.StructureViewerModel.StructureData;
102 import jalview.datamodel.features.FeatureMatcher;
103 import jalview.datamodel.features.FeatureMatcherI;
104 import jalview.datamodel.features.FeatureMatcherSet;
105 import jalview.datamodel.features.FeatureMatcherSetI;
106 import jalview.ext.varna.RnaModel;
107 import jalview.gui.AlignFrame;
108 import jalview.gui.AlignViewport;
109 import jalview.gui.AlignmentPanel;
110 import jalview.gui.AppVarna;
111 import jalview.gui.Desktop;
112 import jalview.gui.JvOptionPane;
113 import jalview.gui.OOMWarning;
114 import jalview.gui.OverviewPanel;
115 import jalview.gui.PCAPanel;
116 import jalview.gui.PaintRefresher;
117 import jalview.gui.SplitFrame;
118 import jalview.gui.StructureViewer;
119 import jalview.gui.StructureViewer.ViewerType;
120 import jalview.gui.StructureViewerBase;
121 import jalview.gui.TreePanel;
122 import jalview.io.BackupFiles;
123 import jalview.io.DataSourceType;
124 import jalview.io.FileFormat;
125 import jalview.io.NewickFile;
126 import jalview.math.Matrix;
127 import jalview.math.MatrixI;
128 import jalview.renderer.ResidueShaderI;
129 import jalview.schemes.AnnotationColourGradient;
130 import jalview.schemes.ColourSchemeI;
131 import jalview.schemes.ColourSchemeProperty;
132 import jalview.schemes.FeatureColour;
133 import jalview.schemes.ResidueProperties;
134 import jalview.schemes.UserColourScheme;
135 import jalview.structure.StructureSelectionManager;
136 import jalview.structures.models.AAStructureBindingModel;
137 import jalview.util.Format;
138 import jalview.util.HttpUtils;
139 import jalview.util.MessageManager;
140 import jalview.util.Platform;
141 import jalview.util.StringUtils;
142 import jalview.util.jarInputStreamProvider;
143 import jalview.util.matcher.Condition;
144 import jalview.viewmodel.AlignmentViewport;
145 import jalview.viewmodel.PCAModel;
146 import jalview.viewmodel.ViewportRanges;
147 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
148 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
149 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
150 import jalview.ws.jws2.Jws2Discoverer;
151 import jalview.ws.jws2.dm.AAConSettings;
152 import jalview.ws.jws2.jabaws2.Jws2Instance;
153 import jalview.ws.params.ArgumentI;
154 import jalview.ws.params.AutoCalcSetting;
155 import jalview.ws.params.WsParamSetI;
156 import jalview.xml.binding.jalview.AlcodonFrame;
157 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
158 import jalview.xml.binding.jalview.Annotation;
159 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
160 import jalview.xml.binding.jalview.AnnotationColourScheme;
161 import jalview.xml.binding.jalview.AnnotationElement;
162 import jalview.xml.binding.jalview.DoubleMatrix;
163 import jalview.xml.binding.jalview.DoubleVector;
164 import jalview.xml.binding.jalview.Feature;
165 import jalview.xml.binding.jalview.Feature.OtherData;
166 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
167 import jalview.xml.binding.jalview.FilterBy;
168 import jalview.xml.binding.jalview.JalviewModel;
169 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
170 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
171 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
172 import jalview.xml.binding.jalview.JalviewModel.JGroup;
173 import jalview.xml.binding.jalview.JalviewModel.JSeq;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
176 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
177 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
178 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
181 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
182 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
183 import jalview.xml.binding.jalview.JalviewModel.Tree;
184 import jalview.xml.binding.jalview.JalviewModel.UserColours;
185 import jalview.xml.binding.jalview.JalviewModel.Viewport;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
187 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
188 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
189 import jalview.xml.binding.jalview.JalviewUserColours;
190 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
191 import jalview.xml.binding.jalview.MapListType.MapListFrom;
192 import jalview.xml.binding.jalview.MapListType.MapListTo;
193 import jalview.xml.binding.jalview.Mapping;
194 import jalview.xml.binding.jalview.NoValueColour;
195 import jalview.xml.binding.jalview.ObjectFactory;
196 import jalview.xml.binding.jalview.PcaDataType;
197 import jalview.xml.binding.jalview.Pdbentry.Property;
198 import jalview.xml.binding.jalview.Sequence;
199 import jalview.xml.binding.jalview.Sequence.DBRef;
200 import jalview.xml.binding.jalview.SequenceSet;
201 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
202 import jalview.xml.binding.jalview.ThresholdType;
203 import jalview.xml.binding.jalview.VAMSAS;
206 * Write out the current jalview desktop state as a Jalview XML stream.
208 * Note: the vamsas objects referred to here are primitive versions of the
209 * VAMSAS project schema elements - they are not the same and most likely never
213 * @version $Revision: 1.134 $
215 public class Jalview2XML
218 // BH 2018 we add the .jvp binary extension to J2S so that
219 // it will declare that binary when we do the file save from the browser
223 Platform.addJ2SBinaryType(".jvp?");
226 private static final String VIEWER_PREFIX = "viewer_";
228 private static final String RNA_PREFIX = "rna_";
230 private static final String UTF_8 = "UTF-8";
233 * prefix for recovering datasets for alignments with multiple views where
234 * non-existent dataset IDs were written for some views
236 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
238 // use this with nextCounter() to make unique names for entities
239 private int counter = 0;
242 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
243 * of sequence objects are created.
245 IdentityHashMap<SequenceI, String> seqsToIds = null;
248 * jalview XML Sequence ID to jalview sequence object reference (both dataset
249 * and alignment sequences. Populated as XML reps of sequence objects are
252 Map<String, SequenceI> seqRefIds = null;
254 Map<String, SequenceI> incompleteSeqs = null;
256 List<SeqFref> frefedSequence = null;
258 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
261 * Map of reconstructed AlignFrame objects that appear to have come from
262 * SplitFrame objects (have a dna/protein complement view).
264 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
267 * Map from displayed rna structure models to their saved session state jar
270 private Map<RnaModel, String> rnaSessions = new HashMap<>();
273 * A helper method for safely using the value of an optional attribute that
274 * may be null if not present in the XML. Answers the boolean value, or false
280 public static boolean safeBoolean(Boolean b)
282 return b == null ? false : b.booleanValue();
286 * A helper method for safely using the value of an optional attribute that
287 * may be null if not present in the XML. Answers the integer value, or zero
293 public static int safeInt(Integer i)
295 return i == null ? 0 : i.intValue();
299 * A helper method for safely using the value of an optional attribute that
300 * may be null if not present in the XML. Answers the float value, or zero if
306 public static float safeFloat(Float f)
308 return f == null ? 0f : f.floatValue();
312 * create/return unique hash string for sq
315 * @return new or existing unique string for sq
317 String seqHash(SequenceI sq)
319 if (seqsToIds == null)
323 if (seqsToIds.containsKey(sq))
325 return seqsToIds.get(sq);
329 // create sequential key
330 String key = "sq" + (seqsToIds.size() + 1);
331 key = makeHashCode(sq, key); // check we don't have an external reference
333 seqsToIds.put(sq, key);
340 if (seqsToIds == null)
342 seqsToIds = new IdentityHashMap<>();
344 if (seqRefIds == null)
346 seqRefIds = new HashMap<>();
348 if (incompleteSeqs == null)
350 incompleteSeqs = new HashMap<>();
352 if (frefedSequence == null)
354 frefedSequence = new ArrayList<>();
362 public Jalview2XML(boolean raiseGUI)
364 this.raiseGUI = raiseGUI;
368 * base class for resolving forward references to sequences by their ID
373 abstract class SeqFref
379 public SeqFref(String _sref, String type)
385 public String getSref()
390 public SequenceI getSrefSeq()
392 return seqRefIds.get(sref);
395 public boolean isResolvable()
397 return seqRefIds.get(sref) != null;
400 public SequenceI getSrefDatasetSeq()
402 SequenceI sq = seqRefIds.get(sref);
405 while (sq.getDatasetSequence() != null)
407 sq = sq.getDatasetSequence();
414 * @return true if the forward reference was fully resolved
416 abstract boolean resolve();
419 public String toString()
421 return type + " reference to " + sref;
426 * create forward reference for a mapping
432 public SeqFref newMappingRef(final String sref,
433 final jalview.datamodel.Mapping _jmap)
435 SeqFref fref = new SeqFref(sref, "Mapping")
437 public jalview.datamodel.Mapping jmap = _jmap;
442 SequenceI seq = getSrefDatasetSeq();
454 public SeqFref newAlcodMapRef(final String sref,
455 final AlignedCodonFrame _cf,
456 final jalview.datamodel.Mapping _jmap)
459 SeqFref fref = new SeqFref(sref, "Codon Frame")
461 AlignedCodonFrame cf = _cf;
463 public jalview.datamodel.Mapping mp = _jmap;
466 public boolean isResolvable()
468 return super.isResolvable() && mp.getTo() != null;
474 SequenceI seq = getSrefDatasetSeq();
479 cf.addMap(seq, mp.getTo(), mp.getMap());
486 public void resolveFrefedSequences()
488 Iterator<SeqFref> nextFref = frefedSequence.iterator();
489 int toresolve = frefedSequence.size();
490 int unresolved = 0, failedtoresolve = 0;
491 while (nextFref.hasNext())
493 SeqFref ref = nextFref.next();
494 if (ref.isResolvable())
506 } catch (Exception x)
509 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
522 System.err.println("Jalview Project Import: There were " + unresolved
523 + " forward references left unresolved on the stack.");
525 if (failedtoresolve > 0)
527 System.err.println("SERIOUS! " + failedtoresolve
528 + " resolvable forward references failed to resolve.");
530 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
533 "Jalview Project Import: There are " + incompleteSeqs.size()
534 + " sequences which may have incomplete metadata.");
535 if (incompleteSeqs.size() < 10)
537 for (SequenceI s : incompleteSeqs.values())
539 System.err.println(s.toString());
545 "Too many to report. Skipping output of incomplete sequences.");
551 * This maintains a map of viewports, the key being the seqSetId. Important to
552 * set historyItem and redoList for multiple views
554 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
556 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
558 String uniqueSetSuffix = "";
561 * List of pdbfiles added to Jar
563 List<String> pdbfiles = null;
565 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
566 public void saveState(File statefile)
568 FileOutputStream fos = null;
573 fos = new FileOutputStream(statefile);
575 JarOutputStream jout = new JarOutputStream(fos);
579 } catch (Exception e)
581 Cache.log.error("Couln't write Jalview state to " + statefile, e);
582 // TODO: inform user of the problem - they need to know if their data was
584 if (errorMessage == null)
586 errorMessage = "Did't write Jalview Archive to output file '"
587 + statefile + "' - See console error log for details";
591 errorMessage += "(Didn't write Jalview Archive to output file '"
602 } catch (IOException e)
612 * Writes a jalview project archive to the given Jar output stream.
616 public void saveState(JarOutputStream jout)
618 AlignFrame[] frames = Desktop.getAlignFrames();
624 saveAllFrames(Arrays.asList(frames), jout);
628 * core method for storing state for a set of AlignFrames.
631 * - frames involving all data to be exported (including containing
634 * - project output stream
636 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
638 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
641 * ensure cached data is clear before starting
643 // todo tidy up seqRefIds, seqsToIds initialisation / reset
645 splitFrameCandidates.clear();
650 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
651 // //////////////////////////////////////////////////
653 List<String> shortNames = new ArrayList<>();
654 List<String> viewIds = new ArrayList<>();
657 for (int i = frames.size() - 1; i > -1; i--)
659 AlignFrame af = frames.get(i);
661 if (skipList != null && skipList
662 .containsKey(af.getViewport().getSequenceSetId()))
667 String shortName = makeFilename(af, shortNames);
669 int apSize = af.getAlignPanels().size();
671 for (int ap = 0; ap < apSize; ap++)
673 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
675 String fileName = apSize == 1 ? shortName : ap + shortName;
676 if (!fileName.endsWith(".xml"))
678 fileName = fileName + ".xml";
681 saveState(apanel, fileName, jout, viewIds);
683 String dssid = getDatasetIdRef(
684 af.getViewport().getAlignment().getDataset());
685 if (!dsses.containsKey(dssid))
687 dsses.put(dssid, af);
692 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
698 } catch (Exception foo)
702 } catch (Exception ex)
704 // TODO: inform user of the problem - they need to know if their data was
706 if (errorMessage == null)
708 errorMessage = "Couldn't write Jalview Archive - see error output for details";
710 ex.printStackTrace();
715 * Generates a distinct file name, based on the title of the AlignFrame, by
716 * appending _n for increasing n until an unused name is generated. The new
717 * name (without its extension) is added to the list.
721 * @return the generated name, with .xml extension
723 protected String makeFilename(AlignFrame af, List<String> namesUsed)
725 String shortName = af.getTitle();
727 if (shortName.indexOf(File.separatorChar) > -1)
729 shortName = shortName
730 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
735 while (namesUsed.contains(shortName))
737 if (shortName.endsWith("_" + (count - 1)))
739 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
742 shortName = shortName.concat("_" + count);
746 namesUsed.add(shortName);
748 if (!shortName.endsWith(".xml"))
750 shortName = shortName + ".xml";
755 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
756 public boolean saveAlignment(AlignFrame af, String jarFile,
761 // create backupfiles object and get new temp filename destination
762 boolean doBackup = BackupFiles.getEnabled();
763 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
764 FileOutputStream fos = new FileOutputStream(
765 doBackup ? backupfiles.getTempFilePath() : jarFile);
767 JarOutputStream jout = new JarOutputStream(fos);
768 List<AlignFrame> frames = new ArrayList<>();
770 // resolve splitframes
771 if (af.getViewport().getCodingComplement() != null)
773 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
779 saveAllFrames(frames, jout);
783 } catch (Exception foo)
787 boolean success = true;
791 backupfiles.setWriteSuccess(success);
792 success = backupfiles.rollBackupsAndRenameTempFile();
796 } catch (Exception ex)
798 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
799 ex.printStackTrace();
804 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
805 String fileName, JarOutputStream jout)
808 for (String dssids : dsses.keySet())
810 AlignFrame _af = dsses.get(dssids);
811 String jfileName = fileName + " Dataset for " + _af.getTitle();
812 if (!jfileName.endsWith(".xml"))
814 jfileName = jfileName + ".xml";
816 saveState(_af.alignPanel, jfileName, true, jout, null);
821 * create a JalviewModel from an alignment view and marshall it to a
825 * panel to create jalview model for
827 * name of alignment panel written to output stream
834 public JalviewModel saveState(AlignmentPanel ap, String fileName,
835 JarOutputStream jout, List<String> viewIds)
837 return saveState(ap, fileName, false, jout, viewIds);
841 * create a JalviewModel from an alignment view and marshall it to a
845 * panel to create jalview model for
847 * name of alignment panel written to output stream
849 * when true, only write the dataset for the alignment, not the data
850 * associated with the view.
856 public JalviewModel saveState(AlignmentPanel ap, String fileName,
857 boolean storeDS, JarOutputStream jout, List<String> viewIds)
861 viewIds = new ArrayList<>();
866 List<UserColourScheme> userColours = new ArrayList<>();
868 AlignViewport av = ap.av;
869 ViewportRanges vpRanges = av.getRanges();
871 final ObjectFactory objectFactory = new ObjectFactory();
872 JalviewModel object = objectFactory.createJalviewModel();
873 object.setVamsasModel(new VAMSAS());
875 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
878 GregorianCalendar c = new GregorianCalendar();
879 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
880 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
881 object.setCreationDate(now);
882 } catch (DatatypeConfigurationException e)
884 System.err.println("error writing date: " + e.toString());
887 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
890 * rjal is full height alignment, jal is actual alignment with full metadata
891 * but excludes hidden sequences.
893 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
895 if (av.hasHiddenRows())
897 rjal = jal.getHiddenSequences().getFullAlignment();
900 SequenceSet vamsasSet = new SequenceSet();
902 // JalviewModelSequence jms = new JalviewModelSequence();
904 vamsasSet.setGapChar(jal.getGapCharacter() + "");
906 if (jal.getDataset() != null)
908 // dataset id is the dataset's hashcode
909 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
912 // switch jal and the dataset
913 jal = jal.getDataset();
917 if (jal.getProperties() != null)
919 Enumeration en = jal.getProperties().keys();
920 while (en.hasMoreElements())
922 String key = en.nextElement().toString();
923 SequenceSetProperties ssp = new SequenceSetProperties();
925 ssp.setValue(jal.getProperties().get(key).toString());
926 // vamsasSet.addSequenceSetProperties(ssp);
927 vamsasSet.getSequenceSetProperties().add(ssp);
932 Set<String> calcIdSet = new HashSet<>();
933 // record the set of vamsas sequence XML POJO we create.
934 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
936 for (final SequenceI jds : rjal.getSequences())
938 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
939 : jds.getDatasetSequence();
940 String id = seqHash(jds);
941 if (vamsasSetIds.get(id) == null)
943 if (seqRefIds.get(id) != null && !storeDS)
945 // This happens for two reasons: 1. multiple views are being
947 // 2. the hashCode has collided with another sequence's code. This
949 // HAPPEN! (PF00072.15.stk does this)
950 // JBPNote: Uncomment to debug writing out of files that do not read
951 // back in due to ArrayOutOfBoundExceptions.
952 // System.err.println("vamsasSeq backref: "+id+"");
953 // System.err.println(jds.getName()+"
954 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
955 // System.err.println("Hashcode: "+seqHash(jds));
956 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
957 // System.err.println(rsq.getName()+"
958 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
959 // System.err.println("Hashcode: "+seqHash(rsq));
963 vamsasSeq = createVamsasSequence(id, jds);
964 // vamsasSet.addSequence(vamsasSeq);
965 vamsasSet.getSequence().add(vamsasSeq);
966 vamsasSetIds.put(id, vamsasSeq);
967 seqRefIds.put(id, jds);
971 jseq.setStart(jds.getStart());
972 jseq.setEnd(jds.getEnd());
973 jseq.setColour(av.getSequenceColour(jds).getRGB());
975 jseq.setId(id); // jseq id should be a string not a number
978 // Store any sequences this sequence represents
979 if (av.hasHiddenRows())
981 // use rjal, contains the full height alignment
983 av.getAlignment().getHiddenSequences().isHidden(jds));
985 if (av.isHiddenRepSequence(jds))
987 jalview.datamodel.SequenceI[] reps = av
988 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
990 for (int h = 0; h < reps.length; h++)
994 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
995 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1000 // mark sequence as reference - if it is the reference for this view
1001 if (jal.hasSeqrep())
1003 jseq.setViewreference(jds == jal.getSeqrep());
1007 // TODO: omit sequence features from each alignment view's XML dump if we
1008 // are storing dataset
1009 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1010 for (SequenceFeature sf : sfs)
1012 // Features features = new Features();
1013 Feature features = new Feature();
1015 features.setBegin(sf.getBegin());
1016 features.setEnd(sf.getEnd());
1017 features.setDescription(sf.getDescription());
1018 features.setType(sf.getType());
1019 features.setFeatureGroup(sf.getFeatureGroup());
1020 features.setScore(sf.getScore());
1021 if (sf.links != null)
1023 for (int l = 0; l < sf.links.size(); l++)
1025 OtherData keyValue = new OtherData();
1026 keyValue.setKey("LINK_" + l);
1027 keyValue.setValue(sf.links.elementAt(l).toString());
1028 // features.addOtherData(keyValue);
1029 features.getOtherData().add(keyValue);
1032 if (sf.otherDetails != null)
1035 * save feature attributes, which may be simple strings or
1036 * map valued (have sub-attributes)
1038 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1040 String key = entry.getKey();
1041 Object value = entry.getValue();
1042 if (value instanceof Map<?, ?>)
1044 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1047 OtherData otherData = new OtherData();
1048 otherData.setKey(key);
1049 otherData.setKey2(subAttribute.getKey());
1050 otherData.setValue(subAttribute.getValue().toString());
1051 // features.addOtherData(otherData);
1052 features.getOtherData().add(otherData);
1057 OtherData otherData = new OtherData();
1058 otherData.setKey(key);
1059 otherData.setValue(value.toString());
1060 // features.addOtherData(otherData);
1061 features.getOtherData().add(otherData);
1066 // jseq.addFeatures(features);
1067 jseq.getFeatures().add(features);
1070 if (jdatasq.getAllPDBEntries() != null)
1072 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1073 while (en.hasMoreElements())
1075 Pdbids pdb = new Pdbids();
1076 jalview.datamodel.PDBEntry entry = en.nextElement();
1078 String pdbId = entry.getId();
1080 pdb.setType(entry.getType());
1083 * Store any structure views associated with this sequence. This
1084 * section copes with duplicate entries in the project, so a dataset
1085 * only view *should* be coped with sensibly.
1087 // This must have been loaded, is it still visible?
1088 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1089 String matchedFile = null;
1090 for (int f = frames.length - 1; f > -1; f--)
1092 if (frames[f] instanceof StructureViewerBase)
1094 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1095 matchedFile = saveStructureViewer(ap, jds, pdb, entry,
1096 viewIds, matchedFile, viewFrame);
1098 * Only store each structure viewer's state once in the project
1099 * jar. First time through only (storeDS==false)
1101 String viewId = viewFrame.getViewId();
1102 String viewerType = viewFrame.getViewerType().toString();
1103 if (!storeDS && !viewIds.contains(viewId))
1105 viewIds.add(viewId);
1106 File viewerState = viewFrame.saveSession();
1107 if (viewerState != null)
1109 copyFileToJar(jout, viewerState.getPath(),
1110 getViewerJarEntryName(viewId), viewerType);
1115 "Failed to save viewer state for " + viewerType);
1121 if (matchedFile != null || entry.getFile() != null)
1123 if (entry.getFile() != null)
1126 matchedFile = entry.getFile();
1128 pdb.setFile(matchedFile); // entry.getFile());
1129 if (pdbfiles == null)
1131 pdbfiles = new ArrayList<>();
1134 if (!pdbfiles.contains(pdbId))
1136 pdbfiles.add(pdbId);
1137 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1141 Enumeration<String> props = entry.getProperties();
1142 if (props.hasMoreElements())
1144 // PdbentryItem item = new PdbentryItem();
1145 while (props.hasMoreElements())
1147 Property prop = new Property();
1148 String key = props.nextElement();
1150 prop.setValue(entry.getProperty(key).toString());
1151 // item.addProperty(prop);
1152 pdb.getProperty().add(prop);
1154 // pdb.addPdbentryItem(item);
1157 // jseq.addPdbids(pdb);
1158 jseq.getPdbids().add(pdb);
1162 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1164 // jms.addJSeq(jseq);
1165 object.getJSeq().add(jseq);
1168 if (!storeDS && av.hasHiddenRows())
1170 jal = av.getAlignment();
1174 if (storeDS && jal.getCodonFrames() != null)
1176 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1177 for (AlignedCodonFrame acf : jac)
1179 AlcodonFrame alc = new AlcodonFrame();
1180 if (acf.getProtMappings() != null
1181 && acf.getProtMappings().length > 0)
1183 boolean hasMap = false;
1184 SequenceI[] dnas = acf.getdnaSeqs();
1185 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1186 for (int m = 0; m < pmaps.length; m++)
1188 AlcodMap alcmap = new AlcodMap();
1189 alcmap.setDnasq(seqHash(dnas[m]));
1191 createVamsasMapping(pmaps[m], dnas[m], null, false));
1192 // alc.addAlcodMap(alcmap);
1193 alc.getAlcodMap().add(alcmap);
1198 // vamsasSet.addAlcodonFrame(alc);
1199 vamsasSet.getAlcodonFrame().add(alc);
1202 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1204 // AlcodonFrame alc = new AlcodonFrame();
1205 // vamsasSet.addAlcodonFrame(alc);
1206 // for (int p = 0; p < acf.aaWidth; p++)
1208 // Alcodon cmap = new Alcodon();
1209 // if (acf.codons[p] != null)
1211 // // Null codons indicate a gapped column in the translated peptide
1213 // cmap.setPos1(acf.codons[p][0]);
1214 // cmap.setPos2(acf.codons[p][1]);
1215 // cmap.setPos3(acf.codons[p][2]);
1217 // alc.addAlcodon(cmap);
1219 // if (acf.getProtMappings() != null
1220 // && acf.getProtMappings().length > 0)
1222 // SequenceI[] dnas = acf.getdnaSeqs();
1223 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1224 // for (int m = 0; m < pmaps.length; m++)
1226 // AlcodMap alcmap = new AlcodMap();
1227 // alcmap.setDnasq(seqHash(dnas[m]));
1228 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1230 // alc.addAlcodMap(alcmap);
1237 // /////////////////////////////////
1238 if (!storeDS && av.getCurrentTree() != null)
1240 // FIND ANY ASSOCIATED TREES
1241 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1242 if (Desktop.desktop != null)
1244 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1246 for (int t = 0; t < frames.length; t++)
1248 if (frames[t] instanceof TreePanel)
1250 TreePanel tp = (TreePanel) frames[t];
1252 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1254 JalviewModel.Tree tree = new JalviewModel.Tree();
1255 tree.setTitle(tp.getTitle());
1256 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1257 tree.setNewick(tp.getTree().print());
1258 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1260 tree.setFitToWindow(tp.fitToWindow.getState());
1261 tree.setFontName(tp.getTreeFont().getName());
1262 tree.setFontSize(tp.getTreeFont().getSize());
1263 tree.setFontStyle(tp.getTreeFont().getStyle());
1264 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1266 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1267 tree.setShowDistances(tp.distanceMenu.getState());
1269 tree.setHeight(tp.getHeight());
1270 tree.setWidth(tp.getWidth());
1271 tree.setXpos(tp.getX());
1272 tree.setYpos(tp.getY());
1273 tree.setId(makeHashCode(tp, null));
1274 tree.setLinkToAllViews(
1275 tp.getTreeCanvas().isApplyToAllViews());
1277 // jms.addTree(tree);
1278 object.getTree().add(tree);
1288 if (!storeDS && Desktop.desktop != null)
1290 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1292 if (frame instanceof PCAPanel)
1294 PCAPanel panel = (PCAPanel) frame;
1295 if (panel.getAlignViewport().getAlignment() == jal)
1297 savePCA(panel, object);
1305 * store forward refs from an annotationRow to any groups
1307 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1310 for (SequenceI sq : jal.getSequences())
1312 // Store annotation on dataset sequences only
1313 AlignmentAnnotation[] aa = sq.getAnnotation();
1314 if (aa != null && aa.length > 0)
1316 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1323 if (jal.getAlignmentAnnotation() != null)
1325 // Store the annotation shown on the alignment.
1326 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1327 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1332 if (jal.getGroups() != null)
1334 JGroup[] groups = new JGroup[jal.getGroups().size()];
1336 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1338 JGroup jGroup = new JGroup();
1339 groups[++i] = jGroup;
1341 jGroup.setStart(sg.getStartRes());
1342 jGroup.setEnd(sg.getEndRes());
1343 jGroup.setName(sg.getName());
1344 if (groupRefs.containsKey(sg))
1346 // group has references so set its ID field
1347 jGroup.setId(groupRefs.get(sg));
1349 ColourSchemeI colourScheme = sg.getColourScheme();
1350 if (colourScheme != null)
1352 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1353 if (groupColourScheme.conservationApplied())
1355 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1357 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1359 jGroup.setColour(setUserColourScheme(colourScheme,
1360 userColours, object));
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);
1563 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1565 FeatureMatcherI firstFilter = filters.next();
1566 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1567 filters, filter.isAnded()));
1571 * save colour scheme for the feature type
1573 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1574 if (!fcol.isSimpleColour())
1576 setting.setColour(fcol.getMaxColour().getRGB());
1577 setting.setMincolour(fcol.getMinColour().getRGB());
1578 setting.setMin(fcol.getMin());
1579 setting.setMax(fcol.getMax());
1580 setting.setColourByLabel(fcol.isColourByLabel());
1581 if (fcol.isColourByAttribute())
1583 String[] attName = fcol.getAttributeName();
1584 setting.getAttributeName().add(attName[0]);
1585 if (attName.length > 1)
1587 setting.getAttributeName().add(attName[1]);
1590 setting.setAutoScale(fcol.isAutoScaled());
1591 setting.setThreshold(fcol.getThreshold());
1592 Color noColour = fcol.getNoColour();
1593 if (noColour == null)
1595 setting.setNoValueColour(NoValueColour.NONE);
1597 else if (noColour.equals(fcol.getMaxColour()))
1599 setting.setNoValueColour(NoValueColour.MAX);
1603 setting.setNoValueColour(NoValueColour.MIN);
1605 // -1 = No threshold, 0 = Below, 1 = Above
1606 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1607 : (fcol.isBelowThreshold() ? 0 : -1));
1611 setting.setColour(fcol.getColour().getRGB());
1615 av.getFeaturesDisplayed().isVisible(featureType));
1616 float rorder = fr.getOrder(featureType);
1619 setting.setOrder(rorder);
1621 /// fs.addSetting(setting);
1622 fs.getSetting().add(setting);
1623 settingsAdded.addElement(featureType);
1627 // is groups actually supposed to be a map here ?
1628 Iterator<String> en = fr.getFeatureGroups().iterator();
1629 Vector<String> groupsAdded = new Vector<>();
1630 while (en.hasNext())
1632 String grp = en.next();
1633 if (groupsAdded.contains(grp))
1637 Group g = new Group();
1639 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1642 fs.getGroup().add(g);
1643 groupsAdded.addElement(grp);
1645 // jms.setFeatureSettings(fs);
1646 object.setFeatureSettings(fs);
1649 if (av.hasHiddenColumns())
1651 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1652 .getHiddenColumns();
1655 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1659 Iterator<int[]> hiddenRegions = hidden.iterator();
1660 while (hiddenRegions.hasNext())
1662 int[] region = hiddenRegions.next();
1663 HiddenColumns hc = new HiddenColumns();
1664 hc.setStart(region[0]);
1665 hc.setEnd(region[1]);
1666 // view.addHiddenColumns(hc);
1667 view.getHiddenColumns().add(hc);
1671 if (calcIdSet.size() > 0)
1673 for (String calcId : calcIdSet)
1675 if (calcId.trim().length() > 0)
1677 CalcIdParam cidp = createCalcIdParam(calcId, av);
1678 // Some calcIds have no parameters.
1681 // view.addCalcIdParam(cidp);
1682 view.getCalcIdParam().add(cidp);
1688 // jms.addViewport(view);
1689 object.getViewport().add(view);
1691 // object.setJalviewModelSequence(jms);
1692 // object.getVamsasModel().addSequenceSet(vamsasSet);
1693 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1695 if (jout != null && fileName != null)
1697 // We may not want to write the object to disk,
1698 // eg we can copy the alignViewport to a new view object
1699 // using save and then load
1702 fileName = fileName.replace('\\', '/');
1703 System.out.println("Writing jar entry " + fileName);
1704 JarEntry entry = new JarEntry(fileName);
1705 jout.putNextEntry(entry);
1706 PrintWriter pout = new PrintWriter(
1707 new OutputStreamWriter(jout, UTF_8));
1708 JAXBContext jaxbContext = JAXBContext
1709 .newInstance(JalviewModel.class);
1710 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1712 // output pretty printed
1713 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1714 jaxbMarshaller.marshal(
1715 new ObjectFactory().createJalviewModel(object), pout);
1717 // jaxbMarshaller.marshal(object, pout);
1718 // marshaller.marshal(object);
1721 } catch (Exception ex)
1723 // TODO: raise error in GUI if marshalling failed.
1724 System.err.println("Error writing Jalview project");
1725 ex.printStackTrace();
1732 * Writes PCA viewer attributes and computed values to an XML model object and
1733 * adds it to the JalviewModel. Any exceptions are reported by logging.
1735 protected void savePCA(PCAPanel panel, JalviewModel object)
1739 PcaViewer viewer = new PcaViewer();
1740 viewer.setHeight(panel.getHeight());
1741 viewer.setWidth(panel.getWidth());
1742 viewer.setXpos(panel.getX());
1743 viewer.setYpos(panel.getY());
1744 viewer.setTitle(panel.getTitle());
1745 PCAModel pcaModel = panel.getPcaModel();
1746 viewer.setScoreModelName(pcaModel.getScoreModelName());
1747 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1748 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1749 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1751 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1752 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1753 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1754 SeqPointMin spmin = new SeqPointMin();
1755 spmin.setXPos(spMin[0]);
1756 spmin.setYPos(spMin[1]);
1757 spmin.setZPos(spMin[2]);
1758 viewer.setSeqPointMin(spmin);
1759 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1760 SeqPointMax spmax = new SeqPointMax();
1761 spmax.setXPos(spMax[0]);
1762 spmax.setYPos(spMax[1]);
1763 spmax.setZPos(spMax[2]);
1764 viewer.setSeqPointMax(spmax);
1765 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1766 viewer.setLinkToAllViews(
1767 panel.getRotatableCanvas().isApplyToAllViews());
1768 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1769 viewer.setIncludeGaps(sp.includeGaps());
1770 viewer.setMatchGaps(sp.matchGaps());
1771 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1772 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1775 * sequence points on display
1777 for (jalview.datamodel.SequencePoint spt : pcaModel
1778 .getSequencePoints())
1780 SequencePoint point = new SequencePoint();
1781 point.setSequenceRef(seqHash(spt.getSequence()));
1782 point.setXPos(spt.coord.x);
1783 point.setYPos(spt.coord.y);
1784 point.setZPos(spt.coord.z);
1785 viewer.getSequencePoint().add(point);
1789 * (end points of) axes on display
1791 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1794 Axis axis = new Axis();
1798 viewer.getAxis().add(axis);
1802 * raw PCA data (note we are not restoring PCA inputs here -
1803 * alignment view, score model, similarity parameters)
1805 PcaDataType data = new PcaDataType();
1806 viewer.setPcaData(data);
1807 PCA pca = pcaModel.getPcaData();
1809 DoubleMatrix pm = new DoubleMatrix();
1810 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1811 data.setPairwiseMatrix(pm);
1813 DoubleMatrix tm = new DoubleMatrix();
1814 saveDoubleMatrix(pca.getTridiagonal(), tm);
1815 data.setTridiagonalMatrix(tm);
1817 DoubleMatrix eigenMatrix = new DoubleMatrix();
1818 data.setEigenMatrix(eigenMatrix);
1819 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1821 object.getPcaViewer().add(viewer);
1822 } catch (Throwable t)
1824 Cache.log.error("Error saving PCA: " + t.getMessage());
1829 * Stores values from a matrix into an XML element, including (if present) the
1834 * @see #loadDoubleMatrix(DoubleMatrix)
1836 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1838 xmlMatrix.setRows(m.height());
1839 xmlMatrix.setColumns(m.width());
1840 for (int i = 0; i < m.height(); i++)
1842 DoubleVector row = new DoubleVector();
1843 for (int j = 0; j < m.width(); j++)
1845 row.getV().add(m.getValue(i, j));
1847 xmlMatrix.getRow().add(row);
1849 if (m.getD() != null)
1851 DoubleVector dVector = new DoubleVector();
1852 for (double d : m.getD())
1854 dVector.getV().add(d);
1856 xmlMatrix.setD(dVector);
1858 if (m.getE() != null)
1860 DoubleVector eVector = new DoubleVector();
1861 for (double e : m.getE())
1863 eVector.getV().add(e);
1865 xmlMatrix.setE(eVector);
1870 * Loads XML matrix data into a new Matrix object, including the D and/or E
1871 * vectors (if present)
1875 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1877 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1879 int rows = mData.getRows();
1880 double[][] vals = new double[rows][];
1882 for (int i = 0; i < rows; i++)
1884 List<Double> dVector = mData.getRow().get(i).getV();
1885 vals[i] = new double[dVector.size()];
1887 for (Double d : dVector)
1893 MatrixI m = new Matrix(vals);
1895 if (mData.getD() != null)
1897 List<Double> dVector = mData.getD().getV();
1898 double[] vec = new double[dVector.size()];
1900 for (Double d : dVector)
1906 if (mData.getE() != null)
1908 List<Double> dVector = mData.getE().getV();
1909 double[] vec = new double[dVector.size()];
1911 for (Double d : dVector)
1922 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1923 * for each viewer, with
1925 * <li>viewer geometry (position, size, split pane divider location)</li>
1926 * <li>index of the selected structure in the viewer (currently shows gapped
1928 * <li>the id of the annotation holding RNA secondary structure</li>
1929 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1931 * Varna viewer state is also written out (in native Varna XML) to separate
1932 * project jar entries. A separate entry is written for each RNA structure
1933 * displayed, with the naming convention
1935 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1943 * @param storeDataset
1945 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1946 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1947 boolean storeDataset)
1949 if (Desktop.desktop == null)
1953 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1954 for (int f = frames.length - 1; f > -1; f--)
1956 if (frames[f] instanceof AppVarna)
1958 AppVarna varna = (AppVarna) frames[f];
1960 * link the sequence to every viewer that is showing it and is linked to
1961 * its alignment panel
1963 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1965 String viewId = varna.getViewId();
1966 RnaViewer rna = new RnaViewer();
1967 rna.setViewId(viewId);
1968 rna.setTitle(varna.getTitle());
1969 rna.setXpos(varna.getX());
1970 rna.setYpos(varna.getY());
1971 rna.setWidth(varna.getWidth());
1972 rna.setHeight(varna.getHeight());
1973 rna.setDividerLocation(varna.getDividerLocation());
1974 rna.setSelectedRna(varna.getSelectedIndex());
1975 // jseq.addRnaViewer(rna);
1976 jseq.getRnaViewer().add(rna);
1979 * Store each Varna panel's state once in the project per sequence.
1980 * First time through only (storeDataset==false)
1982 // boolean storeSessions = false;
1983 // String sequenceViewId = viewId + seqsToIds.get(jds);
1984 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1986 // viewIds.add(sequenceViewId);
1987 // storeSessions = true;
1989 for (RnaModel model : varna.getModels())
1991 if (model.seq == jds)
1994 * VARNA saves each view (sequence or alignment secondary
1995 * structure, gapped or trimmed) as a separate XML file
1997 String jarEntryName = rnaSessions.get(model);
1998 if (jarEntryName == null)
2001 String varnaStateFile = varna.getStateInfo(model.rna);
2002 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2003 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2004 rnaSessions.put(model, jarEntryName);
2006 SecondaryStructure ss = new SecondaryStructure();
2007 String annotationId = varna.getAnnotation(jds).annotationId;
2008 ss.setAnnotationId(annotationId);
2009 ss.setViewerState(jarEntryName);
2010 ss.setGapped(model.gapped);
2011 ss.setTitle(model.title);
2012 // rna.addSecondaryStructure(ss);
2013 rna.getSecondaryStructure().add(ss);
2022 * Copy the contents of a file to a new entry added to the output jar
2026 * @param jarEntryName
2028 * additional identifying info to log to the console
2030 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2031 String jarEntryName, String msg)
2033 try (InputStream is = new FileInputStream(infilePath))
2035 File file = new File(infilePath);
2036 if (file.exists() && jout != null)
2039 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2040 jout.putNextEntry(new JarEntry(jarEntryName));
2043 // dis = new DataInputStream(new FileInputStream(file));
2044 // byte[] data = new byte[(int) file.length()];
2045 // dis.readFully(data);
2046 // writeJarEntry(jout, jarEntryName, data);
2048 } catch (Exception ex)
2050 ex.printStackTrace();
2055 * Copies input to output, in 4K buffers; handles any data (text or binary)
2059 * @throws IOException
2061 protected void copyAll(InputStream in, OutputStream out)
2064 byte[] buffer = new byte[4096];
2066 while ((bytesRead = in.read(buffer)) != -1)
2068 out.write(buffer, 0, bytesRead);
2073 * Save the state of a structure viewer
2078 * the archive XML element under which to save the state
2081 * @param matchedFile
2085 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2086 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2087 String matchedFile, StructureViewerBase viewFrame)
2089 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2092 * Look for any bindings for this viewer to the PDB file of interest
2093 * (including part matches excluding chain id)
2095 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2097 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2098 final String pdbId = pdbentry.getId();
2099 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2100 && entry.getId().toLowerCase(Locale.ROOT)
2101 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2104 * not interested in a binding to a different PDB entry here
2108 if (matchedFile == null)
2110 matchedFile = pdbentry.getFile();
2112 else if (!matchedFile.equals(pdbentry.getFile()))
2115 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2116 + pdbentry.getFile());
2120 // can get at it if the ID
2121 // match is ambiguous (e.g.
2124 for (int smap = 0; smap < viewFrame.getBinding()
2125 .getSequence()[peid].length; smap++)
2127 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2128 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2130 StructureState state = new StructureState();
2131 state.setVisible(true);
2132 state.setXpos(viewFrame.getX());
2133 state.setYpos(viewFrame.getY());
2134 state.setWidth(viewFrame.getWidth());
2135 state.setHeight(viewFrame.getHeight());
2136 final String viewId = viewFrame.getViewId();
2137 state.setViewId(viewId);
2138 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2139 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2140 state.setColourByJmol(viewFrame.isColouredByViewer());
2141 state.setType(viewFrame.getViewerType().toString());
2142 // pdb.addStructureState(state);
2143 pdb.getStructureState().add(state);
2151 * Populates the AnnotationColourScheme xml for save. This captures the
2152 * settings of the options in the 'Colour by Annotation' dialog.
2155 * @param userColours
2159 private AnnotationColourScheme constructAnnotationColours(
2160 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2163 AnnotationColourScheme ac = new AnnotationColourScheme();
2164 ac.setAboveThreshold(acg.getAboveThreshold());
2165 ac.setThreshold(acg.getAnnotationThreshold());
2166 // 2.10.2 save annotationId (unique) not annotation label
2167 ac.setAnnotation(acg.getAnnotation().annotationId);
2168 if (acg.getBaseColour() instanceof UserColourScheme)
2171 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2176 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2179 ac.setMaxColour(acg.getMaxColour().getRGB());
2180 ac.setMinColour(acg.getMinColour().getRGB());
2181 ac.setPerSequence(acg.isSeqAssociated());
2182 ac.setPredefinedColours(acg.isPredefinedColours());
2186 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2187 IdentityHashMap<SequenceGroup, String> groupRefs,
2188 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2189 SequenceSet vamsasSet)
2192 for (int i = 0; i < aa.length; i++)
2194 Annotation an = new Annotation();
2196 AlignmentAnnotation annotation = aa[i];
2197 if (annotation.annotationId != null)
2199 annotationIds.put(annotation.annotationId, annotation);
2202 an.setId(annotation.annotationId);
2204 an.setVisible(annotation.visible);
2206 an.setDescription(annotation.description);
2208 if (annotation.sequenceRef != null)
2210 // 2.9 JAL-1781 xref on sequence id rather than name
2211 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2213 if (annotation.groupRef != null)
2215 String groupIdr = groupRefs.get(annotation.groupRef);
2216 if (groupIdr == null)
2218 // make a locally unique String
2219 groupRefs.put(annotation.groupRef,
2220 groupIdr = ("" + System.currentTimeMillis()
2221 + annotation.groupRef.getName()
2222 + groupRefs.size()));
2224 an.setGroupRef(groupIdr.toString());
2227 // store all visualization attributes for annotation
2228 an.setGraphHeight(annotation.graphHeight);
2229 an.setCentreColLabels(annotation.centreColLabels);
2230 an.setScaleColLabels(annotation.scaleColLabel);
2231 an.setShowAllColLabels(annotation.showAllColLabels);
2232 an.setBelowAlignment(annotation.belowAlignment);
2234 if (annotation.graph > 0)
2237 an.setGraphType(annotation.graph);
2238 an.setGraphGroup(annotation.graphGroup);
2239 if (annotation.getThreshold() != null)
2241 ThresholdLine line = new ThresholdLine();
2242 line.setLabel(annotation.getThreshold().label);
2243 line.setValue(annotation.getThreshold().value);
2244 line.setColour(annotation.getThreshold().colour.getRGB());
2245 an.setThresholdLine(line);
2253 an.setLabel(annotation.label);
2255 if (annotation == av.getAlignmentQualityAnnot()
2256 || annotation == av.getAlignmentConservationAnnotation()
2257 || annotation == av.getAlignmentConsensusAnnotation()
2258 || annotation.autoCalculated)
2260 // new way of indicating autocalculated annotation -
2261 an.setAutoCalculated(annotation.autoCalculated);
2263 if (annotation.hasScore())
2265 an.setScore(annotation.getScore());
2268 if (annotation.getCalcId() != null)
2270 calcIdSet.add(annotation.getCalcId());
2271 an.setCalcId(annotation.getCalcId());
2273 if (annotation.hasProperties())
2275 for (String pr : annotation.getProperties())
2277 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2279 prop.setValue(annotation.getProperty(pr));
2280 // an.addProperty(prop);
2281 an.getProperty().add(prop);
2285 AnnotationElement ae;
2286 if (annotation.annotations != null)
2288 an.setScoreOnly(false);
2289 for (int a = 0; a < annotation.annotations.length; a++)
2291 if ((annotation == null) || (annotation.annotations[a] == null))
2296 ae = new AnnotationElement();
2297 if (annotation.annotations[a].description != null)
2299 ae.setDescription(annotation.annotations[a].description);
2301 if (annotation.annotations[a].displayCharacter != null)
2303 ae.setDisplayCharacter(
2304 annotation.annotations[a].displayCharacter);
2307 if (!Float.isNaN(annotation.annotations[a].value))
2309 ae.setValue(annotation.annotations[a].value);
2313 if (annotation.annotations[a].secondaryStructure > ' ')
2315 ae.setSecondaryStructure(
2316 annotation.annotations[a].secondaryStructure + "");
2319 if (annotation.annotations[a].colour != null
2320 && annotation.annotations[a].colour != java.awt.Color.black)
2322 ae.setColour(annotation.annotations[a].colour.getRGB());
2325 // an.addAnnotationElement(ae);
2326 an.getAnnotationElement().add(ae);
2327 if (annotation.autoCalculated)
2329 // only write one non-null entry into the annotation row -
2330 // sufficient to get the visualization attributes necessary to
2338 an.setScoreOnly(true);
2340 if (!storeDS || (storeDS && !annotation.autoCalculated))
2342 // skip autocalculated annotation - these are only provided for
2344 // vamsasSet.addAnnotation(an);
2345 vamsasSet.getAnnotation().add(an);
2351 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2353 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2354 if (settings != null)
2356 CalcIdParam vCalcIdParam = new CalcIdParam();
2357 vCalcIdParam.setCalcId(calcId);
2358 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2359 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2360 // generic URI allowing a third party to resolve another instance of the
2361 // service used for this calculation
2362 for (String url : settings.getServiceURLs())
2364 // vCalcIdParam.addServiceURL(urls);
2365 vCalcIdParam.getServiceURL().add(url);
2367 vCalcIdParam.setVersion("1.0");
2368 if (settings.getPreset() != null)
2370 WsParamSetI setting = settings.getPreset();
2371 vCalcIdParam.setName(setting.getName());
2372 vCalcIdParam.setDescription(setting.getDescription());
2376 vCalcIdParam.setName("");
2377 vCalcIdParam.setDescription("Last used parameters");
2379 // need to be able to recover 1) settings 2) user-defined presets or
2380 // recreate settings from preset 3) predefined settings provided by
2381 // service - or settings that can be transferred (or discarded)
2382 vCalcIdParam.setParameters(
2383 settings.getWsParamFile().replace("\n", "|\\n|"));
2384 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2385 // todo - decide if updateImmediately is needed for any projects.
2387 return vCalcIdParam;
2392 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2395 if (calcIdParam.getVersion().equals("1.0"))
2397 final String[] calcIds = calcIdParam.getServiceURL()
2398 .toArray(new String[0]);
2399 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2400 .getPreferredServiceFor(calcIds);
2401 if (service != null)
2403 WsParamSetI parmSet = null;
2406 parmSet = service.getParamStore().parseServiceParameterFile(
2407 calcIdParam.getName(), calcIdParam.getDescription(),
2409 calcIdParam.getParameters().replace("|\\n|", "\n"));
2410 } catch (IOException x)
2412 warn("Couldn't parse parameter data for "
2413 + calcIdParam.getCalcId(), x);
2416 List<ArgumentI> argList = null;
2417 if (calcIdParam.getName().length() > 0)
2419 parmSet = service.getParamStore()
2420 .getPreset(calcIdParam.getName());
2421 if (parmSet != null)
2423 // TODO : check we have a good match with settings in AACon -
2424 // otherwise we'll need to create a new preset
2429 argList = parmSet.getArguments();
2432 AAConSettings settings = new AAConSettings(
2433 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2434 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2435 calcIdParam.isNeedsUpdate());
2440 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2444 throw new Error(MessageManager.formatMessage(
2445 "error.unsupported_version_calcIdparam", new Object[]
2446 { calcIdParam.toString() }));
2450 * External mapping between jalview objects and objects yielding a valid and
2451 * unique object ID string. This is null for normal Jalview project IO, but
2452 * non-null when a jalview project is being read or written as part of a
2455 IdentityHashMap jv2vobj = null;
2458 * Construct a unique ID for jvobj using either existing bindings or if none
2459 * exist, the result of the hashcode call for the object.
2462 * jalview data object
2463 * @return unique ID for referring to jvobj
2465 private String makeHashCode(Object jvobj, String altCode)
2467 if (jv2vobj != null)
2469 Object id = jv2vobj.get(jvobj);
2472 return id.toString();
2474 // check string ID mappings
2475 if (jvids2vobj != null && jvobj instanceof String)
2477 id = jvids2vobj.get(jvobj);
2481 return id.toString();
2483 // give up and warn that something has gone wrong
2484 warn("Cannot find ID for object in external mapping : " + jvobj);
2490 * return local jalview object mapped to ID, if it exists
2494 * @return null or object bound to idcode
2496 private Object retrieveExistingObj(String idcode)
2498 if (idcode != null && vobj2jv != null)
2500 return vobj2jv.get(idcode);
2506 * binding from ID strings from external mapping table to jalview data model
2509 private Hashtable vobj2jv;
2511 private Sequence createVamsasSequence(String id, SequenceI jds)
2513 return createVamsasSequence(true, id, jds, null);
2516 private Sequence createVamsasSequence(boolean recurse, String id,
2517 SequenceI jds, SequenceI parentseq)
2519 Sequence vamsasSeq = new Sequence();
2520 vamsasSeq.setId(id);
2521 vamsasSeq.setName(jds.getName());
2522 vamsasSeq.setSequence(jds.getSequenceAsString());
2523 vamsasSeq.setDescription(jds.getDescription());
2524 List<DBRefEntry> dbrefs = null;
2525 if (jds.getDatasetSequence() != null)
2527 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2531 // seqId==dsseqid so we can tell which sequences really are
2532 // dataset sequences only
2533 vamsasSeq.setDsseqid(id);
2534 dbrefs = jds.getDBRefs();
2535 if (parentseq == null)
2542 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2546 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2548 DBRef dbref = new DBRef();
2549 DBRefEntry ref = dbrefs.get(d);
2550 dbref.setSource(ref.getSource());
2551 dbref.setVersion(ref.getVersion());
2552 dbref.setAccessionId(ref.getAccessionId());
2553 dbref.setCanonical(ref.isCanonical());
2554 if (ref instanceof GeneLocus)
2556 dbref.setLocus(true);
2560 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2562 dbref.setMapping(mp);
2564 vamsasSeq.getDBRef().add(dbref);
2570 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2571 SequenceI parentseq, SequenceI jds, boolean recurse)
2574 if (jmp.getMap() != null)
2578 jalview.util.MapList mlst = jmp.getMap();
2579 List<int[]> r = mlst.getFromRanges();
2580 for (int[] range : r)
2582 MapListFrom mfrom = new MapListFrom();
2583 mfrom.setStart(range[0]);
2584 mfrom.setEnd(range[1]);
2585 // mp.addMapListFrom(mfrom);
2586 mp.getMapListFrom().add(mfrom);
2588 r = mlst.getToRanges();
2589 for (int[] range : r)
2591 MapListTo mto = new MapListTo();
2592 mto.setStart(range[0]);
2593 mto.setEnd(range[1]);
2594 // mp.addMapListTo(mto);
2595 mp.getMapListTo().add(mto);
2597 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2598 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2599 if (jmp.getTo() != null)
2601 // MappingChoice mpc = new MappingChoice();
2603 // check/create ID for the sequence referenced by getTo()
2606 SequenceI ps = null;
2607 if (parentseq != jmp.getTo()
2608 && parentseq.getDatasetSequence() != jmp.getTo())
2610 // chaining dbref rather than a handshaking one
2611 jmpid = seqHash(ps = jmp.getTo());
2615 jmpid = seqHash(ps = parentseq);
2617 // mpc.setDseqFor(jmpid);
2618 mp.setDseqFor(jmpid);
2619 if (!seqRefIds.containsKey(jmpid))
2621 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2622 seqRefIds.put(jmpid, ps);
2626 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2629 // mp.setMappingChoice(mpc);
2635 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2636 List<UserColourScheme> userColours, JalviewModel jm)
2639 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2640 boolean newucs = false;
2641 if (!userColours.contains(ucs))
2643 userColours.add(ucs);
2646 id = "ucs" + userColours.indexOf(ucs);
2649 // actually create the scheme's entry in the XML model
2650 java.awt.Color[] colours = ucs.getColours();
2651 UserColours uc = new UserColours();
2652 // UserColourScheme jbucs = new UserColourScheme();
2653 JalviewUserColours jbucs = new JalviewUserColours();
2655 for (int i = 0; i < colours.length; i++)
2657 Colour col = new Colour();
2658 col.setName(ResidueProperties.aa[i]);
2659 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2660 // jbucs.addColour(col);
2661 jbucs.getColour().add(col);
2663 if (ucs.getLowerCaseColours() != null)
2665 colours = ucs.getLowerCaseColours();
2666 for (int i = 0; i < colours.length; i++)
2668 Colour col = new Colour();
2669 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2670 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2671 // jbucs.addColour(col);
2672 jbucs.getColour().add(col);
2677 uc.setUserColourScheme(jbucs);
2678 // jm.addUserColours(uc);
2679 jm.getUserColours().add(uc);
2685 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2688 List<UserColours> uc = jm.getUserColours();
2689 UserColours colours = null;
2691 for (int i = 0; i < uc.length; i++)
2693 if (uc[i].getId().equals(id))
2700 for (UserColours c : uc)
2702 if (c.getId().equals(id))
2709 java.awt.Color[] newColours = new java.awt.Color[24];
2711 for (int i = 0; i < 24; i++)
2713 newColours[i] = new java.awt.Color(Integer.parseInt(
2714 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2715 colours.getUserColourScheme().getColour().get(i).getRGB(),
2719 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2722 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2724 newColours = new java.awt.Color[23];
2725 for (int i = 0; i < 23; i++)
2727 newColours[i] = new java.awt.Color(
2728 Integer.parseInt(colours.getUserColourScheme().getColour()
2729 .get(i + 24).getRGB(), 16));
2731 ucs.setLowerCaseColours(newColours);
2738 * contains last error message (if any) encountered by XML loader.
2740 String errorMessage = null;
2743 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2744 * exceptions are raised during project XML parsing
2746 public boolean attemptversion1parse = false;
2749 * Load a jalview project archive from a jar file
2752 * - HTTP URL or filename
2754 public AlignFrame loadJalviewAlign(final Object file)
2757 jalview.gui.AlignFrame af = null;
2761 // create list to store references for any new Jmol viewers created
2762 newStructureViewers = new Vector<>();
2763 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2764 // Workaround is to make sure caller implements the JarInputStreamProvider
2766 // so we can re-open the jar input stream for each entry.
2768 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2769 af = loadJalviewAlign(jprovider);
2772 af.setMenusForViewport();
2774 } catch (MalformedURLException e)
2776 errorMessage = "Invalid URL format for '" + file + "'";
2782 SwingUtilities.invokeAndWait(new Runnable()
2787 setLoadingFinishedForNewStructureViewers();
2790 } catch (Exception x)
2792 System.err.println("Error loading alignment: " + x.getMessage());
2798 @SuppressWarnings("unused")
2799 private jarInputStreamProvider createjarInputStreamProvider(
2800 final Object ofile) throws MalformedURLException
2803 // BH 2018 allow for bytes already attached to File object
2806 String file = (ofile instanceof File
2807 ? ((File) ofile).getCanonicalPath()
2808 : ofile.toString());
2809 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2812 errorMessage = null;
2813 uniqueSetSuffix = null;
2815 viewportsAdded.clear();
2816 frefedSequence = null;
2818 if (HttpUtils.startsWithHttpOrHttps(file))
2820 url = new URL(file);
2822 final URL _url = url;
2823 return new jarInputStreamProvider()
2827 public JarInputStream getJarInputStream() throws IOException
2831 // System.out.println("Jalview2XML: opening byte jarInputStream for
2832 // bytes.length=" + bytes.length);
2833 return new JarInputStream(new ByteArrayInputStream(bytes));
2837 // System.out.println("Jalview2XML: opening url jarInputStream for "
2839 return new JarInputStream(_url.openStream());
2843 // System.out.println("Jalview2XML: opening file jarInputStream for
2845 return new JarInputStream(new FileInputStream(file));
2850 public String getFilename()
2855 } catch (IOException e)
2857 e.printStackTrace();
2863 * Recover jalview session from a jalview project archive. Caller may
2864 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2865 * themselves. Any null fields will be initialised with default values,
2866 * non-null fields are left alone.
2871 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2873 errorMessage = null;
2874 if (uniqueSetSuffix == null)
2876 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2878 if (seqRefIds == null)
2882 AlignFrame af = null, _af = null;
2883 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2884 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2885 final String file = jprovider.getFilename();
2888 JarInputStream jin = null;
2889 JarEntry jarentry = null;
2894 jin = jprovider.getJarInputStream();
2895 for (int i = 0; i < entryCount; i++)
2897 jarentry = jin.getNextJarEntry();
2900 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2902 JAXBContext jc = JAXBContext
2903 .newInstance("jalview.xml.binding.jalview");
2904 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2905 .createXMLStreamReader(jin);
2906 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2907 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2908 JalviewModel.class);
2909 JalviewModel object = jbe.getValue();
2911 if (true) // !skipViewport(object))
2913 _af = loadFromObject(object, file, true, jprovider);
2914 if (_af != null && object.getViewport().size() > 0)
2915 // getJalviewModelSequence().getViewportCount() > 0)
2919 // store a reference to the first view
2922 if (_af.getViewport().isGatherViewsHere())
2924 // if this is a gathered view, keep its reference since
2925 // after gathering views, only this frame will remain
2927 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2930 // Save dataset to register mappings once all resolved
2931 importedDatasets.put(
2932 af.getViewport().getAlignment().getDataset(),
2933 af.getViewport().getAlignment().getDataset());
2938 else if (jarentry != null)
2940 // Some other file here.
2943 } while (jarentry != null);
2945 resolveFrefedSequences();
2946 } catch (IOException ex)
2948 ex.printStackTrace();
2949 errorMessage = "Couldn't locate Jalview XML file : " + file;
2951 "Exception whilst loading jalview XML file : " + ex + "\n");
2952 } catch (Exception ex)
2954 System.err.println("Parsing as Jalview Version 2 file failed.");
2955 ex.printStackTrace(System.err);
2956 if (attemptversion1parse)
2958 // used to attempt to parse as V1 castor-generated xml
2960 if (Desktop.instance != null)
2962 Desktop.instance.stopLoading();
2966 System.out.println("Successfully loaded archive file");
2969 ex.printStackTrace();
2972 "Exception whilst loading jalview XML file : " + ex + "\n");
2973 } catch (OutOfMemoryError e)
2975 // Don't use the OOM Window here
2976 errorMessage = "Out of memory loading jalview XML file";
2977 System.err.println("Out of memory whilst loading jalview XML file");
2978 e.printStackTrace();
2982 * Regather multiple views (with the same sequence set id) to the frame (if
2983 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2984 * views instead of separate frames. Note this doesn't restore a state where
2985 * some expanded views in turn have tabbed views - the last "first tab" read
2986 * in will play the role of gatherer for all.
2988 for (AlignFrame fr : gatherToThisFrame.values())
2990 Desktop.instance.gatherViews(fr);
2993 restoreSplitFrames();
2994 for (AlignmentI ds : importedDatasets.keySet())
2996 if (ds.getCodonFrames() != null)
2998 StructureSelectionManager
2999 .getStructureSelectionManager(Desktop.instance)
3000 .registerMappings(ds.getCodonFrames());
3003 if (errorMessage != null)
3008 if (Desktop.instance != null)
3010 Desktop.instance.stopLoading();
3017 * Try to reconstruct and display SplitFrame windows, where each contains
3018 * complementary dna and protein alignments. Done by pairing up AlignFrame
3019 * objects (created earlier) which have complementary viewport ids associated.
3021 protected void restoreSplitFrames()
3023 List<SplitFrame> gatherTo = new ArrayList<>();
3024 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3025 Map<String, AlignFrame> dna = new HashMap<>();
3028 * Identify the DNA alignments
3030 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3033 AlignFrame af = candidate.getValue();
3034 if (af.getViewport().getAlignment().isNucleotide())
3036 dna.put(candidate.getKey().getId(), af);
3041 * Try to match up the protein complements
3043 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3046 AlignFrame af = candidate.getValue();
3047 if (!af.getViewport().getAlignment().isNucleotide())
3049 String complementId = candidate.getKey().getComplementId();
3050 // only non-null complements should be in the Map
3051 if (complementId != null && dna.containsKey(complementId))
3053 final AlignFrame dnaFrame = dna.get(complementId);
3054 SplitFrame sf = createSplitFrame(dnaFrame, af);
3055 addedToSplitFrames.add(dnaFrame);
3056 addedToSplitFrames.add(af);
3057 dnaFrame.setMenusForViewport();
3058 af.setMenusForViewport();
3059 if (af.getViewport().isGatherViewsHere())
3068 * Open any that we failed to pair up (which shouldn't happen!) as
3069 * standalone AlignFrame's.
3071 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3074 AlignFrame af = candidate.getValue();
3075 if (!addedToSplitFrames.contains(af))
3077 Viewport view = candidate.getKey();
3078 Desktop.addInternalFrame(af, view.getTitle(),
3079 safeInt(view.getWidth()), safeInt(view.getHeight()));
3080 af.setMenusForViewport();
3081 System.err.println("Failed to restore view " + view.getTitle()
3082 + " to split frame");
3087 * Gather back into tabbed views as flagged.
3089 for (SplitFrame sf : gatherTo)
3091 Desktop.instance.gatherViews(sf);
3094 splitFrameCandidates.clear();
3098 * Construct and display one SplitFrame holding DNA and protein alignments.
3101 * @param proteinFrame
3104 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3105 AlignFrame proteinFrame)
3107 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3108 String title = MessageManager.getString("label.linked_view_title");
3109 int width = (int) dnaFrame.getBounds().getWidth();
3110 int height = (int) (dnaFrame.getBounds().getHeight()
3111 + proteinFrame.getBounds().getHeight() + 50);
3114 * SplitFrame location is saved to both enclosed frames
3116 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3117 Desktop.addInternalFrame(splitFrame, title, width, height);
3120 * And compute cDNA consensus (couldn't do earlier with consensus as
3121 * mappings were not yet present)
3123 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3129 * check errorMessage for a valid error message and raise an error box in the
3130 * GUI or write the current errorMessage to stderr and then clear the error
3133 protected void reportErrors()
3135 reportErrors(false);
3138 protected void reportErrors(final boolean saving)
3140 if (errorMessage != null)
3142 final String finalErrorMessage = errorMessage;
3145 javax.swing.SwingUtilities.invokeLater(new Runnable()
3150 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3152 "Error " + (saving ? "saving" : "loading")
3154 JvOptionPane.WARNING_MESSAGE);
3160 System.err.println("Problem loading Jalview file: " + errorMessage);
3163 errorMessage = null;
3166 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3169 * when set, local views will be updated from view stored in JalviewXML
3170 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3171 * sync if this is set to true.
3173 private final boolean updateLocalViews = false;
3176 * Returns the path to a temporary file holding the PDB file for the given PDB
3177 * id. The first time of asking, searches for a file of that name in the
3178 * Jalview project jar, and copies it to a new temporary file. Any repeat
3179 * requests just return the path to the file previously created.
3185 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3188 if (alreadyLoadedPDB.containsKey(pdbId))
3190 return alreadyLoadedPDB.get(pdbId).toString();
3193 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3195 if (tempFile != null)
3197 alreadyLoadedPDB.put(pdbId, tempFile);
3203 * Copies the jar entry of given name to a new temporary file and returns the
3204 * path to the file, or null if the entry is not found.
3207 * @param jarEntryName
3209 * a prefix for the temporary file name, must be at least three
3211 * @param suffixModel
3212 * null or original file - so new file can be given the same suffix
3216 protected String copyJarEntry(jarInputStreamProvider jprovider,
3217 String jarEntryName, String prefix, String suffixModel)
3219 String suffix = ".tmp";
3220 if (suffixModel == null)
3222 suffixModel = jarEntryName;
3224 int sfpos = suffixModel.lastIndexOf(".");
3225 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3227 suffix = "." + suffixModel.substring(sfpos + 1);
3230 try (JarInputStream jin = jprovider.getJarInputStream())
3232 JarEntry entry = null;
3235 entry = jin.getNextJarEntry();
3236 } while (entry != null && !entry.getName().equals(jarEntryName));
3240 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3241 File outFile = File.createTempFile(prefix, suffix);
3242 outFile.deleteOnExit();
3243 try (OutputStream os = new FileOutputStream(outFile))
3247 String t = outFile.getAbsolutePath();
3252 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3254 } catch (Exception ex)
3256 ex.printStackTrace();
3262 private class JvAnnotRow
3264 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3271 * persisted version of annotation row from which to take vis properties
3273 public jalview.datamodel.AlignmentAnnotation template;
3276 * original position of the annotation row in the alignment
3282 * Load alignment frame from jalview XML DOM object
3284 * @param jalviewModel
3287 * filename source string
3288 * @param loadTreesAndStructures
3289 * when false only create Viewport
3291 * data source provider
3292 * @return alignment frame created from view stored in DOM
3294 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3295 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3297 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3299 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3301 // JalviewModelSequence jms = object.getJalviewModelSequence();
3303 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3305 Viewport view = (jalviewModel.getViewport().size() > 0)
3306 ? jalviewModel.getViewport().get(0)
3309 // ////////////////////////////////
3310 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3313 // If we just load in the same jar file again, the sequenceSetId
3314 // will be the same, and we end up with multiple references
3315 // to the same sequenceSet. We must modify this id on load
3316 // so that each load of the file gives a unique id
3319 * used to resolve correct alignment dataset for alignments with multiple
3322 String uniqueSeqSetId = null;
3323 String viewId = null;
3326 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3327 viewId = (view.getId() == null ? null
3328 : view.getId() + uniqueSetSuffix);
3331 // ////////////////////////////////
3334 List<SequenceI> hiddenSeqs = null;
3336 List<SequenceI> tmpseqs = new ArrayList<>();
3338 boolean multipleView = false;
3339 SequenceI referenceseqForView = null;
3340 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3341 List<JSeq> jseqs = jalviewModel.getJSeq();
3342 int vi = 0; // counter in vamsasSeq array
3343 for (int i = 0; i < jseqs.size(); i++)
3345 JSeq jseq = jseqs.get(i);
3346 String seqId = jseq.getId();
3348 SequenceI tmpSeq = seqRefIds.get(seqId);
3351 if (!incompleteSeqs.containsKey(seqId))
3353 // may not need this check, but keep it for at least 2.9,1 release
3354 if (tmpSeq.getStart() != jseq.getStart()
3355 || tmpSeq.getEnd() != jseq.getEnd())
3357 System.err.println(String.format(
3358 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3359 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3360 jseq.getStart(), jseq.getEnd()));
3365 incompleteSeqs.remove(seqId);
3367 if (vamsasSeqs.size() > vi
3368 && vamsasSeqs.get(vi).getId().equals(seqId))
3370 // most likely we are reading a dataset XML document so
3371 // update from vamsasSeq section of XML for this sequence
3372 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3373 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3374 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3379 // reading multiple views, so vamsasSeq set is a subset of JSeq
3380 multipleView = true;
3382 tmpSeq.setStart(jseq.getStart());
3383 tmpSeq.setEnd(jseq.getEnd());
3384 tmpseqs.add(tmpSeq);
3388 Sequence vamsasSeq = vamsasSeqs.get(vi);
3389 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3390 vamsasSeq.getSequence());
3391 tmpSeq.setDescription(vamsasSeq.getDescription());
3392 tmpSeq.setStart(jseq.getStart());
3393 tmpSeq.setEnd(jseq.getEnd());
3394 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3395 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3396 tmpseqs.add(tmpSeq);
3400 if (safeBoolean(jseq.isViewreference()))
3402 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3405 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3407 if (hiddenSeqs == null)
3409 hiddenSeqs = new ArrayList<>();
3412 hiddenSeqs.add(tmpSeq);
3417 // Create the alignment object from the sequence set
3418 // ///////////////////////////////
3419 SequenceI[] orderedSeqs = tmpseqs
3420 .toArray(new SequenceI[tmpseqs.size()]);
3422 AlignmentI al = null;
3423 // so we must create or recover the dataset alignment before going further
3424 // ///////////////////////////////
3425 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3427 // older jalview projects do not have a dataset - so creat alignment and
3429 al = new Alignment(orderedSeqs);
3430 al.setDataset(null);
3434 boolean isdsal = jalviewModel.getViewport().isEmpty();
3437 // we are importing a dataset record, so
3438 // recover reference to an alignment already materialsed as dataset
3439 al = getDatasetFor(vamsasSet.getDatasetId());
3443 // materialse the alignment
3444 al = new Alignment(orderedSeqs);
3448 addDatasetRef(vamsasSet.getDatasetId(), al);
3451 // finally, verify all data in vamsasSet is actually present in al
3452 // passing on flag indicating if it is actually a stored dataset
3453 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3456 if (referenceseqForView != null)
3458 al.setSeqrep(referenceseqForView);
3460 // / Add the alignment properties
3461 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3463 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3465 al.setProperty(ssp.getKey(), ssp.getValue());
3468 // ///////////////////////////////
3470 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3473 // load sequence features, database references and any associated PDB
3474 // structures for the alignment
3476 // prior to 2.10, this part would only be executed the first time a
3477 // sequence was encountered, but not afterwards.
3478 // now, for 2.10 projects, this is also done if the xml doc includes
3479 // dataset sequences not actually present in any particular view.
3481 for (int i = 0; i < vamsasSeqs.size(); i++)
3483 JSeq jseq = jseqs.get(i);
3484 if (jseq.getFeatures().size() > 0)
3486 List<Feature> features = jseq.getFeatures();
3487 for (int f = 0; f < features.size(); f++)
3489 Feature feat = features.get(f);
3490 SequenceFeature sf = new SequenceFeature(feat.getType(),
3491 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3492 safeFloat(feat.getScore()), feat.getFeatureGroup());
3493 sf.setStatus(feat.getStatus());
3496 * load any feature attributes - include map-valued attributes
3498 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3499 for (int od = 0; od < feat.getOtherData().size(); od++)
3501 OtherData keyValue = feat.getOtherData().get(od);
3502 String attributeName = keyValue.getKey();
3503 String attributeValue = keyValue.getValue();
3504 if (attributeName.startsWith("LINK"))
3506 sf.addLink(attributeValue);
3510 String subAttribute = keyValue.getKey2();
3511 if (subAttribute == null)
3513 // simple string-valued attribute
3514 sf.setValue(attributeName, attributeValue);
3518 // attribute 'key' has sub-attribute 'key2'
3519 if (!mapAttributes.containsKey(attributeName))
3521 mapAttributes.put(attributeName, new HashMap<>());
3523 mapAttributes.get(attributeName).put(subAttribute,
3528 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3531 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3534 // adds feature to datasequence's feature set (since Jalview 2.10)
3535 al.getSequenceAt(i).addSequenceFeature(sf);
3538 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3540 // adds dbrefs to datasequence's set (since Jalview 2.10)
3542 al.getSequenceAt(i).getDatasetSequence() == null
3543 ? al.getSequenceAt(i)
3544 : al.getSequenceAt(i).getDatasetSequence(),
3547 if (jseq.getPdbids().size() > 0)
3549 List<Pdbids> ids = jseq.getPdbids();
3550 for (int p = 0; p < ids.size(); p++)
3552 Pdbids pdbid = ids.get(p);
3553 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3554 entry.setId(pdbid.getId());
3555 if (pdbid.getType() != null)
3557 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3559 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3563 entry.setType(PDBEntry.Type.FILE);
3566 // jprovider is null when executing 'New View'
3567 if (pdbid.getFile() != null && jprovider != null)
3569 if (!pdbloaded.containsKey(pdbid.getFile()))
3571 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3576 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3580 if (pdbid.getPdbentryItem() != null)
3582 for (PdbentryItem item : pdbid.getPdbentryItem())
3584 for (Property pr : item.getProperty())
3586 entry.setProperty(pr.getName(), pr.getValue());
3591 for (Property prop : pdbid.getProperty())
3593 entry.setProperty(prop.getName(), prop.getValue());
3595 StructureSelectionManager
3596 .getStructureSelectionManager(Desktop.instance)
3597 .registerPDBEntry(entry);
3598 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3599 if (al.getSequenceAt(i).getDatasetSequence() != null)
3601 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3605 al.getSequenceAt(i).addPDBId(entry);
3610 } // end !multipleview
3612 // ///////////////////////////////
3613 // LOAD SEQUENCE MAPPINGS
3615 if (vamsasSet.getAlcodonFrame().size() > 0)
3617 // TODO Potentially this should only be done once for all views of an
3619 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3620 for (int i = 0; i < alc.size(); i++)
3622 AlignedCodonFrame cf = new AlignedCodonFrame();
3623 if (alc.get(i).getAlcodMap().size() > 0)
3625 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3626 for (int m = 0; m < maps.size(); m++)
3628 AlcodMap map = maps.get(m);
3629 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3631 jalview.datamodel.Mapping mapping = null;
3632 // attach to dna sequence reference.
3633 if (map.getMapping() != null)
3635 mapping = addMapping(map.getMapping());
3636 if (dnaseq != null && mapping.getTo() != null)
3638 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3644 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3648 al.addCodonFrame(cf);
3653 // ////////////////////////////////
3655 List<JvAnnotRow> autoAlan = new ArrayList<>();
3658 * store any annotations which forward reference a group's ID
3660 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3662 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3664 List<Annotation> an = vamsasSet.getAnnotation();
3666 for (int i = 0; i < an.size(); i++)
3668 Annotation annotation = an.get(i);
3671 * test if annotation is automatically calculated for this view only
3673 boolean autoForView = false;
3674 if (annotation.getLabel().equals("Quality")
3675 || annotation.getLabel().equals("Conservation")
3676 || annotation.getLabel().equals("Consensus"))
3678 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3680 // JAXB has no has() test; schema defaults value to false
3681 // if (!annotation.hasAutoCalculated())
3683 // annotation.setAutoCalculated(true);
3686 if (autoForView || annotation.isAutoCalculated())
3688 // remove ID - we don't recover annotation from other views for
3689 // view-specific annotation
3690 annotation.setId(null);
3693 // set visibility for other annotation in this view
3694 String annotationId = annotation.getId();
3695 if (annotationId != null && annotationIds.containsKey(annotationId))
3697 AlignmentAnnotation jda = annotationIds.get(annotationId);
3698 // in principle Visible should always be true for annotation displayed
3699 // in multiple views
3700 if (annotation.isVisible() != null)
3702 jda.visible = annotation.isVisible();
3705 al.addAnnotation(jda);
3709 // Construct new annotation from model.
3710 List<AnnotationElement> ae = annotation.getAnnotationElement();
3711 jalview.datamodel.Annotation[] anot = null;
3712 java.awt.Color firstColour = null;
3714 if (!annotation.isScoreOnly())
3716 anot = new jalview.datamodel.Annotation[al.getWidth()];
3717 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3719 AnnotationElement annElement = ae.get(aa);
3720 anpos = annElement.getPosition();
3722 if (anpos >= anot.length)
3727 float value = safeFloat(annElement.getValue());
3728 anot[anpos] = new jalview.datamodel.Annotation(
3729 annElement.getDisplayCharacter(),
3730 annElement.getDescription(),
3731 (annElement.getSecondaryStructure() == null
3732 || annElement.getSecondaryStructure()
3736 .getSecondaryStructure()
3739 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3740 if (firstColour == null)
3742 firstColour = anot[anpos].colour;
3746 jalview.datamodel.AlignmentAnnotation jaa = null;
3748 if (annotation.isGraph())
3750 float llim = 0, hlim = 0;
3751 // if (autoForView || an[i].isAutoCalculated()) {
3754 jaa = new jalview.datamodel.AlignmentAnnotation(
3755 annotation.getLabel(), annotation.getDescription(), anot,
3756 llim, hlim, safeInt(annotation.getGraphType()));
3758 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3759 jaa._linecolour = firstColour;
3760 if (annotation.getThresholdLine() != null)
3762 jaa.setThreshold(new jalview.datamodel.GraphLine(
3763 safeFloat(annotation.getThresholdLine().getValue()),
3764 annotation.getThresholdLine().getLabel(),
3765 new java.awt.Color(safeInt(
3766 annotation.getThresholdLine().getColour()))));
3768 if (autoForView || annotation.isAutoCalculated())
3770 // Hardwire the symbol display line to ensure that labels for
3771 // histograms are displayed
3777 jaa = new jalview.datamodel.AlignmentAnnotation(
3778 annotation.getLabel(), annotation.getDescription(), anot);
3779 jaa._linecolour = firstColour;
3781 // register new annotation
3782 if (annotation.getId() != null)
3784 annotationIds.put(annotation.getId(), jaa);
3785 jaa.annotationId = annotation.getId();
3787 // recover sequence association
3788 String sequenceRef = annotation.getSequenceRef();
3789 if (sequenceRef != null)
3791 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3792 SequenceI sequence = seqRefIds.get(sequenceRef);
3793 if (sequence == null)
3795 // in pre-2.9 projects sequence ref is to sequence name
3796 sequence = al.findName(sequenceRef);
3798 if (sequence != null)
3800 jaa.createSequenceMapping(sequence, 1, true);
3801 sequence.addAlignmentAnnotation(jaa);
3804 // and make a note of any group association
3805 if (annotation.getGroupRef() != null
3806 && annotation.getGroupRef().length() > 0)
3808 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3809 .get(annotation.getGroupRef());
3812 aal = new ArrayList<>();
3813 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3818 if (annotation.getScore() != null)
3820 jaa.setScore(annotation.getScore().doubleValue());
3822 if (annotation.isVisible() != null)
3824 jaa.visible = annotation.isVisible().booleanValue();
3827 if (annotation.isCentreColLabels() != null)
3829 jaa.centreColLabels = annotation.isCentreColLabels()
3833 if (annotation.isScaleColLabels() != null)
3835 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3837 if (annotation.isAutoCalculated())
3839 // newer files have an 'autoCalculated' flag and store calculation
3840 // state in viewport properties
3841 jaa.autoCalculated = true; // means annotation will be marked for
3842 // update at end of load.
3844 if (annotation.getGraphHeight() != null)
3846 jaa.graphHeight = annotation.getGraphHeight().intValue();
3848 jaa.belowAlignment = annotation.isBelowAlignment();
3849 jaa.setCalcId(annotation.getCalcId());
3850 if (annotation.getProperty().size() > 0)
3852 for (Annotation.Property prop : annotation.getProperty())
3854 jaa.setProperty(prop.getName(), prop.getValue());
3857 if (jaa.autoCalculated)
3859 autoAlan.add(new JvAnnotRow(i, jaa));
3862 // if (!autoForView)
3864 // add autocalculated group annotation and any user created annotation
3866 al.addAnnotation(jaa);
3870 // ///////////////////////
3872 // Create alignment markup and styles for this view
3873 if (jalviewModel.getJGroup().size() > 0)
3875 List<JGroup> groups = jalviewModel.getJGroup();
3876 boolean addAnnotSchemeGroup = false;
3877 for (int i = 0; i < groups.size(); i++)
3879 JGroup jGroup = groups.get(i);
3880 ColourSchemeI cs = null;
3881 if (jGroup.getColour() != null)
3883 if (jGroup.getColour().startsWith("ucs"))
3885 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3887 else if (jGroup.getColour().equals("AnnotationColourGradient")
3888 && jGroup.getAnnotationColours() != null)
3890 addAnnotSchemeGroup = true;
3894 cs = ColourSchemeProperty.getColourScheme(null, al,
3895 jGroup.getColour());
3898 int pidThreshold = safeInt(jGroup.getPidThreshold());
3900 Vector<SequenceI> seqs = new Vector<>();
3902 for (int s = 0; s < jGroup.getSeq().size(); s++)
3904 String seqId = jGroup.getSeq().get(s);
3905 SequenceI ts = seqRefIds.get(seqId);
3909 seqs.addElement(ts);
3913 if (seqs.size() < 1)
3918 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3919 safeBoolean(jGroup.isDisplayBoxes()),
3920 safeBoolean(jGroup.isDisplayText()),
3921 safeBoolean(jGroup.isColourText()),
3922 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3923 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3924 sg.getGroupColourScheme()
3925 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3926 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3928 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3929 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3930 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3931 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3932 // attributes with a default in the schema are never null
3933 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3934 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3935 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3936 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3937 if (jGroup.getConsThreshold() != null
3938 && jGroup.getConsThreshold().intValue() != 0)
3940 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3943 c.verdict(false, 25);
3944 sg.cs.setConservation(c);
3947 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3949 // re-instate unique group/annotation row reference
3950 List<AlignmentAnnotation> jaal = groupAnnotRefs
3951 .get(jGroup.getId());
3954 for (AlignmentAnnotation jaa : jaal)
3957 if (jaa.autoCalculated)
3959 // match up and try to set group autocalc alignment row for this
3961 if (jaa.label.startsWith("Consensus for "))
3963 sg.setConsensus(jaa);
3965 // match up and try to set group autocalc alignment row for this
3967 if (jaa.label.startsWith("Conservation for "))
3969 sg.setConservationRow(jaa);
3976 if (addAnnotSchemeGroup)
3978 // reconstruct the annotation colourscheme
3980 constructAnnotationColour(jGroup.getAnnotationColours(),
3981 null, al, jalviewModel, false));
3987 // only dataset in this model, so just return.
3990 // ///////////////////////////////
3993 AlignFrame af = null;
3994 AlignViewport av = null;
3995 // now check to see if we really need to create a new viewport.
3996 if (multipleView && viewportsAdded.size() == 0)
3998 // We recovered an alignment for which a viewport already exists.
3999 // TODO: fix up any settings necessary for overlaying stored state onto
4000 // state recovered from another document. (may not be necessary).
4001 // we may need a binding from a viewport in memory to one recovered from
4003 // and then recover its containing af to allow the settings to be applied.
4004 // TODO: fix for vamsas demo
4006 "About to recover a viewport for existing alignment: Sequence set ID is "
4008 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4009 if (seqsetobj != null)
4011 if (seqsetobj instanceof String)
4013 uniqueSeqSetId = (String) seqsetobj;
4015 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4021 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4027 * indicate that annotation colours are applied across all groups (pre
4028 * Jalview 2.8.1 behaviour)
4030 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4031 jalviewModel.getVersion());
4033 AlignmentPanel ap = null;
4034 boolean isnewview = true;
4037 // Check to see if this alignment already has a view id == viewId
4038 jalview.gui.AlignmentPanel views[] = Desktop
4039 .getAlignmentPanels(uniqueSeqSetId);
4040 if (views != null && views.length > 0)
4042 for (int v = 0; v < views.length; v++)
4044 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4046 // recover the existing alignpanel, alignframe, viewport
4047 af = views[v].alignFrame;
4050 // TODO: could even skip resetting view settings if we don't want to
4051 // change the local settings from other jalview processes
4060 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4061 uniqueSeqSetId, viewId, autoAlan);
4062 av = af.getViewport();
4067 * Load any trees, PDB structures and viewers, Overview
4069 * Not done if flag is false (when this method is used for New View)
4071 if (loadTreesAndStructures)
4073 loadTrees(jalviewModel, view, af, av, ap);
4074 loadPCAViewers(jalviewModel, ap);
4075 loadPDBStructures(jprovider, jseqs, af, ap);
4076 loadRnaViewers(jprovider, jseqs, ap);
4077 loadOverview(view, af);
4079 // and finally return.
4084 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4085 * and geometry as saved
4090 protected void loadOverview(Viewport view, AlignFrame af)
4092 Overview overview = view.getOverview();
4093 if (overview != null)
4095 OverviewPanel overviewPanel = af
4096 .openOverviewPanel(overview.isShowHidden());
4097 JInternalFrame frame = (JInternalFrame) SwingUtilities
4098 .getAncestorOfClass(JInternalFrame.class, overviewPanel);
4099 frame.setTitle(overview.getTitle());
4100 frame.setBounds(overview.getXpos(), overview.getYpos(),
4101 overview.getWidth(), overview.getHeight());
4102 Color gap = new Color(overview.getGapColour());
4103 Color residue = new Color(overview.getResidueColour());
4104 Color hidden = new Color(overview.getHiddenColour());
4105 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4110 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4111 * panel is restored from separate jar entries, two (gapped and trimmed) per
4112 * sequence and secondary structure.
4114 * Currently each viewer shows just one sequence and structure (gapped and
4115 * trimmed), however this method is designed to support multiple sequences or
4116 * structures in viewers if wanted in future.
4122 private void loadRnaViewers(jarInputStreamProvider jprovider,
4123 List<JSeq> jseqs, AlignmentPanel ap)
4126 * scan the sequences for references to viewers; create each one the first
4127 * time it is referenced, add Rna models to existing viewers
4129 for (JSeq jseq : jseqs)
4131 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4133 RnaViewer viewer = jseq.getRnaViewer().get(i);
4134 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4137 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4139 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4140 SequenceI seq = seqRefIds.get(jseq.getId());
4141 AlignmentAnnotation ann = this.annotationIds
4142 .get(ss.getAnnotationId());
4145 * add the structure to the Varna display (with session state copied
4146 * from the jar to a temporary file)
4148 boolean gapped = safeBoolean(ss.isGapped());
4149 String rnaTitle = ss.getTitle();
4150 String sessionState = ss.getViewerState();
4151 String tempStateFile = copyJarEntry(jprovider, sessionState,
4153 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4154 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4156 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4162 * Locate and return an already instantiated matching AppVarna, or create one
4166 * @param viewIdSuffix
4170 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4171 String viewIdSuffix, AlignmentPanel ap)
4174 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4175 * if load is repeated
4177 String postLoadId = viewer.getViewId() + viewIdSuffix;
4178 for (JInternalFrame frame : getAllFrames())
4180 if (frame instanceof AppVarna)
4182 AppVarna varna = (AppVarna) frame;
4183 if (postLoadId.equals(varna.getViewId()))
4185 // this viewer is already instantiated
4186 // could in future here add ap as another 'parent' of the
4187 // AppVarna window; currently just 1-to-many
4194 * viewer not found - make it
4196 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4197 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4198 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4199 safeInt(viewer.getDividerLocation()));
4200 AppVarna varna = new AppVarna(model, ap);
4206 * Load any saved trees
4214 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4215 AlignViewport av, AlignmentPanel ap)
4217 // TODO result of automated refactoring - are all these parameters needed?
4220 for (int t = 0; t < jm.getTree().size(); t++)
4223 Tree tree = jm.getTree().get(t);
4225 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4228 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4229 tree.getTitle(), safeInt(tree.getWidth()),
4230 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4231 safeInt(tree.getYpos()));
4232 if (tree.getId() != null)
4234 // perhaps bind the tree id to something ?
4239 // update local tree attributes ?
4240 // TODO: should check if tp has been manipulated by user - if so its
4241 // settings shouldn't be modified
4242 tp.setTitle(tree.getTitle());
4243 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4244 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4245 safeInt(tree.getHeight())));
4246 tp.setViewport(av); // af.viewport;
4247 // TODO: verify 'associate with all views' works still
4248 tp.getTreeCanvas().setViewport(av); // af.viewport;
4249 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4251 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4254 warn("There was a problem recovering stored Newick tree: \n"
4255 + tree.getNewick());
4259 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4260 tp.fitToWindow_actionPerformed(null);
4262 if (tree.getFontName() != null)
4265 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4266 safeInt(tree.getFontSize())));
4271 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4272 safeInt(view.getFontSize())));
4275 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4276 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4277 tp.showDistances(safeBoolean(tree.isShowDistances()));
4279 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4281 if (safeBoolean(tree.isCurrentTree()))
4283 af.getViewport().setCurrentTree(tp.getTree());
4287 } catch (Exception ex)
4289 ex.printStackTrace();
4294 * Load and link any saved structure viewers.
4301 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4302 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4305 * Run through all PDB ids on the alignment, and collect mappings between
4306 * distinct view ids and all sequences referring to that view.
4308 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4310 for (int i = 0; i < jseqs.size(); i++)
4312 JSeq jseq = jseqs.get(i);
4313 if (jseq.getPdbids().size() > 0)
4315 List<Pdbids> ids = jseq.getPdbids();
4316 for (int p = 0; p < ids.size(); p++)
4318 Pdbids pdbid = ids.get(p);
4319 final int structureStateCount = pdbid.getStructureState().size();
4320 for (int s = 0; s < structureStateCount; s++)
4322 // check to see if we haven't already created this structure view
4323 final StructureState structureState = pdbid.getStructureState()
4325 String sviewid = (structureState.getViewId() == null) ? null
4326 : structureState.getViewId() + uniqueSetSuffix;
4327 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4328 // Originally : pdbid.getFile()
4329 // : TODO: verify external PDB file recovery still works in normal
4330 // jalview project load
4332 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4333 jpdb.setId(pdbid.getId());
4335 int x = safeInt(structureState.getXpos());
4336 int y = safeInt(structureState.getYpos());
4337 int width = safeInt(structureState.getWidth());
4338 int height = safeInt(structureState.getHeight());
4340 // Probably don't need to do this anymore...
4341 // Desktop.desktop.getComponentAt(x, y);
4342 // TODO: NOW: check that this recovers the PDB file correctly.
4343 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4345 jalview.datamodel.SequenceI seq = seqRefIds
4346 .get(jseq.getId() + "");
4347 if (sviewid == null)
4349 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4352 if (!structureViewers.containsKey(sviewid))
4354 String viewerType = structureState.getType();
4355 if (viewerType == null) // pre Jalview 2.9
4357 viewerType = ViewerType.JMOL.toString();
4359 structureViewers.put(sviewid,
4360 new StructureViewerModel(x, y, width, height, false,
4361 false, true, structureState.getViewId(),
4363 // Legacy pre-2.7 conversion JAL-823 :
4364 // do not assume any view has to be linked for colour by
4368 // assemble String[] { pdb files }, String[] { id for each
4369 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4370 // seqs_file 2}, boolean[] {
4371 // linkAlignPanel,superposeWithAlignpanel}} from hash
4372 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4373 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4374 || structureState.isAlignwithAlignPanel());
4377 * Default colour by linked panel to false if not specified (e.g.
4378 * for pre-2.7 projects)
4380 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4381 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4382 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4385 * Default colour by viewer to true if not specified (e.g. for
4388 boolean colourByViewer = jmoldat.isColourByViewer();
4389 colourByViewer &= structureState.isColourByJmol();
4390 jmoldat.setColourByViewer(colourByViewer);
4392 if (jmoldat.getStateData().length() < structureState.getValue()
4393 /*Content()*/.length())
4395 jmoldat.setStateData(structureState.getValue());// Content());
4397 if (pdbid.getFile() != null)
4399 File mapkey = new File(pdbid.getFile());
4400 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4401 if (seqstrmaps == null)
4403 jmoldat.getFileData().put(mapkey,
4404 seqstrmaps = jmoldat.new StructureData(pdbFile,
4407 if (!seqstrmaps.getSeqList().contains(seq))
4409 seqstrmaps.getSeqList().add(seq);
4415 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");
4422 // Instantiate the associated structure views
4423 for (Entry<String, StructureViewerModel> entry : structureViewers
4428 createOrLinkStructureViewer(entry, af, ap, jprovider);
4429 } catch (Exception e)
4432 "Error loading structure viewer: " + e.getMessage());
4433 // failed - try the next one
4445 protected void createOrLinkStructureViewer(
4446 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4447 AlignmentPanel ap, jarInputStreamProvider jprovider)
4449 final StructureViewerModel stateData = viewerData.getValue();
4452 * Search for any viewer windows already open from other alignment views
4453 * that exactly match the stored structure state
4455 StructureViewerBase comp = findMatchingViewer(viewerData);
4459 linkStructureViewer(ap, comp, stateData);
4463 String type = stateData.getType();
4466 ViewerType viewerType = ViewerType.valueOf(type);
4467 createStructureViewer(viewerType, viewerData, af, jprovider);
4468 } catch (IllegalArgumentException | NullPointerException e)
4470 // TODO JAL-3619 show error dialog / offer an alternative viewer
4471 Cache.log.error("Invalid structure viewer type: " + type);
4476 * Generates a name for the entry in the project jar file to hold state
4477 * information for a structure viewer
4482 protected String getViewerJarEntryName(String viewId)
4484 return VIEWER_PREFIX + viewId;
4488 * Returns any open frame that matches given structure viewer data. The match
4489 * is based on the unique viewId, or (for older project versions) the frame's
4495 protected StructureViewerBase findMatchingViewer(
4496 Entry<String, StructureViewerModel> viewerData)
4498 final String sviewid = viewerData.getKey();
4499 final StructureViewerModel svattrib = viewerData.getValue();
4500 StructureViewerBase comp = null;
4501 JInternalFrame[] frames = getAllFrames();
4502 for (JInternalFrame frame : frames)
4504 if (frame instanceof StructureViewerBase)
4507 * Post jalview 2.4 schema includes structure view id
4509 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4512 comp = (StructureViewerBase) frame;
4513 break; // break added in 2.9
4516 * Otherwise test for matching position and size of viewer frame
4518 else if (frame.getX() == svattrib.getX()
4519 && frame.getY() == svattrib.getY()
4520 && frame.getHeight() == svattrib.getHeight()
4521 && frame.getWidth() == svattrib.getWidth())
4523 comp = (StructureViewerBase) frame;
4524 // no break in faint hope of an exact match on viewId
4532 * Link an AlignmentPanel to an existing structure viewer.
4537 * @param useinViewerSuperpos
4538 * @param usetoColourbyseq
4539 * @param viewerColouring
4541 protected void linkStructureViewer(AlignmentPanel ap,
4542 StructureViewerBase viewer, StructureViewerModel stateData)
4544 // NOTE: if the jalview project is part of a shared session then
4545 // view synchronization should/could be done here.
4547 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4548 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4549 final boolean viewerColouring = stateData.isColourByViewer();
4550 Map<File, StructureData> oldFiles = stateData.getFileData();
4553 * Add mapping for sequences in this view to an already open viewer
4555 final AAStructureBindingModel binding = viewer.getBinding();
4556 for (File id : oldFiles.keySet())
4558 // add this and any other pdb files that should be present in the
4560 StructureData filedat = oldFiles.get(id);
4561 String pdbFile = filedat.getFilePath();
4562 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4563 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4565 binding.addSequenceForStructFile(pdbFile, seq);
4567 // and add the AlignmentPanel's reference to the view panel
4568 viewer.addAlignmentPanel(ap);
4569 if (useinViewerSuperpos)
4571 viewer.useAlignmentPanelForSuperposition(ap);
4575 viewer.excludeAlignmentPanelForSuperposition(ap);
4577 if (usetoColourbyseq)
4579 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4583 viewer.excludeAlignmentPanelForColourbyseq(ap);
4588 * Get all frames within the Desktop.
4592 protected JInternalFrame[] getAllFrames()
4594 JInternalFrame[] frames = null;
4595 // TODO is this necessary - is it safe - risk of hanging?
4600 frames = Desktop.desktop.getAllFrames();
4601 } catch (ArrayIndexOutOfBoundsException e)
4603 // occasional No such child exceptions are thrown here...
4607 } catch (InterruptedException f)
4611 } while (frames == null);
4616 * Answers true if 'version' is equal to or later than 'supported', where each
4617 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4618 * changes. Development and test values for 'version' are leniently treated
4622 * - minimum version we are comparing against
4624 * - version of data being processsed
4627 public static boolean isVersionStringLaterThan(String supported,
4630 if (supported == null || version == null
4631 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4632 || version.equalsIgnoreCase("Test")
4633 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4635 System.err.println("Assuming project file with "
4636 + (version == null ? "null" : version)
4637 + " is compatible with Jalview version " + supported);
4642 return StringUtils.compareVersions(version, supported, "b") >= 0;
4646 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4648 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4650 if (newStructureViewers != null)
4652 sview.getBinding().setFinishedLoadingFromArchive(false);
4653 newStructureViewers.add(sview);
4657 protected void setLoadingFinishedForNewStructureViewers()
4659 if (newStructureViewers != null)
4661 for (JalviewStructureDisplayI sview : newStructureViewers)
4663 sview.getBinding().setFinishedLoadingFromArchive(true);
4665 newStructureViewers.clear();
4666 newStructureViewers = null;
4670 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4671 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4672 Viewport view, String uniqueSeqSetId, String viewId,
4673 List<JvAnnotRow> autoAlan)
4675 AlignFrame af = null;
4676 af = new AlignFrame(al, safeInt(view.getWidth()),
4677 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4681 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4682 // System.out.println("Jalview2XML AF " + e);
4683 // super.processKeyEvent(e);
4690 af.setFileName(file, FileFormat.Jalview);
4692 final AlignViewport viewport = af.getViewport();
4693 for (int i = 0; i < JSEQ.size(); i++)
4695 int colour = safeInt(JSEQ.get(i).getColour());
4696 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4702 viewport.setColourByReferenceSeq(true);
4703 viewport.setDisplayReferenceSeq(true);
4706 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4708 if (view.getSequenceSetId() != null)
4710 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4712 viewport.setSequenceSetId(uniqueSeqSetId);
4715 // propagate shared settings to this new view
4716 viewport.setHistoryList(av.getHistoryList());
4717 viewport.setRedoList(av.getRedoList());
4721 viewportsAdded.put(uniqueSeqSetId, viewport);
4723 // TODO: check if this method can be called repeatedly without
4724 // side-effects if alignpanel already registered.
4725 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4727 // apply Hidden regions to view.
4728 if (hiddenSeqs != null)
4730 for (int s = 0; s < JSEQ.size(); s++)
4732 SequenceGroup hidden = new SequenceGroup();
4733 boolean isRepresentative = false;
4734 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4736 isRepresentative = true;
4737 SequenceI sequenceToHide = al
4738 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4739 hidden.addSequence(sequenceToHide, false);
4740 // remove from hiddenSeqs list so we don't try to hide it twice
4741 hiddenSeqs.remove(sequenceToHide);
4743 if (isRepresentative)
4745 SequenceI representativeSequence = al.getSequenceAt(s);
4746 hidden.addSequence(representativeSequence, false);
4747 viewport.hideRepSequences(representativeSequence, hidden);
4751 SequenceI[] hseqs = hiddenSeqs
4752 .toArray(new SequenceI[hiddenSeqs.size()]);
4753 viewport.hideSequence(hseqs);
4756 // recover view properties and display parameters
4758 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4759 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4760 final int pidThreshold = safeInt(view.getPidThreshold());
4761 viewport.setThreshold(pidThreshold);
4763 viewport.setColourText(safeBoolean(view.isShowColourText()));
4765 viewport.setConservationSelected(
4766 safeBoolean(view.isConservationSelected()));
4767 viewport.setIncrement(safeInt(view.getConsThreshold()));
4768 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4769 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4770 viewport.setFont(new Font(view.getFontName(),
4771 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4773 ViewStyleI vs = viewport.getViewStyle();
4774 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4775 viewport.setViewStyle(vs);
4776 // TODO: allow custom charWidth/Heights to be restored by updating them
4777 // after setting font - which means set above to false
4778 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4779 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4780 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4782 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4784 viewport.setShowText(safeBoolean(view.isShowText()));
4786 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4787 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4788 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4789 viewport.setShowUnconserved(view.isShowUnconserved());
4790 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4792 if (view.getViewName() != null)
4794 viewport.setViewName(view.getViewName());
4795 af.setInitialTabVisible();
4797 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4798 safeInt(view.getWidth()), safeInt(view.getHeight()));
4799 // startSeq set in af.alignPanel.updateLayout below
4800 af.alignPanel.updateLayout();
4801 ColourSchemeI cs = null;
4802 // apply colourschemes
4803 if (view.getBgColour() != null)
4805 if (view.getBgColour().startsWith("ucs"))
4807 cs = getUserColourScheme(jm, view.getBgColour());
4809 else if (view.getBgColour().startsWith("Annotation"))
4811 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4812 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4819 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4820 view.getBgColour());
4825 * turn off 'alignment colour applies to all groups'
4826 * while restoring global colour scheme
4828 viewport.setColourAppliesToAllGroups(false);
4829 viewport.setGlobalColourScheme(cs);
4830 viewport.getResidueShading().setThreshold(pidThreshold,
4831 view.isIgnoreGapsinConsensus());
4832 viewport.getResidueShading()
4833 .setConsensus(viewport.getSequenceConsensusHash());
4834 if (safeBoolean(view.isConservationSelected()) && cs != null)
4836 viewport.getResidueShading()
4837 .setConservationInc(safeInt(view.getConsThreshold()));
4839 af.changeColour(cs);
4840 viewport.setColourAppliesToAllGroups(true);
4842 viewport.setShowSequenceFeatures(
4843 safeBoolean(view.isShowSequenceFeatures()));
4845 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4846 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4847 viewport.setFollowHighlight(view.isFollowHighlight());
4848 viewport.followSelection = view.isFollowSelection();
4849 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4850 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4851 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4852 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4853 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4854 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4855 viewport.setShowGroupConservation(view.isShowGroupConservation());
4856 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4857 viewport.setShowComplementFeaturesOnTop(
4858 view.isShowComplementFeaturesOnTop());
4860 // recover feature settings
4861 if (jm.getFeatureSettings() != null)
4863 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4864 .getFeatureRenderer();
4865 FeaturesDisplayed fdi;
4866 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4867 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
4869 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4870 Map<String, Float> featureOrder = new Hashtable<>();
4872 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
4875 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4876 String featureType = setting.getType();
4879 * restore feature filters (if any)
4881 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4883 if (filters != null)
4885 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
4887 if (!filter.isEmpty())
4889 fr.setFeatureFilter(featureType, filter);
4894 * restore feature colour scheme
4896 Color maxColour = new Color(setting.getColour());
4897 if (setting.getMincolour() != null)
4900 * minColour is always set unless a simple colour
4901 * (including for colour by label though it doesn't use it)
4903 Color minColour = new Color(setting.getMincolour().intValue());
4904 Color noValueColour = minColour;
4905 NoValueColour noColour = setting.getNoValueColour();
4906 if (noColour == NoValueColour.NONE)
4908 noValueColour = null;
4910 else if (noColour == NoValueColour.MAX)
4912 noValueColour = maxColour;
4914 float min = safeFloat(safeFloat(setting.getMin()));
4915 float max = setting.getMax() == null ? 1f
4916 : setting.getMax().floatValue();
4917 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4918 maxColour, noValueColour, min, max);
4919 if (setting.getAttributeName().size() > 0)
4921 gc.setAttributeName(setting.getAttributeName().toArray(
4922 new String[setting.getAttributeName().size()]));
4924 if (setting.getThreshold() != null)
4926 gc.setThreshold(setting.getThreshold().floatValue());
4927 int threshstate = safeInt(setting.getThreshstate());
4928 // -1 = None, 0 = Below, 1 = Above threshold
4929 if (threshstate == 0)
4931 gc.setBelowThreshold(true);
4933 else if (threshstate == 1)
4935 gc.setAboveThreshold(true);
4938 gc.setAutoScaled(true); // default
4939 if (setting.isAutoScale() != null)
4941 gc.setAutoScaled(setting.isAutoScale());
4943 if (setting.isColourByLabel() != null)
4945 gc.setColourByLabel(setting.isColourByLabel());
4947 // and put in the feature colour table.
4948 featureColours.put(featureType, gc);
4952 featureColours.put(featureType, new FeatureColour(maxColour));
4954 renderOrder[fs] = featureType;
4955 if (setting.getOrder() != null)
4957 featureOrder.put(featureType, setting.getOrder().floatValue());
4961 featureOrder.put(featureType, Float.valueOf(
4962 fs / jm.getFeatureSettings().getSetting().size()));
4964 if (safeBoolean(setting.isDisplay()))
4966 fdi.setVisible(featureType);
4969 Map<String, Boolean> fgtable = new Hashtable<>();
4970 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4972 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4973 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4975 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4976 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4977 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4978 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4979 fgtable, featureColours, 1.0f, featureOrder);
4980 fr.transferSettings(frs);
4983 if (view.getHiddenColumns().size() > 0)
4985 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4987 final HiddenColumns hc = view.getHiddenColumns().get(c);
4988 viewport.hideColumns(safeInt(hc.getStart()),
4989 safeInt(hc.getEnd()) /* +1 */);
4992 if (view.getCalcIdParam() != null)
4994 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4996 if (calcIdParam != null)
4998 if (recoverCalcIdParam(calcIdParam, viewport))
5003 warn("Couldn't recover parameters for "
5004 + calcIdParam.getCalcId());
5009 af.setMenusFromViewport(viewport);
5010 af.setTitle(view.getTitle());
5011 // TODO: we don't need to do this if the viewport is aready visible.
5013 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5014 * has a 'cdna/protein complement' view, in which case save it in order to
5015 * populate a SplitFrame once all views have been read in.
5017 String complementaryViewId = view.getComplementId();
5018 if (complementaryViewId == null)
5020 Desktop.addInternalFrame(af, view.getTitle(),
5021 safeInt(view.getWidth()), safeInt(view.getHeight()));
5022 // recompute any autoannotation
5023 af.alignPanel.updateAnnotation(false, true);
5024 reorderAutoannotation(af, al, autoAlan);
5025 af.alignPanel.alignmentChanged();
5029 splitFrameCandidates.put(view, af);
5036 * Reads saved data to restore Colour by Annotation settings
5038 * @param viewAnnColour
5042 * @param checkGroupAnnColour
5045 private ColourSchemeI constructAnnotationColour(
5046 AnnotationColourScheme viewAnnColour, AlignFrame af,
5047 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5049 boolean propagateAnnColour = false;
5050 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5052 if (checkGroupAnnColour && al.getGroups() != null
5053 && al.getGroups().size() > 0)
5055 // pre 2.8.1 behaviour
5056 // check to see if we should transfer annotation colours
5057 propagateAnnColour = true;
5058 for (SequenceGroup sg : al.getGroups())
5060 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5062 propagateAnnColour = false;
5068 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5070 String annotationId = viewAnnColour.getAnnotation();
5071 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5074 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5076 if (matchedAnnotation == null
5077 && annAlignment.getAlignmentAnnotation() != null)
5079 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5082 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5084 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5089 if (matchedAnnotation == null)
5091 System.err.println("Failed to match annotation colour scheme for "
5095 if (matchedAnnotation.getThreshold() == null)
5097 matchedAnnotation.setThreshold(
5098 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5099 "Threshold", Color.black));
5102 AnnotationColourGradient cs = null;
5103 if (viewAnnColour.getColourScheme().equals("None"))
5105 cs = new AnnotationColourGradient(matchedAnnotation,
5106 new Color(safeInt(viewAnnColour.getMinColour())),
5107 new Color(safeInt(viewAnnColour.getMaxColour())),
5108 safeInt(viewAnnColour.getAboveThreshold()));
5110 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5112 cs = new AnnotationColourGradient(matchedAnnotation,
5113 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5114 safeInt(viewAnnColour.getAboveThreshold()));
5118 cs = new AnnotationColourGradient(matchedAnnotation,
5119 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5120 viewAnnColour.getColourScheme()),
5121 safeInt(viewAnnColour.getAboveThreshold()));
5124 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5125 boolean useOriginalColours = safeBoolean(
5126 viewAnnColour.isPredefinedColours());
5127 cs.setSeqAssociated(perSequenceOnly);
5128 cs.setPredefinedColours(useOriginalColours);
5130 if (propagateAnnColour && al.getGroups() != null)
5132 // Also use these settings for all the groups
5133 for (int g = 0; g < al.getGroups().size(); g++)
5135 SequenceGroup sg = al.getGroups().get(g);
5136 if (sg.getGroupColourScheme() == null)
5141 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5142 matchedAnnotation, sg.getColourScheme(),
5143 safeInt(viewAnnColour.getAboveThreshold()));
5144 sg.setColourScheme(groupScheme);
5145 groupScheme.setSeqAssociated(perSequenceOnly);
5146 groupScheme.setPredefinedColours(useOriginalColours);
5152 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5153 List<JvAnnotRow> autoAlan)
5155 // copy over visualization settings for autocalculated annotation in the
5157 if (al.getAlignmentAnnotation() != null)
5160 * Kludge for magic autoannotation names (see JAL-811)
5162 String[] magicNames = new String[] { "Consensus", "Quality",
5164 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5165 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5166 for (String nm : magicNames)
5168 visan.put(nm, nullAnnot);
5170 for (JvAnnotRow auan : autoAlan)
5172 visan.put(auan.template.label
5173 + (auan.template.getCalcId() == null ? ""
5174 : "\t" + auan.template.getCalcId()),
5177 int hSize = al.getAlignmentAnnotation().length;
5178 List<JvAnnotRow> reorder = new ArrayList<>();
5179 // work through any autoCalculated annotation already on the view
5180 // removing it if it should be placed in a different location on the
5181 // annotation panel.
5182 List<String> remains = new ArrayList<>(visan.keySet());
5183 for (int h = 0; h < hSize; h++)
5185 jalview.datamodel.AlignmentAnnotation jalan = al
5186 .getAlignmentAnnotation()[h];
5187 if (jalan.autoCalculated)
5190 JvAnnotRow valan = visan.get(k = jalan.label);
5191 if (jalan.getCalcId() != null)
5193 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5198 // delete the auto calculated row from the alignment
5199 al.deleteAnnotation(jalan, false);
5203 if (valan != nullAnnot)
5205 if (jalan != valan.template)
5207 // newly created autoannotation row instance
5208 // so keep a reference to the visible annotation row
5209 // and copy over all relevant attributes
5210 if (valan.template.graphHeight >= 0)
5213 jalan.graphHeight = valan.template.graphHeight;
5215 jalan.visible = valan.template.visible;
5217 reorder.add(new JvAnnotRow(valan.order, jalan));
5222 // Add any (possibly stale) autocalculated rows that were not appended to
5223 // the view during construction
5224 for (String other : remains)
5226 JvAnnotRow othera = visan.get(other);
5227 if (othera != nullAnnot && othera.template.getCalcId() != null
5228 && othera.template.getCalcId().length() > 0)
5230 reorder.add(othera);
5233 // now put the automatic annotation in its correct place
5234 int s = 0, srt[] = new int[reorder.size()];
5235 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5236 for (JvAnnotRow jvar : reorder)
5239 srt[s++] = jvar.order;
5242 jalview.util.QuickSort.sort(srt, rws);
5243 // and re-insert the annotation at its correct position
5244 for (JvAnnotRow jvar : rws)
5246 al.addAnnotation(jvar.template, jvar.order);
5248 af.alignPanel.adjustAnnotationHeight();
5252 Hashtable skipList = null;
5255 * TODO remove this method
5258 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5259 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5260 * throw new Error("Implementation Error. No skipList defined for this
5261 * Jalview2XML instance."); } return (AlignFrame)
5262 * skipList.get(view.getSequenceSetId()); }
5266 * Check if the Jalview view contained in object should be skipped or not.
5269 * @return true if view's sequenceSetId is a key in skipList
5271 private boolean skipViewport(JalviewModel object)
5273 if (skipList == null)
5277 String id = object.getViewport().get(0).getSequenceSetId();
5278 if (skipList.containsKey(id))
5280 if (Cache.log != null && Cache.log.isDebugEnabled())
5282 Cache.log.debug("Skipping seuqence set id " + id);
5289 public void addToSkipList(AlignFrame af)
5291 if (skipList == null)
5293 skipList = new Hashtable();
5295 skipList.put(af.getViewport().getSequenceSetId(), af);
5298 public void clearSkipList()
5300 if (skipList != null)
5307 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5308 boolean ignoreUnrefed, String uniqueSeqSetId)
5310 jalview.datamodel.AlignmentI ds = getDatasetFor(
5311 vamsasSet.getDatasetId());
5312 AlignmentI xtant_ds = ds;
5313 if (xtant_ds == null)
5315 // good chance we are about to create a new dataset, but check if we've
5316 // seen some of the dataset sequence IDs before.
5317 // TODO: skip this check if we are working with project generated by
5318 // version 2.11 or later
5319 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5320 if (xtant_ds != null)
5323 addDatasetRef(vamsasSet.getDatasetId(), ds);
5326 Vector<SequenceI> dseqs = null;
5329 // recovering an alignment View
5330 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5331 if (seqSetDS != null)
5333 if (ds != null && ds != seqSetDS)
5335 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5336 + " - CDS/Protein crossreference data may be lost");
5337 if (xtant_ds != null)
5339 // This can only happen if the unique sequence set ID was bound to a
5340 // dataset that did not contain any of the sequences in the view
5341 // currently being restored.
5342 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.");
5346 addDatasetRef(vamsasSet.getDatasetId(), ds);
5351 // try even harder to restore dataset
5352 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5353 // create a list of new dataset sequences
5354 dseqs = new Vector<>();
5356 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5358 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5359 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5361 // create a new dataset
5364 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5365 dseqs.copyInto(dsseqs);
5366 ds = new jalview.datamodel.Alignment(dsseqs);
5367 debug("Created new dataset " + vamsasSet.getDatasetId()
5368 + " for alignment " + System.identityHashCode(al));
5369 addDatasetRef(vamsasSet.getDatasetId(), ds);
5371 // set the dataset for the newly imported alignment.
5372 if (al.getDataset() == null && !ignoreUnrefed)
5375 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5376 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5378 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5382 * XML dataset sequence ID to materialised dataset reference
5384 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5387 * @return the first materialised dataset reference containing a dataset
5388 * sequence referenced in the given view
5390 * - sequences from the view
5392 AlignmentI checkIfHasDataset(List<Sequence> list)
5394 for (Sequence restoredSeq : list)
5396 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5397 if (datasetFor != null)
5406 * Register ds as the containing dataset for the dataset sequences referenced
5407 * by sequences in list
5410 * - sequences in a view
5413 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5415 for (Sequence restoredSeq : list)
5417 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5418 if (prevDS != null && prevDS != ds)
5420 warn("Dataset sequence appears in many datasets: "
5421 + restoredSeq.getDsseqid());
5422 // TODO: try to merge!
5430 * sequence definition to create/merge dataset sequence for
5434 * vector to add new dataset sequence to
5435 * @param ignoreUnrefed
5436 * - when true, don't create new sequences from vamsasSeq if it's id
5437 * doesn't already have an asssociated Jalview sequence.
5439 * - used to reorder the sequence in the alignment according to the
5440 * vamsasSeq array ordering, to preserve ordering of dataset
5442 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5443 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5446 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5448 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5449 boolean reorder = false;
5450 SequenceI dsq = null;
5451 if (sq != null && sq.getDatasetSequence() != null)
5453 dsq = sq.getDatasetSequence();
5459 if (sq == null && ignoreUnrefed)
5463 String sqid = vamsasSeq.getDsseqid();
5466 // need to create or add a new dataset sequence reference to this sequence
5469 dsq = seqRefIds.get(sqid);
5474 // make a new dataset sequence
5475 dsq = sq.createDatasetSequence();
5478 // make up a new dataset reference for this sequence
5479 sqid = seqHash(dsq);
5481 dsq.setVamsasId(uniqueSetSuffix + sqid);
5482 seqRefIds.put(sqid, dsq);
5487 dseqs.addElement(dsq);
5492 ds.addSequence(dsq);
5498 { // make this dataset sequence sq's dataset sequence
5499 sq.setDatasetSequence(dsq);
5500 // and update the current dataset alignment
5505 if (!dseqs.contains(dsq))
5512 if (ds.findIndex(dsq) < 0)
5514 ds.addSequence(dsq);
5521 // TODO: refactor this as a merge dataset sequence function
5522 // now check that sq (the dataset sequence) sequence really is the union of
5523 // all references to it
5524 // boolean pre = sq.getStart() < dsq.getStart();
5525 // boolean post = sq.getEnd() > dsq.getEnd();
5529 // StringBuffer sb = new StringBuffer();
5530 String newres = jalview.analysis.AlignSeq.extractGaps(
5531 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5532 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5533 && newres.length() > dsq.getLength())
5535 // Update with the longer sequence.
5539 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5540 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5541 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5542 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5544 dsq.setSequence(newres);
5546 // TODO: merges will never happen if we 'know' we have the real dataset
5547 // sequence - this should be detected when id==dssid
5549 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5550 // + (pre ? "prepended" : "") + " "
5551 // + (post ? "appended" : ""));
5556 // sequence refs are identical. We may need to update the existing dataset
5557 // alignment with this one, though.
5558 if (ds != null && dseqs == null)
5560 int opos = ds.findIndex(dsq);
5561 SequenceI tseq = null;
5562 if (opos != -1 && vseqpos != opos)
5564 // remove from old position
5565 ds.deleteSequence(dsq);
5567 if (vseqpos < ds.getHeight())
5569 if (vseqpos != opos)
5571 // save sequence at destination position
5572 tseq = ds.getSequenceAt(vseqpos);
5573 ds.replaceSequenceAt(vseqpos, dsq);
5574 ds.addSequence(tseq);
5579 ds.addSequence(dsq);
5586 * TODO use AlignmentI here and in related methods - needs
5587 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5589 Hashtable<String, AlignmentI> datasetIds = null;
5591 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5593 private AlignmentI getDatasetFor(String datasetId)
5595 if (datasetIds == null)
5597 datasetIds = new Hashtable<>();
5600 if (datasetIds.containsKey(datasetId))
5602 return datasetIds.get(datasetId);
5607 private void addDatasetRef(String datasetId, AlignmentI dataset)
5609 if (datasetIds == null)
5611 datasetIds = new Hashtable<>();
5613 datasetIds.put(datasetId, dataset);
5617 * make a new dataset ID for this jalview dataset alignment
5622 private String getDatasetIdRef(AlignmentI dataset)
5624 if (dataset.getDataset() != null)
5626 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5628 String datasetId = makeHashCode(dataset, null);
5629 if (datasetId == null)
5631 // make a new datasetId and record it
5632 if (dataset2Ids == null)
5634 dataset2Ids = new IdentityHashMap<>();
5638 datasetId = dataset2Ids.get(dataset);
5640 if (datasetId == null)
5642 datasetId = "ds" + dataset2Ids.size() + 1;
5643 dataset2Ids.put(dataset, datasetId);
5650 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5651 * constructed as a special subclass GeneLocus.
5653 * @param datasetSequence
5656 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5658 for (int d = 0; d < sequence.getDBRef().size(); d++)
5660 DBRef dr = sequence.getDBRef().get(d);
5664 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5665 dr.getAccessionId());
5669 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5670 dr.getAccessionId());
5672 if (dr.getMapping() != null)
5674 entry.setMap(addMapping(dr.getMapping()));
5676 entry.setCanonical(dr.isCanonical());
5677 datasetSequence.addDBRef(entry);
5681 private jalview.datamodel.Mapping addMapping(Mapping m)
5683 SequenceI dsto = null;
5684 // Mapping m = dr.getMapping();
5685 int fr[] = new int[m.getMapListFrom().size() * 2];
5686 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5687 for (int _i = 0; from.hasNext(); _i += 2)
5689 MapListFrom mf = from.next();
5690 fr[_i] = mf.getStart();
5691 fr[_i + 1] = mf.getEnd();
5693 int fto[] = new int[m.getMapListTo().size() * 2];
5694 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5695 for (int _i = 0; to.hasNext(); _i += 2)
5697 MapListTo mf = to.next();
5698 fto[_i] = mf.getStart();
5699 fto[_i + 1] = mf.getEnd();
5701 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5702 fto, m.getMapFromUnit().intValue(),
5703 m.getMapToUnit().intValue());
5706 * (optional) choice of dseqFor or Sequence
5708 if (m.getDseqFor() != null)
5710 String dsfor = m.getDseqFor();
5711 if (seqRefIds.containsKey(dsfor))
5716 jmap.setTo(seqRefIds.get(dsfor));
5720 frefedSequence.add(newMappingRef(dsfor, jmap));
5723 else if (m.getSequence() != null)
5726 * local sequence definition
5728 Sequence ms = m.getSequence();
5729 SequenceI djs = null;
5730 String sqid = ms.getDsseqid();
5731 if (sqid != null && sqid.length() > 0)
5734 * recover dataset sequence
5736 djs = seqRefIds.get(sqid);
5741 "Warning - making up dataset sequence id for DbRef sequence map reference");
5742 sqid = ((Object) ms).toString(); // make up a new hascode for
5743 // undefined dataset sequence hash
5744 // (unlikely to happen)
5750 * make a new dataset sequence and add it to refIds hash
5752 djs = new jalview.datamodel.Sequence(ms.getName(),
5754 djs.setStart(jmap.getMap().getToLowest());
5755 djs.setEnd(jmap.getMap().getToHighest());
5756 djs.setVamsasId(uniqueSetSuffix + sqid);
5758 incompleteSeqs.put(sqid, djs);
5759 seqRefIds.put(sqid, djs);
5762 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5771 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5772 * view as XML (but not to file), and then reloading it
5777 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5780 JalviewModel jm = saveState(ap, null, null, null);
5783 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5784 ap.getAlignment().getDataset());
5786 uniqueSetSuffix = "";
5787 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5788 jm.getViewport().get(0).setId(null);
5789 // we don't overwrite the view we just copied
5791 if (this.frefedSequence == null)
5793 frefedSequence = new Vector<>();
5796 viewportsAdded.clear();
5798 AlignFrame af = loadFromObject(jm, null, false, null);
5799 af.getAlignPanels().clear();
5800 af.closeMenuItem_actionPerformed(true);
5803 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5804 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5805 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5806 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5807 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5810 return af.alignPanel;
5813 private Hashtable jvids2vobj;
5815 private void warn(String msg)
5820 private void warn(String msg, Exception e)
5822 if (Cache.log != null)
5826 Cache.log.warn(msg, e);
5830 Cache.log.warn(msg);
5835 System.err.println("Warning: " + msg);
5838 e.printStackTrace();
5843 private void debug(String string)
5845 debug(string, null);
5848 private void debug(String msg, Exception e)
5850 if (Cache.log != null)
5854 Cache.log.debug(msg, e);
5858 Cache.log.debug(msg);
5863 System.err.println("Warning: " + msg);
5866 e.printStackTrace();
5872 * set the object to ID mapping tables used to write/recover objects and XML
5873 * ID strings for the jalview project. If external tables are provided then
5874 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5875 * object goes out of scope. - also populates the datasetIds hashtable with
5876 * alignment objects containing dataset sequences
5879 * Map from ID strings to jalview datamodel
5881 * Map from jalview datamodel to ID strings
5885 public void setObjectMappingTables(Hashtable vobj2jv,
5886 IdentityHashMap jv2vobj)
5888 this.jv2vobj = jv2vobj;
5889 this.vobj2jv = vobj2jv;
5890 Iterator ds = jv2vobj.keySet().iterator();
5892 while (ds.hasNext())
5894 Object jvobj = ds.next();
5895 id = jv2vobj.get(jvobj).toString();
5896 if (jvobj instanceof jalview.datamodel.Alignment)
5898 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5900 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5903 else if (jvobj instanceof jalview.datamodel.Sequence)
5905 // register sequence object so the XML parser can recover it.
5906 if (seqRefIds == null)
5908 seqRefIds = new HashMap<>();
5910 if (seqsToIds == null)
5912 seqsToIds = new IdentityHashMap<>();
5914 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5915 seqsToIds.put((SequenceI) jvobj, id);
5917 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5920 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5921 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5922 if (jvann.annotationId == null)
5924 jvann.annotationId = anid;
5926 if (!jvann.annotationId.equals(anid))
5928 // TODO verify that this is the correct behaviour
5929 this.warn("Overriding Annotation ID for " + anid
5930 + " from different id : " + jvann.annotationId);
5931 jvann.annotationId = anid;
5934 else if (jvobj instanceof String)
5936 if (jvids2vobj == null)
5938 jvids2vobj = new Hashtable();
5939 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5944 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5950 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5951 * objects created from the project archive. If string is null (default for
5952 * construction) then suffix will be set automatically.
5956 public void setUniqueSetSuffix(String string)
5958 uniqueSetSuffix = string;
5963 * uses skipList2 as the skipList for skipping views on sequence sets
5964 * associated with keys in the skipList
5968 public void setSkipList(Hashtable skipList2)
5970 skipList = skipList2;
5974 * Reads the jar entry of given name and returns its contents, or null if the
5975 * entry is not found.
5978 * @param jarEntryName
5981 protected String readJarEntry(jarInputStreamProvider jprovider,
5982 String jarEntryName)
5984 String result = null;
5985 BufferedReader in = null;
5990 * Reopen the jar input stream and traverse its entries to find a matching
5993 JarInputStream jin = jprovider.getJarInputStream();
5994 JarEntry entry = null;
5997 entry = jin.getNextJarEntry();
5998 } while (entry != null && !entry.getName().equals(jarEntryName));
6002 StringBuilder out = new StringBuilder(256);
6003 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6006 while ((data = in.readLine()) != null)
6010 result = out.toString();
6014 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6016 } catch (Exception ex)
6018 ex.printStackTrace();
6026 } catch (IOException e)
6037 * Returns an incrementing counter (0, 1, 2...)
6041 private synchronized int nextCounter()
6047 * Loads any saved PCA viewers
6052 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6056 List<PcaViewer> pcaviewers = model.getPcaViewer();
6057 for (PcaViewer viewer : pcaviewers)
6059 String modelName = viewer.getScoreModelName();
6060 SimilarityParamsI params = new SimilarityParams(
6061 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6062 viewer.isIncludeGaps(),
6063 viewer.isDenominateByShortestLength());
6066 * create the panel (without computing the PCA)
6068 PCAPanel panel = new PCAPanel(ap, modelName, params);
6070 panel.setTitle(viewer.getTitle());
6071 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6072 viewer.getWidth(), viewer.getHeight()));
6074 boolean showLabels = viewer.isShowLabels();
6075 panel.setShowLabels(showLabels);
6076 panel.getRotatableCanvas().setShowLabels(showLabels);
6077 panel.getRotatableCanvas()
6078 .setBgColour(new Color(viewer.getBgColour()));
6079 panel.getRotatableCanvas()
6080 .setApplyToAllViews(viewer.isLinkToAllViews());
6083 * load PCA output data
6085 ScoreModelI scoreModel = ScoreModels.getInstance()
6086 .getScoreModel(modelName, ap);
6087 PCA pca = new PCA(null, scoreModel, params);
6088 PcaDataType pcaData = viewer.getPcaData();
6090 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6091 pca.setPairwiseScores(pairwise);
6093 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6094 pca.setTridiagonal(triDiag);
6096 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6097 pca.setEigenmatrix(result);
6099 panel.getPcaModel().setPCA(pca);
6102 * we haven't saved the input data! (JAL-2647 to do)
6104 panel.setInputData(null);
6107 * add the sequence points for the PCA display
6109 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6110 for (SequencePoint sp : viewer.getSequencePoint())
6112 String seqId = sp.getSequenceRef();
6113 SequenceI seq = seqRefIds.get(seqId);
6116 throw new IllegalStateException(
6117 "Unmatched seqref for PCA: " + seqId);
6119 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6120 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6122 seqPoints.add(seqPoint);
6124 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6127 * set min-max ranges and scale after setPoints (which recomputes them)
6129 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6130 SeqPointMin spMin = viewer.getSeqPointMin();
6131 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6133 SeqPointMax spMax = viewer.getSeqPointMax();
6134 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6136 panel.getRotatableCanvas().setSeqMinMax(min, max);
6138 // todo: hold points list in PCAModel only
6139 panel.getPcaModel().setSequencePoints(seqPoints);
6141 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6142 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6143 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6145 // is this duplication needed?
6146 panel.setTop(seqPoints.size() - 1);
6147 panel.getPcaModel().setTop(seqPoints.size() - 1);
6150 * add the axes' end points for the display
6152 for (int i = 0; i < 3; i++)
6154 Axis axis = viewer.getAxis().get(i);
6155 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6156 axis.getXPos(), axis.getYPos(), axis.getZPos());
6159 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6160 "label.calc_title", "PCA", modelName), 475, 450);
6162 } catch (Exception ex)
6164 Cache.log.error("Error loading PCA: " + ex.toString());
6169 * Creates a new structure viewer window
6176 protected void createStructureViewer(ViewerType viewerType,
6177 final Entry<String, StructureViewerModel> viewerData,
6178 AlignFrame af, jarInputStreamProvider jprovider)
6180 final StructureViewerModel viewerModel = viewerData.getValue();
6181 String sessionFilePath = null;
6183 if (viewerType == ViewerType.JMOL)
6185 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6189 String viewerJarEntryName = getViewerJarEntryName(
6190 viewerModel.getViewId());
6191 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6192 "viewerSession", ".tmp");
6194 final String sessionPath = sessionFilePath;
6195 final String sviewid = viewerData.getKey();
6198 SwingUtilities.invokeAndWait(new Runnable()
6203 JalviewStructureDisplayI sview = null;
6206 sview = StructureViewer.createView(viewerType, af.alignPanel,
6207 viewerModel, sessionPath, sviewid);
6208 addNewStructureViewer(sview);
6209 } catch (OutOfMemoryError ex)
6211 new OOMWarning("Restoring structure view for " + viewerType,
6212 (OutOfMemoryError) ex.getCause());
6213 if (sview != null && sview.isVisible())
6215 sview.closeViewer(false);
6216 sview.setVisible(false);
6222 } catch (InvocationTargetException | InterruptedException ex)
6224 warn("Unexpected error when opening " + viewerType
6225 + " structure viewer", ex);
6230 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6231 * the path of the file. "load file" commands are rewritten to change the
6232 * original PDB file names to those created as the Jalview project is loaded.
6238 private String rewriteJmolSession(StructureViewerModel svattrib,
6239 jarInputStreamProvider jprovider)
6241 String state = svattrib.getStateData(); // Jalview < 2.9
6242 if (state == null || state.isEmpty()) // Jalview >= 2.9
6244 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6245 state = readJarEntry(jprovider, jarEntryName);
6247 // TODO or simpler? for each key in oldFiles,
6248 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6249 // (allowing for different path escapings)
6250 StringBuilder rewritten = new StringBuilder(state.length());
6251 int cp = 0, ncp, ecp;
6252 Map<File, StructureData> oldFiles = svattrib.getFileData();
6253 while ((ncp = state.indexOf("load ", cp)) > -1)
6257 // look for next filename in load statement
6258 rewritten.append(state.substring(cp,
6259 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6260 String oldfilenam = state.substring(ncp,
6261 ecp = state.indexOf("\"", ncp));
6262 // recover the new mapping data for this old filename
6263 // have to normalize filename - since Jmol and jalview do
6264 // filename translation differently.
6265 StructureData filedat = oldFiles.get(new File(oldfilenam));
6266 if (filedat == null)
6268 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6269 filedat = oldFiles.get(new File(reformatedOldFilename));
6271 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6272 rewritten.append("\"");
6273 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6274 // look for next file statement.
6275 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6279 // just append rest of state
6280 rewritten.append(state.substring(cp));
6284 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6285 rewritten = new StringBuilder(state);
6286 rewritten.append("; load append ");
6287 for (File id : oldFiles.keySet())
6289 // add pdb files that should be present in the viewer
6290 StructureData filedat = oldFiles.get(id);
6291 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6293 rewritten.append(";");
6296 if (rewritten.length() == 0)
6300 final String history = "history = ";
6301 int historyIndex = rewritten.indexOf(history);
6302 if (historyIndex > -1)
6305 * change "history = [true|false];" to "history = [1|0];"
6307 historyIndex += history.length();
6308 String val = rewritten.substring(historyIndex, historyIndex + 5);
6309 if (val.startsWith("true"))
6311 rewritten.replace(historyIndex, historyIndex + 4, "1");
6313 else if (val.startsWith("false"))
6315 rewritten.replace(historyIndex, historyIndex + 5, "0");
6321 File tmp = File.createTempFile("viewerSession", ".tmp");
6322 try (OutputStream os = new FileOutputStream(tmp))
6324 InputStream is = new ByteArrayInputStream(
6325 rewritten.toString().getBytes());
6327 return tmp.getAbsolutePath();
6329 } catch (IOException e)
6331 Cache.log.error("Error restoring Jmol session: " + e.toString());
6337 * Populates an XML model of the feature colour scheme for one feature type
6339 * @param featureType
6343 public static Colour marshalColour(String featureType,
6344 FeatureColourI fcol)
6346 Colour col = new Colour();
6347 if (fcol.isSimpleColour())
6349 col.setRGB(Format.getHexString(fcol.getColour()));
6353 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6354 col.setMin(fcol.getMin());
6355 col.setMax(fcol.getMax());
6356 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6357 col.setAutoScale(fcol.isAutoScaled());
6358 col.setThreshold(fcol.getThreshold());
6359 col.setColourByLabel(fcol.isColourByLabel());
6360 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6361 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6362 : ThresholdType.NONE));
6363 if (fcol.isColourByAttribute())
6365 final String[] attName = fcol.getAttributeName();
6366 col.getAttributeName().add(attName[0]);
6367 if (attName.length > 1)
6369 col.getAttributeName().add(attName[1]);
6372 Color noColour = fcol.getNoColour();
6373 if (noColour == null)
6375 col.setNoValueColour(NoValueColour.NONE);
6377 else if (noColour == fcol.getMaxColour())
6379 col.setNoValueColour(NoValueColour.MAX);
6383 col.setNoValueColour(NoValueColour.MIN);
6386 col.setName(featureType);
6391 * Populates an XML model of the feature filter(s) for one feature type
6393 * @param firstMatcher
6394 * the first (or only) match condition)
6396 * remaining match conditions (if any)
6398 * if true, conditions are and-ed, else or-ed
6400 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6401 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6404 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6406 if (filters.hasNext())
6411 CompoundMatcher compound = new CompoundMatcher();
6412 compound.setAnd(and);
6413 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6414 firstMatcher, Collections.emptyIterator(), and);
6415 // compound.addMatcherSet(matcher1);
6416 compound.getMatcherSet().add(matcher1);
6417 FeatureMatcherI nextMatcher = filters.next();
6418 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6419 nextMatcher, filters, and);
6420 // compound.addMatcherSet(matcher2);
6421 compound.getMatcherSet().add(matcher2);
6422 result.setCompoundMatcher(compound);
6427 * single condition matcher
6429 // MatchCondition matcherModel = new MatchCondition();
6430 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6431 matcherModel.setCondition(
6432 firstMatcher.getMatcher().getCondition().getStableName());
6433 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6434 if (firstMatcher.isByAttribute())
6436 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6437 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6438 String[] attName = firstMatcher.getAttribute();
6439 matcherModel.getAttributeName().add(attName[0]); // attribute
6440 if (attName.length > 1)
6442 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6445 else if (firstMatcher.isByLabel())
6447 matcherModel.setBy(FilterBy.BY_LABEL);
6449 else if (firstMatcher.isByScore())
6451 matcherModel.setBy(FilterBy.BY_SCORE);
6453 result.setMatchCondition(matcherModel);
6460 * Loads one XML model of a feature filter to a Jalview object
6462 * @param featureType
6463 * @param matcherSetModel
6466 public static FeatureMatcherSetI parseFilter(String featureType,
6467 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6469 FeatureMatcherSetI result = new FeatureMatcherSet();
6472 parseFilterConditions(result, matcherSetModel, true);
6473 } catch (IllegalStateException e)
6475 // mixing AND and OR conditions perhaps
6477 String.format("Error reading filter conditions for '%s': %s",
6478 featureType, e.getMessage()));
6479 // return as much as was parsed up to the error
6486 * Adds feature match conditions to matcherSet as unmarshalled from XML
6487 * (possibly recursively for compound conditions)
6490 * @param matcherSetModel
6492 * if true, multiple conditions are AND-ed, else they are OR-ed
6493 * @throws IllegalStateException
6494 * if AND and OR conditions are mixed
6496 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6497 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6500 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6501 .getMatchCondition();
6507 FilterBy filterBy = mc.getBy();
6508 Condition cond = Condition.fromString(mc.getCondition());
6509 String pattern = mc.getValue();
6510 FeatureMatcherI matchCondition = null;
6511 if (filterBy == FilterBy.BY_LABEL)
6513 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6515 else if (filterBy == FilterBy.BY_SCORE)
6517 matchCondition = FeatureMatcher.byScore(cond, pattern);
6520 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6522 final List<String> attributeName = mc.getAttributeName();
6523 String[] attNames = attributeName
6524 .toArray(new String[attributeName.size()]);
6525 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6530 * note this throws IllegalStateException if AND-ing to a
6531 * previously OR-ed compound condition, or vice versa
6535 matcherSet.and(matchCondition);
6539 matcherSet.or(matchCondition);
6545 * compound condition
6547 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6548 .getCompoundMatcher().getMatcherSet();
6549 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6550 if (matchers.size() == 2)
6552 parseFilterConditions(matcherSet, matchers.get(0), anded);
6553 parseFilterConditions(matcherSet, matchers.get(1), anded);
6557 System.err.println("Malformed compound filter condition");
6563 * Loads one XML model of a feature colour to a Jalview object
6565 * @param colourModel
6568 public static FeatureColourI parseColour(Colour colourModel)
6570 FeatureColourI colour = null;
6572 if (colourModel.getMax() != null)
6574 Color mincol = null;
6575 Color maxcol = null;
6576 Color noValueColour = null;
6580 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6581 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6582 } catch (Exception e)
6584 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6587 NoValueColour noCol = colourModel.getNoValueColour();
6588 if (noCol == NoValueColour.MIN)
6590 noValueColour = mincol;
6592 else if (noCol == NoValueColour.MAX)
6594 noValueColour = maxcol;
6597 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6598 safeFloat(colourModel.getMin()),
6599 safeFloat(colourModel.getMax()));
6600 final List<String> attributeName = colourModel.getAttributeName();
6601 String[] attributes = attributeName
6602 .toArray(new String[attributeName.size()]);
6603 if (attributes != null && attributes.length > 0)
6605 colour.setAttributeName(attributes);
6607 if (colourModel.isAutoScale() != null)
6609 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6611 if (colourModel.isColourByLabel() != null)
6613 colour.setColourByLabel(
6614 colourModel.isColourByLabel().booleanValue());
6616 if (colourModel.getThreshold() != null)
6618 colour.setThreshold(colourModel.getThreshold().floatValue());
6620 ThresholdType ttyp = colourModel.getThreshType();
6621 if (ttyp == ThresholdType.ABOVE)
6623 colour.setAboveThreshold(true);
6625 else if (ttyp == ThresholdType.BELOW)
6627 colour.setBelowThreshold(true);
6632 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6633 colour = new FeatureColour(color);