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;
32 import java.io.DataInputStream;
33 import java.io.DataOutputStream;
35 import java.io.FileInputStream;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.InputStreamReader;
40 import java.io.OutputStream;
41 import java.io.OutputStreamWriter;
42 import java.io.PrintWriter;
43 import java.lang.reflect.InvocationTargetException;
44 import java.math.BigInteger;
45 import java.net.MalformedURLException;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collections;
50 import java.util.Enumeration;
51 import java.util.GregorianCalendar;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Hashtable;
55 import java.util.IdentityHashMap;
56 import java.util.Iterator;
57 import java.util.LinkedHashMap;
58 import java.util.List;
60 import java.util.Map.Entry;
62 import java.util.Vector;
63 import java.util.jar.JarEntry;
64 import java.util.jar.JarInputStream;
65 import java.util.jar.JarOutputStream;
67 import javax.swing.JInternalFrame;
68 import javax.swing.SwingUtilities;
69 import javax.xml.bind.JAXBContext;
70 import javax.xml.bind.JAXBElement;
71 import javax.xml.bind.Marshaller;
72 import javax.xml.datatype.DatatypeConfigurationException;
73 import javax.xml.datatype.DatatypeFactory;
74 import javax.xml.datatype.XMLGregorianCalendar;
75 import javax.xml.stream.XMLInputFactory;
76 import javax.xml.stream.XMLStreamReader;
78 import jalview.analysis.Conservation;
79 import jalview.analysis.PCA;
80 import jalview.analysis.scoremodels.ScoreModels;
81 import jalview.analysis.scoremodels.SimilarityParams;
82 import jalview.api.FeatureColourI;
83 import jalview.api.ViewStyleI;
84 import jalview.api.analysis.ScoreModelI;
85 import jalview.api.analysis.SimilarityParamsI;
86 import jalview.api.structures.JalviewStructureDisplayI;
87 import jalview.bin.Cache;
88 import jalview.datamodel.AlignedCodonFrame;
89 import jalview.datamodel.Alignment;
90 import jalview.datamodel.AlignmentAnnotation;
91 import jalview.datamodel.AlignmentI;
92 import jalview.datamodel.DBRefEntry;
93 import jalview.datamodel.GeneLocus;
94 import jalview.datamodel.GraphLine;
95 import jalview.datamodel.PDBEntry;
96 import jalview.datamodel.Point;
97 import jalview.datamodel.RnaViewerModel;
98 import jalview.datamodel.SequenceFeature;
99 import jalview.datamodel.SequenceGroup;
100 import jalview.datamodel.SequenceI;
101 import jalview.datamodel.StructureViewerModel;
102 import jalview.datamodel.StructureViewerModel.StructureData;
103 import jalview.datamodel.features.FeatureMatcher;
104 import jalview.datamodel.features.FeatureMatcherI;
105 import jalview.datamodel.features.FeatureMatcherSet;
106 import jalview.datamodel.features.FeatureMatcherSetI;
107 import jalview.ext.varna.RnaModel;
108 import jalview.gui.AlignFrame;
109 import jalview.gui.AlignViewport;
110 import jalview.gui.AlignmentPanel;
111 import jalview.gui.AppVarna;
112 import jalview.gui.ChimeraViewFrame;
113 import jalview.gui.Desktop;
114 import jalview.gui.JvOptionPane;
115 import jalview.gui.OOMWarning;
116 import jalview.gui.PCAPanel;
117 import jalview.gui.PaintRefresher;
118 import jalview.gui.SplitFrame;
119 import jalview.gui.StructureViewer;
120 import jalview.gui.StructureViewer.ViewerType;
121 import jalview.gui.StructureViewerBase;
122 import jalview.gui.TreePanel;
123 import jalview.io.BackupFiles;
124 import jalview.io.DataSourceType;
125 import jalview.io.FileFormat;
126 import jalview.io.NewickFile;
127 import jalview.math.Matrix;
128 import jalview.math.MatrixI;
129 import jalview.renderer.ResidueShaderI;
130 import jalview.schemes.AnnotationColourGradient;
131 import jalview.schemes.ColourSchemeI;
132 import jalview.schemes.ColourSchemeProperty;
133 import jalview.schemes.FeatureColour;
134 import jalview.schemes.ResidueProperties;
135 import jalview.schemes.UserColourScheme;
136 import jalview.structure.StructureSelectionManager;
137 import jalview.structures.models.AAStructureBindingModel;
138 import jalview.util.Format;
139 import jalview.util.HttpUtils;
140 import jalview.util.MessageManager;
141 import jalview.util.Platform;
142 import jalview.util.StringUtils;
143 import jalview.util.jarInputStreamProvider;
144 import jalview.util.matcher.Condition;
145 import jalview.viewmodel.AlignmentViewport;
146 import jalview.viewmodel.PCAModel;
147 import jalview.viewmodel.ViewportRanges;
148 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
149 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
150 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
151 import jalview.ws.jws2.Jws2Discoverer;
152 import jalview.ws.jws2.dm.AAConSettings;
153 import jalview.ws.jws2.jabaws2.Jws2Instance;
154 import jalview.ws.params.ArgumentI;
155 import jalview.ws.params.AutoCalcSetting;
156 import jalview.ws.params.WsParamSetI;
157 import jalview.xml.binding.jalview.AlcodonFrame;
158 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
159 import jalview.xml.binding.jalview.Annotation;
160 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
161 import jalview.xml.binding.jalview.AnnotationColourScheme;
162 import jalview.xml.binding.jalview.AnnotationElement;
163 import jalview.xml.binding.jalview.DoubleMatrix;
164 import jalview.xml.binding.jalview.DoubleVector;
165 import jalview.xml.binding.jalview.Feature;
166 import jalview.xml.binding.jalview.Feature.OtherData;
167 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
168 import jalview.xml.binding.jalview.FilterBy;
169 import jalview.xml.binding.jalview.JalviewModel;
170 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
171 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
172 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
173 import jalview.xml.binding.jalview.JalviewModel.JGroup;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
176 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
177 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
178 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
181 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
182 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
183 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
184 import jalview.xml.binding.jalview.JalviewModel.Tree;
185 import jalview.xml.binding.jalview.JalviewModel.UserColours;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport;
187 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
188 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
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(doBackup ?
765 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, viewIds,
1096 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);
1114 Cache.log.error("Failed to save viewer state for "
1122 if (matchedFile != null || entry.getFile() != null)
1124 if (entry.getFile() != null)
1127 matchedFile = entry.getFile();
1129 pdb.setFile(matchedFile); // entry.getFile());
1130 if (pdbfiles == null)
1132 pdbfiles = new ArrayList<>();
1135 if (!pdbfiles.contains(pdbId))
1137 pdbfiles.add(pdbId);
1138 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1142 Enumeration<String> props = entry.getProperties();
1143 if (props.hasMoreElements())
1145 // PdbentryItem item = new PdbentryItem();
1146 while (props.hasMoreElements())
1148 Property prop = new Property();
1149 String key = props.nextElement();
1151 prop.setValue(entry.getProperty(key).toString());
1152 // item.addProperty(prop);
1153 pdb.getProperty().add(prop);
1155 // pdb.addPdbentryItem(item);
1158 // jseq.addPdbids(pdb);
1159 jseq.getPdbids().add(pdb);
1163 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1165 // jms.addJSeq(jseq);
1166 object.getJSeq().add(jseq);
1169 if (!storeDS && av.hasHiddenRows())
1171 jal = av.getAlignment();
1175 if (storeDS && jal.getCodonFrames() != null)
1177 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1178 for (AlignedCodonFrame acf : jac)
1180 AlcodonFrame alc = new AlcodonFrame();
1181 if (acf.getProtMappings() != null
1182 && acf.getProtMappings().length > 0)
1184 boolean hasMap = false;
1185 SequenceI[] dnas = acf.getdnaSeqs();
1186 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1187 for (int m = 0; m < pmaps.length; m++)
1189 AlcodMap alcmap = new AlcodMap();
1190 alcmap.setDnasq(seqHash(dnas[m]));
1192 createVamsasMapping(pmaps[m], dnas[m], null, false));
1193 // alc.addAlcodMap(alcmap);
1194 alc.getAlcodMap().add(alcmap);
1199 // vamsasSet.addAlcodonFrame(alc);
1200 vamsasSet.getAlcodonFrame().add(alc);
1203 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1205 // AlcodonFrame alc = new AlcodonFrame();
1206 // vamsasSet.addAlcodonFrame(alc);
1207 // for (int p = 0; p < acf.aaWidth; p++)
1209 // Alcodon cmap = new Alcodon();
1210 // if (acf.codons[p] != null)
1212 // // Null codons indicate a gapped column in the translated peptide
1214 // cmap.setPos1(acf.codons[p][0]);
1215 // cmap.setPos2(acf.codons[p][1]);
1216 // cmap.setPos3(acf.codons[p][2]);
1218 // alc.addAlcodon(cmap);
1220 // if (acf.getProtMappings() != null
1221 // && acf.getProtMappings().length > 0)
1223 // SequenceI[] dnas = acf.getdnaSeqs();
1224 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1225 // for (int m = 0; m < pmaps.length; m++)
1227 // AlcodMap alcmap = new AlcodMap();
1228 // alcmap.setDnasq(seqHash(dnas[m]));
1229 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1231 // alc.addAlcodMap(alcmap);
1238 // /////////////////////////////////
1239 if (!storeDS && av.getCurrentTree() != null)
1241 // FIND ANY ASSOCIATED TREES
1242 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1243 if (Desktop.desktop != null)
1245 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1247 for (int t = 0; t < frames.length; t++)
1249 if (frames[t] instanceof TreePanel)
1251 TreePanel tp = (TreePanel) frames[t];
1253 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1255 JalviewModel.Tree tree = new JalviewModel.Tree();
1256 tree.setTitle(tp.getTitle());
1257 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1258 tree.setNewick(tp.getTree().print());
1259 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1261 tree.setFitToWindow(tp.fitToWindow.getState());
1262 tree.setFontName(tp.getTreeFont().getName());
1263 tree.setFontSize(tp.getTreeFont().getSize());
1264 tree.setFontStyle(tp.getTreeFont().getStyle());
1265 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1267 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1268 tree.setShowDistances(tp.distanceMenu.getState());
1270 tree.setHeight(tp.getHeight());
1271 tree.setWidth(tp.getWidth());
1272 tree.setXpos(tp.getX());
1273 tree.setYpos(tp.getY());
1274 tree.setId(makeHashCode(tp, null));
1275 tree.setLinkToAllViews(
1276 tp.getTreeCanvas().isApplyToAllViews());
1278 // jms.addTree(tree);
1279 object.getTree().add(tree);
1289 if (!storeDS && Desktop.desktop != null)
1291 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1293 if (frame instanceof PCAPanel)
1295 PCAPanel panel = (PCAPanel) frame;
1296 if (panel.getAlignViewport().getAlignment() == jal)
1298 savePCA(panel, object);
1306 * store forward refs from an annotationRow to any groups
1308 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1311 for (SequenceI sq : jal.getSequences())
1313 // Store annotation on dataset sequences only
1314 AlignmentAnnotation[] aa = sq.getAnnotation();
1315 if (aa != null && aa.length > 0)
1317 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1324 if (jal.getAlignmentAnnotation() != null)
1326 // Store the annotation shown on the alignment.
1327 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1328 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1333 if (jal.getGroups() != null)
1335 JGroup[] groups = new JGroup[jal.getGroups().size()];
1337 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1339 JGroup jGroup = new JGroup();
1340 groups[++i] = jGroup;
1342 jGroup.setStart(sg.getStartRes());
1343 jGroup.setEnd(sg.getEndRes());
1344 jGroup.setName(sg.getName());
1345 if (groupRefs.containsKey(sg))
1347 // group has references so set its ID field
1348 jGroup.setId(groupRefs.get(sg));
1350 ColourSchemeI colourScheme = sg.getColourScheme();
1351 if (colourScheme != null)
1353 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1354 if (groupColourScheme.conservationApplied())
1356 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1358 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1361 setUserColourScheme(colourScheme, userColours,
1366 jGroup.setColour(colourScheme.getSchemeName());
1369 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1371 jGroup.setColour("AnnotationColourGradient");
1372 jGroup.setAnnotationColours(constructAnnotationColours(
1373 (jalview.schemes.AnnotationColourGradient) colourScheme,
1374 userColours, object));
1376 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1379 setUserColourScheme(colourScheme, userColours, object));
1383 jGroup.setColour(colourScheme.getSchemeName());
1386 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1389 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1390 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1391 jGroup.setDisplayText(sg.getDisplayText());
1392 jGroup.setColourText(sg.getColourText());
1393 jGroup.setTextCol1(sg.textColour.getRGB());
1394 jGroup.setTextCol2(sg.textColour2.getRGB());
1395 jGroup.setTextColThreshold(sg.thresholdTextColour);
1396 jGroup.setShowUnconserved(sg.getShowNonconserved());
1397 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1398 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1399 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1400 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1401 for (SequenceI seq : sg.getSequences())
1403 // jGroup.addSeq(seqHash(seq));
1404 jGroup.getSeq().add(seqHash(seq));
1408 // jms.setJGroup(groups);
1410 for (JGroup grp : groups)
1412 object.getJGroup().add(grp);
1417 // /////////SAVE VIEWPORT
1418 Viewport view = new Viewport();
1419 view.setTitle(ap.alignFrame.getTitle());
1420 view.setSequenceSetId(
1421 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1422 view.setId(av.getViewId());
1423 if (av.getCodingComplement() != null)
1425 view.setComplementId(av.getCodingComplement().getViewId());
1427 view.setViewName(av.getViewName());
1428 view.setGatheredViews(av.isGatherViewsHere());
1430 Rectangle size = ap.av.getExplodedGeometry();
1431 Rectangle position = size;
1434 size = ap.alignFrame.getBounds();
1435 if (av.getCodingComplement() != null)
1437 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1445 view.setXpos(position.x);
1446 view.setYpos(position.y);
1448 view.setWidth(size.width);
1449 view.setHeight(size.height);
1451 view.setStartRes(vpRanges.getStartRes());
1452 view.setStartSeq(vpRanges.getStartSeq());
1454 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1456 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1457 userColours, object));
1460 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1462 AnnotationColourScheme ac = constructAnnotationColours(
1463 (jalview.schemes.AnnotationColourGradient) av
1464 .getGlobalColourScheme(),
1465 userColours, object);
1467 view.setAnnotationColours(ac);
1468 view.setBgColour("AnnotationColourGradient");
1472 view.setBgColour(ColourSchemeProperty
1473 .getColourName(av.getGlobalColourScheme()));
1476 ResidueShaderI vcs = av.getResidueShading();
1477 ColourSchemeI cs = av.getGlobalColourScheme();
1481 if (vcs.conservationApplied())
1483 view.setConsThreshold(vcs.getConservationInc());
1484 if (cs instanceof jalview.schemes.UserColourScheme)
1486 view.setBgColour(setUserColourScheme(cs, userColours, object));
1489 view.setPidThreshold(vcs.getThreshold());
1492 view.setConservationSelected(av.getConservationSelected());
1493 view.setPidSelected(av.getAbovePIDThreshold());
1494 final Font font = av.getFont();
1495 view.setFontName(font.getName());
1496 view.setFontSize(font.getSize());
1497 view.setFontStyle(font.getStyle());
1498 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1499 view.setRenderGaps(av.isRenderGaps());
1500 view.setShowAnnotation(av.isShowAnnotation());
1501 view.setShowBoxes(av.getShowBoxes());
1502 view.setShowColourText(av.getColourText());
1503 view.setShowFullId(av.getShowJVSuffix());
1504 view.setRightAlignIds(av.isRightAlignIds());
1505 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1506 view.setShowText(av.getShowText());
1507 view.setShowUnconserved(av.getShowUnconserved());
1508 view.setWrapAlignment(av.getWrapAlignment());
1509 view.setTextCol1(av.getTextColour().getRGB());
1510 view.setTextCol2(av.getTextColour2().getRGB());
1511 view.setTextColThreshold(av.getThresholdTextColour());
1512 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1513 view.setShowSequenceLogo(av.isShowSequenceLogo());
1514 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1515 view.setShowGroupConsensus(av.isShowGroupConsensus());
1516 view.setShowGroupConservation(av.isShowGroupConservation());
1517 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1518 view.setShowDbRefTooltip(av.isShowDBRefs());
1519 view.setFollowHighlight(av.isFollowHighlight());
1520 view.setFollowSelection(av.followSelection);
1521 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1522 view.setShowComplementFeatures(av.isShowComplementFeatures());
1523 view.setShowComplementFeaturesOnTop(
1524 av.isShowComplementFeaturesOnTop());
1525 if (av.getFeaturesDisplayed() != null)
1527 FeatureSettings fs = new FeatureSettings();
1529 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1530 .getFeatureRenderer();
1531 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1533 Vector<String> settingsAdded = new Vector<>();
1534 if (renderOrder != null)
1536 for (String featureType : renderOrder)
1538 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1539 setting.setType(featureType);
1542 * save any filter for the feature type
1544 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1545 if (filter != null) {
1546 Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
1547 FeatureMatcherI firstFilter = filters.next();
1548 setting.setMatcherSet(Jalview2XML.marshalFilter(
1549 firstFilter, filters, filter.isAnded()));
1553 * save colour scheme for the feature type
1555 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1556 if (!fcol.isSimpleColour())
1558 setting.setColour(fcol.getMaxColour().getRGB());
1559 setting.setMincolour(fcol.getMinColour().getRGB());
1560 setting.setMin(fcol.getMin());
1561 setting.setMax(fcol.getMax());
1562 setting.setColourByLabel(fcol.isColourByLabel());
1563 if (fcol.isColourByAttribute())
1565 String[] attName = fcol.getAttributeName();
1566 setting.getAttributeName().add(attName[0]);
1567 if (attName.length > 1)
1569 setting.getAttributeName().add(attName[1]);
1572 setting.setAutoScale(fcol.isAutoScaled());
1573 setting.setThreshold(fcol.getThreshold());
1574 Color noColour = fcol.getNoColour();
1575 if (noColour == null)
1577 setting.setNoValueColour(NoValueColour.NONE);
1579 else if (noColour.equals(fcol.getMaxColour()))
1581 setting.setNoValueColour(NoValueColour.MAX);
1585 setting.setNoValueColour(NoValueColour.MIN);
1587 // -1 = No threshold, 0 = Below, 1 = Above
1588 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1589 : (fcol.isBelowThreshold() ? 0 : -1));
1593 setting.setColour(fcol.getColour().getRGB());
1597 av.getFeaturesDisplayed().isVisible(featureType));
1599 .getOrder(featureType);
1602 setting.setOrder(rorder);
1604 /// fs.addSetting(setting);
1605 fs.getSetting().add(setting);
1606 settingsAdded.addElement(featureType);
1610 // is groups actually supposed to be a map here ?
1611 Iterator<String> en = fr.getFeatureGroups().iterator();
1612 Vector<String> groupsAdded = new Vector<>();
1613 while (en.hasNext())
1615 String grp = en.next();
1616 if (groupsAdded.contains(grp))
1620 Group g = new Group();
1622 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1625 fs.getGroup().add(g);
1626 groupsAdded.addElement(grp);
1628 // jms.setFeatureSettings(fs);
1629 object.setFeatureSettings(fs);
1632 if (av.hasHiddenColumns())
1634 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1635 .getHiddenColumns();
1638 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1642 Iterator<int[]> hiddenRegions = hidden.iterator();
1643 while (hiddenRegions.hasNext())
1645 int[] region = hiddenRegions.next();
1646 HiddenColumns hc = new HiddenColumns();
1647 hc.setStart(region[0]);
1648 hc.setEnd(region[1]);
1649 // view.addHiddenColumns(hc);
1650 view.getHiddenColumns().add(hc);
1654 if (calcIdSet.size() > 0)
1656 for (String calcId : calcIdSet)
1658 if (calcId.trim().length() > 0)
1660 CalcIdParam cidp = createCalcIdParam(calcId, av);
1661 // Some calcIds have no parameters.
1664 // view.addCalcIdParam(cidp);
1665 view.getCalcIdParam().add(cidp);
1671 // jms.addViewport(view);
1672 object.getViewport().add(view);
1674 // object.setJalviewModelSequence(jms);
1675 // object.getVamsasModel().addSequenceSet(vamsasSet);
1676 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1678 if (jout != null && fileName != null)
1680 // We may not want to write the object to disk,
1681 // eg we can copy the alignViewport to a new view object
1682 // using save and then load
1685 fileName = fileName.replace('\\', '/');
1686 System.out.println("Writing jar entry " + fileName);
1687 JarEntry entry = new JarEntry(fileName);
1688 jout.putNextEntry(entry);
1689 PrintWriter pout = new PrintWriter(
1690 new OutputStreamWriter(jout, UTF_8));
1691 JAXBContext jaxbContext = JAXBContext
1692 .newInstance(JalviewModel.class);
1693 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1695 // output pretty printed
1696 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1697 jaxbMarshaller.marshal(
1698 new ObjectFactory().createJalviewModel(object), pout);
1700 // jaxbMarshaller.marshal(object, pout);
1701 // marshaller.marshal(object);
1704 } catch (Exception ex)
1706 // TODO: raise error in GUI if marshalling failed.
1707 System.err.println("Error writing Jalview project");
1708 ex.printStackTrace();
1715 * Writes PCA viewer attributes and computed values to an XML model object and
1716 * adds it to the JalviewModel. Any exceptions are reported by logging.
1718 protected void savePCA(PCAPanel panel, JalviewModel object)
1722 PcaViewer viewer = new PcaViewer();
1723 viewer.setHeight(panel.getHeight());
1724 viewer.setWidth(panel.getWidth());
1725 viewer.setXpos(panel.getX());
1726 viewer.setYpos(panel.getY());
1727 viewer.setTitle(panel.getTitle());
1728 PCAModel pcaModel = panel.getPcaModel();
1729 viewer.setScoreModelName(pcaModel.getScoreModelName());
1730 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1731 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1732 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1734 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1735 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1736 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1737 SeqPointMin spmin = new SeqPointMin();
1738 spmin.setXPos(spMin[0]);
1739 spmin.setYPos(spMin[1]);
1740 spmin.setZPos(spMin[2]);
1741 viewer.setSeqPointMin(spmin);
1742 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1743 SeqPointMax spmax = new SeqPointMax();
1744 spmax.setXPos(spMax[0]);
1745 spmax.setYPos(spMax[1]);
1746 spmax.setZPos(spMax[2]);
1747 viewer.setSeqPointMax(spmax);
1748 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1749 viewer.setLinkToAllViews(
1750 panel.getRotatableCanvas().isApplyToAllViews());
1751 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1752 viewer.setIncludeGaps(sp.includeGaps());
1753 viewer.setMatchGaps(sp.matchGaps());
1754 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1755 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1758 * sequence points on display
1760 for (jalview.datamodel.SequencePoint spt : pcaModel
1761 .getSequencePoints())
1763 SequencePoint point = new SequencePoint();
1764 point.setSequenceRef(seqHash(spt.getSequence()));
1765 point.setXPos(spt.coord.x);
1766 point.setYPos(spt.coord.y);
1767 point.setZPos(spt.coord.z);
1768 viewer.getSequencePoint().add(point);
1772 * (end points of) axes on display
1774 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1777 Axis axis = new Axis();
1781 viewer.getAxis().add(axis);
1785 * raw PCA data (note we are not restoring PCA inputs here -
1786 * alignment view, score model, similarity parameters)
1788 PcaDataType data = new PcaDataType();
1789 viewer.setPcaData(data);
1790 PCA pca = pcaModel.getPcaData();
1792 DoubleMatrix pm = new DoubleMatrix();
1793 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1794 data.setPairwiseMatrix(pm);
1796 DoubleMatrix tm = new DoubleMatrix();
1797 saveDoubleMatrix(pca.getTridiagonal(), tm);
1798 data.setTridiagonalMatrix(tm);
1800 DoubleMatrix eigenMatrix = new DoubleMatrix();
1801 data.setEigenMatrix(eigenMatrix);
1802 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1804 object.getPcaViewer().add(viewer);
1805 } catch (Throwable t)
1807 Cache.log.error("Error saving PCA: " + t.getMessage());
1812 * Stores values from a matrix into an XML element, including (if present) the
1817 * @see #loadDoubleMatrix(DoubleMatrix)
1819 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1821 xmlMatrix.setRows(m.height());
1822 xmlMatrix.setColumns(m.width());
1823 for (int i = 0; i < m.height(); i++)
1825 DoubleVector row = new DoubleVector();
1826 for (int j = 0; j < m.width(); j++)
1828 row.getV().add(m.getValue(i, j));
1830 xmlMatrix.getRow().add(row);
1832 if (m.getD() != null)
1834 DoubleVector dVector = new DoubleVector();
1835 for (double d : m.getD())
1837 dVector.getV().add(d);
1839 xmlMatrix.setD(dVector);
1841 if (m.getE() != null)
1843 DoubleVector eVector = new DoubleVector();
1844 for (double e : m.getE())
1846 eVector.getV().add(e);
1848 xmlMatrix.setE(eVector);
1853 * Loads XML matrix data into a new Matrix object, including the D and/or E
1854 * vectors (if present)
1858 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1860 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1862 int rows = mData.getRows();
1863 double[][] vals = new double[rows][];
1865 for (int i = 0; i < rows; i++)
1867 List<Double> dVector = mData.getRow().get(i).getV();
1868 vals[i] = new double[dVector.size()];
1870 for (Double d : dVector)
1876 MatrixI m = new Matrix(vals);
1878 if (mData.getD() != null)
1880 List<Double> dVector = mData.getD().getV();
1881 double[] vec = new double[dVector.size()];
1883 for (Double d : dVector)
1889 if (mData.getE() != null)
1891 List<Double> dVector = mData.getE().getV();
1892 double[] vec = new double[dVector.size()];
1894 for (Double d : dVector)
1905 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1906 * for each viewer, with
1908 * <li>viewer geometry (position, size, split pane divider location)</li>
1909 * <li>index of the selected structure in the viewer (currently shows gapped
1911 * <li>the id of the annotation holding RNA secondary structure</li>
1912 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1914 * Varna viewer state is also written out (in native Varna XML) to separate
1915 * project jar entries. A separate entry is written for each RNA structure
1916 * displayed, with the naming convention
1918 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1926 * @param storeDataset
1928 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1929 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1930 boolean storeDataset)
1932 if (Desktop.desktop == null)
1936 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1937 for (int f = frames.length - 1; f > -1; f--)
1939 if (frames[f] instanceof AppVarna)
1941 AppVarna varna = (AppVarna) frames[f];
1943 * link the sequence to every viewer that is showing it and is linked to
1944 * its alignment panel
1946 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1948 String viewId = varna.getViewId();
1949 RnaViewer rna = new RnaViewer();
1950 rna.setViewId(viewId);
1951 rna.setTitle(varna.getTitle());
1952 rna.setXpos(varna.getX());
1953 rna.setYpos(varna.getY());
1954 rna.setWidth(varna.getWidth());
1955 rna.setHeight(varna.getHeight());
1956 rna.setDividerLocation(varna.getDividerLocation());
1957 rna.setSelectedRna(varna.getSelectedIndex());
1958 // jseq.addRnaViewer(rna);
1959 jseq.getRnaViewer().add(rna);
1962 * Store each Varna panel's state once in the project per sequence.
1963 * First time through only (storeDataset==false)
1965 // boolean storeSessions = false;
1966 // String sequenceViewId = viewId + seqsToIds.get(jds);
1967 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1969 // viewIds.add(sequenceViewId);
1970 // storeSessions = true;
1972 for (RnaModel model : varna.getModels())
1974 if (model.seq == jds)
1977 * VARNA saves each view (sequence or alignment secondary
1978 * structure, gapped or trimmed) as a separate XML file
1980 String jarEntryName = rnaSessions.get(model);
1981 if (jarEntryName == null)
1984 String varnaStateFile = varna.getStateInfo(model.rna);
1985 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1986 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
1987 rnaSessions.put(model, jarEntryName);
1989 SecondaryStructure ss = new SecondaryStructure();
1990 String annotationId = varna.getAnnotation(jds).annotationId;
1991 ss.setAnnotationId(annotationId);
1992 ss.setViewerState(jarEntryName);
1993 ss.setGapped(model.gapped);
1994 ss.setTitle(model.title);
1995 // rna.addSecondaryStructure(ss);
1996 rna.getSecondaryStructure().add(ss);
2005 * Copy the contents of a file to a new entry added to the output jar
2009 * @param jarEntryName
2011 * additional identifying info to log to the console
2013 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2014 String jarEntryName, String msg)
2016 try (InputStream is = new FileInputStream(infilePath))
2018 File file = new File(infilePath);
2019 if (file.exists() && jout != null)
2022 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2023 jout.putNextEntry(new JarEntry(jarEntryName));
2026 // dis = new DataInputStream(new FileInputStream(file));
2027 // byte[] data = new byte[(int) file.length()];
2028 // dis.readFully(data);
2029 // writeJarEntry(jout, jarEntryName, data);
2031 } catch (Exception ex)
2033 ex.printStackTrace();
2038 * Copies input to output, in 4K buffers; handles any data (text or binary)
2042 * @throws IOException
2044 protected void copyAll(InputStream in, OutputStream out)
2047 byte[] buffer = new byte[4096];
2049 while ((bytesRead = in.read(buffer)) != -1)
2051 out.write(buffer, 0, bytesRead);
2056 * Save the state of a structure viewer
2061 * the archive XML element under which to save the state
2064 * @param matchedFile
2068 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2069 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2070 String matchedFile, StructureViewerBase viewFrame)
2072 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2075 * Look for any bindings for this viewer to the PDB file of interest
2076 * (including part matches excluding chain id)
2078 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2080 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2081 final String pdbId = pdbentry.getId();
2082 if (!pdbId.equals(entry.getId())
2083 && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
2084 .startsWith(pdbId.toLowerCase())))
2087 * not interested in a binding to a different PDB entry here
2091 if (matchedFile == null)
2093 matchedFile = pdbentry.getFile();
2095 else if (!matchedFile.equals(pdbentry.getFile()))
2098 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2099 + pdbentry.getFile());
2103 // can get at it if the ID
2104 // match is ambiguous (e.g.
2107 for (int smap = 0; smap < viewFrame.getBinding()
2108 .getSequence()[peid].length; smap++)
2110 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2111 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2113 StructureState state = new StructureState();
2114 state.setVisible(true);
2115 state.setXpos(viewFrame.getX());
2116 state.setYpos(viewFrame.getY());
2117 state.setWidth(viewFrame.getWidth());
2118 state.setHeight(viewFrame.getHeight());
2119 final String viewId = viewFrame.getViewId();
2120 state.setViewId(viewId);
2121 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2122 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2123 state.setColourByJmol(viewFrame.isColouredByViewer());
2124 state.setType(viewFrame.getViewerType().toString());
2125 // pdb.addStructureState(state);
2126 pdb.getStructureState().add(state);
2134 * Populates the AnnotationColourScheme xml for save. This captures the
2135 * settings of the options in the 'Colour by Annotation' dialog.
2138 * @param userColours
2142 private AnnotationColourScheme constructAnnotationColours(
2143 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2146 AnnotationColourScheme ac = new AnnotationColourScheme();
2147 ac.setAboveThreshold(acg.getAboveThreshold());
2148 ac.setThreshold(acg.getAnnotationThreshold());
2149 // 2.10.2 save annotationId (unique) not annotation label
2150 ac.setAnnotation(acg.getAnnotation().annotationId);
2151 if (acg.getBaseColour() instanceof UserColourScheme)
2154 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2159 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2162 ac.setMaxColour(acg.getMaxColour().getRGB());
2163 ac.setMinColour(acg.getMinColour().getRGB());
2164 ac.setPerSequence(acg.isSeqAssociated());
2165 ac.setPredefinedColours(acg.isPredefinedColours());
2169 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2170 IdentityHashMap<SequenceGroup, String> groupRefs,
2171 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2172 SequenceSet vamsasSet)
2175 for (int i = 0; i < aa.length; i++)
2177 Annotation an = new Annotation();
2179 AlignmentAnnotation annotation = aa[i];
2180 if (annotation.annotationId != null)
2182 annotationIds.put(annotation.annotationId, annotation);
2185 an.setId(annotation.annotationId);
2187 an.setVisible(annotation.visible);
2189 an.setDescription(annotation.description);
2191 if (annotation.sequenceRef != null)
2193 // 2.9 JAL-1781 xref on sequence id rather than name
2194 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2196 if (annotation.groupRef != null)
2198 String groupIdr = groupRefs.get(annotation.groupRef);
2199 if (groupIdr == null)
2201 // make a locally unique String
2202 groupRefs.put(annotation.groupRef,
2203 groupIdr = ("" + System.currentTimeMillis()
2204 + annotation.groupRef.getName()
2205 + groupRefs.size()));
2207 an.setGroupRef(groupIdr.toString());
2210 // store all visualization attributes for annotation
2211 an.setGraphHeight(annotation.graphHeight);
2212 an.setCentreColLabels(annotation.centreColLabels);
2213 an.setScaleColLabels(annotation.scaleColLabel);
2214 an.setShowAllColLabels(annotation.showAllColLabels);
2215 an.setBelowAlignment(annotation.belowAlignment);
2217 if (annotation.graph > 0)
2220 an.setGraphType(annotation.graph);
2221 an.setGraphGroup(annotation.graphGroup);
2222 if (annotation.getThreshold() != null)
2224 ThresholdLine line = new ThresholdLine();
2225 line.setLabel(annotation.getThreshold().label);
2226 line.setValue(annotation.getThreshold().value);
2227 line.setColour(annotation.getThreshold().colour.getRGB());
2228 an.setThresholdLine(line);
2236 an.setLabel(annotation.label);
2238 if (annotation == av.getAlignmentQualityAnnot()
2239 || annotation == av.getAlignmentConservationAnnotation()
2240 || annotation == av.getAlignmentConsensusAnnotation()
2241 || annotation.autoCalculated)
2243 // new way of indicating autocalculated annotation -
2244 an.setAutoCalculated(annotation.autoCalculated);
2246 if (annotation.hasScore())
2248 an.setScore(annotation.getScore());
2251 if (annotation.getCalcId() != null)
2253 calcIdSet.add(annotation.getCalcId());
2254 an.setCalcId(annotation.getCalcId());
2256 if (annotation.hasProperties())
2258 for (String pr : annotation.getProperties())
2260 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2262 prop.setValue(annotation.getProperty(pr));
2263 // an.addProperty(prop);
2264 an.getProperty().add(prop);
2268 AnnotationElement ae;
2269 if (annotation.annotations != null)
2271 an.setScoreOnly(false);
2272 for (int a = 0; a < annotation.annotations.length; a++)
2274 if ((annotation == null) || (annotation.annotations[a] == null))
2279 ae = new AnnotationElement();
2280 if (annotation.annotations[a].description != null)
2282 ae.setDescription(annotation.annotations[a].description);
2284 if (annotation.annotations[a].displayCharacter != null)
2286 ae.setDisplayCharacter(
2287 annotation.annotations[a].displayCharacter);
2290 if (!Float.isNaN(annotation.annotations[a].value))
2292 ae.setValue(annotation.annotations[a].value);
2296 if (annotation.annotations[a].secondaryStructure > ' ')
2298 ae.setSecondaryStructure(
2299 annotation.annotations[a].secondaryStructure + "");
2302 if (annotation.annotations[a].colour != null
2303 && annotation.annotations[a].colour != java.awt.Color.black)
2305 ae.setColour(annotation.annotations[a].colour.getRGB());
2308 // an.addAnnotationElement(ae);
2309 an.getAnnotationElement().add(ae);
2310 if (annotation.autoCalculated)
2312 // only write one non-null entry into the annotation row -
2313 // sufficient to get the visualization attributes necessary to
2321 an.setScoreOnly(true);
2323 if (!storeDS || (storeDS && !annotation.autoCalculated))
2325 // skip autocalculated annotation - these are only provided for
2327 // vamsasSet.addAnnotation(an);
2328 vamsasSet.getAnnotation().add(an);
2334 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2336 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2337 if (settings != null)
2339 CalcIdParam vCalcIdParam = new CalcIdParam();
2340 vCalcIdParam.setCalcId(calcId);
2341 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2342 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2343 // generic URI allowing a third party to resolve another instance of the
2344 // service used for this calculation
2345 for (String url : settings.getServiceURLs())
2347 // vCalcIdParam.addServiceURL(urls);
2348 vCalcIdParam.getServiceURL().add(url);
2350 vCalcIdParam.setVersion("1.0");
2351 if (settings.getPreset() != null)
2353 WsParamSetI setting = settings.getPreset();
2354 vCalcIdParam.setName(setting.getName());
2355 vCalcIdParam.setDescription(setting.getDescription());
2359 vCalcIdParam.setName("");
2360 vCalcIdParam.setDescription("Last used parameters");
2362 // need to be able to recover 1) settings 2) user-defined presets or
2363 // recreate settings from preset 3) predefined settings provided by
2364 // service - or settings that can be transferred (or discarded)
2365 vCalcIdParam.setParameters(
2366 settings.getWsParamFile().replace("\n", "|\\n|"));
2367 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2368 // todo - decide if updateImmediately is needed for any projects.
2370 return vCalcIdParam;
2375 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2378 if (calcIdParam.getVersion().equals("1.0"))
2380 final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
2381 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2382 .getPreferredServiceFor(calcIds);
2383 if (service != null)
2385 WsParamSetI parmSet = null;
2388 parmSet = service.getParamStore().parseServiceParameterFile(
2389 calcIdParam.getName(), calcIdParam.getDescription(),
2391 calcIdParam.getParameters().replace("|\\n|", "\n"));
2392 } catch (IOException x)
2394 warn("Couldn't parse parameter data for "
2395 + calcIdParam.getCalcId(), x);
2398 List<ArgumentI> argList = null;
2399 if (calcIdParam.getName().length() > 0)
2401 parmSet = service.getParamStore()
2402 .getPreset(calcIdParam.getName());
2403 if (parmSet != null)
2405 // TODO : check we have a good match with settings in AACon -
2406 // otherwise we'll need to create a new preset
2411 argList = parmSet.getArguments();
2414 AAConSettings settings = new AAConSettings(
2415 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2416 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2417 calcIdParam.isNeedsUpdate());
2422 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2426 throw new Error(MessageManager.formatMessage(
2427 "error.unsupported_version_calcIdparam", new Object[]
2428 { calcIdParam.toString() }));
2432 * External mapping between jalview objects and objects yielding a valid and
2433 * unique object ID string. This is null for normal Jalview project IO, but
2434 * non-null when a jalview project is being read or written as part of a
2437 IdentityHashMap jv2vobj = null;
2440 * Construct a unique ID for jvobj using either existing bindings or if none
2441 * exist, the result of the hashcode call for the object.
2444 * jalview data object
2445 * @return unique ID for referring to jvobj
2447 private String makeHashCode(Object jvobj, String altCode)
2449 if (jv2vobj != null)
2451 Object id = jv2vobj.get(jvobj);
2454 return id.toString();
2456 // check string ID mappings
2457 if (jvids2vobj != null && jvobj instanceof String)
2459 id = jvids2vobj.get(jvobj);
2463 return id.toString();
2465 // give up and warn that something has gone wrong
2466 warn("Cannot find ID for object in external mapping : " + jvobj);
2472 * return local jalview object mapped to ID, if it exists
2476 * @return null or object bound to idcode
2478 private Object retrieveExistingObj(String idcode)
2480 if (idcode != null && vobj2jv != null)
2482 return vobj2jv.get(idcode);
2488 * binding from ID strings from external mapping table to jalview data model
2491 private Hashtable vobj2jv;
2493 private Sequence createVamsasSequence(String id, SequenceI jds)
2495 return createVamsasSequence(true, id, jds, null);
2498 private Sequence createVamsasSequence(boolean recurse, String id,
2499 SequenceI jds, SequenceI parentseq)
2501 Sequence vamsasSeq = new Sequence();
2502 vamsasSeq.setId(id);
2503 vamsasSeq.setName(jds.getName());
2504 vamsasSeq.setSequence(jds.getSequenceAsString());
2505 vamsasSeq.setDescription(jds.getDescription());
2506 List<DBRefEntry> dbrefs = null;
2507 if (jds.getDatasetSequence() != null)
2509 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2513 // seqId==dsseqid so we can tell which sequences really are
2514 // dataset sequences only
2515 vamsasSeq.setDsseqid(id);
2516 dbrefs = jds.getDBRefs();
2517 if (parentseq == null)
2524 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2528 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2530 DBRef dbref = new DBRef();
2531 DBRefEntry ref = dbrefs.get(d);
2532 dbref.setSource(ref.getSource());
2533 dbref.setVersion(ref.getVersion());
2534 dbref.setAccessionId(ref.getAccessionId());
2535 if (ref instanceof GeneLocus)
2537 dbref.setLocus(true);
2541 Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
2543 dbref.setMapping(mp);
2545 vamsasSeq.getDBRef().add(dbref);
2551 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2552 SequenceI parentseq, SequenceI jds, boolean recurse)
2555 if (jmp.getMap() != null)
2559 jalview.util.MapList mlst = jmp.getMap();
2560 List<int[]> r = mlst.getFromRanges();
2561 for (int[] range : r)
2563 MapListFrom mfrom = new MapListFrom();
2564 mfrom.setStart(range[0]);
2565 mfrom.setEnd(range[1]);
2566 // mp.addMapListFrom(mfrom);
2567 mp.getMapListFrom().add(mfrom);
2569 r = mlst.getToRanges();
2570 for (int[] range : r)
2572 MapListTo mto = new MapListTo();
2573 mto.setStart(range[0]);
2574 mto.setEnd(range[1]);
2575 // mp.addMapListTo(mto);
2576 mp.getMapListTo().add(mto);
2578 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2579 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2580 if (jmp.getTo() != null)
2582 // MappingChoice mpc = new MappingChoice();
2584 // check/create ID for the sequence referenced by getTo()
2587 SequenceI ps = null;
2588 if (parentseq != jmp.getTo()
2589 && parentseq.getDatasetSequence() != jmp.getTo())
2591 // chaining dbref rather than a handshaking one
2592 jmpid = seqHash(ps = jmp.getTo());
2596 jmpid = seqHash(ps = parentseq);
2598 // mpc.setDseqFor(jmpid);
2599 mp.setDseqFor(jmpid);
2600 if (!seqRefIds.containsKey(jmpid))
2602 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2603 seqRefIds.put(jmpid, ps);
2607 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2610 // mp.setMappingChoice(mpc);
2616 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2617 List<UserColourScheme> userColours, JalviewModel jm)
2620 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2621 boolean newucs = false;
2622 if (!userColours.contains(ucs))
2624 userColours.add(ucs);
2627 id = "ucs" + userColours.indexOf(ucs);
2630 // actually create the scheme's entry in the XML model
2631 java.awt.Color[] colours = ucs.getColours();
2632 UserColours uc = new UserColours();
2633 // UserColourScheme jbucs = new UserColourScheme();
2634 JalviewUserColours jbucs = new JalviewUserColours();
2636 for (int i = 0; i < colours.length; i++)
2638 Colour col = new Colour();
2639 col.setName(ResidueProperties.aa[i]);
2640 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2641 // jbucs.addColour(col);
2642 jbucs.getColour().add(col);
2644 if (ucs.getLowerCaseColours() != null)
2646 colours = ucs.getLowerCaseColours();
2647 for (int i = 0; i < colours.length; i++)
2649 Colour col = new Colour();
2650 col.setName(ResidueProperties.aa[i].toLowerCase());
2651 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2652 // jbucs.addColour(col);
2653 jbucs.getColour().add(col);
2658 uc.setUserColourScheme(jbucs);
2659 // jm.addUserColours(uc);
2660 jm.getUserColours().add(uc);
2666 jalview.schemes.UserColourScheme getUserColourScheme(
2667 JalviewModel jm, String id)
2669 List<UserColours> uc = jm.getUserColours();
2670 UserColours colours = null;
2672 for (int i = 0; i < uc.length; i++)
2674 if (uc[i].getId().equals(id))
2681 for (UserColours c : uc)
2683 if (c.getId().equals(id))
2690 java.awt.Color[] newColours = new java.awt.Color[24];
2692 for (int i = 0; i < 24; i++)
2694 newColours[i] = new java.awt.Color(Integer.parseInt(
2695 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2696 colours.getUserColourScheme().getColour().get(i).getRGB(),
2700 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2703 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2705 newColours = new java.awt.Color[23];
2706 for (int i = 0; i < 23; i++)
2708 newColours[i] = new java.awt.Color(Integer.parseInt(
2709 colours.getUserColourScheme().getColour().get(i + 24)
2713 ucs.setLowerCaseColours(newColours);
2720 * contains last error message (if any) encountered by XML loader.
2722 String errorMessage = null;
2725 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2726 * exceptions are raised during project XML parsing
2728 public boolean attemptversion1parse = false;
2731 * Load a jalview project archive from a jar file
2734 * - HTTP URL or filename
2736 public AlignFrame loadJalviewAlign(final Object file)
2739 jalview.gui.AlignFrame af = null;
2743 // create list to store references for any new Jmol viewers created
2744 newStructureViewers = new Vector<>();
2745 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2746 // Workaround is to make sure caller implements the JarInputStreamProvider
2748 // so we can re-open the jar input stream for each entry.
2750 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2751 af = loadJalviewAlign(jprovider);
2754 af.setMenusForViewport();
2756 } catch (MalformedURLException e)
2758 errorMessage = "Invalid URL format for '" + file + "'";
2764 SwingUtilities.invokeAndWait(new Runnable()
2769 setLoadingFinishedForNewStructureViewers();
2772 } catch (Exception x)
2774 System.err.println("Error loading alignment: " + x.getMessage());
2780 @SuppressWarnings("unused")
2781 private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
2783 // BH 2018 allow for bytes already attached to File object
2785 String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
2786 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
2789 errorMessage = null;
2790 uniqueSetSuffix = null;
2792 viewportsAdded.clear();
2793 frefedSequence = null;
2795 if (HttpUtils.startsWithHttpOrHttps(file))
2797 url = new URL(file);
2799 final URL _url = url;
2800 return new jarInputStreamProvider()
2804 public JarInputStream getJarInputStream() throws IOException {
2805 if (bytes != null) {
2806 // System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
2807 return new JarInputStream(new ByteArrayInputStream(bytes));
2810 // System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
2811 return new JarInputStream(_url.openStream());
2813 // System.out.println("Jalview2XML: opening file jarInputStream for " + file);
2814 return new JarInputStream(new FileInputStream(file));
2819 public String getFilename() {
2823 } catch (IOException e) {
2824 e.printStackTrace();
2830 * Recover jalview session from a jalview project archive. Caller may
2831 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2832 * themselves. Any null fields will be initialised with default values,
2833 * non-null fields are left alone.
2838 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2840 errorMessage = null;
2841 if (uniqueSetSuffix == null)
2843 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2845 if (seqRefIds == null)
2849 AlignFrame af = null, _af = null;
2850 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2851 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2852 final String file = jprovider.getFilename();
2855 JarInputStream jin = null;
2856 JarEntry jarentry = null;
2861 jin = jprovider.getJarInputStream();
2862 for (int i = 0; i < entryCount; i++)
2864 jarentry = jin.getNextJarEntry();
2867 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2869 JAXBContext jc = JAXBContext
2870 .newInstance("jalview.xml.binding.jalview");
2871 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2872 .createXMLStreamReader(jin);
2873 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2874 JAXBElement<JalviewModel> jbe = um
2875 .unmarshal(streamReader, JalviewModel.class);
2876 JalviewModel object = jbe.getValue();
2878 if (true) // !skipViewport(object))
2880 _af = loadFromObject(object, file, true, jprovider);
2881 if (_af != null && object.getViewport().size() > 0)
2882 // getJalviewModelSequence().getViewportCount() > 0)
2886 // store a reference to the first view
2889 if (_af.getViewport().isGatherViewsHere())
2891 // if this is a gathered view, keep its reference since
2892 // after gathering views, only this frame will remain
2894 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2897 // Save dataset to register mappings once all resolved
2898 importedDatasets.put(
2899 af.getViewport().getAlignment().getDataset(),
2900 af.getViewport().getAlignment().getDataset());
2905 else if (jarentry != null)
2907 // Some other file here.
2910 } while (jarentry != null);
2911 resolveFrefedSequences();
2912 } catch (IOException ex)
2914 ex.printStackTrace();
2915 errorMessage = "Couldn't locate Jalview XML file : " + file;
2917 "Exception whilst loading jalview XML file : " + ex + "\n");
2918 } catch (Exception ex)
2920 System.err.println("Parsing as Jalview Version 2 file failed.");
2921 ex.printStackTrace(System.err);
2922 if (attemptversion1parse)
2924 // used to attempt to parse as V1 castor-generated xml
2926 if (Desktop.instance != null)
2928 Desktop.instance.stopLoading();
2932 System.out.println("Successfully loaded archive file");
2935 ex.printStackTrace();
2938 "Exception whilst loading jalview XML file : " + ex + "\n");
2939 } catch (OutOfMemoryError e)
2941 // Don't use the OOM Window here
2942 errorMessage = "Out of memory loading jalview XML file";
2943 System.err.println("Out of memory whilst loading jalview XML file");
2944 e.printStackTrace();
2948 * Regather multiple views (with the same sequence set id) to the frame (if
2949 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2950 * views instead of separate frames. Note this doesn't restore a state where
2951 * some expanded views in turn have tabbed views - the last "first tab" read
2952 * in will play the role of gatherer for all.
2954 for (AlignFrame fr : gatherToThisFrame.values())
2956 Desktop.instance.gatherViews(fr);
2959 restoreSplitFrames();
2960 for (AlignmentI ds : importedDatasets.keySet())
2962 if (ds.getCodonFrames() != null)
2964 StructureSelectionManager
2965 .getStructureSelectionManager(Desktop.instance)
2966 .registerMappings(ds.getCodonFrames());
2969 if (errorMessage != null)
2974 if (Desktop.instance != null)
2976 Desktop.instance.stopLoading();
2983 * Try to reconstruct and display SplitFrame windows, where each contains
2984 * complementary dna and protein alignments. Done by pairing up AlignFrame
2985 * objects (created earlier) which have complementary viewport ids associated.
2987 protected void restoreSplitFrames()
2989 List<SplitFrame> gatherTo = new ArrayList<>();
2990 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2991 Map<String, AlignFrame> dna = new HashMap<>();
2994 * Identify the DNA alignments
2996 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2999 AlignFrame af = candidate.getValue();
3000 if (af.getViewport().getAlignment().isNucleotide())
3002 dna.put(candidate.getKey().getId(), af);
3007 * Try to match up the protein complements
3009 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3012 AlignFrame af = candidate.getValue();
3013 if (!af.getViewport().getAlignment().isNucleotide())
3015 String complementId = candidate.getKey().getComplementId();
3016 // only non-null complements should be in the Map
3017 if (complementId != null && dna.containsKey(complementId))
3019 final AlignFrame dnaFrame = dna.get(complementId);
3020 SplitFrame sf = createSplitFrame(dnaFrame, af);
3021 addedToSplitFrames.add(dnaFrame);
3022 addedToSplitFrames.add(af);
3023 dnaFrame.setMenusForViewport();
3024 af.setMenusForViewport();
3025 if (af.getViewport().isGatherViewsHere())
3034 * Open any that we failed to pair up (which shouldn't happen!) as
3035 * standalone AlignFrame's.
3037 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3040 AlignFrame af = candidate.getValue();
3041 if (!addedToSplitFrames.contains(af))
3043 Viewport view = candidate.getKey();
3044 Desktop.addInternalFrame(af, view.getTitle(),
3045 safeInt(view.getWidth()), safeInt(view.getHeight()));
3046 af.setMenusForViewport();
3047 System.err.println("Failed to restore view " + view.getTitle()
3048 + " to split frame");
3053 * Gather back into tabbed views as flagged.
3055 for (SplitFrame sf : gatherTo)
3057 Desktop.instance.gatherViews(sf);
3060 splitFrameCandidates.clear();
3064 * Construct and display one SplitFrame holding DNA and protein alignments.
3067 * @param proteinFrame
3070 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3071 AlignFrame proteinFrame)
3073 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3074 String title = MessageManager.getString("label.linked_view_title");
3075 int width = (int) dnaFrame.getBounds().getWidth();
3076 int height = (int) (dnaFrame.getBounds().getHeight()
3077 + proteinFrame.getBounds().getHeight() + 50);
3080 * SplitFrame location is saved to both enclosed frames
3082 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3083 Desktop.addInternalFrame(splitFrame, title, width, height);
3086 * And compute cDNA consensus (couldn't do earlier with consensus as
3087 * mappings were not yet present)
3089 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3095 * check errorMessage for a valid error message and raise an error box in the
3096 * GUI or write the current errorMessage to stderr and then clear the error
3099 protected void reportErrors()
3101 reportErrors(false);
3104 protected void reportErrors(final boolean saving)
3106 if (errorMessage != null)
3108 final String finalErrorMessage = errorMessage;
3111 javax.swing.SwingUtilities.invokeLater(new Runnable()
3116 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3118 "Error " + (saving ? "saving" : "loading")
3120 JvOptionPane.WARNING_MESSAGE);
3126 System.err.println("Problem loading Jalview file: " + errorMessage);
3129 errorMessage = null;
3132 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3135 * when set, local views will be updated from view stored in JalviewXML
3136 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3137 * sync if this is set to true.
3139 private final boolean updateLocalViews = false;
3142 * Returns the path to a temporary file holding the PDB file for the given PDB
3143 * id. The first time of asking, searches for a file of that name in the
3144 * Jalview project jar, and copies it to a new temporary file. Any repeat
3145 * requests just return the path to the file previously created.
3151 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3154 if (alreadyLoadedPDB.containsKey(pdbId))
3156 return alreadyLoadedPDB.get(pdbId).toString();
3159 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3161 if (tempFile != null)
3163 alreadyLoadedPDB.put(pdbId, tempFile);
3169 * Copies the jar entry of given name to a new temporary file and returns the
3170 * path to the file, or null if the entry is not found.
3173 * @param jarEntryName
3175 * a prefix for the temporary file name, must be at least three
3177 * @param suffixModel
3178 * null or original file - so new file can be given the same suffix
3182 protected String copyJarEntry(jarInputStreamProvider jprovider,
3183 String jarEntryName, String prefix, String suffixModel)
3185 String suffix = ".tmp";
3186 if (suffixModel == null)
3188 suffixModel = jarEntryName;
3190 int sfpos = suffixModel.lastIndexOf(".");
3191 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3193 suffix = "." + suffixModel.substring(sfpos + 1);
3196 try (JarInputStream jin = jprovider.getJarInputStream())
3198 JarEntry entry = null;
3201 entry = jin.getNextJarEntry();
3202 } while (entry != null && !entry.getName().equals(jarEntryName));
3206 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3207 File outFile = File.createTempFile(prefix, suffix);
3208 outFile.deleteOnExit();
3209 try (OutputStream os = new FileOutputStream(outFile))
3213 String t = outFile.getAbsolutePath();
3218 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3220 } catch (Exception ex)
3222 ex.printStackTrace();
3228 private class JvAnnotRow
3230 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3237 * persisted version of annotation row from which to take vis properties
3239 public jalview.datamodel.AlignmentAnnotation template;
3242 * original position of the annotation row in the alignment
3248 * Load alignment frame from jalview XML DOM object
3250 * @param jalviewModel
3253 * filename source string
3254 * @param loadTreesAndStructures
3255 * when false only create Viewport
3257 * data source provider
3258 * @return alignment frame created from view stored in DOM
3260 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3261 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3263 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
3264 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3266 // JalviewModelSequence jms = object.getJalviewModelSequence();
3268 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3270 Viewport view = (jalviewModel.getViewport().size() > 0)
3271 ? jalviewModel.getViewport().get(0)
3274 // ////////////////////////////////
3275 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3278 // If we just load in the same jar file again, the sequenceSetId
3279 // will be the same, and we end up with multiple references
3280 // to the same sequenceSet. We must modify this id on load
3281 // so that each load of the file gives a unique id
3284 * used to resolve correct alignment dataset for alignments with multiple
3287 String uniqueSeqSetId = null;
3288 String viewId = null;
3291 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3292 viewId = (view.getId() == null ? null
3293 : view.getId() + uniqueSetSuffix);
3296 // ////////////////////////////////
3299 List<SequenceI> hiddenSeqs = null;
3301 List<SequenceI> tmpseqs = new ArrayList<>();
3303 boolean multipleView = false;
3304 SequenceI referenceseqForView = null;
3305 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3306 List<JSeq> jseqs = jalviewModel.getJSeq();
3307 int vi = 0; // counter in vamsasSeq array
3308 for (int i = 0; i < jseqs.size(); i++)
3310 JSeq jseq = jseqs.get(i);
3311 String seqId = jseq.getId();
3313 SequenceI tmpSeq = seqRefIds.get(seqId);
3316 if (!incompleteSeqs.containsKey(seqId))
3318 // may not need this check, but keep it for at least 2.9,1 release
3319 if (tmpSeq.getStart() != jseq.getStart()
3320 || tmpSeq.getEnd() != jseq.getEnd())
3323 String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3324 tmpSeq.getName(), tmpSeq.getStart(),
3325 tmpSeq.getEnd(), jseq.getStart(),
3331 incompleteSeqs.remove(seqId);
3333 if (vamsasSeqs.size() > vi
3334 && vamsasSeqs.get(vi).getId().equals(seqId))
3336 // most likely we are reading a dataset XML document so
3337 // update from vamsasSeq section of XML for this sequence
3338 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3339 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3340 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3345 // reading multiple views, so vamsasSeq set is a subset of JSeq
3346 multipleView = true;
3348 tmpSeq.setStart(jseq.getStart());
3349 tmpSeq.setEnd(jseq.getEnd());
3350 tmpseqs.add(tmpSeq);
3354 Sequence vamsasSeq = vamsasSeqs.get(vi);
3355 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3356 vamsasSeq.getSequence());
3357 tmpSeq.setDescription(vamsasSeq.getDescription());
3358 tmpSeq.setStart(jseq.getStart());
3359 tmpSeq.setEnd(jseq.getEnd());
3360 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3361 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3362 tmpseqs.add(tmpSeq);
3366 if (safeBoolean(jseq.isViewreference()))
3368 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3371 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3373 if (hiddenSeqs == null)
3375 hiddenSeqs = new ArrayList<>();
3378 hiddenSeqs.add(tmpSeq);
3383 // Create the alignment object from the sequence set
3384 // ///////////////////////////////
3385 SequenceI[] orderedSeqs = tmpseqs
3386 .toArray(new SequenceI[tmpseqs.size()]);
3388 AlignmentI al = null;
3389 // so we must create or recover the dataset alignment before going further
3390 // ///////////////////////////////
3391 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3393 // older jalview projects do not have a dataset - so creat alignment and
3395 al = new Alignment(orderedSeqs);
3396 al.setDataset(null);
3400 boolean isdsal = jalviewModel.getViewport().isEmpty();
3403 // we are importing a dataset record, so
3404 // recover reference to an alignment already materialsed as dataset
3405 al = getDatasetFor(vamsasSet.getDatasetId());
3409 // materialse the alignment
3410 al = new Alignment(orderedSeqs);
3414 addDatasetRef(vamsasSet.getDatasetId(), al);
3417 // finally, verify all data in vamsasSet is actually present in al
3418 // passing on flag indicating if it is actually a stored dataset
3419 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3422 if (referenceseqForView != null)
3424 al.setSeqrep(referenceseqForView);
3426 // / Add the alignment properties
3427 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3429 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3431 al.setProperty(ssp.getKey(), ssp.getValue());
3434 // ///////////////////////////////
3436 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3439 // load sequence features, database references and any associated PDB
3440 // structures for the alignment
3442 // prior to 2.10, this part would only be executed the first time a
3443 // sequence was encountered, but not afterwards.
3444 // now, for 2.10 projects, this is also done if the xml doc includes
3445 // dataset sequences not actually present in any particular view.
3447 for (int i = 0; i < vamsasSeqs.size(); i++)
3449 JSeq jseq = jseqs.get(i);
3450 if (jseq.getFeatures().size() > 0)
3452 List<Feature> features = jseq.getFeatures();
3453 for (int f = 0; f < features.size(); f++)
3455 Feature feat = features.get(f);
3456 SequenceFeature sf = new SequenceFeature(feat.getType(),
3457 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3458 safeFloat(feat.getScore()), feat.getFeatureGroup());
3459 sf.setStatus(feat.getStatus());
3462 * load any feature attributes - include map-valued attributes
3464 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3465 for (int od = 0; od < feat.getOtherData().size(); od++)
3467 OtherData keyValue = feat.getOtherData().get(od);
3468 String attributeName = keyValue.getKey();
3469 String attributeValue = keyValue.getValue();
3470 if (attributeName.startsWith("LINK"))
3472 sf.addLink(attributeValue);
3476 String subAttribute = keyValue.getKey2();
3477 if (subAttribute == null)
3479 // simple string-valued attribute
3480 sf.setValue(attributeName, attributeValue);
3484 // attribute 'key' has sub-attribute 'key2'
3485 if (!mapAttributes.containsKey(attributeName))
3487 mapAttributes.put(attributeName, new HashMap<>());
3489 mapAttributes.get(attributeName).put(subAttribute,
3494 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3497 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3500 // adds feature to datasequence's feature set (since Jalview 2.10)
3501 al.getSequenceAt(i).addSequenceFeature(sf);
3504 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3506 // adds dbrefs to datasequence's set (since Jalview 2.10)
3508 al.getSequenceAt(i).getDatasetSequence() == null
3509 ? al.getSequenceAt(i)
3510 : al.getSequenceAt(i).getDatasetSequence(),
3513 if (jseq.getPdbids().size() > 0)
3515 List<Pdbids> ids = jseq.getPdbids();
3516 for (int p = 0; p < ids.size(); p++)
3518 Pdbids pdbid = ids.get(p);
3519 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3520 entry.setId(pdbid.getId());
3521 if (pdbid.getType() != null)
3523 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3525 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3529 entry.setType(PDBEntry.Type.FILE);
3532 // jprovider is null when executing 'New View'
3533 if (pdbid.getFile() != null && jprovider != null)
3535 if (!pdbloaded.containsKey(pdbid.getFile()))
3537 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3542 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3546 if (pdbid.getPdbentryItem() != null)
3548 for (PdbentryItem item : pdbid.getPdbentryItem())
3550 for (Property pr : item.getProperty())
3552 entry.setProperty(pr.getName(), pr.getValue());
3557 for (Property prop : pdbid.getProperty())
3559 entry.setProperty(prop.getName(), prop.getValue());
3561 StructureSelectionManager
3562 .getStructureSelectionManager(Desktop.instance)
3563 .registerPDBEntry(entry);
3564 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3565 if (al.getSequenceAt(i).getDatasetSequence() != null)
3567 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3571 al.getSequenceAt(i).addPDBId(entry);
3576 } // end !multipleview
3578 // ///////////////////////////////
3579 // LOAD SEQUENCE MAPPINGS
3581 if (vamsasSet.getAlcodonFrame().size() > 0)
3583 // TODO Potentially this should only be done once for all views of an
3585 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3586 for (int i = 0; i < alc.size(); i++)
3588 AlignedCodonFrame cf = new AlignedCodonFrame();
3589 if (alc.get(i).getAlcodMap().size() > 0)
3591 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3592 for (int m = 0; m < maps.size(); m++)
3594 AlcodMap map = maps.get(m);
3595 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3597 jalview.datamodel.Mapping mapping = null;
3598 // attach to dna sequence reference.
3599 if (map.getMapping() != null)
3601 mapping = addMapping(map.getMapping());
3602 if (dnaseq != null && mapping.getTo() != null)
3604 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3610 newAlcodMapRef(map.getDnasq(), cf, mapping));
3614 al.addCodonFrame(cf);
3619 // ////////////////////////////////
3621 List<JvAnnotRow> autoAlan = new ArrayList<>();
3624 * store any annotations which forward reference a group's ID
3626 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3628 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3630 List<Annotation> an = vamsasSet.getAnnotation();
3632 for (int i = 0; i < an.size(); i++)
3634 Annotation annotation = an.get(i);
3637 * test if annotation is automatically calculated for this view only
3639 boolean autoForView = false;
3640 if (annotation.getLabel().equals("Quality")
3641 || annotation.getLabel().equals("Conservation")
3642 || annotation.getLabel().equals("Consensus"))
3644 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3646 // JAXB has no has() test; schema defaults value to false
3647 // if (!annotation.hasAutoCalculated())
3649 // annotation.setAutoCalculated(true);
3652 if (autoForView || annotation.isAutoCalculated())
3654 // remove ID - we don't recover annotation from other views for
3655 // view-specific annotation
3656 annotation.setId(null);
3659 // set visibility for other annotation in this view
3660 String annotationId = annotation.getId();
3661 if (annotationId != null && annotationIds.containsKey(annotationId))
3663 AlignmentAnnotation jda = annotationIds.get(annotationId);
3664 // in principle Visible should always be true for annotation displayed
3665 // in multiple views
3666 if (annotation.isVisible() != null)
3668 jda.visible = annotation.isVisible();
3671 al.addAnnotation(jda);
3675 // Construct new annotation from model.
3676 List<AnnotationElement> ae = annotation.getAnnotationElement();
3677 jalview.datamodel.Annotation[] anot = null;
3678 java.awt.Color firstColour = null;
3680 if (!annotation.isScoreOnly())
3682 anot = new jalview.datamodel.Annotation[al.getWidth()];
3683 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3685 AnnotationElement annElement = ae.get(aa);
3686 anpos = annElement.getPosition();
3688 if (anpos >= anot.length)
3693 float value = safeFloat(annElement.getValue());
3694 anot[anpos] = new jalview.datamodel.Annotation(
3695 annElement.getDisplayCharacter(),
3696 annElement.getDescription(),
3697 (annElement.getSecondaryStructure() == null
3698 || annElement.getSecondaryStructure()
3702 .getSecondaryStructure()
3705 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3706 if (firstColour == null)
3708 firstColour = anot[anpos].colour;
3712 jalview.datamodel.AlignmentAnnotation jaa = null;
3714 if (annotation.isGraph())
3716 float llim = 0, hlim = 0;
3717 // if (autoForView || an[i].isAutoCalculated()) {
3720 jaa = new jalview.datamodel.AlignmentAnnotation(
3721 annotation.getLabel(), annotation.getDescription(), anot,
3722 llim, hlim, safeInt(annotation.getGraphType()));
3724 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3725 jaa._linecolour = firstColour;
3726 if (annotation.getThresholdLine() != null)
3728 jaa.setThreshold(new jalview.datamodel.GraphLine(
3729 safeFloat(annotation.getThresholdLine().getValue()),
3730 annotation.getThresholdLine().getLabel(),
3731 new java.awt.Color(safeInt(
3732 annotation.getThresholdLine().getColour()))));
3734 if (autoForView || annotation.isAutoCalculated())
3736 // Hardwire the symbol display line to ensure that labels for
3737 // histograms are displayed
3743 jaa = new jalview.datamodel.AlignmentAnnotation(
3744 annotation.getLabel(), annotation.getDescription(), anot);
3745 jaa._linecolour = firstColour;
3747 // register new annotation
3748 if (annotation.getId() != null)
3750 annotationIds.put(annotation.getId(), jaa);
3751 jaa.annotationId = annotation.getId();
3753 // recover sequence association
3754 String sequenceRef = annotation.getSequenceRef();
3755 if (sequenceRef != null)
3757 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3758 SequenceI sequence = seqRefIds.get(sequenceRef);
3759 if (sequence == null)
3761 // in pre-2.9 projects sequence ref is to sequence name
3762 sequence = al.findName(sequenceRef);
3764 if (sequence != null)
3766 jaa.createSequenceMapping(sequence, 1, true);
3767 sequence.addAlignmentAnnotation(jaa);
3770 // and make a note of any group association
3771 if (annotation.getGroupRef() != null
3772 && annotation.getGroupRef().length() > 0)
3774 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3775 .get(annotation.getGroupRef());
3778 aal = new ArrayList<>();
3779 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3784 if (annotation.getScore() != null)
3786 jaa.setScore(annotation.getScore().doubleValue());
3788 if (annotation.isVisible() != null)
3790 jaa.visible = annotation.isVisible().booleanValue();
3793 if (annotation.isCentreColLabels() != null)
3795 jaa.centreColLabels = annotation.isCentreColLabels()
3799 if (annotation.isScaleColLabels() != null)
3801 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3803 if (annotation.isAutoCalculated())
3805 // newer files have an 'autoCalculated' flag and store calculation
3806 // state in viewport properties
3807 jaa.autoCalculated = true; // means annotation will be marked for
3808 // update at end of load.
3810 if (annotation.getGraphHeight() != null)
3812 jaa.graphHeight = annotation.getGraphHeight().intValue();
3814 jaa.belowAlignment = annotation.isBelowAlignment();
3815 jaa.setCalcId(annotation.getCalcId());
3816 if (annotation.getProperty().size() > 0)
3818 for (Annotation.Property prop : annotation
3821 jaa.setProperty(prop.getName(), prop.getValue());
3824 if (jaa.autoCalculated)
3826 autoAlan.add(new JvAnnotRow(i, jaa));
3829 // if (!autoForView)
3831 // add autocalculated group annotation and any user created annotation
3833 al.addAnnotation(jaa);
3837 // ///////////////////////
3839 // Create alignment markup and styles for this view
3840 if (jalviewModel.getJGroup().size() > 0)
3842 List<JGroup> groups = jalviewModel.getJGroup();
3843 boolean addAnnotSchemeGroup = false;
3844 for (int i = 0; i < groups.size(); i++)
3846 JGroup jGroup = groups.get(i);
3847 ColourSchemeI cs = null;
3848 if (jGroup.getColour() != null)
3850 if (jGroup.getColour().startsWith("ucs"))
3852 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3854 else if (jGroup.getColour().equals("AnnotationColourGradient")
3855 && jGroup.getAnnotationColours() != null)
3857 addAnnotSchemeGroup = true;
3861 cs = ColourSchemeProperty.getColourScheme(null, al,
3862 jGroup.getColour());
3865 int pidThreshold = safeInt(jGroup.getPidThreshold());
3867 Vector<SequenceI> seqs = new Vector<>();
3869 for (int s = 0; s < jGroup.getSeq().size(); s++)
3871 String seqId = jGroup.getSeq().get(s);
3872 SequenceI ts = seqRefIds.get(seqId);
3876 seqs.addElement(ts);
3880 if (seqs.size() < 1)
3885 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3886 safeBoolean(jGroup.isDisplayBoxes()),
3887 safeBoolean(jGroup.isDisplayText()),
3888 safeBoolean(jGroup.isColourText()),
3889 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3890 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3891 sg.getGroupColourScheme()
3892 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3893 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3895 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3896 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3897 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3898 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3899 // attributes with a default in the schema are never null
3900 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3901 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3902 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3903 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3904 if (jGroup.getConsThreshold() != null
3905 && jGroup.getConsThreshold().intValue() != 0)
3907 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3910 c.verdict(false, 25);
3911 sg.cs.setConservation(c);
3914 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3916 // re-instate unique group/annotation row reference
3917 List<AlignmentAnnotation> jaal = groupAnnotRefs
3918 .get(jGroup.getId());
3921 for (AlignmentAnnotation jaa : jaal)
3924 if (jaa.autoCalculated)
3926 // match up and try to set group autocalc alignment row for this
3928 if (jaa.label.startsWith("Consensus for "))
3930 sg.setConsensus(jaa);
3932 // match up and try to set group autocalc alignment row for this
3934 if (jaa.label.startsWith("Conservation for "))
3936 sg.setConservationRow(jaa);
3943 if (addAnnotSchemeGroup)
3945 // reconstruct the annotation colourscheme
3946 sg.setColourScheme(constructAnnotationColour(
3947 jGroup.getAnnotationColours(), null, al, jalviewModel, false));
3953 // only dataset in this model, so just return.
3956 // ///////////////////////////////
3959 AlignFrame af = null;
3960 AlignViewport av = null;
3961 // now check to see if we really need to create a new viewport.
3962 if (multipleView && viewportsAdded.size() == 0)
3964 // We recovered an alignment for which a viewport already exists.
3965 // TODO: fix up any settings necessary for overlaying stored state onto
3966 // state recovered from another document. (may not be necessary).
3967 // we may need a binding from a viewport in memory to one recovered from
3969 // and then recover its containing af to allow the settings to be applied.
3970 // TODO: fix for vamsas demo
3972 "About to recover a viewport for existing alignment: Sequence set ID is "
3974 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3975 if (seqsetobj != null)
3977 if (seqsetobj instanceof String)
3979 uniqueSeqSetId = (String) seqsetobj;
3981 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
3987 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
3993 * indicate that annotation colours are applied across all groups (pre
3994 * Jalview 2.8.1 behaviour)
3996 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
3997 jalviewModel.getVersion());
3999 AlignmentPanel ap = null;
4000 boolean isnewview = true;
4003 // Check to see if this alignment already has a view id == viewId
4004 jalview.gui.AlignmentPanel views[] = Desktop
4005 .getAlignmentPanels(uniqueSeqSetId);
4006 if (views != null && views.length > 0)
4008 for (int v = 0; v < views.length; v++)
4010 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4012 // recover the existing alignpanel, alignframe, viewport
4013 af = views[v].alignFrame;
4016 // TODO: could even skip resetting view settings if we don't want to
4017 // change the local settings from other jalview processes
4026 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4027 uniqueSeqSetId, viewId, autoAlan);
4028 av = af.getViewport();
4033 * Load any trees, PDB structures and viewers
4035 * Not done if flag is false (when this method is used for New View)
4037 if (loadTreesAndStructures)
4039 loadTrees(jalviewModel, view, af, av, ap);
4040 loadPCAViewers(jalviewModel, ap);
4041 loadPDBStructures(jprovider, jseqs, af, ap);
4042 loadRnaViewers(jprovider, jseqs, ap);
4044 // and finally return.
4049 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4050 * panel is restored from separate jar entries, two (gapped and trimmed) per
4051 * sequence and secondary structure.
4053 * Currently each viewer shows just one sequence and structure (gapped and
4054 * trimmed), however this method is designed to support multiple sequences or
4055 * structures in viewers if wanted in future.
4061 private void loadRnaViewers(jarInputStreamProvider jprovider,
4062 List<JSeq> jseqs, AlignmentPanel ap)
4065 * scan the sequences for references to viewers; create each one the first
4066 * time it is referenced, add Rna models to existing viewers
4068 for (JSeq jseq : jseqs)
4070 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4072 RnaViewer viewer = jseq.getRnaViewer().get(i);
4073 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4076 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4078 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4079 SequenceI seq = seqRefIds.get(jseq.getId());
4080 AlignmentAnnotation ann = this.annotationIds
4081 .get(ss.getAnnotationId());
4084 * add the structure to the Varna display (with session state copied
4085 * from the jar to a temporary file)
4087 boolean gapped = safeBoolean(ss.isGapped());
4088 String rnaTitle = ss.getTitle();
4089 String sessionState = ss.getViewerState();
4090 String tempStateFile = copyJarEntry(jprovider, sessionState,
4092 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4093 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4095 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4101 * Locate and return an already instantiated matching AppVarna, or create one
4105 * @param viewIdSuffix
4109 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4110 String viewIdSuffix, AlignmentPanel ap)
4113 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4114 * if load is repeated
4116 String postLoadId = viewer.getViewId() + viewIdSuffix;
4117 for (JInternalFrame frame : getAllFrames())
4119 if (frame instanceof AppVarna)
4121 AppVarna varna = (AppVarna) frame;
4122 if (postLoadId.equals(varna.getViewId()))
4124 // this viewer is already instantiated
4125 // could in future here add ap as another 'parent' of the
4126 // AppVarna window; currently just 1-to-many
4133 * viewer not found - make it
4135 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4136 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4137 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4138 safeInt(viewer.getDividerLocation()));
4139 AppVarna varna = new AppVarna(model, ap);
4145 * Load any saved trees
4153 protected void loadTrees(JalviewModel jm, Viewport view,
4154 AlignFrame af, AlignViewport av, AlignmentPanel ap)
4156 // TODO result of automated refactoring - are all these parameters needed?
4159 for (int t = 0; t < jm.getTree().size(); t++)
4162 Tree tree = jm.getTree().get(t);
4164 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4167 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4168 tree.getTitle(), safeInt(tree.getWidth()),
4169 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4170 safeInt(tree.getYpos()));
4171 if (tree.getId() != null)
4173 // perhaps bind the tree id to something ?
4178 // update local tree attributes ?
4179 // TODO: should check if tp has been manipulated by user - if so its
4180 // settings shouldn't be modified
4181 tp.setTitle(tree.getTitle());
4182 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4183 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4184 safeInt(tree.getHeight())));
4185 tp.setViewport(av); // af.viewport;
4186 // TODO: verify 'associate with all views' works still
4187 tp.getTreeCanvas().setViewport(av); // af.viewport;
4188 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4190 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4193 warn("There was a problem recovering stored Newick tree: \n"
4194 + tree.getNewick());
4198 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4199 tp.fitToWindow_actionPerformed(null);
4201 if (tree.getFontName() != null)
4204 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4205 safeInt(tree.getFontSize())));
4210 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4211 safeInt(view.getFontSize())));
4214 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4215 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4216 tp.showDistances(safeBoolean(tree.isShowDistances()));
4218 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4220 if (safeBoolean(tree.isCurrentTree()))
4222 af.getViewport().setCurrentTree(tp.getTree());
4226 } catch (Exception ex)
4228 ex.printStackTrace();
4233 * Load and link any saved structure viewers.
4240 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4241 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4244 * Run through all PDB ids on the alignment, and collect mappings between
4245 * distinct view ids and all sequences referring to that view.
4247 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4249 for (int i = 0; i < jseqs.size(); i++)
4251 JSeq jseq = jseqs.get(i);
4252 if (jseq.getPdbids().size() > 0)
4254 List<Pdbids> ids = jseq.getPdbids();
4255 for (int p = 0; p < ids.size(); p++)
4257 Pdbids pdbid = ids.get(p);
4258 final int structureStateCount = pdbid.getStructureState().size();
4259 for (int s = 0; s < structureStateCount; s++)
4261 // check to see if we haven't already created this structure view
4262 final StructureState structureState = pdbid
4263 .getStructureState().get(s);
4264 String sviewid = (structureState.getViewId() == null) ? null
4265 : structureState.getViewId() + uniqueSetSuffix;
4266 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4267 // Originally : pdbid.getFile()
4268 // : TODO: verify external PDB file recovery still works in normal
4269 // jalview project load
4271 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4272 jpdb.setId(pdbid.getId());
4274 int x = safeInt(structureState.getXpos());
4275 int y = safeInt(structureState.getYpos());
4276 int width = safeInt(structureState.getWidth());
4277 int height = safeInt(structureState.getHeight());
4279 // Probably don't need to do this anymore...
4280 // Desktop.desktop.getComponentAt(x, y);
4281 // TODO: NOW: check that this recovers the PDB file correctly.
4282 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4284 jalview.datamodel.SequenceI seq = seqRefIds
4285 .get(jseq.getId() + "");
4286 if (sviewid == null)
4288 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4291 if (!structureViewers.containsKey(sviewid))
4293 String viewerType = structureState.getType();
4294 if (viewerType == null) // pre Jalview 2.9
4296 viewerType = ViewerType.JMOL.toString();
4298 structureViewers.put(sviewid,
4299 new StructureViewerModel(x, y, width, height, false,
4300 false, true, structureState.getViewId(),
4302 // Legacy pre-2.7 conversion JAL-823 :
4303 // do not assume any view has to be linked for colour by
4307 // assemble String[] { pdb files }, String[] { id for each
4308 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4309 // seqs_file 2}, boolean[] {
4310 // linkAlignPanel,superposeWithAlignpanel}} from hash
4311 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4312 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4313 || structureState.isAlignwithAlignPanel());
4316 * Default colour by linked panel to false if not specified (e.g.
4317 * for pre-2.7 projects)
4319 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4320 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4321 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4324 * Default colour by viewer to true if not specified (e.g. for
4327 boolean colourByViewer = jmoldat.isColourByViewer();
4328 colourByViewer &= structureState.isColourByJmol();
4329 jmoldat.setColourByViewer(colourByViewer);
4331 if (jmoldat.getStateData().length() < structureState
4332 .getValue()/*Content()*/.length())
4334 jmoldat.setStateData(structureState.getValue());// Content());
4336 if (pdbid.getFile() != null)
4338 File mapkey = new File(pdbid.getFile());
4339 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4340 if (seqstrmaps == null)
4342 jmoldat.getFileData().put(mapkey,
4343 seqstrmaps = jmoldat.new StructureData(pdbFile,
4346 if (!seqstrmaps.getSeqList().contains(seq))
4348 seqstrmaps.getSeqList().add(seq);
4354 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");
4361 // Instantiate the associated structure views
4362 for (Entry<String, StructureViewerModel> entry : structureViewers
4367 createOrLinkStructureViewer(entry, af, ap, jprovider);
4368 } catch (Exception e)
4371 "Error loading structure viewer: " + e.getMessage());
4372 // failed - try the next one
4384 protected void createOrLinkStructureViewer(
4385 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4386 AlignmentPanel ap, jarInputStreamProvider jprovider)
4388 final StructureViewerModel stateData = viewerData.getValue();
4391 * Search for any viewer windows already open from other alignment views
4392 * that exactly match the stored structure state
4394 StructureViewerBase comp = findMatchingViewer(viewerData);
4398 linkStructureViewer(ap, comp, stateData);
4402 String type = stateData.getType();
4405 ViewerType viewerType = ViewerType.valueOf(type);
4406 createStructureViewer(viewerType, viewerData, af, jprovider);
4407 } catch (IllegalArgumentException | NullPointerException e)
4409 // TODO JAL-3619 show error dialog / offer an alternative viewer
4411 "Invalid structure viewer type: " + type);
4416 * Generates a name for the entry in the project jar file to hold state
4417 * information for a structure viewer
4422 protected String getViewerJarEntryName(String viewId)
4424 return VIEWER_PREFIX + viewId;
4428 * Returns any open frame that matches given structure viewer data. The match
4429 * is based on the unique viewId, or (for older project versions) the frame's
4435 protected StructureViewerBase findMatchingViewer(
4436 Entry<String, StructureViewerModel> viewerData)
4438 final String sviewid = viewerData.getKey();
4439 final StructureViewerModel svattrib = viewerData.getValue();
4440 StructureViewerBase comp = null;
4441 JInternalFrame[] frames = getAllFrames();
4442 for (JInternalFrame frame : frames)
4444 if (frame instanceof StructureViewerBase)
4447 * Post jalview 2.4 schema includes structure view id
4449 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4452 comp = (StructureViewerBase) frame;
4453 break; // break added in 2.9
4456 * Otherwise test for matching position and size of viewer frame
4458 else if (frame.getX() == svattrib.getX()
4459 && frame.getY() == svattrib.getY()
4460 && frame.getHeight() == svattrib.getHeight()
4461 && frame.getWidth() == svattrib.getWidth())
4463 comp = (StructureViewerBase) frame;
4464 // no break in faint hope of an exact match on viewId
4472 * Link an AlignmentPanel to an existing structure viewer.
4477 * @param useinViewerSuperpos
4478 * @param usetoColourbyseq
4479 * @param viewerColouring
4481 protected void linkStructureViewer(AlignmentPanel ap,
4482 StructureViewerBase viewer, StructureViewerModel stateData)
4484 // NOTE: if the jalview project is part of a shared session then
4485 // view synchronization should/could be done here.
4487 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4488 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4489 final boolean viewerColouring = stateData.isColourByViewer();
4490 Map<File, StructureData> oldFiles = stateData.getFileData();
4493 * Add mapping for sequences in this view to an already open viewer
4495 final AAStructureBindingModel binding = viewer.getBinding();
4496 for (File id : oldFiles.keySet())
4498 // add this and any other pdb files that should be present in the
4500 StructureData filedat = oldFiles.get(id);
4501 String pdbFile = filedat.getFilePath();
4502 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4503 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4505 binding.addSequenceForStructFile(pdbFile, seq);
4507 // and add the AlignmentPanel's reference to the view panel
4508 viewer.addAlignmentPanel(ap);
4509 if (useinViewerSuperpos)
4511 viewer.useAlignmentPanelForSuperposition(ap);
4515 viewer.excludeAlignmentPanelForSuperposition(ap);
4517 if (usetoColourbyseq)
4519 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4523 viewer.excludeAlignmentPanelForColourbyseq(ap);
4528 * Get all frames within the Desktop.
4532 protected JInternalFrame[] getAllFrames()
4534 JInternalFrame[] frames = null;
4535 // TODO is this necessary - is it safe - risk of hanging?
4540 frames = Desktop.desktop.getAllFrames();
4541 } catch (ArrayIndexOutOfBoundsException e)
4543 // occasional No such child exceptions are thrown here...
4547 } catch (InterruptedException f)
4551 } while (frames == null);
4556 * Answers true if 'version' is equal to or later than 'supported', where each
4557 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4558 * changes. Development and test values for 'version' are leniently treated
4562 * - minimum version we are comparing against
4564 * - version of data being processsed
4567 public static boolean isVersionStringLaterThan(String supported,
4570 if (supported == null || version == null
4571 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4572 || version.equalsIgnoreCase("Test")
4573 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4575 System.err.println("Assuming project file with "
4576 + (version == null ? "null" : version)
4577 + " is compatible with Jalview version " + supported);
4582 return StringUtils.compareVersions(version, supported, "b") >= 0;
4586 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4588 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4590 if (newStructureViewers != null)
4592 sview.getBinding().setFinishedLoadingFromArchive(false);
4593 newStructureViewers.add(sview);
4597 protected void setLoadingFinishedForNewStructureViewers()
4599 if (newStructureViewers != null)
4601 for (JalviewStructureDisplayI sview : newStructureViewers)
4603 sview.getBinding().setFinishedLoadingFromArchive(true);
4605 newStructureViewers.clear();
4606 newStructureViewers = null;
4610 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4611 List<SequenceI> hiddenSeqs, AlignmentI al,
4612 JalviewModel jm, Viewport view, String uniqueSeqSetId,
4613 String viewId, List<JvAnnotRow> autoAlan)
4615 AlignFrame af = null;
4616 af = new AlignFrame(al, safeInt(view.getWidth()),
4617 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
4621 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
4622 // System.out.println("Jalview2XML AF " + e);
4623 // super.processKeyEvent(e);
4630 af.setFileName(file, FileFormat.Jalview);
4632 final AlignViewport viewport = af.getViewport();
4633 for (int i = 0; i < JSEQ.size(); i++)
4635 int colour = safeInt(JSEQ.get(i).getColour());
4636 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4642 viewport.setColourByReferenceSeq(true);
4643 viewport.setDisplayReferenceSeq(true);
4646 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4648 if (view.getSequenceSetId() != null)
4650 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4652 viewport.setSequenceSetId(uniqueSeqSetId);
4655 // propagate shared settings to this new view
4656 viewport.setHistoryList(av.getHistoryList());
4657 viewport.setRedoList(av.getRedoList());
4661 viewportsAdded.put(uniqueSeqSetId, viewport);
4663 // TODO: check if this method can be called repeatedly without
4664 // side-effects if alignpanel already registered.
4665 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4667 // apply Hidden regions to view.
4668 if (hiddenSeqs != null)
4670 for (int s = 0; s < JSEQ.size(); s++)
4672 SequenceGroup hidden = new SequenceGroup();
4673 boolean isRepresentative = false;
4674 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4676 isRepresentative = true;
4677 SequenceI sequenceToHide = al
4678 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4679 hidden.addSequence(sequenceToHide, false);
4680 // remove from hiddenSeqs list so we don't try to hide it twice
4681 hiddenSeqs.remove(sequenceToHide);
4683 if (isRepresentative)
4685 SequenceI representativeSequence = al.getSequenceAt(s);
4686 hidden.addSequence(representativeSequence, false);
4687 viewport.hideRepSequences(representativeSequence, hidden);
4691 SequenceI[] hseqs = hiddenSeqs
4692 .toArray(new SequenceI[hiddenSeqs.size()]);
4693 viewport.hideSequence(hseqs);
4696 // recover view properties and display parameters
4698 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4699 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4700 final int pidThreshold = safeInt(view.getPidThreshold());
4701 viewport.setThreshold(pidThreshold);
4703 viewport.setColourText(safeBoolean(view.isShowColourText()));
4706 .setConservationSelected(
4707 safeBoolean(view.isConservationSelected()));
4708 viewport.setIncrement(safeInt(view.getConsThreshold()));
4709 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4710 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4711 viewport.setFont(new Font(view.getFontName(),
4712 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4714 ViewStyleI vs = viewport.getViewStyle();
4715 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4716 viewport.setViewStyle(vs);
4717 // TODO: allow custom charWidth/Heights to be restored by updating them
4718 // after setting font - which means set above to false
4719 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4720 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4721 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4723 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4725 viewport.setShowText(safeBoolean(view.isShowText()));
4727 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4728 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4729 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4730 viewport.setShowUnconserved(view.isShowUnconserved());
4731 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4733 if (view.getViewName() != null)
4735 viewport.setViewName(view.getViewName());
4736 af.setInitialTabVisible();
4738 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4739 safeInt(view.getWidth()), safeInt(view.getHeight()));
4740 // startSeq set in af.alignPanel.updateLayout below
4741 af.alignPanel.updateLayout();
4742 ColourSchemeI cs = null;
4743 // apply colourschemes
4744 if (view.getBgColour() != null)
4746 if (view.getBgColour().startsWith("ucs"))
4748 cs = getUserColourScheme(jm, view.getBgColour());
4750 else if (view.getBgColour().startsWith("Annotation"))
4752 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4753 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4760 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4761 view.getBgColour());
4766 * turn off 'alignment colour applies to all groups'
4767 * while restoring global colour scheme
4769 viewport.setColourAppliesToAllGroups(false);
4770 viewport.setGlobalColourScheme(cs);
4771 viewport.getResidueShading().setThreshold(pidThreshold,
4772 view.isIgnoreGapsinConsensus());
4773 viewport.getResidueShading()
4774 .setConsensus(viewport.getSequenceConsensusHash());
4775 if (safeBoolean(view.isConservationSelected()) && cs != null)
4777 viewport.getResidueShading()
4778 .setConservationInc(safeInt(view.getConsThreshold()));
4780 af.changeColour(cs);
4781 viewport.setColourAppliesToAllGroups(true);
4784 .setShowSequenceFeatures(
4785 safeBoolean(view.isShowSequenceFeatures()));
4787 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
4788 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
4789 viewport.setFollowHighlight(view.isFollowHighlight());
4790 viewport.followSelection = view.isFollowSelection();
4791 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
4792 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
4793 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
4794 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
4795 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
4796 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
4797 viewport.setShowGroupConservation(view.isShowGroupConservation());
4798 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
4799 viewport.setShowComplementFeaturesOnTop(
4800 view.isShowComplementFeaturesOnTop());
4802 // recover feature settings
4803 if (jm.getFeatureSettings() != null)
4805 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
4806 .getFeatureRenderer();
4807 FeaturesDisplayed fdi;
4808 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
4809 String[] renderOrder = new String[jm.getFeatureSettings()
4810 .getSetting().size()];
4811 Map<String, FeatureColourI> featureColours = new Hashtable<>();
4812 Map<String, Float> featureOrder = new Hashtable<>();
4814 for (int fs = 0; fs < jm.getFeatureSettings()
4815 .getSetting().size(); fs++)
4817 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
4818 String featureType = setting.getType();
4821 * restore feature filters (if any)
4823 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
4825 if (filters != null)
4827 FeatureMatcherSetI filter = Jalview2XML
4828 .parseFilter(featureType, filters);
4829 if (!filter.isEmpty())
4831 fr.setFeatureFilter(featureType, filter);
4836 * restore feature colour scheme
4838 Color maxColour = new Color(setting.getColour());
4839 if (setting.getMincolour() != null)
4842 * minColour is always set unless a simple colour
4843 * (including for colour by label though it doesn't use it)
4845 Color minColour = new Color(setting.getMincolour().intValue());
4846 Color noValueColour = minColour;
4847 NoValueColour noColour = setting.getNoValueColour();
4848 if (noColour == NoValueColour.NONE)
4850 noValueColour = null;
4852 else if (noColour == NoValueColour.MAX)
4854 noValueColour = maxColour;
4856 float min = safeFloat(safeFloat(setting.getMin()));
4857 float max = setting.getMax() == null ? 1f
4858 : setting.getMax().floatValue();
4859 FeatureColourI gc = new FeatureColour(maxColour, minColour,
4861 noValueColour, min, max);
4862 if (setting.getAttributeName().size() > 0)
4864 gc.setAttributeName(setting.getAttributeName().toArray(
4865 new String[setting.getAttributeName().size()]));
4867 if (setting.getThreshold() != null)
4869 gc.setThreshold(setting.getThreshold().floatValue());
4870 int threshstate = safeInt(setting.getThreshstate());
4871 // -1 = None, 0 = Below, 1 = Above threshold
4872 if (threshstate == 0)
4874 gc.setBelowThreshold(true);
4876 else if (threshstate == 1)
4878 gc.setAboveThreshold(true);
4881 gc.setAutoScaled(true); // default
4882 if (setting.isAutoScale() != null)
4884 gc.setAutoScaled(setting.isAutoScale());
4886 if (setting.isColourByLabel() != null)
4888 gc.setColourByLabel(setting.isColourByLabel());
4890 // and put in the feature colour table.
4891 featureColours.put(featureType, gc);
4895 featureColours.put(featureType,
4896 new FeatureColour(maxColour));
4898 renderOrder[fs] = featureType;
4899 if (setting.getOrder() != null)
4901 featureOrder.put(featureType, setting.getOrder().floatValue());
4905 featureOrder.put(featureType, Float.valueOf(
4906 fs / jm.getFeatureSettings().getSetting().size()));
4908 if (safeBoolean(setting.isDisplay()))
4910 fdi.setVisible(featureType);
4913 Map<String, Boolean> fgtable = new Hashtable<>();
4914 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
4916 Group grp = jm.getFeatureSettings().getGroup().get(gs);
4917 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
4919 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4920 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
4921 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
4922 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
4923 fgtable, featureColours, 1.0f, featureOrder);
4924 fr.transferSettings(frs);
4927 if (view.getHiddenColumns().size() > 0)
4929 for (int c = 0; c < view.getHiddenColumns().size(); c++)
4931 final HiddenColumns hc = view.getHiddenColumns().get(c);
4932 viewport.hideColumns(safeInt(hc.getStart()),
4933 safeInt(hc.getEnd()) /* +1 */);
4936 if (view.getCalcIdParam() != null)
4938 for (CalcIdParam calcIdParam : view.getCalcIdParam())
4940 if (calcIdParam != null)
4942 if (recoverCalcIdParam(calcIdParam, viewport))
4947 warn("Couldn't recover parameters for "
4948 + calcIdParam.getCalcId());
4953 af.setMenusFromViewport(viewport);
4954 af.setTitle(view.getTitle());
4955 // TODO: we don't need to do this if the viewport is aready visible.
4957 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
4958 * has a 'cdna/protein complement' view, in which case save it in order to
4959 * populate a SplitFrame once all views have been read in.
4961 String complementaryViewId = view.getComplementId();
4962 if (complementaryViewId == null)
4964 Desktop.addInternalFrame(af, view.getTitle(),
4965 safeInt(view.getWidth()), safeInt(view.getHeight()));
4966 // recompute any autoannotation
4967 af.alignPanel.updateAnnotation(false, true);
4968 reorderAutoannotation(af, al, autoAlan);
4969 af.alignPanel.alignmentChanged();
4973 splitFrameCandidates.put(view, af);
4979 * Reads saved data to restore Colour by Annotation settings
4981 * @param viewAnnColour
4985 * @param checkGroupAnnColour
4988 private ColourSchemeI constructAnnotationColour(
4989 AnnotationColourScheme viewAnnColour, AlignFrame af,
4990 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
4992 boolean propagateAnnColour = false;
4993 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
4995 if (checkGroupAnnColour && al.getGroups() != null
4996 && al.getGroups().size() > 0)
4998 // pre 2.8.1 behaviour
4999 // check to see if we should transfer annotation colours
5000 propagateAnnColour = true;
5001 for (SequenceGroup sg : al.getGroups())
5003 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5005 propagateAnnColour = false;
5011 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5013 String annotationId = viewAnnColour.getAnnotation();
5014 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5017 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5019 if (matchedAnnotation == null
5020 && annAlignment.getAlignmentAnnotation() != null)
5022 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5025 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5027 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5032 if (matchedAnnotation == null)
5034 System.err.println("Failed to match annotation colour scheme for "
5038 if (matchedAnnotation.getThreshold() == null)
5040 matchedAnnotation.setThreshold(
5041 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5042 "Threshold", Color.black));
5045 AnnotationColourGradient cs = null;
5046 if (viewAnnColour.getColourScheme().equals("None"))
5048 cs = new AnnotationColourGradient(matchedAnnotation,
5049 new Color(safeInt(viewAnnColour.getMinColour())),
5050 new Color(safeInt(viewAnnColour.getMaxColour())),
5051 safeInt(viewAnnColour.getAboveThreshold()));
5053 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5055 cs = new AnnotationColourGradient(matchedAnnotation,
5056 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5057 safeInt(viewAnnColour.getAboveThreshold()));
5061 cs = new AnnotationColourGradient(matchedAnnotation,
5062 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5063 viewAnnColour.getColourScheme()),
5064 safeInt(viewAnnColour.getAboveThreshold()));
5067 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5068 boolean useOriginalColours = safeBoolean(
5069 viewAnnColour.isPredefinedColours());
5070 cs.setSeqAssociated(perSequenceOnly);
5071 cs.setPredefinedColours(useOriginalColours);
5073 if (propagateAnnColour && al.getGroups() != null)
5075 // Also use these settings for all the groups
5076 for (int g = 0; g < al.getGroups().size(); g++)
5078 SequenceGroup sg = al.getGroups().get(g);
5079 if (sg.getGroupColourScheme() == null)
5084 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5085 matchedAnnotation, sg.getColourScheme(),
5086 safeInt(viewAnnColour.getAboveThreshold()));
5087 sg.setColourScheme(groupScheme);
5088 groupScheme.setSeqAssociated(perSequenceOnly);
5089 groupScheme.setPredefinedColours(useOriginalColours);
5095 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5096 List<JvAnnotRow> autoAlan)
5098 // copy over visualization settings for autocalculated annotation in the
5100 if (al.getAlignmentAnnotation() != null)
5103 * Kludge for magic autoannotation names (see JAL-811)
5105 String[] magicNames = new String[] { "Consensus", "Quality",
5107 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5108 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5109 for (String nm : magicNames)
5111 visan.put(nm, nullAnnot);
5113 for (JvAnnotRow auan : autoAlan)
5115 visan.put(auan.template.label
5116 + (auan.template.getCalcId() == null ? ""
5117 : "\t" + auan.template.getCalcId()),
5120 int hSize = al.getAlignmentAnnotation().length;
5121 List<JvAnnotRow> reorder = new ArrayList<>();
5122 // work through any autoCalculated annotation already on the view
5123 // removing it if it should be placed in a different location on the
5124 // annotation panel.
5125 List<String> remains = new ArrayList<>(visan.keySet());
5126 for (int h = 0; h < hSize; h++)
5128 jalview.datamodel.AlignmentAnnotation jalan = al
5129 .getAlignmentAnnotation()[h];
5130 if (jalan.autoCalculated)
5133 JvAnnotRow valan = visan.get(k = jalan.label);
5134 if (jalan.getCalcId() != null)
5136 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5141 // delete the auto calculated row from the alignment
5142 al.deleteAnnotation(jalan, false);
5146 if (valan != nullAnnot)
5148 if (jalan != valan.template)
5150 // newly created autoannotation row instance
5151 // so keep a reference to the visible annotation row
5152 // and copy over all relevant attributes
5153 if (valan.template.graphHeight >= 0)
5156 jalan.graphHeight = valan.template.graphHeight;
5158 jalan.visible = valan.template.visible;
5160 reorder.add(new JvAnnotRow(valan.order, jalan));
5165 // Add any (possibly stale) autocalculated rows that were not appended to
5166 // the view during construction
5167 for (String other : remains)
5169 JvAnnotRow othera = visan.get(other);
5170 if (othera != nullAnnot && othera.template.getCalcId() != null
5171 && othera.template.getCalcId().length() > 0)
5173 reorder.add(othera);
5176 // now put the automatic annotation in its correct place
5177 int s = 0, srt[] = new int[reorder.size()];
5178 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5179 for (JvAnnotRow jvar : reorder)
5182 srt[s++] = jvar.order;
5185 jalview.util.QuickSort.sort(srt, rws);
5186 // and re-insert the annotation at its correct position
5187 for (JvAnnotRow jvar : rws)
5189 al.addAnnotation(jvar.template, jvar.order);
5191 af.alignPanel.adjustAnnotationHeight();
5195 Hashtable skipList = null;
5198 * TODO remove this method
5201 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5202 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5203 * throw new Error("Implementation Error. No skipList defined for this
5204 * Jalview2XML instance."); } return (AlignFrame)
5205 * skipList.get(view.getSequenceSetId()); }
5209 * Check if the Jalview view contained in object should be skipped or not.
5212 * @return true if view's sequenceSetId is a key in skipList
5214 private boolean skipViewport(JalviewModel object)
5216 if (skipList == null)
5220 String id = object.getViewport().get(0).getSequenceSetId();
5221 if (skipList.containsKey(id))
5223 if (Cache.log != null && Cache.log.isDebugEnabled())
5225 Cache.log.debug("Skipping seuqence set id " + id);
5232 public void addToSkipList(AlignFrame af)
5234 if (skipList == null)
5236 skipList = new Hashtable();
5238 skipList.put(af.getViewport().getSequenceSetId(), af);
5241 public void clearSkipList()
5243 if (skipList != null)
5250 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5251 boolean ignoreUnrefed, String uniqueSeqSetId)
5253 jalview.datamodel.AlignmentI ds = getDatasetFor(
5254 vamsasSet.getDatasetId());
5255 AlignmentI xtant_ds = ds;
5256 if (xtant_ds == null)
5258 // good chance we are about to create a new dataset, but check if we've
5259 // seen some of the dataset sequence IDs before.
5260 // TODO: skip this check if we are working with project generated by
5261 // version 2.11 or later
5262 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5263 if (xtant_ds != null)
5266 addDatasetRef(vamsasSet.getDatasetId(), ds);
5269 Vector<SequenceI> dseqs = null;
5272 // recovering an alignment View
5273 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5274 if (seqSetDS != null)
5276 if (ds != null && ds != seqSetDS)
5278 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5279 + " - CDS/Protein crossreference data may be lost");
5280 if (xtant_ds != null)
5282 // This can only happen if the unique sequence set ID was bound to a
5283 // dataset that did not contain any of the sequences in the view
5284 // currently being restored.
5285 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.");
5289 addDatasetRef(vamsasSet.getDatasetId(), ds);
5294 // try even harder to restore dataset
5295 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5296 // create a list of new dataset sequences
5297 dseqs = new Vector<>();
5299 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5301 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5302 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5304 // create a new dataset
5307 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5308 dseqs.copyInto(dsseqs);
5309 ds = new jalview.datamodel.Alignment(dsseqs);
5310 debug("Created new dataset " + vamsasSet.getDatasetId()
5311 + " for alignment " + System.identityHashCode(al));
5312 addDatasetRef(vamsasSet.getDatasetId(), ds);
5314 // set the dataset for the newly imported alignment.
5315 if (al.getDataset() == null && !ignoreUnrefed)
5318 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5319 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5321 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5325 * XML dataset sequence ID to materialised dataset reference
5327 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5330 * @return the first materialised dataset reference containing a dataset
5331 * sequence referenced in the given view
5333 * - sequences from the view
5335 AlignmentI checkIfHasDataset(List<Sequence> list)
5337 for (Sequence restoredSeq : list)
5339 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5340 if (datasetFor != null)
5349 * Register ds as the containing dataset for the dataset sequences referenced
5350 * by sequences in list
5353 * - sequences in a view
5356 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5358 for (Sequence restoredSeq : list)
5360 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5361 if (prevDS != null && prevDS != ds)
5363 warn("Dataset sequence appears in many datasets: "
5364 + restoredSeq.getDsseqid());
5365 // TODO: try to merge!
5372 * sequence definition to create/merge dataset sequence for
5376 * vector to add new dataset sequence to
5377 * @param ignoreUnrefed
5378 * - when true, don't create new sequences from vamsasSeq if it's id
5379 * doesn't already have an asssociated Jalview sequence.
5381 * - used to reorder the sequence in the alignment according to the
5382 * vamsasSeq array ordering, to preserve ordering of dataset
5384 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5385 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5388 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5390 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5391 boolean reorder = false;
5392 SequenceI dsq = null;
5393 if (sq != null && sq.getDatasetSequence() != null)
5395 dsq = sq.getDatasetSequence();
5401 if (sq == null && ignoreUnrefed)
5405 String sqid = vamsasSeq.getDsseqid();
5408 // need to create or add a new dataset sequence reference to this sequence
5411 dsq = seqRefIds.get(sqid);
5416 // make a new dataset sequence
5417 dsq = sq.createDatasetSequence();
5420 // make up a new dataset reference for this sequence
5421 sqid = seqHash(dsq);
5423 dsq.setVamsasId(uniqueSetSuffix + sqid);
5424 seqRefIds.put(sqid, dsq);
5429 dseqs.addElement(dsq);
5434 ds.addSequence(dsq);
5440 { // make this dataset sequence sq's dataset sequence
5441 sq.setDatasetSequence(dsq);
5442 // and update the current dataset alignment
5447 if (!dseqs.contains(dsq))
5454 if (ds.findIndex(dsq) < 0)
5456 ds.addSequence(dsq);
5463 // TODO: refactor this as a merge dataset sequence function
5464 // now check that sq (the dataset sequence) sequence really is the union of
5465 // all references to it
5466 // boolean pre = sq.getStart() < dsq.getStart();
5467 // boolean post = sq.getEnd() > dsq.getEnd();
5471 // StringBuffer sb = new StringBuffer();
5472 String newres = jalview.analysis.AlignSeq.extractGaps(
5473 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5474 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5475 && newres.length() > dsq.getLength())
5477 // Update with the longer sequence.
5481 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5482 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5483 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5484 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5486 dsq.setSequence(newres);
5488 // TODO: merges will never happen if we 'know' we have the real dataset
5489 // sequence - this should be detected when id==dssid
5491 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5492 // + (pre ? "prepended" : "") + " "
5493 // + (post ? "appended" : ""));
5498 // sequence refs are identical. We may need to update the existing dataset
5499 // alignment with this one, though.
5500 if (ds != null && dseqs == null)
5502 int opos = ds.findIndex(dsq);
5503 SequenceI tseq = null;
5504 if (opos != -1 && vseqpos != opos)
5506 // remove from old position
5507 ds.deleteSequence(dsq);
5509 if (vseqpos < ds.getHeight())
5511 if (vseqpos != opos)
5513 // save sequence at destination position
5514 tseq = ds.getSequenceAt(vseqpos);
5515 ds.replaceSequenceAt(vseqpos, dsq);
5516 ds.addSequence(tseq);
5521 ds.addSequence(dsq);
5528 * TODO use AlignmentI here and in related methods - needs
5529 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5531 Hashtable<String, AlignmentI> datasetIds = null;
5533 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5535 private AlignmentI getDatasetFor(String datasetId)
5537 if (datasetIds == null)
5539 datasetIds = new Hashtable<>();
5542 if (datasetIds.containsKey(datasetId))
5544 return datasetIds.get(datasetId);
5549 private void addDatasetRef(String datasetId, AlignmentI dataset)
5551 if (datasetIds == null)
5553 datasetIds = new Hashtable<>();
5555 datasetIds.put(datasetId, dataset);
5559 * make a new dataset ID for this jalview dataset alignment
5564 private String getDatasetIdRef(AlignmentI dataset)
5566 if (dataset.getDataset() != null)
5568 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5570 String datasetId = makeHashCode(dataset, null);
5571 if (datasetId == null)
5573 // make a new datasetId and record it
5574 if (dataset2Ids == null)
5576 dataset2Ids = new IdentityHashMap<>();
5580 datasetId = dataset2Ids.get(dataset);
5582 if (datasetId == null)
5584 datasetId = "ds" + dataset2Ids.size() + 1;
5585 dataset2Ids.put(dataset, datasetId);
5592 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5593 * constructed as a special subclass GeneLocus.
5595 * @param datasetSequence
5598 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5600 for (int d = 0; d < sequence.getDBRef().size(); d++)
5602 DBRef dr = sequence.getDBRef().get(d);
5606 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5607 dr.getAccessionId());
5611 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5612 dr.getAccessionId());
5614 if (dr.getMapping() != null)
5616 entry.setMap(addMapping(dr.getMapping()));
5618 datasetSequence.addDBRef(entry);
5622 private jalview.datamodel.Mapping addMapping(Mapping m)
5624 SequenceI dsto = null;
5625 // Mapping m = dr.getMapping();
5626 int fr[] = new int[m.getMapListFrom().size() * 2];
5627 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5628 for (int _i = 0; from.hasNext(); _i += 2)
5630 MapListFrom mf = from.next();
5631 fr[_i] = mf.getStart();
5632 fr[_i + 1] = mf.getEnd();
5634 int fto[] = new int[m.getMapListTo().size() * 2];
5635 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5636 for (int _i = 0; to.hasNext(); _i += 2)
5638 MapListTo mf = to.next();
5639 fto[_i] = mf.getStart();
5640 fto[_i + 1] = mf.getEnd();
5642 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5643 fto, m.getMapFromUnit().intValue(),
5644 m.getMapToUnit().intValue());
5647 * (optional) choice of dseqFor or Sequence
5649 if (m.getDseqFor() != null)
5651 String dsfor = m.getDseqFor();
5652 if (seqRefIds.containsKey(dsfor))
5657 jmap.setTo(seqRefIds.get(dsfor));
5661 frefedSequence.add(newMappingRef(dsfor, jmap));
5664 else if (m.getSequence() != null)
5667 * local sequence definition
5669 Sequence ms = m.getSequence();
5670 SequenceI djs = null;
5671 String sqid = ms.getDsseqid();
5672 if (sqid != null && sqid.length() > 0)
5675 * recover dataset sequence
5677 djs = seqRefIds.get(sqid);
5682 "Warning - making up dataset sequence id for DbRef sequence map reference");
5683 sqid = ((Object) ms).toString(); // make up a new hascode for
5684 // undefined dataset sequence hash
5685 // (unlikely to happen)
5691 * make a new dataset sequence and add it to refIds hash
5693 djs = new jalview.datamodel.Sequence(ms.getName(),
5695 djs.setStart(jmap.getMap().getToLowest());
5696 djs.setEnd(jmap.getMap().getToHighest());
5697 djs.setVamsasId(uniqueSetSuffix + sqid);
5699 incompleteSeqs.put(sqid, djs);
5700 seqRefIds.put(sqid, djs);
5703 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5712 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5713 * view as XML (but not to file), and then reloading it
5718 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5721 JalviewModel jm = saveState(ap, null, null, null);
5724 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5725 ap.getAlignment().getDataset());
5727 uniqueSetSuffix = "";
5728 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5729 jm.getViewport().get(0).setId(null);
5730 // we don't overwrite the view we just copied
5732 if (this.frefedSequence == null)
5734 frefedSequence = new Vector<>();
5737 viewportsAdded.clear();
5739 AlignFrame af = loadFromObject(jm, null, false, null);
5740 af.getAlignPanels().clear();
5741 af.closeMenuItem_actionPerformed(true);
5744 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5745 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5746 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5747 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5748 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5751 return af.alignPanel;
5754 private Hashtable jvids2vobj;
5756 private void warn(String msg)
5761 private void warn(String msg, Exception e)
5763 if (Cache.log != null)
5767 Cache.log.warn(msg, e);
5771 Cache.log.warn(msg);
5776 System.err.println("Warning: " + msg);
5779 e.printStackTrace();
5784 private void debug(String string)
5786 debug(string, null);
5789 private void debug(String msg, Exception e)
5791 if (Cache.log != null)
5795 Cache.log.debug(msg, e);
5799 Cache.log.debug(msg);
5804 System.err.println("Warning: " + msg);
5807 e.printStackTrace();
5813 * set the object to ID mapping tables used to write/recover objects and XML
5814 * ID strings for the jalview project. If external tables are provided then
5815 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
5816 * object goes out of scope. - also populates the datasetIds hashtable with
5817 * alignment objects containing dataset sequences
5820 * Map from ID strings to jalview datamodel
5822 * Map from jalview datamodel to ID strings
5826 public void setObjectMappingTables(Hashtable vobj2jv,
5827 IdentityHashMap jv2vobj)
5829 this.jv2vobj = jv2vobj;
5830 this.vobj2jv = vobj2jv;
5831 Iterator ds = jv2vobj.keySet().iterator();
5833 while (ds.hasNext())
5835 Object jvobj = ds.next();
5836 id = jv2vobj.get(jvobj).toString();
5837 if (jvobj instanceof jalview.datamodel.Alignment)
5839 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
5841 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
5844 else if (jvobj instanceof jalview.datamodel.Sequence)
5846 // register sequence object so the XML parser can recover it.
5847 if (seqRefIds == null)
5849 seqRefIds = new HashMap<>();
5851 if (seqsToIds == null)
5853 seqsToIds = new IdentityHashMap<>();
5855 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
5856 seqsToIds.put((SequenceI) jvobj, id);
5858 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
5861 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
5862 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
5863 if (jvann.annotationId == null)
5865 jvann.annotationId = anid;
5867 if (!jvann.annotationId.equals(anid))
5869 // TODO verify that this is the correct behaviour
5870 this.warn("Overriding Annotation ID for " + anid
5871 + " from different id : " + jvann.annotationId);
5872 jvann.annotationId = anid;
5875 else if (jvobj instanceof String)
5877 if (jvids2vobj == null)
5879 jvids2vobj = new Hashtable();
5880 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
5885 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
5891 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
5892 * objects created from the project archive. If string is null (default for
5893 * construction) then suffix will be set automatically.
5897 public void setUniqueSetSuffix(String string)
5899 uniqueSetSuffix = string;
5904 * uses skipList2 as the skipList for skipping views on sequence sets
5905 * associated with keys in the skipList
5909 public void setSkipList(Hashtable skipList2)
5911 skipList = skipList2;
5915 * Reads the jar entry of given name and returns its contents, or null if the
5916 * entry is not found.
5919 * @param jarEntryName
5922 protected String readJarEntry(jarInputStreamProvider jprovider,
5923 String jarEntryName)
5925 String result = null;
5926 BufferedReader in = null;
5931 * Reopen the jar input stream and traverse its entries to find a matching
5934 JarInputStream jin = jprovider.getJarInputStream();
5935 JarEntry entry = null;
5938 entry = jin.getNextJarEntry();
5939 } while (entry != null && !entry.getName().equals(jarEntryName));
5943 StringBuilder out = new StringBuilder(256);
5944 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
5947 while ((data = in.readLine()) != null)
5951 result = out.toString();
5955 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
5957 } catch (Exception ex)
5959 ex.printStackTrace();
5967 } catch (IOException e)
5978 * Returns an incrementing counter (0, 1, 2...)
5982 private synchronized int nextCounter()
5988 * Loads any saved PCA viewers
5993 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
5997 List<PcaViewer> pcaviewers = model.getPcaViewer();
5998 for (PcaViewer viewer : pcaviewers)
6000 String modelName = viewer.getScoreModelName();
6001 SimilarityParamsI params = new SimilarityParams(
6002 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6003 viewer.isIncludeGaps(),
6004 viewer.isDenominateByShortestLength());
6007 * create the panel (without computing the PCA)
6009 PCAPanel panel = new PCAPanel(ap, modelName, params);
6011 panel.setTitle(viewer.getTitle());
6012 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6013 viewer.getWidth(), viewer.getHeight()));
6015 boolean showLabels = viewer.isShowLabels();
6016 panel.setShowLabels(showLabels);
6017 panel.getRotatableCanvas().setShowLabels(showLabels);
6018 panel.getRotatableCanvas()
6019 .setBgColour(new Color(viewer.getBgColour()));
6020 panel.getRotatableCanvas()
6021 .setApplyToAllViews(viewer.isLinkToAllViews());
6024 * load PCA output data
6026 ScoreModelI scoreModel = ScoreModels.getInstance()
6027 .getScoreModel(modelName, ap);
6028 PCA pca = new PCA(null, scoreModel, params);
6029 PcaDataType pcaData = viewer.getPcaData();
6031 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6032 pca.setPairwiseScores(pairwise);
6034 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6035 pca.setTridiagonal(triDiag);
6037 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6038 pca.setEigenmatrix(result);
6040 panel.getPcaModel().setPCA(pca);
6043 * we haven't saved the input data! (JAL-2647 to do)
6045 panel.setInputData(null);
6048 * add the sequence points for the PCA display
6050 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6051 for (SequencePoint sp : viewer.getSequencePoint())
6053 String seqId = sp.getSequenceRef();
6054 SequenceI seq = seqRefIds.get(seqId);
6057 throw new IllegalStateException(
6058 "Unmatched seqref for PCA: " + seqId);
6060 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6061 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6063 seqPoints.add(seqPoint);
6065 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6068 * set min-max ranges and scale after setPoints (which recomputes them)
6070 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6071 SeqPointMin spMin = viewer.getSeqPointMin();
6072 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6074 SeqPointMax spMax = viewer.getSeqPointMax();
6075 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6077 panel.getRotatableCanvas().setSeqMinMax(min, max);
6079 // todo: hold points list in PCAModel only
6080 panel.getPcaModel().setSequencePoints(seqPoints);
6082 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6083 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6084 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6086 // is this duplication needed?
6087 panel.setTop(seqPoints.size() - 1);
6088 panel.getPcaModel().setTop(seqPoints.size() - 1);
6091 * add the axes' end points for the display
6093 for (int i = 0; i < 3; i++)
6095 Axis axis = viewer.getAxis().get(i);
6096 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6097 axis.getXPos(), axis.getYPos(), axis.getZPos());
6100 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6101 "label.calc_title", "PCA", modelName), 475, 450);
6103 } catch (Exception ex)
6105 Cache.log.error("Error loading PCA: " + ex.toString());
6110 * Creates a new structure viewer window
6117 protected void createStructureViewer(
6118 ViewerType viewerType, final Entry<String, StructureViewerModel> viewerData,
6119 AlignFrame af, jarInputStreamProvider jprovider)
6121 final StructureViewerModel viewerModel = viewerData.getValue();
6122 String sessionFilePath = null;
6124 if (viewerType == ViewerType.JMOL)
6126 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6130 String viewerJarEntryName = getViewerJarEntryName(
6131 viewerModel.getViewId());
6132 sessionFilePath = copyJarEntry(jprovider,
6134 "viewerSession", ".tmp");
6136 final String sessionPath = sessionFilePath;
6137 final String sviewid = viewerData.getKey();
6140 SwingUtilities.invokeAndWait(new Runnable()
6145 JalviewStructureDisplayI sview = null;
6148 sview = StructureViewer.createView(viewerType, af.alignPanel,
6149 viewerModel, sessionPath, sviewid);
6150 addNewStructureViewer(sview);
6151 } catch (OutOfMemoryError ex)
6153 new OOMWarning("Restoring structure view for "
6155 (OutOfMemoryError) ex.getCause());
6156 if (sview != null && sview.isVisible())
6158 sview.closeViewer(false);
6159 sview.setVisible(false);
6165 } catch (InvocationTargetException | InterruptedException ex)
6167 warn("Unexpected error when opening " + viewerType
6168 + " structure viewer", ex);
6173 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6174 * the path of the file. "load file" commands are rewritten to change the
6175 * original PDB file names to those created as the Jalview project is loaded.
6181 private String rewriteJmolSession(StructureViewerModel svattrib,
6182 jarInputStreamProvider jprovider)
6184 String state = svattrib.getStateData(); // Jalview < 2.9
6185 if (state == null || state.isEmpty()) // Jalview >= 2.9
6187 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6188 state = readJarEntry(jprovider, jarEntryName);
6190 // TODO or simpler? for each key in oldFiles,
6191 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6192 // (allowing for different path escapings)
6193 StringBuilder rewritten = new StringBuilder(state.length());
6194 int cp = 0, ncp, ecp;
6195 Map<File, StructureData> oldFiles = svattrib.getFileData();
6196 while ((ncp = state.indexOf("load ", cp)) > -1)
6200 // look for next filename in load statement
6201 rewritten.append(state.substring(cp,
6202 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6203 String oldfilenam = state.substring(ncp,
6204 ecp = state.indexOf("\"", ncp));
6205 // recover the new mapping data for this old filename
6206 // have to normalize filename - since Jmol and jalview do
6207 // filename translation differently.
6208 StructureData filedat = oldFiles.get(new File(oldfilenam));
6209 if (filedat == null)
6211 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6212 filedat = oldFiles.get(new File(reformatedOldFilename));
6215 .append(Platform.escapeBackslashes(filedat.getFilePath()));
6216 rewritten.append("\"");
6217 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6218 // look for next file statement.
6219 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6223 // just append rest of state
6224 rewritten.append(state.substring(cp));
6228 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6229 rewritten = new StringBuilder(state);
6230 rewritten.append("; load append ");
6231 for (File id : oldFiles.keySet())
6233 // add pdb files that should be present in the viewer
6234 StructureData filedat = oldFiles.get(id);
6235 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6237 rewritten.append(";");
6240 if (rewritten.length() == 0)
6244 final String history = "history = ";
6245 int historyIndex = rewritten.indexOf(history);
6246 if (historyIndex > -1)
6249 * change "history = [true|false];" to "history = [1|0];"
6251 historyIndex += history.length();
6252 String val = rewritten.substring(historyIndex, historyIndex + 5);
6253 if (val.startsWith("true"))
6255 rewritten.replace(historyIndex, historyIndex + 4, "1");
6257 else if (val.startsWith("false"))
6259 rewritten.replace(historyIndex, historyIndex + 5, "0");
6265 File tmp = File.createTempFile("viewerSession", ".tmp");
6266 try (OutputStream os = new FileOutputStream(tmp))
6268 InputStream is = new ByteArrayInputStream(
6269 rewritten.toString().getBytes());
6271 return tmp.getAbsolutePath();
6273 } catch (IOException e)
6275 Cache.log.error("Error restoring Jmol session: " + e.toString());
6281 * Populates an XML model of the feature colour scheme for one feature type
6283 * @param featureType
6287 public static Colour marshalColour(
6288 String featureType, FeatureColourI fcol)
6290 Colour col = new Colour();
6291 if (fcol.isSimpleColour())
6293 col.setRGB(Format.getHexString(fcol.getColour()));
6297 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6298 col.setMin(fcol.getMin());
6299 col.setMax(fcol.getMax());
6300 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6301 col.setAutoScale(fcol.isAutoScaled());
6302 col.setThreshold(fcol.getThreshold());
6303 col.setColourByLabel(fcol.isColourByLabel());
6304 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6305 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6306 : ThresholdType.NONE));
6307 if (fcol.isColourByAttribute())
6309 final String[] attName = fcol.getAttributeName();
6310 col.getAttributeName().add(attName[0]);
6311 if (attName.length > 1)
6313 col.getAttributeName().add(attName[1]);
6316 Color noColour = fcol.getNoColour();
6317 if (noColour == null)
6319 col.setNoValueColour(NoValueColour.NONE);
6321 else if (noColour == fcol.getMaxColour())
6323 col.setNoValueColour(NoValueColour.MAX);
6327 col.setNoValueColour(NoValueColour.MIN);
6330 col.setName(featureType);
6335 * Populates an XML model of the feature filter(s) for one feature type
6337 * @param firstMatcher
6338 * the first (or only) match condition)
6340 * remaining match conditions (if any)
6342 * if true, conditions are and-ed, else or-ed
6344 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6345 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6348 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6350 if (filters.hasNext())
6355 CompoundMatcher compound = new CompoundMatcher();
6356 compound.setAnd(and);
6357 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6358 firstMatcher, Collections.emptyIterator(), and);
6359 // compound.addMatcherSet(matcher1);
6360 compound.getMatcherSet().add(matcher1);
6361 FeatureMatcherI nextMatcher = filters.next();
6362 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6363 nextMatcher, filters, and);
6364 // compound.addMatcherSet(matcher2);
6365 compound.getMatcherSet().add(matcher2);
6366 result.setCompoundMatcher(compound);
6371 * single condition matcher
6373 // MatchCondition matcherModel = new MatchCondition();
6374 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6375 matcherModel.setCondition(
6376 firstMatcher.getMatcher().getCondition().getStableName());
6377 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6378 if (firstMatcher.isByAttribute())
6380 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6381 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6382 String[] attName = firstMatcher.getAttribute();
6383 matcherModel.getAttributeName().add(attName[0]); // attribute
6384 if (attName.length > 1)
6386 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6389 else if (firstMatcher.isByLabel())
6391 matcherModel.setBy(FilterBy.BY_LABEL);
6393 else if (firstMatcher.isByScore())
6395 matcherModel.setBy(FilterBy.BY_SCORE);
6397 result.setMatchCondition(matcherModel);
6404 * Loads one XML model of a feature filter to a Jalview object
6406 * @param featureType
6407 * @param matcherSetModel
6410 public static FeatureMatcherSetI parseFilter(
6412 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6414 FeatureMatcherSetI result = new FeatureMatcherSet();
6417 parseFilterConditions(result, matcherSetModel, true);
6418 } catch (IllegalStateException e)
6420 // mixing AND and OR conditions perhaps
6422 String.format("Error reading filter conditions for '%s': %s",
6423 featureType, e.getMessage()));
6424 // return as much as was parsed up to the error
6431 * Adds feature match conditions to matcherSet as unmarshalled from XML
6432 * (possibly recursively for compound conditions)
6435 * @param matcherSetModel
6437 * if true, multiple conditions are AND-ed, else they are OR-ed
6438 * @throws IllegalStateException
6439 * if AND and OR conditions are mixed
6441 protected static void parseFilterConditions(
6442 FeatureMatcherSetI matcherSet,
6443 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6446 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6447 .getMatchCondition();
6453 FilterBy filterBy = mc.getBy();
6454 Condition cond = Condition.fromString(mc.getCondition());
6455 String pattern = mc.getValue();
6456 FeatureMatcherI matchCondition = null;
6457 if (filterBy == FilterBy.BY_LABEL)
6459 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6461 else if (filterBy == FilterBy.BY_SCORE)
6463 matchCondition = FeatureMatcher.byScore(cond, pattern);
6466 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6468 final List<String> attributeName = mc.getAttributeName();
6469 String[] attNames = attributeName
6470 .toArray(new String[attributeName.size()]);
6471 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6476 * note this throws IllegalStateException if AND-ing to a
6477 * previously OR-ed compound condition, or vice versa
6481 matcherSet.and(matchCondition);
6485 matcherSet.or(matchCondition);
6491 * compound condition
6493 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6494 .getCompoundMatcher().getMatcherSet();
6495 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6496 if (matchers.size() == 2)
6498 parseFilterConditions(matcherSet, matchers.get(0), anded);
6499 parseFilterConditions(matcherSet, matchers.get(1), anded);
6503 System.err.println("Malformed compound filter condition");
6509 * Loads one XML model of a feature colour to a Jalview object
6511 * @param colourModel
6514 public static FeatureColourI parseColour(Colour colourModel)
6516 FeatureColourI colour = null;
6518 if (colourModel.getMax() != null)
6520 Color mincol = null;
6521 Color maxcol = null;
6522 Color noValueColour = null;
6526 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6527 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6528 } catch (Exception e)
6530 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6533 NoValueColour noCol = colourModel.getNoValueColour();
6534 if (noCol == NoValueColour.MIN)
6536 noValueColour = mincol;
6538 else if (noCol == NoValueColour.MAX)
6540 noValueColour = maxcol;
6543 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6544 safeFloat(colourModel.getMin()),
6545 safeFloat(colourModel.getMax()));
6546 final List<String> attributeName = colourModel.getAttributeName();
6547 String[] attributes = attributeName
6548 .toArray(new String[attributeName.size()]);
6549 if (attributes != null && attributes.length > 0)
6551 colour.setAttributeName(attributes);
6553 if (colourModel.isAutoScale() != null)
6555 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6557 if (colourModel.isColourByLabel() != null)
6559 colour.setColourByLabel(
6560 colourModel.isColourByLabel().booleanValue());
6562 if (colourModel.getThreshold() != null)
6564 colour.setThreshold(colourModel.getThreshold().floatValue());
6566 ThresholdType ttyp = colourModel.getThreshType();
6567 if (ttyp == ThresholdType.ABOVE)
6569 colour.setAboveThreshold(true);
6571 else if (ttyp == ThresholdType.BELOW)
6573 colour.setBelowThreshold(true);
6578 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6579 colour = new FeatureColour(color);