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.DataInputStream;
32 import java.io.DataOutputStream;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStreamReader;
38 import java.io.OutputStreamWriter;
39 import java.io.PrintWriter;
40 import java.lang.reflect.InvocationTargetException;
41 import java.math.BigInteger;
42 import java.net.MalformedURLException;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.Enumeration;
48 import java.util.GregorianCalendar;
49 import java.util.HashMap;
50 import java.util.HashSet;
51 import java.util.Hashtable;
52 import java.util.IdentityHashMap;
53 import java.util.Iterator;
54 import java.util.LinkedHashMap;
55 import java.util.List;
56 import java.util.Locale;
58 import java.util.Map.Entry;
60 import java.util.Vector;
61 import java.util.jar.JarEntry;
62 import java.util.jar.JarInputStream;
63 import java.util.jar.JarOutputStream;
65 import javax.swing.JInternalFrame;
66 import javax.swing.SwingUtilities;
67 import javax.xml.bind.JAXBContext;
68 import javax.xml.bind.JAXBElement;
69 import javax.xml.bind.Marshaller;
70 import javax.xml.datatype.DatatypeConfigurationException;
71 import javax.xml.datatype.DatatypeFactory;
72 import javax.xml.datatype.XMLGregorianCalendar;
73 import javax.xml.stream.XMLInputFactory;
74 import javax.xml.stream.XMLStreamReader;
76 import jalview.analysis.Conservation;
77 import jalview.analysis.PCA;
78 import jalview.analysis.scoremodels.ScoreModels;
79 import jalview.analysis.scoremodels.SimilarityParams;
80 import jalview.api.FeatureColourI;
81 import jalview.api.ViewStyleI;
82 import jalview.api.analysis.ScoreModelI;
83 import jalview.api.analysis.SimilarityParamsI;
84 import jalview.api.structures.JalviewStructureDisplayI;
85 import jalview.bin.Cache;
86 import jalview.datamodel.AlignedCodonFrame;
87 import jalview.datamodel.Alignment;
88 import jalview.datamodel.AlignmentAnnotation;
89 import jalview.datamodel.AlignmentI;
90 import jalview.datamodel.DBRefEntry;
91 import jalview.datamodel.GeneLocus;
92 import jalview.datamodel.GraphLine;
93 import jalview.datamodel.PDBEntry;
94 import jalview.datamodel.Point;
95 import jalview.datamodel.RnaViewerModel;
96 import jalview.datamodel.SequenceFeature;
97 import jalview.datamodel.SequenceGroup;
98 import jalview.datamodel.SequenceI;
99 import jalview.datamodel.StructureViewerModel;
100 import jalview.datamodel.StructureViewerModel.StructureData;
101 import jalview.datamodel.features.FeatureMatcher;
102 import jalview.datamodel.features.FeatureMatcherI;
103 import jalview.datamodel.features.FeatureMatcherSet;
104 import jalview.datamodel.features.FeatureMatcherSetI;
105 import jalview.ext.varna.RnaModel;
106 import jalview.gui.AlignFrame;
107 import jalview.gui.AlignViewport;
108 import jalview.gui.AlignmentPanel;
109 import jalview.gui.AppVarna;
110 import jalview.gui.ChimeraViewFrame;
111 import jalview.gui.Desktop;
112 import jalview.gui.JvOptionPane;
113 import jalview.gui.OOMWarning;
114 import jalview.gui.PCAPanel;
115 import jalview.gui.PaintRefresher;
116 import jalview.gui.SplitFrame;
117 import jalview.gui.StructureViewer;
118 import jalview.gui.StructureViewer.ViewerType;
119 import jalview.gui.StructureViewerBase;
120 import jalview.gui.TreePanel;
121 import jalview.io.BackupFiles;
122 import jalview.io.DataSourceType;
123 import jalview.io.FileFormat;
124 import jalview.io.NewickFile;
125 import jalview.math.Matrix;
126 import jalview.math.MatrixI;
127 import jalview.renderer.ResidueShaderI;
128 import jalview.schemes.AnnotationColourGradient;
129 import jalview.schemes.ColourSchemeI;
130 import jalview.schemes.ColourSchemeProperty;
131 import jalview.schemes.FeatureColour;
132 import jalview.schemes.ResidueProperties;
133 import jalview.schemes.UserColourScheme;
134 import jalview.structure.StructureSelectionManager;
135 import jalview.structures.models.AAStructureBindingModel;
136 import jalview.util.Format;
137 import jalview.util.HttpUtils;
138 import jalview.util.MessageManager;
139 import jalview.util.Platform;
140 import jalview.util.StringUtils;
141 import jalview.util.jarInputStreamProvider;
142 import jalview.util.matcher.Condition;
143 import jalview.viewmodel.AlignmentViewport;
144 import jalview.viewmodel.PCAModel;
145 import jalview.viewmodel.ViewportRanges;
146 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
147 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
148 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
149 import jalview.ws.jws2.Jws2Discoverer;
150 import jalview.ws.jws2.dm.AAConSettings;
151 import jalview.ws.jws2.jabaws2.Jws2Instance;
152 import jalview.ws.params.ArgumentI;
153 import jalview.ws.params.AutoCalcSetting;
154 import jalview.ws.params.WsParamSetI;
155 import jalview.xml.binding.jalview.AlcodonFrame;
156 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
157 import jalview.xml.binding.jalview.Annotation;
158 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
159 import jalview.xml.binding.jalview.AnnotationColourScheme;
160 import jalview.xml.binding.jalview.AnnotationElement;
161 import jalview.xml.binding.jalview.DoubleMatrix;
162 import jalview.xml.binding.jalview.DoubleVector;
163 import jalview.xml.binding.jalview.Feature;
164 import jalview.xml.binding.jalview.Feature.OtherData;
165 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
166 import jalview.xml.binding.jalview.FilterBy;
167 import jalview.xml.binding.jalview.JalviewModel;
168 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
169 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
170 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
171 import jalview.xml.binding.jalview.JalviewModel.JGroup;
172 import jalview.xml.binding.jalview.JalviewModel.JSeq;
173 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
174 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
175 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
176 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
177 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
178 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
179 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
180 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
181 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
182 import jalview.xml.binding.jalview.JalviewModel.Tree;
183 import jalview.xml.binding.jalview.JalviewModel.UserColours;
184 import jalview.xml.binding.jalview.JalviewModel.Viewport;
185 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
186 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
187 import jalview.xml.binding.jalview.JalviewUserColours;
188 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
189 import jalview.xml.binding.jalview.MapListType.MapListFrom;
190 import jalview.xml.binding.jalview.MapListType.MapListTo;
191 import jalview.xml.binding.jalview.Mapping;
192 import jalview.xml.binding.jalview.NoValueColour;
193 import jalview.xml.binding.jalview.ObjectFactory;
194 import jalview.xml.binding.jalview.PcaDataType;
195 import jalview.xml.binding.jalview.Pdbentry.Property;
196 import jalview.xml.binding.jalview.Sequence;
197 import jalview.xml.binding.jalview.Sequence.DBRef;
198 import jalview.xml.binding.jalview.SequenceSet;
199 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
200 import jalview.xml.binding.jalview.ThresholdType;
201 import jalview.xml.binding.jalview.VAMSAS;
204 * Write out the current jalview desktop state as a Jalview XML stream.
206 * Note: the vamsas objects referred to here are primitive versions of the
207 * VAMSAS project schema elements - they are not the same and most likely never
211 * @version $Revision: 1.134 $
213 public class Jalview2XML
215 private static final String VIEWER_PREFIX = "viewer_";
217 private static final String RNA_PREFIX = "rna_";
219 private static final String UTF_8 = "UTF-8";
222 * prefix for recovering datasets for alignments with multiple views where
223 * non-existent dataset IDs were written for some views
225 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
227 // use this with nextCounter() to make unique names for entities
228 private int counter = 0;
231 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
232 * of sequence objects are created.
234 IdentityHashMap<SequenceI, String> seqsToIds = null;
237 * jalview XML Sequence ID to jalview sequence object reference (both dataset
238 * and alignment sequences. Populated as XML reps of sequence objects are
241 Map<String, SequenceI> seqRefIds = null;
243 Map<String, SequenceI> incompleteSeqs = null;
245 List<SeqFref> frefedSequence = null;
247 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
250 * Map of reconstructed AlignFrame objects that appear to have come from
251 * SplitFrame objects (have a dna/protein complement view).
253 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
256 * Map from displayed rna structure models to their saved session state jar
259 private Map<RnaModel, String> rnaSessions = new HashMap<>();
262 * A helper method for safely using the value of an optional attribute that
263 * may be null if not present in the XML. Answers the boolean value, or false
269 public static boolean safeBoolean(Boolean b)
271 return b == null ? false : b.booleanValue();
275 * A helper method for safely using the value of an optional attribute that
276 * may be null if not present in the XML. Answers the integer value, or zero
282 public static int safeInt(Integer i)
284 return i == null ? 0 : i.intValue();
288 * A helper method for safely using the value of an optional attribute that
289 * may be null if not present in the XML. Answers the float value, or zero if
295 public static float safeFloat(Float f)
297 return f == null ? 0f : f.floatValue();
301 * create/return unique hash string for sq
304 * @return new or existing unique string for sq
306 String seqHash(SequenceI sq)
308 if (seqsToIds == null)
312 if (seqsToIds.containsKey(sq))
314 return seqsToIds.get(sq);
318 // create sequential key
319 String key = "sq" + (seqsToIds.size() + 1);
320 key = makeHashCode(sq, key); // check we don't have an external reference
322 seqsToIds.put(sq, key);
329 if (seqsToIds == null)
331 seqsToIds = new IdentityHashMap<>();
333 if (seqRefIds == null)
335 seqRefIds = new HashMap<>();
337 if (incompleteSeqs == null)
339 incompleteSeqs = new HashMap<>();
341 if (frefedSequence == null)
343 frefedSequence = new ArrayList<>();
351 public Jalview2XML(boolean raiseGUI)
353 this.raiseGUI = raiseGUI;
357 * base class for resolving forward references to sequences by their ID
362 abstract class SeqFref
368 public SeqFref(String _sref, String type)
374 public String getSref()
379 public SequenceI getSrefSeq()
381 return seqRefIds.get(sref);
384 public boolean isResolvable()
386 return seqRefIds.get(sref) != null;
389 public SequenceI getSrefDatasetSeq()
391 SequenceI sq = seqRefIds.get(sref);
394 while (sq.getDatasetSequence() != null)
396 sq = sq.getDatasetSequence();
403 * @return true if the forward reference was fully resolved
405 abstract boolean resolve();
408 public String toString()
410 return type + " reference to " + sref;
415 * create forward reference for a mapping
421 public SeqFref newMappingRef(final String sref,
422 final jalview.datamodel.Mapping _jmap)
424 SeqFref fref = new SeqFref(sref, "Mapping")
426 public jalview.datamodel.Mapping jmap = _jmap;
431 SequenceI seq = getSrefDatasetSeq();
443 public SeqFref newAlcodMapRef(final String sref,
444 final AlignedCodonFrame _cf,
445 final jalview.datamodel.Mapping _jmap)
448 SeqFref fref = new SeqFref(sref, "Codon Frame")
450 AlignedCodonFrame cf = _cf;
452 public jalview.datamodel.Mapping mp = _jmap;
455 public boolean isResolvable()
457 return super.isResolvable() && mp.getTo() != null;
463 SequenceI seq = getSrefDatasetSeq();
468 cf.addMap(seq, mp.getTo(), mp.getMap());
475 public void resolveFrefedSequences()
477 Iterator<SeqFref> nextFref = frefedSequence.iterator();
478 int toresolve = frefedSequence.size();
479 int unresolved = 0, failedtoresolve = 0;
480 while (nextFref.hasNext())
482 SeqFref ref = nextFref.next();
483 if (ref.isResolvable())
495 } catch (Exception x)
498 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
511 System.err.println("Jalview Project Import: There were " + unresolved
512 + " forward references left unresolved on the stack.");
514 if (failedtoresolve > 0)
516 System.err.println("SERIOUS! " + failedtoresolve
517 + " resolvable forward references failed to resolve.");
519 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
522 "Jalview Project Import: There are " + incompleteSeqs.size()
523 + " sequences which may have incomplete metadata.");
524 if (incompleteSeqs.size() < 10)
526 for (SequenceI s : incompleteSeqs.values())
528 System.err.println(s.toString());
534 "Too many to report. Skipping output of incomplete sequences.");
540 * This maintains a map of viewports, the key being the seqSetId. Important to
541 * set historyItem and redoList for multiple views
543 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
545 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
547 String uniqueSetSuffix = "";
550 * List of pdbfiles added to Jar
552 List<String> pdbfiles = null;
554 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
555 public void saveState(File statefile)
557 FileOutputStream fos = null;
562 fos = new FileOutputStream(statefile);
564 JarOutputStream jout = new JarOutputStream(fos);
568 } catch (Exception e)
570 Cache.log.error("Couln't write Jalview state to " + statefile, e);
571 // TODO: inform user of the problem - they need to know if their data was
573 if (errorMessage == null)
575 errorMessage = "Did't write Jalview Archive to output file '"
576 + statefile + "' - See console error log for details";
580 errorMessage += "(Didn't write Jalview Archive to output file '"
591 } catch (IOException e)
601 * Writes a jalview project archive to the given Jar output stream.
605 public void saveState(JarOutputStream jout)
607 AlignFrame[] frames = Desktop.getAlignFrames();
613 saveAllFrames(Arrays.asList(frames), jout);
617 * core method for storing state for a set of AlignFrames.
620 * - frames involving all data to be exported (including containing
623 * - project output stream
625 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
627 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
630 * ensure cached data is clear before starting
632 // todo tidy up seqRefIds, seqsToIds initialisation / reset
634 splitFrameCandidates.clear();
639 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
640 // //////////////////////////////////////////////////
642 List<String> shortNames = new ArrayList<>();
643 List<String> viewIds = new ArrayList<>();
646 for (int i = frames.size() - 1; i > -1; i--)
648 AlignFrame af = frames.get(i);
650 if (skipList != null && skipList
651 .containsKey(af.getViewport().getSequenceSetId()))
656 String shortName = makeFilename(af, shortNames);
658 int apSize = af.getAlignPanels().size();
660 for (int ap = 0; ap < apSize; ap++)
662 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
664 String fileName = apSize == 1 ? shortName : ap + shortName;
665 if (!fileName.endsWith(".xml"))
667 fileName = fileName + ".xml";
670 saveState(apanel, fileName, jout, viewIds);
672 String dssid = getDatasetIdRef(
673 af.getViewport().getAlignment().getDataset());
674 if (!dsses.containsKey(dssid))
676 dsses.put(dssid, af);
681 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
687 } catch (Exception foo)
692 } catch (Exception ex)
694 // TODO: inform user of the problem - they need to know if their data was
696 if (errorMessage == null)
698 errorMessage = "Couldn't write Jalview Archive - see error output for details";
700 ex.printStackTrace();
705 * Generates a distinct file name, based on the title of the AlignFrame, by
706 * appending _n for increasing n until an unused name is generated. The new
707 * name (without its extension) is added to the list.
711 * @return the generated name, with .xml extension
713 protected String makeFilename(AlignFrame af, List<String> namesUsed)
715 String shortName = af.getTitle();
717 if (shortName.indexOf(File.separatorChar) > -1)
719 shortName = shortName
720 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
725 while (namesUsed.contains(shortName))
727 if (shortName.endsWith("_" + (count - 1)))
729 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
732 shortName = shortName.concat("_" + count);
736 namesUsed.add(shortName);
738 if (!shortName.endsWith(".xml"))
740 shortName = shortName + ".xml";
745 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
746 public boolean saveAlignment(AlignFrame af, String jarFile,
751 // create backupfiles object and get new temp filename destination
752 BackupFiles backupfiles = new BackupFiles(jarFile);
753 FileOutputStream fos = new FileOutputStream(
754 backupfiles.getTempFilePath());
756 JarOutputStream jout = new JarOutputStream(fos);
757 List<AlignFrame> frames = new ArrayList<>();
759 // resolve splitframes
760 if (af.getViewport().getCodingComplement() != null)
762 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
768 saveAllFrames(frames, jout);
772 } catch (Exception foo)
777 boolean success = true;
779 backupfiles.setWriteSuccess(success);
780 success = backupfiles.rollBackupsAndRenameTempFile();
783 } catch (Exception ex)
785 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
786 ex.printStackTrace();
791 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
792 String fileName, JarOutputStream jout)
795 for (String dssids : dsses.keySet())
797 AlignFrame _af = dsses.get(dssids);
798 String jfileName = fileName + " Dataset for " + _af.getTitle();
799 if (!jfileName.endsWith(".xml"))
801 jfileName = jfileName + ".xml";
803 saveState(_af.alignPanel, jfileName, true, jout, null);
808 * create a JalviewModel from an alignment view and marshall it to a
812 * panel to create jalview model for
814 * name of alignment panel written to output stream
821 public JalviewModel saveState(AlignmentPanel ap, String fileName,
822 JarOutputStream jout, List<String> viewIds)
824 return saveState(ap, fileName, false, jout, viewIds);
828 * create a JalviewModel from an alignment view and marshall it to a
832 * panel to create jalview model for
834 * name of alignment panel written to output stream
836 * when true, only write the dataset for the alignment, not the data
837 * associated with the view.
843 public JalviewModel saveState(AlignmentPanel ap, String fileName,
844 boolean storeDS, JarOutputStream jout, List<String> viewIds)
848 viewIds = new ArrayList<>();
853 List<UserColourScheme> userColours = new ArrayList<>();
855 AlignViewport av = ap.av;
856 ViewportRanges vpRanges = av.getRanges();
858 final ObjectFactory objectFactory = new ObjectFactory();
859 JalviewModel object = objectFactory.createJalviewModel();
860 object.setVamsasModel(new VAMSAS());
862 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
865 GregorianCalendar c = new GregorianCalendar();
866 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
867 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
868 object.setCreationDate(now);
869 } catch (DatatypeConfigurationException e)
871 System.err.println("error writing date: " + e.toString());
874 jalview.bin.Cache.getDefault("VERSION", "Development Build"));
877 * rjal is full height alignment, jal is actual alignment with full metadata
878 * but excludes hidden sequences.
880 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
882 if (av.hasHiddenRows())
884 rjal = jal.getHiddenSequences().getFullAlignment();
887 SequenceSet vamsasSet = new SequenceSet();
889 // JalviewModelSequence jms = new JalviewModelSequence();
891 vamsasSet.setGapChar(jal.getGapCharacter() + "");
893 if (jal.getDataset() != null)
895 // dataset id is the dataset's hashcode
896 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
899 // switch jal and the dataset
900 jal = jal.getDataset();
904 if (jal.getProperties() != null)
906 Enumeration en = jal.getProperties().keys();
907 while (en.hasMoreElements())
909 String key = en.nextElement().toString();
910 SequenceSetProperties ssp = new SequenceSetProperties();
912 ssp.setValue(jal.getProperties().get(key).toString());
913 // vamsasSet.addSequenceSetProperties(ssp);
914 vamsasSet.getSequenceSetProperties().add(ssp);
919 Set<String> calcIdSet = new HashSet<>();
920 // record the set of vamsas sequence XML POJO we create.
921 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
923 for (final SequenceI jds : rjal.getSequences())
925 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
926 : jds.getDatasetSequence();
927 String id = seqHash(jds);
928 if (vamsasSetIds.get(id) == null)
930 if (seqRefIds.get(id) != null && !storeDS)
932 // This happens for two reasons: 1. multiple views are being
934 // 2. the hashCode has collided with another sequence's code. This
936 // HAPPEN! (PF00072.15.stk does this)
937 // JBPNote: Uncomment to debug writing out of files that do not read
938 // back in due to ArrayOutOfBoundExceptions.
939 // System.err.println("vamsasSeq backref: "+id+"");
940 // System.err.println(jds.getName()+"
941 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
942 // System.err.println("Hashcode: "+seqHash(jds));
943 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
944 // System.err.println(rsq.getName()+"
945 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
946 // System.err.println("Hashcode: "+seqHash(rsq));
950 vamsasSeq = createVamsasSequence(id, jds);
951 // vamsasSet.addSequence(vamsasSeq);
952 vamsasSet.getSequence().add(vamsasSeq);
953 vamsasSetIds.put(id, vamsasSeq);
954 seqRefIds.put(id, jds);
958 jseq.setStart(jds.getStart());
959 jseq.setEnd(jds.getEnd());
960 jseq.setColour(av.getSequenceColour(jds).getRGB());
962 jseq.setId(id); // jseq id should be a string not a number
965 // Store any sequences this sequence represents
966 if (av.hasHiddenRows())
968 // use rjal, contains the full height alignment
970 av.getAlignment().getHiddenSequences().isHidden(jds));
972 if (av.isHiddenRepSequence(jds))
974 jalview.datamodel.SequenceI[] reps = av
975 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
977 for (int h = 0; h < reps.length; h++)
981 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
982 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
987 // mark sequence as reference - if it is the reference for this view
990 jseq.setViewreference(jds == jal.getSeqrep());
994 // TODO: omit sequence features from each alignment view's XML dump if we
995 // are storing dataset
996 List<SequenceFeature> sfs = jds.getSequenceFeatures();
997 for (SequenceFeature sf : sfs)
999 // Features features = new Features();
1000 Feature features = new Feature();
1002 features.setBegin(sf.getBegin());
1003 features.setEnd(sf.getEnd());
1004 features.setDescription(sf.getDescription());
1005 features.setType(sf.getType());
1006 features.setFeatureGroup(sf.getFeatureGroup());
1007 features.setScore(sf.getScore());
1008 if (sf.links != null)
1010 for (int l = 0; l < sf.links.size(); l++)
1012 OtherData keyValue = new OtherData();
1013 keyValue.setKey("LINK_" + l);
1014 keyValue.setValue(sf.links.elementAt(l).toString());
1015 // features.addOtherData(keyValue);
1016 features.getOtherData().add(keyValue);
1019 if (sf.otherDetails != null)
1022 * save feature attributes, which may be simple strings or
1023 * map valued (have sub-attributes)
1025 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1027 String key = entry.getKey();
1028 Object value = entry.getValue();
1029 if (value instanceof Map<?, ?>)
1031 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1034 OtherData otherData = new OtherData();
1035 otherData.setKey(key);
1036 otherData.setKey2(subAttribute.getKey());
1037 otherData.setValue(subAttribute.getValue().toString());
1038 // features.addOtherData(otherData);
1039 features.getOtherData().add(otherData);
1044 OtherData otherData = new OtherData();
1045 otherData.setKey(key);
1046 otherData.setValue(value.toString());
1047 // features.addOtherData(otherData);
1048 features.getOtherData().add(otherData);
1053 // jseq.addFeatures(features);
1054 jseq.getFeatures().add(features);
1057 if (jdatasq.getAllPDBEntries() != null)
1059 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1060 while (en.hasMoreElements())
1062 Pdbids pdb = new Pdbids();
1063 jalview.datamodel.PDBEntry entry = en.nextElement();
1065 String pdbId = entry.getId();
1067 pdb.setType(entry.getType());
1070 * Store any structure views associated with this sequence. This
1071 * section copes with duplicate entries in the project, so a dataset
1072 * only view *should* be coped with sensibly.
1074 // This must have been loaded, is it still visible?
1075 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1076 String matchedFile = null;
1077 for (int f = frames.length - 1; f > -1; f--)
1079 if (frames[f] instanceof StructureViewerBase)
1081 StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
1082 matchedFile = saveStructureState(ap, jds, pdb, entry, viewIds,
1083 matchedFile, viewFrame);
1085 * Only store each structure viewer's state once in the project
1086 * jar. First time through only (storeDS==false)
1088 String viewId = viewFrame.getViewId();
1089 if (!storeDS && !viewIds.contains(viewId))
1091 viewIds.add(viewId);
1094 String viewerState = viewFrame.getStateInfo();
1095 writeJarEntry(jout, getViewerJarEntryName(viewId),
1096 viewerState.getBytes());
1097 } catch (IOException e)
1100 "Error saving viewer state: " + e.getMessage());
1106 if (matchedFile != null || entry.getFile() != null)
1108 if (entry.getFile() != null)
1111 matchedFile = entry.getFile();
1113 pdb.setFile(matchedFile); // entry.getFile());
1114 if (pdbfiles == null)
1116 pdbfiles = new ArrayList<>();
1119 if (!pdbfiles.contains(pdbId))
1121 pdbfiles.add(pdbId);
1122 copyFileToJar(jout, matchedFile, pdbId);
1126 Enumeration<String> props = entry.getProperties();
1127 if (props.hasMoreElements())
1129 // PdbentryItem item = new PdbentryItem();
1130 while (props.hasMoreElements())
1132 Property prop = new Property();
1133 String key = props.nextElement();
1135 prop.setValue(entry.getProperty(key).toString());
1136 // item.addProperty(prop);
1137 pdb.getProperty().add(prop);
1139 // pdb.addPdbentryItem(item);
1142 // jseq.addPdbids(pdb);
1143 jseq.getPdbids().add(pdb);
1147 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1149 // jms.addJSeq(jseq);
1150 object.getJSeq().add(jseq);
1153 if (!storeDS && av.hasHiddenRows())
1155 jal = av.getAlignment();
1159 if (storeDS && jal.getCodonFrames() != null)
1161 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1162 for (AlignedCodonFrame acf : jac)
1164 AlcodonFrame alc = new AlcodonFrame();
1165 if (acf.getProtMappings() != null
1166 && acf.getProtMappings().length > 0)
1168 boolean hasMap = false;
1169 SequenceI[] dnas = acf.getdnaSeqs();
1170 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1171 for (int m = 0; m < pmaps.length; m++)
1173 AlcodMap alcmap = new AlcodMap();
1174 alcmap.setDnasq(seqHash(dnas[m]));
1176 createVamsasMapping(pmaps[m], dnas[m], null, false));
1177 // alc.addAlcodMap(alcmap);
1178 alc.getAlcodMap().add(alcmap);
1183 // vamsasSet.addAlcodonFrame(alc);
1184 vamsasSet.getAlcodonFrame().add(alc);
1187 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1189 // AlcodonFrame alc = new AlcodonFrame();
1190 // vamsasSet.addAlcodonFrame(alc);
1191 // for (int p = 0; p < acf.aaWidth; p++)
1193 // Alcodon cmap = new Alcodon();
1194 // if (acf.codons[p] != null)
1196 // // Null codons indicate a gapped column in the translated peptide
1198 // cmap.setPos1(acf.codons[p][0]);
1199 // cmap.setPos2(acf.codons[p][1]);
1200 // cmap.setPos3(acf.codons[p][2]);
1202 // alc.addAlcodon(cmap);
1204 // if (acf.getProtMappings() != null
1205 // && acf.getProtMappings().length > 0)
1207 // SequenceI[] dnas = acf.getdnaSeqs();
1208 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1209 // for (int m = 0; m < pmaps.length; m++)
1211 // AlcodMap alcmap = new AlcodMap();
1212 // alcmap.setDnasq(seqHash(dnas[m]));
1213 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1215 // alc.addAlcodMap(alcmap);
1222 // /////////////////////////////////
1223 if (!storeDS && av.getCurrentTree() != null)
1225 // FIND ANY ASSOCIATED TREES
1226 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1227 if (Desktop.desktop != null)
1229 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1231 for (int t = 0; t < frames.length; t++)
1233 if (frames[t] instanceof TreePanel)
1235 TreePanel tp = (TreePanel) frames[t];
1237 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1239 JalviewModel.Tree tree = new JalviewModel.Tree();
1240 tree.setTitle(tp.getTitle());
1241 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1242 tree.setNewick(tp.getTree().print());
1243 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1245 tree.setFitToWindow(tp.fitToWindow.getState());
1246 tree.setFontName(tp.getTreeFont().getName());
1247 tree.setFontSize(tp.getTreeFont().getSize());
1248 tree.setFontStyle(tp.getTreeFont().getStyle());
1249 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1251 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1252 tree.setShowDistances(tp.distanceMenu.getState());
1254 tree.setHeight(tp.getHeight());
1255 tree.setWidth(tp.getWidth());
1256 tree.setXpos(tp.getX());
1257 tree.setYpos(tp.getY());
1258 tree.setId(makeHashCode(tp, null));
1259 tree.setLinkToAllViews(
1260 tp.getTreeCanvas().isApplyToAllViews());
1262 // jms.addTree(tree);
1263 object.getTree().add(tree);
1273 if (!storeDS && Desktop.desktop != null)
1275 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1277 if (frame instanceof PCAPanel)
1279 PCAPanel panel = (PCAPanel) frame;
1280 if (panel.getAlignViewport().getAlignment() == jal)
1282 savePCA(panel, object);
1290 * store forward refs from an annotationRow to any groups
1292 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1295 for (SequenceI sq : jal.getSequences())
1297 // Store annotation on dataset sequences only
1298 AlignmentAnnotation[] aa = sq.getAnnotation();
1299 if (aa != null && aa.length > 0)
1301 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1308 if (jal.getAlignmentAnnotation() != null)
1310 // Store the annotation shown on the alignment.
1311 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1312 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1317 if (jal.getGroups() != null)
1319 JGroup[] groups = new JGroup[jal.getGroups().size()];
1321 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1323 JGroup jGroup = new JGroup();
1324 groups[++i] = jGroup;
1326 jGroup.setStart(sg.getStartRes());
1327 jGroup.setEnd(sg.getEndRes());
1328 jGroup.setName(sg.getName());
1329 if (groupRefs.containsKey(sg))
1331 // group has references so set its ID field
1332 jGroup.setId(groupRefs.get(sg));
1334 ColourSchemeI colourScheme = sg.getColourScheme();
1335 if (colourScheme != null)
1337 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1338 if (groupColourScheme.conservationApplied())
1340 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1342 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1344 jGroup.setColour(setUserColourScheme(colourScheme,
1345 userColours, object));
1349 jGroup.setColour(colourScheme.getSchemeName());
1352 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1354 jGroup.setColour("AnnotationColourGradient");
1355 jGroup.setAnnotationColours(constructAnnotationColours(
1356 (jalview.schemes.AnnotationColourGradient) colourScheme,
1357 userColours, object));
1359 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1362 setUserColourScheme(colourScheme, userColours, object));
1366 jGroup.setColour(colourScheme.getSchemeName());
1369 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1372 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1373 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1374 jGroup.setDisplayText(sg.getDisplayText());
1375 jGroup.setColourText(sg.getColourText());
1376 jGroup.setTextCol1(sg.textColour.getRGB());
1377 jGroup.setTextCol2(sg.textColour2.getRGB());
1378 jGroup.setTextColThreshold(sg.thresholdTextColour);
1379 jGroup.setShowUnconserved(sg.getShowNonconserved());
1380 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1381 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1382 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1383 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1384 for (SequenceI seq : sg.getSequences())
1386 // jGroup.addSeq(seqHash(seq));
1387 jGroup.getSeq().add(seqHash(seq));
1391 // jms.setJGroup(groups);
1393 for (JGroup grp : groups)
1395 object.getJGroup().add(grp);
1400 // /////////SAVE VIEWPORT
1401 Viewport view = new Viewport();
1402 view.setTitle(ap.alignFrame.getTitle());
1403 view.setSequenceSetId(
1404 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1405 view.setId(av.getViewId());
1406 if (av.getCodingComplement() != null)
1408 view.setComplementId(av.getCodingComplement().getViewId());
1410 view.setViewName(av.getViewName());
1411 view.setGatheredViews(av.isGatherViewsHere());
1413 Rectangle size = ap.av.getExplodedGeometry();
1414 Rectangle position = size;
1417 size = ap.alignFrame.getBounds();
1418 if (av.getCodingComplement() != null)
1420 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1428 view.setXpos(position.x);
1429 view.setYpos(position.y);
1431 view.setWidth(size.width);
1432 view.setHeight(size.height);
1434 view.setStartRes(vpRanges.getStartRes());
1435 view.setStartSeq(vpRanges.getStartSeq());
1437 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1439 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1440 userColours, object));
1443 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1445 AnnotationColourScheme ac = constructAnnotationColours(
1446 (jalview.schemes.AnnotationColourGradient) av
1447 .getGlobalColourScheme(),
1448 userColours, object);
1450 view.setAnnotationColours(ac);
1451 view.setBgColour("AnnotationColourGradient");
1455 view.setBgColour(ColourSchemeProperty
1456 .getColourName(av.getGlobalColourScheme()));
1459 ResidueShaderI vcs = av.getResidueShading();
1460 ColourSchemeI cs = av.getGlobalColourScheme();
1464 if (vcs.conservationApplied())
1466 view.setConsThreshold(vcs.getConservationInc());
1467 if (cs instanceof jalview.schemes.UserColourScheme)
1469 view.setBgColour(setUserColourScheme(cs, userColours, object));
1472 view.setPidThreshold(vcs.getThreshold());
1475 view.setConservationSelected(av.getConservationSelected());
1476 view.setPidSelected(av.getAbovePIDThreshold());
1477 final Font font = av.getFont();
1478 view.setFontName(font.getName());
1479 view.setFontSize(font.getSize());
1480 view.setFontStyle(font.getStyle());
1481 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1482 view.setRenderGaps(av.isRenderGaps());
1483 view.setShowAnnotation(av.isShowAnnotation());
1484 view.setShowBoxes(av.getShowBoxes());
1485 view.setShowColourText(av.getColourText());
1486 view.setShowFullId(av.getShowJVSuffix());
1487 view.setRightAlignIds(av.isRightAlignIds());
1488 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1489 view.setShowText(av.getShowText());
1490 view.setShowUnconserved(av.getShowUnconserved());
1491 view.setWrapAlignment(av.getWrapAlignment());
1492 view.setTextCol1(av.getTextColour().getRGB());
1493 view.setTextCol2(av.getTextColour2().getRGB());
1494 view.setTextColThreshold(av.getThresholdTextColour());
1495 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1496 view.setShowSequenceLogo(av.isShowSequenceLogo());
1497 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1498 view.setShowGroupConsensus(av.isShowGroupConsensus());
1499 view.setShowGroupConservation(av.isShowGroupConservation());
1500 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1501 view.setShowDbRefTooltip(av.isShowDBRefs());
1502 view.setFollowHighlight(av.isFollowHighlight());
1503 view.setFollowSelection(av.followSelection);
1504 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1505 view.setShowComplementFeatures(av.isShowComplementFeatures());
1506 view.setShowComplementFeaturesOnTop(
1507 av.isShowComplementFeaturesOnTop());
1508 if (av.getFeaturesDisplayed() != null)
1510 FeatureSettings fs = new FeatureSettings();
1512 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1513 .getFeatureRenderer();
1514 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1516 Vector<String> settingsAdded = new Vector<>();
1517 if (renderOrder != null)
1519 for (String featureType : renderOrder)
1521 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1522 setting.setType(featureType);
1525 * save any filter for the feature type
1527 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1530 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1532 FeatureMatcherI firstFilter = filters.next();
1533 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1534 filters, filter.isAnded()));
1538 * save colour scheme for the feature type
1540 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1541 if (!fcol.isSimpleColour())
1543 setting.setColour(fcol.getMaxColour().getRGB());
1544 setting.setMincolour(fcol.getMinColour().getRGB());
1545 setting.setMin(fcol.getMin());
1546 setting.setMax(fcol.getMax());
1547 setting.setColourByLabel(fcol.isColourByLabel());
1548 if (fcol.isColourByAttribute())
1550 String[] attName = fcol.getAttributeName();
1551 setting.getAttributeName().add(attName[0]);
1552 if (attName.length > 1)
1554 setting.getAttributeName().add(attName[1]);
1557 setting.setAutoScale(fcol.isAutoScaled());
1558 setting.setThreshold(fcol.getThreshold());
1559 Color noColour = fcol.getNoColour();
1560 if (noColour == null)
1562 setting.setNoValueColour(NoValueColour.NONE);
1564 else if (noColour.equals(fcol.getMaxColour()))
1566 setting.setNoValueColour(NoValueColour.MAX);
1570 setting.setNoValueColour(NoValueColour.MIN);
1572 // -1 = No threshold, 0 = Below, 1 = Above
1573 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1574 : (fcol.isBelowThreshold() ? 0 : -1));
1578 setting.setColour(fcol.getColour().getRGB());
1582 av.getFeaturesDisplayed().isVisible(featureType));
1583 float rorder = fr.getOrder(featureType);
1586 setting.setOrder(rorder);
1588 /// fs.addSetting(setting);
1589 fs.getSetting().add(setting);
1590 settingsAdded.addElement(featureType);
1594 // is groups actually supposed to be a map here ?
1595 Iterator<String> en = fr.getFeatureGroups().iterator();
1596 Vector<String> groupsAdded = new Vector<>();
1597 while (en.hasNext())
1599 String grp = en.next();
1600 if (groupsAdded.contains(grp))
1604 Group g = new Group();
1606 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1609 fs.getGroup().add(g);
1610 groupsAdded.addElement(grp);
1612 // jms.setFeatureSettings(fs);
1613 object.setFeatureSettings(fs);
1616 if (av.hasHiddenColumns())
1618 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1619 .getHiddenColumns();
1622 warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1626 Iterator<int[]> hiddenRegions = hidden.iterator();
1627 while (hiddenRegions.hasNext())
1629 int[] region = hiddenRegions.next();
1630 HiddenColumns hc = new HiddenColumns();
1631 hc.setStart(region[0]);
1632 hc.setEnd(region[1]);
1633 // view.addHiddenColumns(hc);
1634 view.getHiddenColumns().add(hc);
1638 if (calcIdSet.size() > 0)
1640 for (String calcId : calcIdSet)
1642 if (calcId.trim().length() > 0)
1644 CalcIdParam cidp = createCalcIdParam(calcId, av);
1645 // Some calcIds have no parameters.
1648 // view.addCalcIdParam(cidp);
1649 view.getCalcIdParam().add(cidp);
1655 // jms.addViewport(view);
1656 object.getViewport().add(view);
1658 // object.setJalviewModelSequence(jms);
1659 // object.getVamsasModel().addSequenceSet(vamsasSet);
1660 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1662 if (jout != null && fileName != null)
1664 // We may not want to write the object to disk,
1665 // eg we can copy the alignViewport to a new view object
1666 // using save and then load
1669 System.out.println("Writing jar entry " + fileName);
1670 JarEntry entry = new JarEntry(fileName);
1671 jout.putNextEntry(entry);
1672 PrintWriter pout = new PrintWriter(
1673 new OutputStreamWriter(jout, UTF_8));
1674 JAXBContext jaxbContext = JAXBContext
1675 .newInstance(JalviewModel.class);
1676 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1678 // output pretty printed
1679 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1680 jaxbMarshaller.marshal(
1681 new ObjectFactory().createJalviewModel(object), pout);
1683 // jaxbMarshaller.marshal(object, pout);
1684 // marshaller.marshal(object);
1687 } catch (Exception ex)
1689 // TODO: raise error in GUI if marshalling failed.
1690 System.err.println("Error writing Jalview project");
1691 ex.printStackTrace();
1698 * Writes PCA viewer attributes and computed values to an XML model object and
1699 * adds it to the JalviewModel. Any exceptions are reported by logging.
1701 protected void savePCA(PCAPanel panel, JalviewModel object)
1705 PcaViewer viewer = new PcaViewer();
1706 viewer.setHeight(panel.getHeight());
1707 viewer.setWidth(panel.getWidth());
1708 viewer.setXpos(panel.getX());
1709 viewer.setYpos(panel.getY());
1710 viewer.setTitle(panel.getTitle());
1711 PCAModel pcaModel = panel.getPcaModel();
1712 viewer.setScoreModelName(pcaModel.getScoreModelName());
1713 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1714 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1715 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1717 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1718 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1719 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1720 SeqPointMin spmin = new SeqPointMin();
1721 spmin.setXPos(spMin[0]);
1722 spmin.setYPos(spMin[1]);
1723 spmin.setZPos(spMin[2]);
1724 viewer.setSeqPointMin(spmin);
1725 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1726 SeqPointMax spmax = new SeqPointMax();
1727 spmax.setXPos(spMax[0]);
1728 spmax.setYPos(spMax[1]);
1729 spmax.setZPos(spMax[2]);
1730 viewer.setSeqPointMax(spmax);
1731 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1732 viewer.setLinkToAllViews(
1733 panel.getRotatableCanvas().isApplyToAllViews());
1734 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1735 viewer.setIncludeGaps(sp.includeGaps());
1736 viewer.setMatchGaps(sp.matchGaps());
1737 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1738 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1741 * sequence points on display
1743 for (jalview.datamodel.SequencePoint spt : pcaModel
1744 .getSequencePoints())
1746 SequencePoint point = new SequencePoint();
1747 point.setSequenceRef(seqHash(spt.getSequence()));
1748 point.setXPos(spt.coord.x);
1749 point.setYPos(spt.coord.y);
1750 point.setZPos(spt.coord.z);
1751 viewer.getSequencePoint().add(point);
1755 * (end points of) axes on display
1757 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1760 Axis axis = new Axis();
1764 viewer.getAxis().add(axis);
1768 * raw PCA data (note we are not restoring PCA inputs here -
1769 * alignment view, score model, similarity parameters)
1771 PcaDataType data = new PcaDataType();
1772 viewer.setPcaData(data);
1773 PCA pca = pcaModel.getPcaData();
1775 DoubleMatrix pm = new DoubleMatrix();
1776 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1777 data.setPairwiseMatrix(pm);
1779 DoubleMatrix tm = new DoubleMatrix();
1780 saveDoubleMatrix(pca.getTridiagonal(), tm);
1781 data.setTridiagonalMatrix(tm);
1783 DoubleMatrix eigenMatrix = new DoubleMatrix();
1784 data.setEigenMatrix(eigenMatrix);
1785 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1787 object.getPcaViewer().add(viewer);
1788 } catch (Throwable t)
1790 Cache.log.error("Error saving PCA: " + t.getMessage());
1795 * Stores values from a matrix into an XML element, including (if present) the
1800 * @see #loadDoubleMatrix(DoubleMatrix)
1802 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1804 xmlMatrix.setRows(m.height());
1805 xmlMatrix.setColumns(m.width());
1806 for (int i = 0; i < m.height(); i++)
1808 DoubleVector row = new DoubleVector();
1809 for (int j = 0; j < m.width(); j++)
1811 row.getV().add(m.getValue(i, j));
1813 xmlMatrix.getRow().add(row);
1815 if (m.getD() != null)
1817 DoubleVector dVector = new DoubleVector();
1818 for (double d : m.getD())
1820 dVector.getV().add(d);
1822 xmlMatrix.setD(dVector);
1824 if (m.getE() != null)
1826 DoubleVector eVector = new DoubleVector();
1827 for (double e : m.getE())
1829 eVector.getV().add(e);
1831 xmlMatrix.setE(eVector);
1836 * Loads XML matrix data into a new Matrix object, including the D and/or E
1837 * vectors (if present)
1841 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
1843 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
1845 int rows = mData.getRows();
1846 double[][] vals = new double[rows][];
1848 for (int i = 0; i < rows; i++)
1850 List<Double> dVector = mData.getRow().get(i).getV();
1851 vals[i] = new double[dVector.size()];
1853 for (Double d : dVector)
1859 MatrixI m = new Matrix(vals);
1861 if (mData.getD() != null)
1863 List<Double> dVector = mData.getD().getV();
1864 double[] vec = new double[dVector.size()];
1866 for (Double d : dVector)
1872 if (mData.getE() != null)
1874 List<Double> dVector = mData.getE().getV();
1875 double[] vec = new double[dVector.size()];
1877 for (Double d : dVector)
1888 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
1889 * for each viewer, with
1891 * <li>viewer geometry (position, size, split pane divider location)</li>
1892 * <li>index of the selected structure in the viewer (currently shows gapped
1894 * <li>the id of the annotation holding RNA secondary structure</li>
1895 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
1897 * Varna viewer state is also written out (in native Varna XML) to separate
1898 * project jar entries. A separate entry is written for each RNA structure
1899 * displayed, with the naming convention
1901 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
1909 * @param storeDataset
1911 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
1912 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
1913 boolean storeDataset)
1915 if (Desktop.desktop == null)
1919 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1920 for (int f = frames.length - 1; f > -1; f--)
1922 if (frames[f] instanceof AppVarna)
1924 AppVarna varna = (AppVarna) frames[f];
1926 * link the sequence to every viewer that is showing it and is linked to
1927 * its alignment panel
1929 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
1931 String viewId = varna.getViewId();
1932 RnaViewer rna = new RnaViewer();
1933 rna.setViewId(viewId);
1934 rna.setTitle(varna.getTitle());
1935 rna.setXpos(varna.getX());
1936 rna.setYpos(varna.getY());
1937 rna.setWidth(varna.getWidth());
1938 rna.setHeight(varna.getHeight());
1939 rna.setDividerLocation(varna.getDividerLocation());
1940 rna.setSelectedRna(varna.getSelectedIndex());
1941 // jseq.addRnaViewer(rna);
1942 jseq.getRnaViewer().add(rna);
1945 * Store each Varna panel's state once in the project per sequence.
1946 * First time through only (storeDataset==false)
1948 // boolean storeSessions = false;
1949 // String sequenceViewId = viewId + seqsToIds.get(jds);
1950 // if (!storeDataset && !viewIds.contains(sequenceViewId))
1952 // viewIds.add(sequenceViewId);
1953 // storeSessions = true;
1955 for (RnaModel model : varna.getModels())
1957 if (model.seq == jds)
1960 * VARNA saves each view (sequence or alignment secondary
1961 * structure, gapped or trimmed) as a separate XML file
1963 String jarEntryName = rnaSessions.get(model);
1964 if (jarEntryName == null)
1967 String varnaStateFile = varna.getStateInfo(model.rna);
1968 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
1969 copyFileToJar(jout, varnaStateFile, jarEntryName);
1970 rnaSessions.put(model, jarEntryName);
1972 SecondaryStructure ss = new SecondaryStructure();
1973 String annotationId = varna.getAnnotation(jds).annotationId;
1974 ss.setAnnotationId(annotationId);
1975 ss.setViewerState(jarEntryName);
1976 ss.setGapped(model.gapped);
1977 ss.setTitle(model.title);
1978 // rna.addSecondaryStructure(ss);
1979 rna.getSecondaryStructure().add(ss);
1988 * Copy the contents of a file to a new entry added to the output jar
1992 * @param jarEntryName
1994 protected void copyFileToJar(JarOutputStream jout, String infilePath,
1995 String jarEntryName)
1997 DataInputStream dis = null;
2000 File file = new File(infilePath);
2001 if (file.exists() && jout != null)
2003 dis = new DataInputStream(new FileInputStream(file));
2004 byte[] data = new byte[(int) file.length()];
2005 dis.readFully(data);
2006 writeJarEntry(jout, jarEntryName, data);
2008 } catch (Exception ex)
2010 ex.printStackTrace();
2018 } catch (IOException e)
2027 * Write the data to a new entry of given name in the output jar file
2030 * @param jarEntryName
2032 * @throws IOException
2034 protected void writeJarEntry(JarOutputStream jout, String jarEntryName,
2035 byte[] data) throws IOException
2039 System.out.println("Writing jar entry " + jarEntryName);
2040 jout.putNextEntry(new JarEntry(jarEntryName));
2041 DataOutputStream dout = new DataOutputStream(jout);
2042 dout.write(data, 0, data.length);
2049 * Save the state of a structure viewer
2054 * the archive XML element under which to save the state
2057 * @param matchedFile
2061 protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
2062 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2063 String matchedFile, StructureViewerBase viewFrame)
2065 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2068 * Look for any bindings for this viewer to the PDB file of interest
2069 * (including part matches excluding chain id)
2071 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2073 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2074 final String pdbId = pdbentry.getId();
2075 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2076 && entry.getId().toLowerCase(Locale.ROOT)
2077 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2080 * not interested in a binding to a different PDB entry here
2084 if (matchedFile == null)
2086 matchedFile = pdbentry.getFile();
2088 else if (!matchedFile.equals(pdbentry.getFile()))
2091 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2092 + pdbentry.getFile());
2096 // can get at it if the ID
2097 // match is ambiguous (e.g.
2100 for (int smap = 0; smap < viewFrame.getBinding()
2101 .getSequence()[peid].length; smap++)
2103 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2104 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2106 StructureState state = new StructureState();
2107 state.setVisible(true);
2108 state.setXpos(viewFrame.getX());
2109 state.setYpos(viewFrame.getY());
2110 state.setWidth(viewFrame.getWidth());
2111 state.setHeight(viewFrame.getHeight());
2112 final String viewId = viewFrame.getViewId();
2113 state.setViewId(viewId);
2114 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2115 state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
2116 state.setColourByJmol(viewFrame.isColouredByViewer());
2117 state.setType(viewFrame.getViewerType().toString());
2118 // pdb.addStructureState(state);
2119 pdb.getStructureState().add(state);
2127 * Populates the AnnotationColourScheme xml for save. This captures the
2128 * settings of the options in the 'Colour by Annotation' dialog.
2131 * @param userColours
2135 private AnnotationColourScheme constructAnnotationColours(
2136 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2139 AnnotationColourScheme ac = new AnnotationColourScheme();
2140 ac.setAboveThreshold(acg.getAboveThreshold());
2141 ac.setThreshold(acg.getAnnotationThreshold());
2142 // 2.10.2 save annotationId (unique) not annotation label
2143 ac.setAnnotation(acg.getAnnotation().annotationId);
2144 if (acg.getBaseColour() instanceof UserColourScheme)
2147 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2152 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2155 ac.setMaxColour(acg.getMaxColour().getRGB());
2156 ac.setMinColour(acg.getMinColour().getRGB());
2157 ac.setPerSequence(acg.isSeqAssociated());
2158 ac.setPredefinedColours(acg.isPredefinedColours());
2162 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2163 IdentityHashMap<SequenceGroup, String> groupRefs,
2164 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2165 SequenceSet vamsasSet)
2168 for (int i = 0; i < aa.length; i++)
2170 Annotation an = new Annotation();
2172 AlignmentAnnotation annotation = aa[i];
2173 if (annotation.annotationId != null)
2175 annotationIds.put(annotation.annotationId, annotation);
2178 an.setId(annotation.annotationId);
2180 an.setVisible(annotation.visible);
2182 an.setDescription(annotation.description);
2184 if (annotation.sequenceRef != null)
2186 // 2.9 JAL-1781 xref on sequence id rather than name
2187 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2189 if (annotation.groupRef != null)
2191 String groupIdr = groupRefs.get(annotation.groupRef);
2192 if (groupIdr == null)
2194 // make a locally unique String
2195 groupRefs.put(annotation.groupRef,
2196 groupIdr = ("" + System.currentTimeMillis()
2197 + annotation.groupRef.getName()
2198 + groupRefs.size()));
2200 an.setGroupRef(groupIdr.toString());
2203 // store all visualization attributes for annotation
2204 an.setGraphHeight(annotation.graphHeight);
2205 an.setCentreColLabels(annotation.centreColLabels);
2206 an.setScaleColLabels(annotation.scaleColLabel);
2207 an.setShowAllColLabels(annotation.showAllColLabels);
2208 an.setBelowAlignment(annotation.belowAlignment);
2210 if (annotation.graph > 0)
2213 an.setGraphType(annotation.graph);
2214 an.setGraphGroup(annotation.graphGroup);
2215 if (annotation.getThreshold() != null)
2217 ThresholdLine line = new ThresholdLine();
2218 line.setLabel(annotation.getThreshold().label);
2219 line.setValue(annotation.getThreshold().value);
2220 line.setColour(annotation.getThreshold().colour.getRGB());
2221 an.setThresholdLine(line);
2229 an.setLabel(annotation.label);
2231 if (annotation == av.getAlignmentQualityAnnot()
2232 || annotation == av.getAlignmentConservationAnnotation()
2233 || annotation == av.getAlignmentConsensusAnnotation()
2234 || annotation.autoCalculated)
2236 // new way of indicating autocalculated annotation -
2237 an.setAutoCalculated(annotation.autoCalculated);
2239 if (annotation.hasScore())
2241 an.setScore(annotation.getScore());
2244 if (annotation.getCalcId() != null)
2246 calcIdSet.add(annotation.getCalcId());
2247 an.setCalcId(annotation.getCalcId());
2249 if (annotation.hasProperties())
2251 for (String pr : annotation.getProperties())
2253 jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
2255 prop.setValue(annotation.getProperty(pr));
2256 // an.addProperty(prop);
2257 an.getProperty().add(prop);
2261 AnnotationElement ae;
2262 if (annotation.annotations != null)
2264 an.setScoreOnly(false);
2265 for (int a = 0; a < annotation.annotations.length; a++)
2267 if ((annotation == null) || (annotation.annotations[a] == null))
2272 ae = new AnnotationElement();
2273 if (annotation.annotations[a].description != null)
2275 ae.setDescription(annotation.annotations[a].description);
2277 if (annotation.annotations[a].displayCharacter != null)
2279 ae.setDisplayCharacter(
2280 annotation.annotations[a].displayCharacter);
2283 if (!Float.isNaN(annotation.annotations[a].value))
2285 ae.setValue(annotation.annotations[a].value);
2289 if (annotation.annotations[a].secondaryStructure > ' ')
2291 ae.setSecondaryStructure(
2292 annotation.annotations[a].secondaryStructure + "");
2295 if (annotation.annotations[a].colour != null
2296 && annotation.annotations[a].colour != java.awt.Color.black)
2298 ae.setColour(annotation.annotations[a].colour.getRGB());
2301 // an.addAnnotationElement(ae);
2302 an.getAnnotationElement().add(ae);
2303 if (annotation.autoCalculated)
2305 // only write one non-null entry into the annotation row -
2306 // sufficient to get the visualization attributes necessary to
2314 an.setScoreOnly(true);
2316 if (!storeDS || (storeDS && !annotation.autoCalculated))
2318 // skip autocalculated annotation - these are only provided for
2320 // vamsasSet.addAnnotation(an);
2321 vamsasSet.getAnnotation().add(an);
2327 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2329 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2330 if (settings != null)
2332 CalcIdParam vCalcIdParam = new CalcIdParam();
2333 vCalcIdParam.setCalcId(calcId);
2334 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2335 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2336 // generic URI allowing a third party to resolve another instance of the
2337 // service used for this calculation
2338 for (String url : settings.getServiceURLs())
2340 // vCalcIdParam.addServiceURL(urls);
2341 vCalcIdParam.getServiceURL().add(url);
2343 vCalcIdParam.setVersion("1.0");
2344 if (settings.getPreset() != null)
2346 WsParamSetI setting = settings.getPreset();
2347 vCalcIdParam.setName(setting.getName());
2348 vCalcIdParam.setDescription(setting.getDescription());
2352 vCalcIdParam.setName("");
2353 vCalcIdParam.setDescription("Last used parameters");
2355 // need to be able to recover 1) settings 2) user-defined presets or
2356 // recreate settings from preset 3) predefined settings provided by
2357 // service - or settings that can be transferred (or discarded)
2358 vCalcIdParam.setParameters(
2359 settings.getWsParamFile().replace("\n", "|\\n|"));
2360 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2361 // todo - decide if updateImmediately is needed for any projects.
2363 return vCalcIdParam;
2368 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2371 if (calcIdParam.getVersion().equals("1.0"))
2373 final String[] calcIds = calcIdParam.getServiceURL()
2374 .toArray(new String[0]);
2375 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2376 .getPreferredServiceFor(calcIds);
2377 if (service != null)
2379 WsParamSetI parmSet = null;
2382 parmSet = service.getParamStore().parseServiceParameterFile(
2383 calcIdParam.getName(), calcIdParam.getDescription(),
2385 calcIdParam.getParameters().replace("|\\n|", "\n"));
2386 } catch (IOException x)
2388 warn("Couldn't parse parameter data for "
2389 + calcIdParam.getCalcId(), x);
2392 List<ArgumentI> argList = null;
2393 if (calcIdParam.getName().length() > 0)
2395 parmSet = service.getParamStore()
2396 .getPreset(calcIdParam.getName());
2397 if (parmSet != null)
2399 // TODO : check we have a good match with settings in AACon -
2400 // otherwise we'll need to create a new preset
2405 argList = parmSet.getArguments();
2408 AAConSettings settings = new AAConSettings(
2409 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2410 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2411 calcIdParam.isNeedsUpdate());
2416 warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2420 throw new Error(MessageManager.formatMessage(
2421 "error.unsupported_version_calcIdparam", new Object[]
2422 { calcIdParam.toString() }));
2426 * External mapping between jalview objects and objects yielding a valid and
2427 * unique object ID string. This is null for normal Jalview project IO, but
2428 * non-null when a jalview project is being read or written as part of a
2431 IdentityHashMap jv2vobj = null;
2434 * Construct a unique ID for jvobj using either existing bindings or if none
2435 * exist, the result of the hashcode call for the object.
2438 * jalview data object
2439 * @return unique ID for referring to jvobj
2441 private String makeHashCode(Object jvobj, String altCode)
2443 if (jv2vobj != null)
2445 Object id = jv2vobj.get(jvobj);
2448 return id.toString();
2450 // check string ID mappings
2451 if (jvids2vobj != null && jvobj instanceof String)
2453 id = jvids2vobj.get(jvobj);
2457 return id.toString();
2459 // give up and warn that something has gone wrong
2460 warn("Cannot find ID for object in external mapping : " + jvobj);
2466 * return local jalview object mapped to ID, if it exists
2470 * @return null or object bound to idcode
2472 private Object retrieveExistingObj(String idcode)
2474 if (idcode != null && vobj2jv != null)
2476 return vobj2jv.get(idcode);
2482 * binding from ID strings from external mapping table to jalview data model
2485 private Hashtable vobj2jv;
2487 private Sequence createVamsasSequence(String id, SequenceI jds)
2489 return createVamsasSequence(true, id, jds, null);
2492 private Sequence createVamsasSequence(boolean recurse, String id,
2493 SequenceI jds, SequenceI parentseq)
2495 Sequence vamsasSeq = new Sequence();
2496 vamsasSeq.setId(id);
2497 vamsasSeq.setName(jds.getName());
2498 vamsasSeq.setSequence(jds.getSequenceAsString());
2499 vamsasSeq.setDescription(jds.getDescription());
2500 jalview.datamodel.DBRefEntry[] dbrefs = null;
2501 if (jds.getDatasetSequence() != null)
2503 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2507 // seqId==dsseqid so we can tell which sequences really are
2508 // dataset sequences only
2509 vamsasSeq.setDsseqid(id);
2510 dbrefs = jds.getDBRefs();
2511 if (parentseq == null)
2518 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2522 for (int d = 0; d < dbrefs.length; d++)
2524 DBRef dbref = new DBRef();
2525 DBRefEntry dbRefEntry = dbrefs[d];
2526 dbref.setSource(dbRefEntry.getSource());
2527 dbref.setVersion(dbRefEntry.getVersion());
2528 dbref.setAccessionId(dbRefEntry.getAccessionId());
2529 if (dbRefEntry instanceof GeneLocus)
2531 dbref.setLocus(true);
2533 if (dbRefEntry.hasMap())
2535 Mapping mp = createVamsasMapping(dbRefEntry.getMap(), parentseq,
2537 dbref.setMapping(mp);
2539 vamsasSeq.getDBRef().add(dbref);
2545 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2546 SequenceI parentseq, SequenceI jds, boolean recurse)
2549 if (jmp.getMap() != null)
2553 jalview.util.MapList mlst = jmp.getMap();
2554 List<int[]> r = mlst.getFromRanges();
2555 for (int[] range : r)
2557 MapListFrom mfrom = new MapListFrom();
2558 mfrom.setStart(range[0]);
2559 mfrom.setEnd(range[1]);
2560 // mp.addMapListFrom(mfrom);
2561 mp.getMapListFrom().add(mfrom);
2563 r = mlst.getToRanges();
2564 for (int[] range : r)
2566 MapListTo mto = new MapListTo();
2567 mto.setStart(range[0]);
2568 mto.setEnd(range[1]);
2569 // mp.addMapListTo(mto);
2570 mp.getMapListTo().add(mto);
2572 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2573 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2574 if (jmp.getTo() != null)
2576 // MappingChoice mpc = new MappingChoice();
2578 // check/create ID for the sequence referenced by getTo()
2581 SequenceI ps = null;
2582 if (parentseq != jmp.getTo()
2583 && parentseq.getDatasetSequence() != jmp.getTo())
2585 // chaining dbref rather than a handshaking one
2586 jmpid = seqHash(ps = jmp.getTo());
2590 jmpid = seqHash(ps = parentseq);
2592 // mpc.setDseqFor(jmpid);
2593 mp.setDseqFor(jmpid);
2594 if (!seqRefIds.containsKey(jmpid))
2596 jalview.bin.Cache.log.debug("creatign new DseqFor ID");
2597 seqRefIds.put(jmpid, ps);
2601 jalview.bin.Cache.log.debug("reusing DseqFor ID");
2604 // mp.setMappingChoice(mpc);
2610 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2611 List<UserColourScheme> userColours, JalviewModel jm)
2614 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2615 boolean newucs = false;
2616 if (!userColours.contains(ucs))
2618 userColours.add(ucs);
2621 id = "ucs" + userColours.indexOf(ucs);
2624 // actually create the scheme's entry in the XML model
2625 java.awt.Color[] colours = ucs.getColours();
2626 UserColours uc = new UserColours();
2627 // UserColourScheme jbucs = new UserColourScheme();
2628 JalviewUserColours jbucs = new JalviewUserColours();
2630 for (int i = 0; i < colours.length; i++)
2632 Colour col = new Colour();
2633 col.setName(ResidueProperties.aa[i]);
2634 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2635 // jbucs.addColour(col);
2636 jbucs.getColour().add(col);
2638 if (ucs.getLowerCaseColours() != null)
2640 colours = ucs.getLowerCaseColours();
2641 for (int i = 0; i < colours.length; i++)
2643 Colour col = new Colour();
2644 col.setName(ResidueProperties.aa[i].toLowerCase());
2645 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2646 // jbucs.addColour(col);
2647 jbucs.getColour().add(col);
2652 uc.setUserColourScheme(jbucs);
2653 // jm.addUserColours(uc);
2654 jm.getUserColours().add(uc);
2660 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2663 List<UserColours> uc = jm.getUserColours();
2664 UserColours colours = null;
2666 for (int i = 0; i < uc.length; i++)
2668 if (uc[i].getId().equals(id))
2675 for (UserColours c : uc)
2677 if (c.getId().equals(id))
2684 java.awt.Color[] newColours = new java.awt.Color[24];
2686 for (int i = 0; i < 24; i++)
2688 newColours[i] = new java.awt.Color(Integer.parseInt(
2689 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
2690 colours.getUserColourScheme().getColour().get(i).getRGB(),
2694 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
2697 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
2699 newColours = new java.awt.Color[23];
2700 for (int i = 0; i < 23; i++)
2702 newColours[i] = new java.awt.Color(
2703 Integer.parseInt(colours.getUserColourScheme().getColour()
2704 .get(i + 24).getRGB(), 16));
2706 ucs.setLowerCaseColours(newColours);
2713 * contains last error message (if any) encountered by XML loader.
2715 String errorMessage = null;
2718 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
2719 * exceptions are raised during project XML parsing
2721 public boolean attemptversion1parse = false;
2724 * Load a jalview project archive from a jar file
2727 * - HTTP URL or filename
2729 public AlignFrame loadJalviewAlign(final String file)
2732 jalview.gui.AlignFrame af = null;
2736 // create list to store references for any new Jmol viewers created
2737 newStructureViewers = new Vector<>();
2738 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
2739 // Workaround is to make sure caller implements the JarInputStreamProvider
2741 // so we can re-open the jar input stream for each entry.
2743 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
2744 af = loadJalviewAlign(jprovider);
2747 af.setMenusForViewport();
2749 } catch (MalformedURLException e)
2751 errorMessage = "Invalid URL format for '" + file + "'";
2757 SwingUtilities.invokeAndWait(new Runnable()
2762 setLoadingFinishedForNewStructureViewers();
2765 } catch (Exception x)
2767 System.err.println("Error loading alignment: " + x.getMessage());
2773 private jarInputStreamProvider createjarInputStreamProvider(
2774 final String file) throws MalformedURLException
2777 errorMessage = null;
2778 uniqueSetSuffix = null;
2780 viewportsAdded.clear();
2781 frefedSequence = null;
2783 if (HttpUtils.startsWithHttpOrHttps(file))
2785 url = new URL(file);
2787 final URL _url = url;
2788 return new jarInputStreamProvider()
2792 public JarInputStream getJarInputStream() throws IOException
2796 return new JarInputStream(_url.openStream());
2800 return new JarInputStream(new FileInputStream(file));
2805 public String getFilename()
2813 * Recover jalview session from a jalview project archive. Caller may
2814 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
2815 * themselves. Any null fields will be initialised with default values,
2816 * non-null fields are left alone.
2821 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
2823 errorMessage = null;
2824 if (uniqueSetSuffix == null)
2826 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
2828 if (seqRefIds == null)
2832 AlignFrame af = null, _af = null;
2833 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
2834 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
2835 final String file = jprovider.getFilename();
2838 JarInputStream jin = null;
2839 JarEntry jarentry = null;
2844 jin = jprovider.getJarInputStream();
2845 for (int i = 0; i < entryCount; i++)
2847 jarentry = jin.getNextJarEntry();
2850 if (jarentry != null && jarentry.getName().endsWith(".xml"))
2852 InputStreamReader in = new InputStreamReader(jin, UTF_8);
2853 // JalviewModel object = new JalviewModel();
2855 JAXBContext jc = JAXBContext
2856 .newInstance("jalview.xml.binding.jalview");
2857 XMLStreamReader streamReader = XMLInputFactory.newInstance()
2858 .createXMLStreamReader(jin);
2859 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
2860 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
2861 JalviewModel.class);
2862 JalviewModel object = jbe.getValue();
2865 Unmarshaller unmar = new Unmarshaller(object);
2866 unmar.setValidation(false);
2867 object = (JalviewModel) unmar.unmarshal(in);
2869 if (true) // !skipViewport(object))
2871 _af = loadFromObject(object, file, true, jprovider);
2872 if (_af != null && object.getViewport().size() > 0)
2873 // getJalviewModelSequence().getViewportCount() > 0)
2877 // store a reference to the first view
2880 if (_af.getViewport().isGatherViewsHere())
2882 // if this is a gathered view, keep its reference since
2883 // after gathering views, only this frame will remain
2885 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
2888 // Save dataset to register mappings once all resolved
2889 importedDatasets.put(
2890 af.getViewport().getAlignment().getDataset(),
2891 af.getViewport().getAlignment().getDataset());
2896 else if (jarentry != null)
2898 // Some other file here.
2901 } while (jarentry != null);
2903 resolveFrefedSequences();
2904 } catch (IOException ex)
2906 ex.printStackTrace();
2907 errorMessage = "Couldn't locate Jalview XML file : " + file;
2909 "Exception whilst loading jalview XML file : " + ex + "\n");
2910 } catch (Exception ex)
2912 System.err.println("Parsing as Jalview Version 2 file failed.");
2913 ex.printStackTrace(System.err);
2914 if (attemptversion1parse)
2916 // used to attempt to parse as V1 castor-generated xml
2918 if (Desktop.instance != null)
2920 Desktop.instance.stopLoading();
2924 System.out.println("Successfully loaded archive file");
2927 ex.printStackTrace();
2930 "Exception whilst loading jalview XML file : " + ex + "\n");
2931 } catch (OutOfMemoryError e)
2933 // Don't use the OOM Window here
2934 errorMessage = "Out of memory loading jalview XML file";
2935 System.err.println("Out of memory whilst loading jalview XML file");
2936 e.printStackTrace();
2940 * Regather multiple views (with the same sequence set id) to the frame (if
2941 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
2942 * views instead of separate frames. Note this doesn't restore a state where
2943 * some expanded views in turn have tabbed views - the last "first tab" read
2944 * in will play the role of gatherer for all.
2946 for (AlignFrame fr : gatherToThisFrame.values())
2948 Desktop.instance.gatherViews(fr);
2951 restoreSplitFrames();
2952 for (AlignmentI ds : importedDatasets.keySet())
2954 if (ds.getCodonFrames() != null)
2956 StructureSelectionManager
2957 .getStructureSelectionManager(Desktop.instance)
2958 .registerMappings(ds.getCodonFrames());
2961 if (errorMessage != null)
2966 if (Desktop.instance != null)
2968 Desktop.instance.stopLoading();
2975 * Try to reconstruct and display SplitFrame windows, where each contains
2976 * complementary dna and protein alignments. Done by pairing up AlignFrame
2977 * objects (created earlier) which have complementary viewport ids associated.
2979 protected void restoreSplitFrames()
2981 List<SplitFrame> gatherTo = new ArrayList<>();
2982 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
2983 Map<String, AlignFrame> dna = new HashMap<>();
2986 * Identify the DNA alignments
2988 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
2991 AlignFrame af = candidate.getValue();
2992 if (af.getViewport().getAlignment().isNucleotide())
2994 dna.put(candidate.getKey().getId(), af);
2999 * Try to match up the protein complements
3001 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3004 AlignFrame af = candidate.getValue();
3005 if (!af.getViewport().getAlignment().isNucleotide())
3007 String complementId = candidate.getKey().getComplementId();
3008 // only non-null complements should be in the Map
3009 if (complementId != null && dna.containsKey(complementId))
3011 final AlignFrame dnaFrame = dna.get(complementId);
3012 SplitFrame sf = createSplitFrame(dnaFrame, af);
3013 addedToSplitFrames.add(dnaFrame);
3014 addedToSplitFrames.add(af);
3015 dnaFrame.setMenusForViewport();
3016 af.setMenusForViewport();
3017 if (af.getViewport().isGatherViewsHere())
3026 * Open any that we failed to pair up (which shouldn't happen!) as
3027 * standalone AlignFrame's.
3029 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3032 AlignFrame af = candidate.getValue();
3033 if (!addedToSplitFrames.contains(af))
3035 Viewport view = candidate.getKey();
3036 Desktop.addInternalFrame(af, view.getTitle(),
3037 safeInt(view.getWidth()), safeInt(view.getHeight()));
3038 af.setMenusForViewport();
3039 System.err.println("Failed to restore view " + view.getTitle()
3040 + " to split frame");
3045 * Gather back into tabbed views as flagged.
3047 for (SplitFrame sf : gatherTo)
3049 Desktop.instance.gatherViews(sf);
3052 splitFrameCandidates.clear();
3056 * Construct and display one SplitFrame holding DNA and protein alignments.
3059 * @param proteinFrame
3062 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3063 AlignFrame proteinFrame)
3065 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3066 String title = MessageManager.getString("label.linked_view_title");
3067 int width = (int) dnaFrame.getBounds().getWidth();
3068 int height = (int) (dnaFrame.getBounds().getHeight()
3069 + proteinFrame.getBounds().getHeight() + 50);
3072 * SplitFrame location is saved to both enclosed frames
3074 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3075 Desktop.addInternalFrame(splitFrame, title, width, height);
3078 * And compute cDNA consensus (couldn't do earlier with consensus as
3079 * mappings were not yet present)
3081 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3087 * check errorMessage for a valid error message and raise an error box in the
3088 * GUI or write the current errorMessage to stderr and then clear the error
3091 protected void reportErrors()
3093 reportErrors(false);
3096 protected void reportErrors(final boolean saving)
3098 if (errorMessage != null)
3100 final String finalErrorMessage = errorMessage;
3103 javax.swing.SwingUtilities.invokeLater(new Runnable()
3108 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3110 "Error " + (saving ? "saving" : "loading")
3112 JvOptionPane.WARNING_MESSAGE);
3118 System.err.println("Problem loading Jalview file: " + errorMessage);
3121 errorMessage = null;
3124 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3127 * when set, local views will be updated from view stored in JalviewXML
3128 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3129 * sync if this is set to true.
3131 private final boolean updateLocalViews = false;
3134 * Returns the path to a temporary file holding the PDB file for the given PDB
3135 * id. The first time of asking, searches for a file of that name in the
3136 * Jalview project jar, and copies it to a new temporary file. Any repeat
3137 * requests just return the path to the file previously created.
3143 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3146 if (alreadyLoadedPDB.containsKey(pdbId))
3148 return alreadyLoadedPDB.get(pdbId).toString();
3151 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3153 if (tempFile != null)
3155 alreadyLoadedPDB.put(pdbId, tempFile);
3161 * Copies the jar entry of given name to a new temporary file and returns the
3162 * path to the file, or null if the entry is not found.
3165 * @param jarEntryName
3167 * a prefix for the temporary file name, must be at least three
3169 * @param suffixModel
3170 * null or original file - so new file can be given the same suffix
3174 protected String copyJarEntry(jarInputStreamProvider jprovider,
3175 String jarEntryName, String prefix, String suffixModel)
3177 BufferedReader in = null;
3178 PrintWriter out = null;
3179 String suffix = ".tmp";
3180 if (suffixModel == null)
3182 suffixModel = jarEntryName;
3184 int sfpos = suffixModel.lastIndexOf(".");
3185 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3187 suffix = "." + suffixModel.substring(sfpos + 1);
3191 JarInputStream jin = jprovider.getJarInputStream();
3193 * if (jprovider.startsWith("http://")) { jin = new JarInputStream(new
3194 * URL(jprovider).openStream()); } else { jin = new JarInputStream(new
3195 * FileInputStream(jprovider)); }
3198 JarEntry entry = null;
3201 entry = jin.getNextJarEntry();
3202 } while (entry != null && !entry.getName().equals(jarEntryName));
3205 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3206 File outFile = File.createTempFile(prefix, suffix);
3207 outFile.deleteOnExit();
3208 out = new PrintWriter(new FileOutputStream(outFile));
3211 while ((data = in.readLine()) != null)
3216 String t = outFile.getAbsolutePath();
3221 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
3223 } catch (Exception ex)
3225 ex.printStackTrace();
3233 } catch (IOException e)
3247 private class JvAnnotRow
3249 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3256 * persisted version of annotation row from which to take vis properties
3258 public jalview.datamodel.AlignmentAnnotation template;
3261 * original position of the annotation row in the alignment
3267 * Load alignment frame from jalview XML DOM object
3269 * @param jalviewModel
3272 * filename source string
3273 * @param loadTreesAndStructures
3274 * when false only create Viewport
3276 * data source provider
3277 * @return alignment frame created from view stored in DOM
3279 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3280 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3282 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3284 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3286 // JalviewModelSequence jms = object.getJalviewModelSequence();
3288 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3290 Viewport view = (jalviewModel.getViewport().size() > 0)
3291 ? jalviewModel.getViewport().get(0)
3294 // ////////////////////////////////
3295 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3298 // If we just load in the same jar file again, the sequenceSetId
3299 // will be the same, and we end up with multiple references
3300 // to the same sequenceSet. We must modify this id on load
3301 // so that each load of the file gives a unique id
3304 * used to resolve correct alignment dataset for alignments with multiple
3307 String uniqueSeqSetId = null;
3308 String viewId = null;
3311 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3312 viewId = (view.getId() == null ? null
3313 : view.getId() + uniqueSetSuffix);
3316 // ////////////////////////////////
3319 List<SequenceI> hiddenSeqs = null;
3321 List<SequenceI> tmpseqs = new ArrayList<>();
3323 boolean multipleView = false;
3324 SequenceI referenceseqForView = null;
3325 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3326 List<JSeq> jseqs = jalviewModel.getJSeq();
3327 int vi = 0; // counter in vamsasSeq array
3328 for (int i = 0; i < jseqs.size(); i++)
3330 JSeq jseq = jseqs.get(i);
3331 String seqId = jseq.getId();
3333 SequenceI tmpSeq = seqRefIds.get(seqId);
3336 if (!incompleteSeqs.containsKey(seqId))
3338 // may not need this check, but keep it for at least 2.9,1 release
3339 if (tmpSeq.getStart() != jseq.getStart()
3340 || tmpSeq.getEnd() != jseq.getEnd())
3342 System.err.println(String.format(
3343 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3344 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3345 jseq.getStart(), jseq.getEnd()));
3350 incompleteSeqs.remove(seqId);
3352 if (vamsasSeqs.size() > vi
3353 && vamsasSeqs.get(vi).getId().equals(seqId))
3355 // most likely we are reading a dataset XML document so
3356 // update from vamsasSeq section of XML for this sequence
3357 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3358 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3359 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3364 // reading multiple views, so vamsasSeq set is a subset of JSeq
3365 multipleView = true;
3367 tmpSeq.setStart(jseq.getStart());
3368 tmpSeq.setEnd(jseq.getEnd());
3369 tmpseqs.add(tmpSeq);
3373 Sequence vamsasSeq = vamsasSeqs.get(vi);
3374 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3375 vamsasSeq.getSequence());
3376 tmpSeq.setDescription(vamsasSeq.getDescription());
3377 tmpSeq.setStart(jseq.getStart());
3378 tmpSeq.setEnd(jseq.getEnd());
3379 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3380 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3381 tmpseqs.add(tmpSeq);
3385 if (safeBoolean(jseq.isViewreference()))
3387 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3390 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3392 if (hiddenSeqs == null)
3394 hiddenSeqs = new ArrayList<>();
3397 hiddenSeqs.add(tmpSeq);
3402 // Create the alignment object from the sequence set
3403 // ///////////////////////////////
3404 SequenceI[] orderedSeqs = tmpseqs
3405 .toArray(new SequenceI[tmpseqs.size()]);
3407 AlignmentI al = null;
3408 // so we must create or recover the dataset alignment before going further
3409 // ///////////////////////////////
3410 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3412 // older jalview projects do not have a dataset - so creat alignment and
3414 al = new Alignment(orderedSeqs);
3415 al.setDataset(null);
3419 boolean isdsal = jalviewModel.getViewport().isEmpty();
3422 // we are importing a dataset record, so
3423 // recover reference to an alignment already materialsed as dataset
3424 al = getDatasetFor(vamsasSet.getDatasetId());
3428 // materialse the alignment
3429 al = new Alignment(orderedSeqs);
3433 addDatasetRef(vamsasSet.getDatasetId(), al);
3436 // finally, verify all data in vamsasSet is actually present in al
3437 // passing on flag indicating if it is actually a stored dataset
3438 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3441 if (referenceseqForView != null)
3443 al.setSeqrep(referenceseqForView);
3445 // / Add the alignment properties
3446 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3448 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3450 al.setProperty(ssp.getKey(), ssp.getValue());
3453 // ///////////////////////////////
3455 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3458 // load sequence features, database references and any associated PDB
3459 // structures for the alignment
3461 // prior to 2.10, this part would only be executed the first time a
3462 // sequence was encountered, but not afterwards.
3463 // now, for 2.10 projects, this is also done if the xml doc includes
3464 // dataset sequences not actually present in any particular view.
3466 for (int i = 0; i < vamsasSeqs.size(); i++)
3468 JSeq jseq = jseqs.get(i);
3469 if (jseq.getFeatures().size() > 0)
3471 List<Feature> features = jseq.getFeatures();
3472 for (int f = 0; f < features.size(); f++)
3474 Feature feat = features.get(f);
3475 SequenceFeature sf = new SequenceFeature(feat.getType(),
3476 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3477 safeFloat(feat.getScore()), feat.getFeatureGroup());
3478 sf.setStatus(feat.getStatus());
3481 * load any feature attributes - include map-valued attributes
3483 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3484 for (int od = 0; od < feat.getOtherData().size(); od++)
3486 OtherData keyValue = feat.getOtherData().get(od);
3487 String attributeName = keyValue.getKey();
3488 String attributeValue = keyValue.getValue();
3489 if (attributeName.startsWith("LINK"))
3491 sf.addLink(attributeValue);
3495 String subAttribute = keyValue.getKey2();
3496 if (subAttribute == null)
3498 // simple string-valued attribute
3499 sf.setValue(attributeName, attributeValue);
3503 // attribute 'key' has sub-attribute 'key2'
3504 if (!mapAttributes.containsKey(attributeName))
3506 mapAttributes.put(attributeName, new HashMap<>());
3508 mapAttributes.get(attributeName).put(subAttribute,
3513 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3516 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3519 // adds feature to datasequence's feature set (since Jalview 2.10)
3520 al.getSequenceAt(i).addSequenceFeature(sf);
3523 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3525 // adds dbrefs to datasequence's set (since Jalview 2.10)
3527 al.getSequenceAt(i).getDatasetSequence() == null
3528 ? al.getSequenceAt(i)
3529 : al.getSequenceAt(i).getDatasetSequence(),
3532 if (jseq.getPdbids().size() > 0)
3534 List<Pdbids> ids = jseq.getPdbids();
3535 for (int p = 0; p < ids.size(); p++)
3537 Pdbids pdbid = ids.get(p);
3538 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3539 entry.setId(pdbid.getId());
3540 if (pdbid.getType() != null)
3542 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3544 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3548 entry.setType(PDBEntry.Type.FILE);
3551 // jprovider is null when executing 'New View'
3552 if (pdbid.getFile() != null && jprovider != null)
3554 if (!pdbloaded.containsKey(pdbid.getFile()))
3556 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3561 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3565 if (pdbid.getPdbentryItem() != null)
3567 for (PdbentryItem item : pdbid.getPdbentryItem())
3569 for (Property pr : item.getProperty())
3571 entry.setProperty(pr.getName(), pr.getValue());
3576 for (Property prop : pdbid.getProperty())
3578 entry.setProperty(prop.getName(), prop.getValue());
3580 StructureSelectionManager
3581 .getStructureSelectionManager(Desktop.instance)
3582 .registerPDBEntry(entry);
3583 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3584 if (al.getSequenceAt(i).getDatasetSequence() != null)
3586 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3590 al.getSequenceAt(i).addPDBId(entry);
3595 } // end !multipleview
3597 // ///////////////////////////////
3598 // LOAD SEQUENCE MAPPINGS
3600 if (vamsasSet.getAlcodonFrame().size() > 0)
3602 // TODO Potentially this should only be done once for all views of an
3604 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3605 for (int i = 0; i < alc.size(); i++)
3607 AlignedCodonFrame cf = new AlignedCodonFrame();
3608 if (alc.get(i).getAlcodMap().size() > 0)
3610 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3611 for (int m = 0; m < maps.size(); m++)
3613 AlcodMap map = maps.get(m);
3614 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3616 jalview.datamodel.Mapping mapping = null;
3617 // attach to dna sequence reference.
3618 if (map.getMapping() != null)
3620 mapping = addMapping(map.getMapping());
3621 if (dnaseq != null && mapping.getTo() != null)
3623 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3629 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3633 al.addCodonFrame(cf);
3638 // ////////////////////////////////
3640 List<JvAnnotRow> autoAlan = new ArrayList<>();
3643 * store any annotations which forward reference a group's ID
3645 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3647 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3649 List<Annotation> an = vamsasSet.getAnnotation();
3651 for (int i = 0; i < an.size(); i++)
3653 Annotation annotation = an.get(i);
3656 * test if annotation is automatically calculated for this view only
3658 boolean autoForView = false;
3659 if (annotation.getLabel().equals("Quality")
3660 || annotation.getLabel().equals("Conservation")
3661 || annotation.getLabel().equals("Consensus"))
3663 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3665 // JAXB has no has() test; schema defaults value to false
3666 // if (!annotation.hasAutoCalculated())
3668 // annotation.setAutoCalculated(true);
3671 if (autoForView || annotation.isAutoCalculated())
3673 // remove ID - we don't recover annotation from other views for
3674 // view-specific annotation
3675 annotation.setId(null);
3678 // set visibility for other annotation in this view
3679 String annotationId = annotation.getId();
3680 if (annotationId != null && annotationIds.containsKey(annotationId))
3682 AlignmentAnnotation jda = annotationIds.get(annotationId);
3683 // in principle Visible should always be true for annotation displayed
3684 // in multiple views
3685 if (annotation.isVisible() != null)
3687 jda.visible = annotation.isVisible();
3690 al.addAnnotation(jda);
3694 // Construct new annotation from model.
3695 List<AnnotationElement> ae = annotation.getAnnotationElement();
3696 jalview.datamodel.Annotation[] anot = null;
3697 java.awt.Color firstColour = null;
3699 if (!annotation.isScoreOnly())
3701 anot = new jalview.datamodel.Annotation[al.getWidth()];
3702 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
3704 AnnotationElement annElement = ae.get(aa);
3705 anpos = annElement.getPosition();
3707 if (anpos >= anot.length)
3712 float value = safeFloat(annElement.getValue());
3713 anot[anpos] = new jalview.datamodel.Annotation(
3714 annElement.getDisplayCharacter(),
3715 annElement.getDescription(),
3716 (annElement.getSecondaryStructure() == null
3717 || annElement.getSecondaryStructure()
3721 .getSecondaryStructure()
3724 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
3725 if (firstColour == null)
3727 firstColour = anot[anpos].colour;
3731 jalview.datamodel.AlignmentAnnotation jaa = null;
3733 if (annotation.isGraph())
3735 float llim = 0, hlim = 0;
3736 // if (autoForView || an[i].isAutoCalculated()) {
3739 jaa = new jalview.datamodel.AlignmentAnnotation(
3740 annotation.getLabel(), annotation.getDescription(), anot,
3741 llim, hlim, safeInt(annotation.getGraphType()));
3743 jaa.graphGroup = safeInt(annotation.getGraphGroup());
3744 jaa._linecolour = firstColour;
3745 if (annotation.getThresholdLine() != null)
3747 jaa.setThreshold(new jalview.datamodel.GraphLine(
3748 safeFloat(annotation.getThresholdLine().getValue()),
3749 annotation.getThresholdLine().getLabel(),
3750 new java.awt.Color(safeInt(
3751 annotation.getThresholdLine().getColour()))));
3753 if (autoForView || annotation.isAutoCalculated())
3755 // Hardwire the symbol display line to ensure that labels for
3756 // histograms are displayed
3762 jaa = new jalview.datamodel.AlignmentAnnotation(
3763 annotation.getLabel(), annotation.getDescription(), anot);
3764 jaa._linecolour = firstColour;
3766 // register new annotation
3767 if (annotation.getId() != null)
3769 annotationIds.put(annotation.getId(), jaa);
3770 jaa.annotationId = annotation.getId();
3772 // recover sequence association
3773 String sequenceRef = annotation.getSequenceRef();
3774 if (sequenceRef != null)
3776 // from 2.9 sequenceRef is to sequence id (JAL-1781)
3777 SequenceI sequence = seqRefIds.get(sequenceRef);
3778 if (sequence == null)
3780 // in pre-2.9 projects sequence ref is to sequence name
3781 sequence = al.findName(sequenceRef);
3783 if (sequence != null)
3785 jaa.createSequenceMapping(sequence, 1, true);
3786 sequence.addAlignmentAnnotation(jaa);
3789 // and make a note of any group association
3790 if (annotation.getGroupRef() != null
3791 && annotation.getGroupRef().length() > 0)
3793 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
3794 .get(annotation.getGroupRef());
3797 aal = new ArrayList<>();
3798 groupAnnotRefs.put(annotation.getGroupRef(), aal);
3803 if (annotation.getScore() != null)
3805 jaa.setScore(annotation.getScore().doubleValue());
3807 if (annotation.isVisible() != null)
3809 jaa.visible = annotation.isVisible().booleanValue();
3812 if (annotation.isCentreColLabels() != null)
3814 jaa.centreColLabels = annotation.isCentreColLabels()
3818 if (annotation.isScaleColLabels() != null)
3820 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
3822 if (annotation.isAutoCalculated())
3824 // newer files have an 'autoCalculated' flag and store calculation
3825 // state in viewport properties
3826 jaa.autoCalculated = true; // means annotation will be marked for
3827 // update at end of load.
3829 if (annotation.getGraphHeight() != null)
3831 jaa.graphHeight = annotation.getGraphHeight().intValue();
3833 jaa.belowAlignment = annotation.isBelowAlignment();
3834 jaa.setCalcId(annotation.getCalcId());
3835 if (annotation.getProperty().size() > 0)
3837 for (Annotation.Property prop : annotation.getProperty())
3839 jaa.setProperty(prop.getName(), prop.getValue());
3842 if (jaa.autoCalculated)
3844 autoAlan.add(new JvAnnotRow(i, jaa));
3847 // if (!autoForView)
3849 // add autocalculated group annotation and any user created annotation
3851 al.addAnnotation(jaa);
3855 // ///////////////////////
3857 // Create alignment markup and styles for this view
3858 if (jalviewModel.getJGroup().size() > 0)
3860 List<JGroup> groups = jalviewModel.getJGroup();
3861 boolean addAnnotSchemeGroup = false;
3862 for (int i = 0; i < groups.size(); i++)
3864 JGroup jGroup = groups.get(i);
3865 ColourSchemeI cs = null;
3866 if (jGroup.getColour() != null)
3868 if (jGroup.getColour().startsWith("ucs"))
3870 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
3872 else if (jGroup.getColour().equals("AnnotationColourGradient")
3873 && jGroup.getAnnotationColours() != null)
3875 addAnnotSchemeGroup = true;
3879 cs = ColourSchemeProperty.getColourScheme(null, al,
3880 jGroup.getColour());
3883 int pidThreshold = safeInt(jGroup.getPidThreshold());
3885 Vector<SequenceI> seqs = new Vector<>();
3887 for (int s = 0; s < jGroup.getSeq().size(); s++)
3889 String seqId = jGroup.getSeq().get(s);
3890 SequenceI ts = seqRefIds.get(seqId);
3894 seqs.addElement(ts);
3898 if (seqs.size() < 1)
3903 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
3904 safeBoolean(jGroup.isDisplayBoxes()),
3905 safeBoolean(jGroup.isDisplayText()),
3906 safeBoolean(jGroup.isColourText()),
3907 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
3908 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
3909 sg.getGroupColourScheme()
3910 .setConservationInc(safeInt(jGroup.getConsThreshold()));
3911 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
3913 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
3914 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
3915 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
3916 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
3917 // attributes with a default in the schema are never null
3918 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
3919 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
3920 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
3921 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
3922 if (jGroup.getConsThreshold() != null
3923 && jGroup.getConsThreshold().intValue() != 0)
3925 Conservation c = new Conservation("All", sg.getSequences(null), 0,
3928 c.verdict(false, 25);
3929 sg.cs.setConservation(c);
3932 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
3934 // re-instate unique group/annotation row reference
3935 List<AlignmentAnnotation> jaal = groupAnnotRefs
3936 .get(jGroup.getId());
3939 for (AlignmentAnnotation jaa : jaal)
3942 if (jaa.autoCalculated)
3944 // match up and try to set group autocalc alignment row for this
3946 if (jaa.label.startsWith("Consensus for "))
3948 sg.setConsensus(jaa);
3950 // match up and try to set group autocalc alignment row for this
3952 if (jaa.label.startsWith("Conservation for "))
3954 sg.setConservationRow(jaa);
3961 if (addAnnotSchemeGroup)
3963 // reconstruct the annotation colourscheme
3965 constructAnnotationColour(jGroup.getAnnotationColours(),
3966 null, al, jalviewModel, false));
3972 // only dataset in this model, so just return.
3975 // ///////////////////////////////
3978 AlignFrame af = null;
3979 AlignViewport av = null;
3980 // now check to see if we really need to create a new viewport.
3981 if (multipleView && viewportsAdded.size() == 0)
3983 // We recovered an alignment for which a viewport already exists.
3984 // TODO: fix up any settings necessary for overlaying stored state onto
3985 // state recovered from another document. (may not be necessary).
3986 // we may need a binding from a viewport in memory to one recovered from
3988 // and then recover its containing af to allow the settings to be applied.
3989 // TODO: fix for vamsas demo
3991 "About to recover a viewport for existing alignment: Sequence set ID is "
3993 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
3994 if (seqsetobj != null)
3996 if (seqsetobj instanceof String)
3998 uniqueSeqSetId = (String) seqsetobj;
4000 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4006 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4012 * indicate that annotation colours are applied across all groups (pre
4013 * Jalview 2.8.1 behaviour)
4015 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4016 jalviewModel.getVersion());
4018 AlignmentPanel ap = null;
4019 boolean isnewview = true;
4022 // Check to see if this alignment already has a view id == viewId
4023 jalview.gui.AlignmentPanel views[] = Desktop
4024 .getAlignmentPanels(uniqueSeqSetId);
4025 if (views != null && views.length > 0)
4027 for (int v = 0; v < views.length; v++)
4029 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4031 // recover the existing alignpanel, alignframe, viewport
4032 af = views[v].alignFrame;
4035 // TODO: could even skip resetting view settings if we don't want to
4036 // change the local settings from other jalview processes
4045 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4046 uniqueSeqSetId, viewId, autoAlan);
4047 av = af.getViewport();
4052 * Load any trees, PDB structures and viewers
4054 * Not done if flag is false (when this method is used for New View)
4056 if (loadTreesAndStructures)
4058 loadTrees(jalviewModel, view, af, av, ap);
4059 loadPCAViewers(jalviewModel, ap);
4060 loadPDBStructures(jprovider, jseqs, af, ap);
4061 loadRnaViewers(jprovider, jseqs, ap);
4063 // and finally return.
4068 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4069 * panel is restored from separate jar entries, two (gapped and trimmed) per
4070 * sequence and secondary structure.
4072 * Currently each viewer shows just one sequence and structure (gapped and
4073 * trimmed), however this method is designed to support multiple sequences or
4074 * structures in viewers if wanted in future.
4080 private void loadRnaViewers(jarInputStreamProvider jprovider,
4081 List<JSeq> jseqs, AlignmentPanel ap)
4084 * scan the sequences for references to viewers; create each one the first
4085 * time it is referenced, add Rna models to existing viewers
4087 for (JSeq jseq : jseqs)
4089 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4091 RnaViewer viewer = jseq.getRnaViewer().get(i);
4092 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4095 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4097 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4098 SequenceI seq = seqRefIds.get(jseq.getId());
4099 AlignmentAnnotation ann = this.annotationIds
4100 .get(ss.getAnnotationId());
4103 * add the structure to the Varna display (with session state copied
4104 * from the jar to a temporary file)
4106 boolean gapped = safeBoolean(ss.isGapped());
4107 String rnaTitle = ss.getTitle();
4108 String sessionState = ss.getViewerState();
4109 String tempStateFile = copyJarEntry(jprovider, sessionState,
4111 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4112 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4114 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4120 * Locate and return an already instantiated matching AppVarna, or create one
4124 * @param viewIdSuffix
4128 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4129 String viewIdSuffix, AlignmentPanel ap)
4132 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4133 * if load is repeated
4135 String postLoadId = viewer.getViewId() + viewIdSuffix;
4136 for (JInternalFrame frame : getAllFrames())
4138 if (frame instanceof AppVarna)
4140 AppVarna varna = (AppVarna) frame;
4141 if (postLoadId.equals(varna.getViewId()))
4143 // this viewer is already instantiated
4144 // could in future here add ap as another 'parent' of the
4145 // AppVarna window; currently just 1-to-many
4152 * viewer not found - make it
4154 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4155 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4156 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4157 safeInt(viewer.getDividerLocation()));
4158 AppVarna varna = new AppVarna(model, ap);
4164 * Load any saved trees
4172 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4173 AlignViewport av, AlignmentPanel ap)
4175 // TODO result of automated refactoring - are all these parameters needed?
4178 for (int t = 0; t < jm.getTree().size(); t++)
4181 Tree tree = jm.getTree().get(t);
4183 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4186 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4187 tree.getTitle(), safeInt(tree.getWidth()),
4188 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4189 safeInt(tree.getYpos()));
4190 if (tree.getId() != null)
4192 // perhaps bind the tree id to something ?
4197 // update local tree attributes ?
4198 // TODO: should check if tp has been manipulated by user - if so its
4199 // settings shouldn't be modified
4200 tp.setTitle(tree.getTitle());
4201 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4202 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4203 safeInt(tree.getHeight())));
4204 tp.setViewport(av); // af.viewport;
4205 // TODO: verify 'associate with all views' works still
4206 tp.getTreeCanvas().setViewport(av); // af.viewport;
4207 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4209 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4212 warn("There was a problem recovering stored Newick tree: \n"
4213 + tree.getNewick());
4217 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4218 tp.fitToWindow_actionPerformed(null);
4220 if (tree.getFontName() != null)
4223 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4224 safeInt(tree.getFontSize())));
4229 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4230 safeInt(view.getFontSize())));
4233 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4234 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4235 tp.showDistances(safeBoolean(tree.isShowDistances()));
4237 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4239 if (safeBoolean(tree.isCurrentTree()))
4241 af.getViewport().setCurrentTree(tp.getTree());
4245 } catch (Exception ex)
4247 ex.printStackTrace();
4252 * Load and link any saved structure viewers.
4259 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4260 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4263 * Run through all PDB ids on the alignment, and collect mappings between
4264 * distinct view ids and all sequences referring to that view.
4266 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4268 for (int i = 0; i < jseqs.size(); i++)
4270 JSeq jseq = jseqs.get(i);
4271 if (jseq.getPdbids().size() > 0)
4273 List<Pdbids> ids = jseq.getPdbids();
4274 for (int p = 0; p < ids.size(); p++)
4276 Pdbids pdbid = ids.get(p);
4277 final int structureStateCount = pdbid.getStructureState().size();
4278 for (int s = 0; s < structureStateCount; s++)
4280 // check to see if we haven't already created this structure view
4281 final StructureState structureState = pdbid.getStructureState()
4283 String sviewid = (structureState.getViewId() == null) ? null
4284 : structureState.getViewId() + uniqueSetSuffix;
4285 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4286 // Originally : pdbid.getFile()
4287 // : TODO: verify external PDB file recovery still works in normal
4288 // jalview project load
4290 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4291 jpdb.setId(pdbid.getId());
4293 int x = safeInt(structureState.getXpos());
4294 int y = safeInt(structureState.getYpos());
4295 int width = safeInt(structureState.getWidth());
4296 int height = safeInt(structureState.getHeight());
4298 // Probably don't need to do this anymore...
4299 // Desktop.desktop.getComponentAt(x, y);
4300 // TODO: NOW: check that this recovers the PDB file correctly.
4301 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4303 jalview.datamodel.SequenceI seq = seqRefIds
4304 .get(jseq.getId() + "");
4305 if (sviewid == null)
4307 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4310 if (!structureViewers.containsKey(sviewid))
4312 structureViewers.put(sviewid,
4313 new StructureViewerModel(x, y, width, height, false,
4314 false, true, structureState.getViewId(),
4315 structureState.getType()));
4316 // Legacy pre-2.7 conversion JAL-823 :
4317 // do not assume any view has to be linked for colour by
4321 // assemble String[] { pdb files }, String[] { id for each
4322 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4323 // seqs_file 2}, boolean[] {
4324 // linkAlignPanel,superposeWithAlignpanel}} from hash
4325 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4326 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4327 || structureState.isAlignwithAlignPanel());
4330 * Default colour by linked panel to false if not specified (e.g.
4331 * for pre-2.7 projects)
4333 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4334 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4335 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4338 * Default colour by viewer to true if not specified (e.g. for
4341 boolean colourByViewer = jmoldat.isColourByViewer();
4342 colourByViewer &= structureState.isColourByJmol();
4343 jmoldat.setColourByViewer(colourByViewer);
4345 if (jmoldat.getStateData().length() < structureState.getValue()
4346 /*Content()*/.length())
4348 jmoldat.setStateData(structureState.getValue());// Content());
4350 if (pdbid.getFile() != null)
4352 File mapkey = new File(pdbid.getFile());
4353 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4354 if (seqstrmaps == null)
4356 jmoldat.getFileData().put(mapkey,
4357 seqstrmaps = jmoldat.new StructureData(pdbFile,
4360 if (!seqstrmaps.getSeqList().contains(seq))
4362 seqstrmaps.getSeqList().add(seq);
4368 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");
4375 // Instantiate the associated structure views
4376 for (Entry<String, StructureViewerModel> entry : structureViewers
4381 createOrLinkStructureViewer(entry, af, ap, jprovider);
4382 } catch (Exception e)
4385 "Error loading structure viewer: " + e.getMessage());
4386 // failed - try the next one
4398 protected void createOrLinkStructureViewer(
4399 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4400 AlignmentPanel ap, jarInputStreamProvider jprovider)
4402 final StructureViewerModel stateData = viewerData.getValue();
4405 * Search for any viewer windows already open from other alignment views
4406 * that exactly match the stored structure state
4408 StructureViewerBase comp = findMatchingViewer(viewerData);
4412 linkStructureViewer(ap, comp, stateData);
4417 * From 2.9: stateData.type contains JMOL or CHIMERA, data is in jar entry
4418 * "viewer_"+stateData.viewId
4420 if (ViewerType.CHIMERA.toString().equals(stateData.getType()))
4422 createChimeraViewer(viewerData, af, jprovider);
4427 * else Jmol (if pre-2.9, stateData contains JMOL state string)
4429 createJmolViewer(viewerData, af, jprovider);
4434 * Create a new Chimera viewer.
4440 protected void createChimeraViewer(
4441 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4442 jarInputStreamProvider jprovider)
4444 StructureViewerModel data = viewerData.getValue();
4445 String chimeraSessionFile = data.getStateData();
4448 * Copy Chimera session from jar entry "viewer_"+viewId to a temporary file
4450 * NB this is the 'saved' viewId as in the project file XML, _not_ the
4451 * 'uniquified' sviewid used to reconstruct the viewer here
4453 String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
4454 chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
4457 Set<Entry<File, StructureData>> fileData = data.getFileData()
4459 List<PDBEntry> pdbs = new ArrayList<>();
4460 List<SequenceI[]> allseqs = new ArrayList<>();
4461 for (Entry<File, StructureData> pdb : fileData)
4463 String filePath = pdb.getValue().getFilePath();
4464 String pdbId = pdb.getValue().getPdbId();
4465 // pdbs.add(new PDBEntry(filePath, pdbId));
4466 pdbs.add(new PDBEntry(pdbId, null, PDBEntry.Type.PDB, filePath));
4467 final List<SequenceI> seqList = pdb.getValue().getSeqList();
4468 SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
4472 boolean colourByChimera = data.isColourByViewer();
4473 boolean colourBySequence = data.isColourWithAlignPanel();
4475 // TODO use StructureViewer as a factory here, see JAL-1761
4476 final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs.size()]);
4477 final SequenceI[][] seqsArray = allseqs
4478 .toArray(new SequenceI[allseqs.size()][]);
4479 String newViewId = viewerData.getKey();
4481 ChimeraViewFrame cvf = new ChimeraViewFrame(chimeraSessionFile,
4482 af.alignPanel, pdbArray, seqsArray, colourByChimera,
4483 colourBySequence, newViewId);
4484 cvf.setSize(data.getWidth(), data.getHeight());
4485 cvf.setLocation(data.getX(), data.getY());
4489 * Create a new Jmol window. First parse the Jmol state to translate filenames
4490 * loaded into the view, and record the order in which files are shown in the
4491 * Jmol view, so we can add the sequence mappings in same order.
4497 protected void createJmolViewer(
4498 final Entry<String, StructureViewerModel> viewerData,
4499 AlignFrame af, jarInputStreamProvider jprovider)
4501 final StructureViewerModel svattrib = viewerData.getValue();
4502 String state = svattrib.getStateData();
4505 * Pre-2.9: state element value is the Jmol state string
4507 * 2.9+: @type is "JMOL", state data is in a Jar file member named "viewer_"
4510 if (ViewerType.JMOL.toString().equals(svattrib.getType()))
4512 state = readJarEntry(jprovider,
4513 getViewerJarEntryName(svattrib.getViewId()));
4516 List<String> pdbfilenames = new ArrayList<>();
4517 List<SequenceI[]> seqmaps = new ArrayList<>();
4518 List<String> pdbids = new ArrayList<>();
4519 StringBuilder newFileLoc = new StringBuilder(64);
4520 int cp = 0, ncp, ecp;
4521 Map<File, StructureData> oldFiles = svattrib.getFileData();
4522 while ((ncp = state.indexOf("load ", cp)) > -1)
4526 // look for next filename in load statement
4527 newFileLoc.append(state.substring(cp,
4528 ncp = (state.indexOf("\"", ncp + 1) + 1)));
4529 String oldfilenam = state.substring(ncp,
4530 ecp = state.indexOf("\"", ncp));
4531 // recover the new mapping data for this old filename
4532 // have to normalize filename - since Jmol and jalview do
4534 // translation differently.
4535 StructureData filedat = oldFiles.get(new File(oldfilenam));
4536 if (filedat == null)
4538 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
4539 filedat = oldFiles.get(new File(reformatedOldFilename));
4542 .append(Platform.escapeBackslashes(filedat.getFilePath()));
4543 pdbfilenames.add(filedat.getFilePath());
4544 pdbids.add(filedat.getPdbId());
4545 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4546 newFileLoc.append("\"");
4547 cp = ecp + 1; // advance beyond last \" and set cursor so we can
4548 // look for next file statement.
4549 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
4553 // just append rest of state
4554 newFileLoc.append(state.substring(cp));
4558 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
4559 newFileLoc = new StringBuilder(state);
4560 newFileLoc.append("; load append ");
4561 for (File id : oldFiles.keySet())
4563 // add this and any other pdb files that should be present in
4565 StructureData filedat = oldFiles.get(id);
4566 newFileLoc.append(filedat.getFilePath());
4567 pdbfilenames.add(filedat.getFilePath());
4568 pdbids.add(filedat.getPdbId());
4569 seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
4570 newFileLoc.append(" \"");
4571 newFileLoc.append(filedat.getFilePath());
4572 newFileLoc.append("\"");
4575 newFileLoc.append(";");
4578 if (newFileLoc.length() == 0)
4582 int histbug = newFileLoc.indexOf("history = ");
4586 * change "history = [true|false];" to "history = [1|0];"
4589 int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
4590 String val = (diff == -1) ? null
4591 : newFileLoc.substring(histbug, diff);
4592 if (val != null && val.length() >= 4)
4594 if (val.contains("e")) // eh? what can it be?
4596 if (val.trim().equals("true"))
4604 newFileLoc.replace(histbug, diff, val);
4609 final String[] pdbf = pdbfilenames
4610 .toArray(new String[pdbfilenames.size()]);
4611 final String[] id = pdbids.toArray(new String[pdbids.size()]);
4612 final SequenceI[][] sq = seqmaps
4613 .toArray(new SequenceI[seqmaps.size()][]);
4614 final String fileloc = newFileLoc.toString();
4615 final String sviewid = viewerData.getKey();
4616 final AlignFrame alf = af;
4617 final Rectangle rect = new Rectangle(svattrib.getX(), svattrib.getY(),
4618 svattrib.getWidth(), svattrib.getHeight());
4621 javax.swing.SwingUtilities.invokeAndWait(new Runnable()
4626 JalviewStructureDisplayI sview = null;
4629 sview = new StructureViewer(
4630 alf.alignPanel.getStructureSelectionManager())
4631 .createView(StructureViewer.ViewerType.JMOL,
4632 pdbf, id, sq, alf.alignPanel, svattrib,
4633 fileloc, rect, sviewid);
4634 addNewStructureViewer(sview);
4635 } catch (OutOfMemoryError ex)
4637 new OOMWarning("restoring structure view for PDB id " + id,
4638 (OutOfMemoryError) ex.getCause());
4639 if (sview != null && sview.isVisible())
4641 sview.closeViewer(false);
4642 sview.setVisible(false);
4648 } catch (InvocationTargetException ex)
4650 warn("Unexpected error when opening Jmol view.", ex);
4652 } catch (InterruptedException e)
4654 // e.printStackTrace();
4660 * Generates a name for the entry in the project jar file to hold state
4661 * information for a structure viewer
4666 protected String getViewerJarEntryName(String viewId)
4668 return VIEWER_PREFIX + viewId;
4672 * Returns any open frame that matches given structure viewer data. The match
4673 * is based on the unique viewId, or (for older project versions) the frame's
4679 protected StructureViewerBase findMatchingViewer(
4680 Entry<String, StructureViewerModel> viewerData)
4682 final String sviewid = viewerData.getKey();
4683 final StructureViewerModel svattrib = viewerData.getValue();
4684 StructureViewerBase comp = null;
4685 JInternalFrame[] frames = getAllFrames();
4686 for (JInternalFrame frame : frames)
4688 if (frame instanceof StructureViewerBase)
4691 * Post jalview 2.4 schema includes structure view id
4693 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4696 comp = (StructureViewerBase) frame;
4697 break; // break added in 2.9
4700 * Otherwise test for matching position and size of viewer frame
4702 else if (frame.getX() == svattrib.getX()
4703 && frame.getY() == svattrib.getY()
4704 && frame.getHeight() == svattrib.getHeight()
4705 && frame.getWidth() == svattrib.getWidth())
4707 comp = (StructureViewerBase) frame;
4708 // no break in faint hope of an exact match on viewId
4716 * Link an AlignmentPanel to an existing structure viewer.
4721 * @param useinViewerSuperpos
4722 * @param usetoColourbyseq
4723 * @param viewerColouring
4725 protected void linkStructureViewer(AlignmentPanel ap,
4726 StructureViewerBase viewer, StructureViewerModel stateData)
4728 // NOTE: if the jalview project is part of a shared session then
4729 // view synchronization should/could be done here.
4731 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
4732 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
4733 final boolean viewerColouring = stateData.isColourByViewer();
4734 Map<File, StructureData> oldFiles = stateData.getFileData();
4737 * Add mapping for sequences in this view to an already open viewer
4739 final AAStructureBindingModel binding = viewer.getBinding();
4740 for (File id : oldFiles.keySet())
4742 // add this and any other pdb files that should be present in the
4744 StructureData filedat = oldFiles.get(id);
4745 String pdbFile = filedat.getFilePath();
4746 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
4747 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
4749 binding.addSequenceForStructFile(pdbFile, seq);
4751 // and add the AlignmentPanel's reference to the view panel
4752 viewer.addAlignmentPanel(ap);
4753 if (useinViewerSuperpos)
4755 viewer.useAlignmentPanelForSuperposition(ap);
4759 viewer.excludeAlignmentPanelForSuperposition(ap);
4761 if (usetoColourbyseq)
4763 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
4767 viewer.excludeAlignmentPanelForColourbyseq(ap);
4772 * Get all frames within the Desktop.
4776 protected JInternalFrame[] getAllFrames()
4778 JInternalFrame[] frames = null;
4779 // TODO is this necessary - is it safe - risk of hanging?
4784 frames = Desktop.desktop.getAllFrames();
4785 } catch (ArrayIndexOutOfBoundsException e)
4787 // occasional No such child exceptions are thrown here...
4791 } catch (InterruptedException f)
4795 } while (frames == null);
4800 * Answers true if 'version' is equal to or later than 'supported', where each
4801 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
4802 * changes. Development and test values for 'version' are leniently treated
4806 * - minimum version we are comparing against
4808 * - version of data being processsed
4811 public static boolean isVersionStringLaterThan(String supported,
4814 if (supported == null || version == null
4815 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
4816 || version.equalsIgnoreCase("Test")
4817 || version.equalsIgnoreCase("AUTOMATED BUILD"))
4819 System.err.println("Assuming project file with "
4820 + (version == null ? "null" : version)
4821 + " is compatible with Jalview version " + supported);
4826 return StringUtils.compareVersions(version, supported, "b") >= 0;
4830 Vector<JalviewStructureDisplayI> newStructureViewers = null;
4832 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
4834 if (newStructureViewers != null)
4836 sview.getBinding().setFinishedLoadingFromArchive(false);
4837 newStructureViewers.add(sview);
4841 protected void setLoadingFinishedForNewStructureViewers()
4843 if (newStructureViewers != null)
4845 for (JalviewStructureDisplayI sview : newStructureViewers)
4847 sview.getBinding().setFinishedLoadingFromArchive(true);
4849 newStructureViewers.clear();
4850 newStructureViewers = null;
4854 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
4855 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
4856 Viewport view, String uniqueSeqSetId, String viewId,
4857 List<JvAnnotRow> autoAlan)
4859 AlignFrame af = null;
4860 af = new AlignFrame(al, safeInt(view.getWidth()),
4861 safeInt(view.getHeight()), uniqueSeqSetId, viewId);
4863 af.setFileName(file, FileFormat.Jalview);
4865 final AlignViewport viewport = af.getViewport();
4866 for (int i = 0; i < JSEQ.size(); i++)
4868 int colour = safeInt(JSEQ.get(i).getColour());
4869 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
4875 viewport.setColourByReferenceSeq(true);
4876 viewport.setDisplayReferenceSeq(true);
4879 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
4881 if (view.getSequenceSetId() != null)
4883 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
4885 viewport.setSequenceSetId(uniqueSeqSetId);
4888 // propagate shared settings to this new view
4889 viewport.setHistoryList(av.getHistoryList());
4890 viewport.setRedoList(av.getRedoList());
4894 viewportsAdded.put(uniqueSeqSetId, viewport);
4896 // TODO: check if this method can be called repeatedly without
4897 // side-effects if alignpanel already registered.
4898 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
4900 // apply Hidden regions to view.
4901 if (hiddenSeqs != null)
4903 for (int s = 0; s < JSEQ.size(); s++)
4905 SequenceGroup hidden = new SequenceGroup();
4906 boolean isRepresentative = false;
4907 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
4909 isRepresentative = true;
4910 SequenceI sequenceToHide = al
4911 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
4912 hidden.addSequence(sequenceToHide, false);
4913 // remove from hiddenSeqs list so we don't try to hide it twice
4914 hiddenSeqs.remove(sequenceToHide);
4916 if (isRepresentative)
4918 SequenceI representativeSequence = al.getSequenceAt(s);
4919 hidden.addSequence(representativeSequence, false);
4920 viewport.hideRepSequences(representativeSequence, hidden);
4924 SequenceI[] hseqs = hiddenSeqs
4925 .toArray(new SequenceI[hiddenSeqs.size()]);
4926 viewport.hideSequence(hseqs);
4929 // recover view properties and display parameters
4931 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4932 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
4933 final int pidThreshold = safeInt(view.getPidThreshold());
4934 viewport.setThreshold(pidThreshold);
4936 viewport.setColourText(safeBoolean(view.isShowColourText()));
4938 viewport.setConservationSelected(
4939 safeBoolean(view.isConservationSelected()));
4940 viewport.setIncrement(safeInt(view.getConsThreshold()));
4941 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
4942 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
4943 viewport.setFont(new Font(view.getFontName(),
4944 safeInt(view.getFontStyle()), safeInt(view.getFontSize())),
4946 ViewStyleI vs = viewport.getViewStyle();
4947 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
4948 viewport.setViewStyle(vs);
4949 // TODO: allow custom charWidth/Heights to be restored by updating them
4950 // after setting font - which means set above to false
4951 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
4952 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
4953 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
4955 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
4957 viewport.setShowText(safeBoolean(view.isShowText()));
4959 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
4960 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
4961 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
4962 viewport.setShowUnconserved(view.isShowUnconserved());
4963 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
4965 if (view.getViewName() != null)
4967 viewport.setViewName(view.getViewName());
4968 af.setInitialTabVisible();
4970 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
4971 safeInt(view.getWidth()), safeInt(view.getHeight()));
4972 // startSeq set in af.alignPanel.updateLayout below
4973 af.alignPanel.updateLayout();
4974 ColourSchemeI cs = null;
4975 // apply colourschemes
4976 if (view.getBgColour() != null)
4978 if (view.getBgColour().startsWith("ucs"))
4980 cs = getUserColourScheme(jm, view.getBgColour());
4982 else if (view.getBgColour().startsWith("Annotation"))
4984 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
4985 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
4992 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
4993 view.getBgColour());
4998 * turn off 'alignment colour applies to all groups'
4999 * while restoring global colour scheme
5001 viewport.setColourAppliesToAllGroups(false);
5002 viewport.setGlobalColourScheme(cs);
5003 viewport.getResidueShading().setThreshold(pidThreshold,
5004 view.isIgnoreGapsinConsensus());
5005 viewport.getResidueShading()
5006 .setConsensus(viewport.getSequenceConsensusHash());
5007 if (safeBoolean(view.isConservationSelected()) && cs != null)
5009 viewport.getResidueShading()
5010 .setConservationInc(safeInt(view.getConsThreshold()));
5012 af.changeColour(cs);
5013 viewport.setColourAppliesToAllGroups(true);
5015 viewport.setShowSequenceFeatures(
5016 safeBoolean(view.isShowSequenceFeatures()));
5018 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5019 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5020 viewport.setFollowHighlight(view.isFollowHighlight());
5021 viewport.followSelection = view.isFollowSelection();
5022 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5023 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5024 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5025 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5026 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5027 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5028 viewport.setShowGroupConservation(view.isShowGroupConservation());
5029 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5030 viewport.setShowComplementFeaturesOnTop(
5031 view.isShowComplementFeaturesOnTop());
5033 // recover feature settings
5034 if (jm.getFeatureSettings() != null)
5036 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5037 .getFeatureRenderer();
5038 FeaturesDisplayed fdi;
5039 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5040 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5042 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5043 Map<String, Float> featureOrder = new Hashtable<>();
5045 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5048 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5049 String featureType = setting.getType();
5052 * restore feature filters (if any)
5054 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5056 if (filters != null)
5058 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5060 if (!filter.isEmpty())
5062 fr.setFeatureFilter(featureType, filter);
5067 * restore feature colour scheme
5069 Color maxColour = new Color(setting.getColour());
5070 if (setting.getMincolour() != null)
5073 * minColour is always set unless a simple colour
5074 * (including for colour by label though it doesn't use it)
5076 Color minColour = new Color(setting.getMincolour().intValue());
5077 Color noValueColour = minColour;
5078 NoValueColour noColour = setting.getNoValueColour();
5079 if (noColour == NoValueColour.NONE)
5081 noValueColour = null;
5083 else if (noColour == NoValueColour.MAX)
5085 noValueColour = maxColour;
5087 float min = safeFloat(safeFloat(setting.getMin()));
5088 float max = setting.getMax() == null ? 1f
5089 : setting.getMax().floatValue();
5090 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5091 maxColour, noValueColour, min, max);
5092 if (setting.getAttributeName().size() > 0)
5094 gc.setAttributeName(setting.getAttributeName().toArray(
5095 new String[setting.getAttributeName().size()]));
5097 if (setting.getThreshold() != null)
5099 gc.setThreshold(setting.getThreshold().floatValue());
5100 int threshstate = safeInt(setting.getThreshstate());
5101 // -1 = None, 0 = Below, 1 = Above threshold
5102 if (threshstate == 0)
5104 gc.setBelowThreshold(true);
5106 else if (threshstate == 1)
5108 gc.setAboveThreshold(true);
5111 gc.setAutoScaled(true); // default
5112 if (setting.isAutoScale() != null)
5114 gc.setAutoScaled(setting.isAutoScale());
5116 if (setting.isColourByLabel() != null)
5118 gc.setColourByLabel(setting.isColourByLabel());
5120 // and put in the feature colour table.
5121 featureColours.put(featureType, gc);
5125 featureColours.put(featureType, new FeatureColour(maxColour));
5127 renderOrder[fs] = featureType;
5128 if (setting.getOrder() != null)
5130 featureOrder.put(featureType, setting.getOrder().floatValue());
5134 featureOrder.put(featureType, Float.valueOf(
5135 fs / jm.getFeatureSettings().getSetting().size()));
5137 if (safeBoolean(setting.isDisplay()))
5139 fdi.setVisible(featureType);
5142 Map<String, Boolean> fgtable = new Hashtable<>();
5143 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5145 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5146 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5148 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5149 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5150 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5151 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5152 fgtable, featureColours, 1.0f, featureOrder);
5153 fr.transferSettings(frs);
5156 if (view.getHiddenColumns().size() > 0)
5158 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5160 final HiddenColumns hc = view.getHiddenColumns().get(c);
5161 viewport.hideColumns(safeInt(hc.getStart()),
5162 safeInt(hc.getEnd()) /* +1 */);
5165 if (view.getCalcIdParam() != null)
5167 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5169 if (calcIdParam != null)
5171 if (recoverCalcIdParam(calcIdParam, viewport))
5176 warn("Couldn't recover parameters for "
5177 + calcIdParam.getCalcId());
5182 af.setMenusFromViewport(viewport);
5183 af.setTitle(view.getTitle());
5184 // TODO: we don't need to do this if the viewport is aready visible.
5186 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5187 * has a 'cdna/protein complement' view, in which case save it in order to
5188 * populate a SplitFrame once all views have been read in.
5190 String complementaryViewId = view.getComplementId();
5191 if (complementaryViewId == null)
5193 Desktop.addInternalFrame(af, view.getTitle(),
5194 safeInt(view.getWidth()), safeInt(view.getHeight()));
5195 // recompute any autoannotation
5196 af.alignPanel.updateAnnotation(false, true);
5197 reorderAutoannotation(af, al, autoAlan);
5198 af.alignPanel.alignmentChanged();
5202 splitFrameCandidates.put(view, af);
5208 * Reads saved data to restore Colour by Annotation settings
5210 * @param viewAnnColour
5214 * @param checkGroupAnnColour
5217 private ColourSchemeI constructAnnotationColour(
5218 AnnotationColourScheme viewAnnColour, AlignFrame af,
5219 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5221 boolean propagateAnnColour = false;
5222 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5224 if (checkGroupAnnColour && al.getGroups() != null
5225 && al.getGroups().size() > 0)
5227 // pre 2.8.1 behaviour
5228 // check to see if we should transfer annotation colours
5229 propagateAnnColour = true;
5230 for (SequenceGroup sg : al.getGroups())
5232 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5234 propagateAnnColour = false;
5240 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5242 String annotationId = viewAnnColour.getAnnotation();
5243 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5246 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5248 if (matchedAnnotation == null
5249 && annAlignment.getAlignmentAnnotation() != null)
5251 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5254 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5256 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5261 if (matchedAnnotation == null)
5263 System.err.println("Failed to match annotation colour scheme for "
5267 if (matchedAnnotation.getThreshold() == null)
5269 matchedAnnotation.setThreshold(
5270 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5271 "Threshold", Color.black));
5274 AnnotationColourGradient cs = null;
5275 if (viewAnnColour.getColourScheme().equals("None"))
5277 cs = new AnnotationColourGradient(matchedAnnotation,
5278 new Color(safeInt(viewAnnColour.getMinColour())),
5279 new Color(safeInt(viewAnnColour.getMaxColour())),
5280 safeInt(viewAnnColour.getAboveThreshold()));
5282 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5284 cs = new AnnotationColourGradient(matchedAnnotation,
5285 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5286 safeInt(viewAnnColour.getAboveThreshold()));
5290 cs = new AnnotationColourGradient(matchedAnnotation,
5291 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5292 viewAnnColour.getColourScheme()),
5293 safeInt(viewAnnColour.getAboveThreshold()));
5296 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5297 boolean useOriginalColours = safeBoolean(
5298 viewAnnColour.isPredefinedColours());
5299 cs.setSeqAssociated(perSequenceOnly);
5300 cs.setPredefinedColours(useOriginalColours);
5302 if (propagateAnnColour && al.getGroups() != null)
5304 // Also use these settings for all the groups
5305 for (int g = 0; g < al.getGroups().size(); g++)
5307 SequenceGroup sg = al.getGroups().get(g);
5308 if (sg.getGroupColourScheme() == null)
5313 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5314 matchedAnnotation, sg.getColourScheme(),
5315 safeInt(viewAnnColour.getAboveThreshold()));
5316 sg.setColourScheme(groupScheme);
5317 groupScheme.setSeqAssociated(perSequenceOnly);
5318 groupScheme.setPredefinedColours(useOriginalColours);
5324 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5325 List<JvAnnotRow> autoAlan)
5327 // copy over visualization settings for autocalculated annotation in the
5329 if (al.getAlignmentAnnotation() != null)
5332 * Kludge for magic autoannotation names (see JAL-811)
5334 String[] magicNames = new String[] { "Consensus", "Quality",
5336 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5337 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5338 for (String nm : magicNames)
5340 visan.put(nm, nullAnnot);
5342 for (JvAnnotRow auan : autoAlan)
5344 visan.put(auan.template.label
5345 + (auan.template.getCalcId() == null ? ""
5346 : "\t" + auan.template.getCalcId()),
5349 int hSize = al.getAlignmentAnnotation().length;
5350 List<JvAnnotRow> reorder = new ArrayList<>();
5351 // work through any autoCalculated annotation already on the view
5352 // removing it if it should be placed in a different location on the
5353 // annotation panel.
5354 List<String> remains = new ArrayList<>(visan.keySet());
5355 for (int h = 0; h < hSize; h++)
5357 jalview.datamodel.AlignmentAnnotation jalan = al
5358 .getAlignmentAnnotation()[h];
5359 if (jalan.autoCalculated)
5362 JvAnnotRow valan = visan.get(k = jalan.label);
5363 if (jalan.getCalcId() != null)
5365 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5370 // delete the auto calculated row from the alignment
5371 al.deleteAnnotation(jalan, false);
5375 if (valan != nullAnnot)
5377 if (jalan != valan.template)
5379 // newly created autoannotation row instance
5380 // so keep a reference to the visible annotation row
5381 // and copy over all relevant attributes
5382 if (valan.template.graphHeight >= 0)
5385 jalan.graphHeight = valan.template.graphHeight;
5387 jalan.visible = valan.template.visible;
5389 reorder.add(new JvAnnotRow(valan.order, jalan));
5394 // Add any (possibly stale) autocalculated rows that were not appended to
5395 // the view during construction
5396 for (String other : remains)
5398 JvAnnotRow othera = visan.get(other);
5399 if (othera != nullAnnot && othera.template.getCalcId() != null
5400 && othera.template.getCalcId().length() > 0)
5402 reorder.add(othera);
5405 // now put the automatic annotation in its correct place
5406 int s = 0, srt[] = new int[reorder.size()];
5407 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5408 for (JvAnnotRow jvar : reorder)
5411 srt[s++] = jvar.order;
5414 jalview.util.QuickSort.sort(srt, rws);
5415 // and re-insert the annotation at its correct position
5416 for (JvAnnotRow jvar : rws)
5418 al.addAnnotation(jvar.template, jvar.order);
5420 af.alignPanel.adjustAnnotationHeight();
5424 Hashtable skipList = null;
5427 * TODO remove this method
5430 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5431 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5432 * throw new Error("Implementation Error. No skipList defined for this
5433 * Jalview2XML instance."); } return (AlignFrame)
5434 * skipList.get(view.getSequenceSetId()); }
5438 * Check if the Jalview view contained in object should be skipped or not.
5441 * @return true if view's sequenceSetId is a key in skipList
5443 private boolean skipViewport(JalviewModel object)
5445 if (skipList == null)
5449 String id = object.getViewport().get(0).getSequenceSetId();
5450 if (skipList.containsKey(id))
5452 if (Cache.log != null && Cache.log.isDebugEnabled())
5454 Cache.log.debug("Skipping seuqence set id " + id);
5461 public void addToSkipList(AlignFrame af)
5463 if (skipList == null)
5465 skipList = new Hashtable();
5467 skipList.put(af.getViewport().getSequenceSetId(), af);
5470 public void clearSkipList()
5472 if (skipList != null)
5479 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5480 boolean ignoreUnrefed, String uniqueSeqSetId)
5482 jalview.datamodel.AlignmentI ds = getDatasetFor(
5483 vamsasSet.getDatasetId());
5484 AlignmentI xtant_ds = ds;
5485 if (xtant_ds == null)
5487 // good chance we are about to create a new dataset, but check if we've
5488 // seen some of the dataset sequence IDs before.
5489 // TODO: skip this check if we are working with project generated by
5490 // version 2.11 or later
5491 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5492 if (xtant_ds != null)
5495 addDatasetRef(vamsasSet.getDatasetId(), ds);
5498 Vector dseqs = null;
5501 // recovering an alignment View
5502 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5503 if (seqSetDS != null)
5505 if (ds != null && ds != seqSetDS)
5507 warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
5508 + " - CDS/Protein crossreference data may be lost");
5509 if (xtant_ds != null)
5511 // This can only happen if the unique sequence set ID was bound to a
5512 // dataset that did not contain any of the sequences in the view
5513 // currently being restored.
5514 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.");
5518 addDatasetRef(vamsasSet.getDatasetId(), ds);
5523 // try even harder to restore dataset
5524 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5525 // create a list of new dataset sequences
5526 dseqs = new Vector();
5528 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5530 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5531 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5533 // create a new dataset
5536 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5537 dseqs.copyInto(dsseqs);
5538 ds = new jalview.datamodel.Alignment(dsseqs);
5539 debug("Created new dataset " + vamsasSet.getDatasetId()
5540 + " for alignment " + System.identityHashCode(al));
5541 addDatasetRef(vamsasSet.getDatasetId(), ds);
5543 // set the dataset for the newly imported alignment.
5544 if (al.getDataset() == null && !ignoreUnrefed)
5547 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5548 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5550 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5554 * XML dataset sequence ID to materialised dataset reference
5556 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5559 * @return the first materialised dataset reference containing a dataset
5560 * sequence referenced in the given view
5562 * - sequences from the view
5564 AlignmentI checkIfHasDataset(List<Sequence> list)
5566 for (Sequence restoredSeq : list)
5568 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5569 if (datasetFor != null)
5578 * Register ds as the containing dataset for the dataset sequences referenced
5579 * by sequences in list
5582 * - sequences in a view
5585 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5587 for (Sequence restoredSeq : list)
5589 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5590 if (prevDS != null && prevDS != ds)
5592 warn("Dataset sequence appears in many datasets: "
5593 + restoredSeq.getDsseqid());
5594 // TODO: try to merge!
5602 * sequence definition to create/merge dataset sequence for
5606 * vector to add new dataset sequence to
5607 * @param ignoreUnrefed
5608 * - when true, don't create new sequences from vamsasSeq if it's id
5609 * doesn't already have an asssociated Jalview sequence.
5611 * - used to reorder the sequence in the alignment according to the
5612 * vamsasSeq array ordering, to preserve ordering of dataset
5614 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5615 AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
5617 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5619 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5620 boolean reorder = false;
5621 SequenceI dsq = null;
5622 if (sq != null && sq.getDatasetSequence() != null)
5624 dsq = sq.getDatasetSequence();
5630 if (sq == null && ignoreUnrefed)
5634 String sqid = vamsasSeq.getDsseqid();
5637 // need to create or add a new dataset sequence reference to this sequence
5640 dsq = seqRefIds.get(sqid);
5645 // make a new dataset sequence
5646 dsq = sq.createDatasetSequence();
5649 // make up a new dataset reference for this sequence
5650 sqid = seqHash(dsq);
5652 dsq.setVamsasId(uniqueSetSuffix + sqid);
5653 seqRefIds.put(sqid, dsq);
5658 dseqs.addElement(dsq);
5663 ds.addSequence(dsq);
5669 { // make this dataset sequence sq's dataset sequence
5670 sq.setDatasetSequence(dsq);
5671 // and update the current dataset alignment
5676 if (!dseqs.contains(dsq))
5683 if (ds.findIndex(dsq) < 0)
5685 ds.addSequence(dsq);
5692 // TODO: refactor this as a merge dataset sequence function
5693 // now check that sq (the dataset sequence) sequence really is the union of
5694 // all references to it
5695 // boolean pre = sq.getStart() < dsq.getStart();
5696 // boolean post = sq.getEnd() > dsq.getEnd();
5700 // StringBuffer sb = new StringBuffer();
5701 String newres = jalview.analysis.AlignSeq.extractGaps(
5702 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
5703 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
5704 && newres.length() > dsq.getLength())
5706 // Update with the longer sequence.
5710 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
5711 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
5712 * sb.append(newres.substring(newres.length() - sq.getEnd() -
5713 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
5715 dsq.setSequence(newres);
5717 // TODO: merges will never happen if we 'know' we have the real dataset
5718 // sequence - this should be detected when id==dssid
5720 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
5721 // + (pre ? "prepended" : "") + " "
5722 // + (post ? "appended" : ""));
5727 // sequence refs are identical. We may need to update the existing dataset
5728 // alignment with this one, though.
5729 if (ds != null && dseqs == null)
5731 int opos = ds.findIndex(dsq);
5732 SequenceI tseq = null;
5733 if (opos != -1 && vseqpos != opos)
5735 // remove from old position
5736 ds.deleteSequence(dsq);
5738 if (vseqpos < ds.getHeight())
5740 if (vseqpos != opos)
5742 // save sequence at destination position
5743 tseq = ds.getSequenceAt(vseqpos);
5744 ds.replaceSequenceAt(vseqpos, dsq);
5745 ds.addSequence(tseq);
5750 ds.addSequence(dsq);
5757 * TODO use AlignmentI here and in related methods - needs
5758 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
5760 Hashtable<String, AlignmentI> datasetIds = null;
5762 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
5764 private AlignmentI getDatasetFor(String datasetId)
5766 if (datasetIds == null)
5768 datasetIds = new Hashtable<>();
5771 if (datasetIds.containsKey(datasetId))
5773 return datasetIds.get(datasetId);
5778 private void addDatasetRef(String datasetId, AlignmentI dataset)
5780 if (datasetIds == null)
5782 datasetIds = new Hashtable<>();
5784 datasetIds.put(datasetId, dataset);
5788 * make a new dataset ID for this jalview dataset alignment
5793 private String getDatasetIdRef(AlignmentI dataset)
5795 if (dataset.getDataset() != null)
5797 warn("Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
5799 String datasetId = makeHashCode(dataset, null);
5800 if (datasetId == null)
5802 // make a new datasetId and record it
5803 if (dataset2Ids == null)
5805 dataset2Ids = new IdentityHashMap<>();
5809 datasetId = dataset2Ids.get(dataset);
5811 if (datasetId == null)
5813 datasetId = "ds" + dataset2Ids.size() + 1;
5814 dataset2Ids.put(dataset, datasetId);
5821 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
5822 * constructed as a special subclass GeneLocus.
5824 * @param datasetSequence
5827 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
5829 for (int d = 0; d < sequence.getDBRef().size(); d++)
5831 DBRef dr = sequence.getDBRef().get(d);
5835 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
5836 dr.getAccessionId());
5840 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
5841 dr.getAccessionId());
5843 if (dr.getMapping() != null)
5845 entry.setMap(addMapping(dr.getMapping()));
5847 datasetSequence.addDBRef(entry);
5851 private jalview.datamodel.Mapping addMapping(Mapping m)
5853 SequenceI dsto = null;
5854 // Mapping m = dr.getMapping();
5855 int fr[] = new int[m.getMapListFrom().size() * 2];
5856 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
5857 for (int _i = 0; from.hasNext(); _i += 2)
5859 MapListFrom mf = from.next();
5860 fr[_i] = mf.getStart();
5861 fr[_i + 1] = mf.getEnd();
5863 int fto[] = new int[m.getMapListTo().size() * 2];
5864 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
5865 for (int _i = 0; to.hasNext(); _i += 2)
5867 MapListTo mf = to.next();
5868 fto[_i] = mf.getStart();
5869 fto[_i + 1] = mf.getEnd();
5871 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
5872 fto, m.getMapFromUnit().intValue(),
5873 m.getMapToUnit().intValue());
5876 * (optional) choice of dseqFor or Sequence
5878 if (m.getDseqFor() != null)
5880 String dsfor = m.getDseqFor();
5881 if (seqRefIds.containsKey(dsfor))
5886 jmap.setTo(seqRefIds.get(dsfor));
5890 frefedSequence.add(newMappingRef(dsfor, jmap));
5893 else if (m.getSequence() != null)
5896 * local sequence definition
5898 Sequence ms = m.getSequence();
5899 SequenceI djs = null;
5900 String sqid = ms.getDsseqid();
5901 if (sqid != null && sqid.length() > 0)
5904 * recover dataset sequence
5906 djs = seqRefIds.get(sqid);
5911 "Warning - making up dataset sequence id for DbRef sequence map reference");
5912 sqid = ((Object) ms).toString(); // make up a new hascode for
5913 // undefined dataset sequence hash
5914 // (unlikely to happen)
5920 * make a new dataset sequence and add it to refIds hash
5922 djs = new jalview.datamodel.Sequence(ms.getName(),
5924 djs.setStart(jmap.getMap().getToLowest());
5925 djs.setEnd(jmap.getMap().getToHighest());
5926 djs.setVamsasId(uniqueSetSuffix + sqid);
5928 incompleteSeqs.put(sqid, djs);
5929 seqRefIds.put(sqid, djs);
5932 jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
5941 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
5942 * view as XML (but not to file), and then reloading it
5947 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
5950 JalviewModel jm = saveState(ap, null, null, null);
5953 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
5954 ap.getAlignment().getDataset());
5956 uniqueSetSuffix = "";
5957 // jm.getJalviewModelSequence().getViewport(0).setId(null);
5958 jm.getViewport().get(0).setId(null);
5959 // we don't overwrite the view we just copied
5961 if (this.frefedSequence == null)
5963 frefedSequence = new Vector<>();
5966 viewportsAdded.clear();
5968 AlignFrame af = loadFromObject(jm, null, false, null);
5969 af.getAlignPanels().clear();
5970 af.closeMenuItem_actionPerformed(true);
5973 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
5974 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
5975 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
5976 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
5977 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
5980 return af.alignPanel;
5983 private Hashtable jvids2vobj;
5985 private void warn(String msg)
5990 private void warn(String msg, Exception e)
5992 if (Cache.log != null)
5996 Cache.log.warn(msg, e);
6000 Cache.log.warn(msg);
6005 System.err.println("Warning: " + msg);
6008 e.printStackTrace();
6013 private void debug(String string)
6015 debug(string, null);
6018 private void debug(String msg, Exception e)
6020 if (Cache.log != null)
6024 Cache.log.debug(msg, e);
6028 Cache.log.debug(msg);
6033 System.err.println("Warning: " + msg);
6036 e.printStackTrace();
6042 * set the object to ID mapping tables used to write/recover objects and XML
6043 * ID strings for the jalview project. If external tables are provided then
6044 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6045 * object goes out of scope. - also populates the datasetIds hashtable with
6046 * alignment objects containing dataset sequences
6049 * Map from ID strings to jalview datamodel
6051 * Map from jalview datamodel to ID strings
6055 public void setObjectMappingTables(Hashtable vobj2jv,
6056 IdentityHashMap jv2vobj)
6058 this.jv2vobj = jv2vobj;
6059 this.vobj2jv = vobj2jv;
6060 Iterator ds = jv2vobj.keySet().iterator();
6062 while (ds.hasNext())
6064 Object jvobj = ds.next();
6065 id = jv2vobj.get(jvobj).toString();
6066 if (jvobj instanceof jalview.datamodel.Alignment)
6068 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6070 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6073 else if (jvobj instanceof jalview.datamodel.Sequence)
6075 // register sequence object so the XML parser can recover it.
6076 if (seqRefIds == null)
6078 seqRefIds = new HashMap<>();
6080 if (seqsToIds == null)
6082 seqsToIds = new IdentityHashMap<>();
6084 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6085 seqsToIds.put((SequenceI) jvobj, id);
6087 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6090 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6091 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6092 if (jvann.annotationId == null)
6094 jvann.annotationId = anid;
6096 if (!jvann.annotationId.equals(anid))
6098 // TODO verify that this is the correct behaviour
6099 this.warn("Overriding Annotation ID for " + anid
6100 + " from different id : " + jvann.annotationId);
6101 jvann.annotationId = anid;
6104 else if (jvobj instanceof String)
6106 if (jvids2vobj == null)
6108 jvids2vobj = new Hashtable();
6109 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6114 Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6120 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6121 * objects created from the project archive. If string is null (default for
6122 * construction) then suffix will be set automatically.
6126 public void setUniqueSetSuffix(String string)
6128 uniqueSetSuffix = string;
6133 * uses skipList2 as the skipList for skipping views on sequence sets
6134 * associated with keys in the skipList
6138 public void setSkipList(Hashtable skipList2)
6140 skipList = skipList2;
6144 * Reads the jar entry of given name and returns its contents, or null if the
6145 * entry is not found.
6148 * @param jarEntryName
6151 protected String readJarEntry(jarInputStreamProvider jprovider,
6152 String jarEntryName)
6154 String result = null;
6155 BufferedReader in = null;
6160 * Reopen the jar input stream and traverse its entries to find a matching
6163 JarInputStream jin = jprovider.getJarInputStream();
6164 JarEntry entry = null;
6167 entry = jin.getNextJarEntry();
6168 } while (entry != null && !entry.getName().equals(jarEntryName));
6172 StringBuilder out = new StringBuilder(256);
6173 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6176 while ((data = in.readLine()) != null)
6180 result = out.toString();
6184 warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
6186 } catch (Exception ex)
6188 ex.printStackTrace();
6196 } catch (IOException e)
6207 * Returns an incrementing counter (0, 1, 2...)
6211 private synchronized int nextCounter()
6217 * Loads any saved PCA viewers
6222 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6226 List<PcaViewer> pcaviewers = model.getPcaViewer();
6227 for (PcaViewer viewer : pcaviewers)
6229 String modelName = viewer.getScoreModelName();
6230 SimilarityParamsI params = new SimilarityParams(
6231 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6232 viewer.isIncludeGaps(),
6233 viewer.isDenominateByShortestLength());
6236 * create the panel (without computing the PCA)
6238 PCAPanel panel = new PCAPanel(ap, modelName, params);
6240 panel.setTitle(viewer.getTitle());
6241 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6242 viewer.getWidth(), viewer.getHeight()));
6244 boolean showLabels = viewer.isShowLabels();
6245 panel.setShowLabels(showLabels);
6246 panel.getRotatableCanvas().setShowLabels(showLabels);
6247 panel.getRotatableCanvas()
6248 .setBgColour(new Color(viewer.getBgColour()));
6249 panel.getRotatableCanvas()
6250 .setApplyToAllViews(viewer.isLinkToAllViews());
6253 * load PCA output data
6255 ScoreModelI scoreModel = ScoreModels.getInstance()
6256 .getScoreModel(modelName, ap);
6257 PCA pca = new PCA(null, scoreModel, params);
6258 PcaDataType pcaData = viewer.getPcaData();
6260 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6261 pca.setPairwiseScores(pairwise);
6263 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6264 pca.setTridiagonal(triDiag);
6266 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6267 pca.setEigenmatrix(result);
6269 panel.getPcaModel().setPCA(pca);
6272 * we haven't saved the input data! (JAL-2647 to do)
6274 panel.setInputData(null);
6277 * add the sequence points for the PCA display
6279 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6280 for (SequencePoint sp : viewer.getSequencePoint())
6282 String seqId = sp.getSequenceRef();
6283 SequenceI seq = seqRefIds.get(seqId);
6286 throw new IllegalStateException(
6287 "Unmatched seqref for PCA: " + seqId);
6289 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6290 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6292 seqPoints.add(seqPoint);
6294 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6297 * set min-max ranges and scale after setPoints (which recomputes them)
6299 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6300 SeqPointMin spMin = viewer.getSeqPointMin();
6301 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6303 SeqPointMax spMax = viewer.getSeqPointMax();
6304 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6306 panel.getRotatableCanvas().setSeqMinMax(min, max);
6308 // todo: hold points list in PCAModel only
6309 panel.getPcaModel().setSequencePoints(seqPoints);
6311 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6312 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6313 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6315 // is this duplication needed?
6316 panel.setTop(seqPoints.size() - 1);
6317 panel.getPcaModel().setTop(seqPoints.size() - 1);
6320 * add the axes' end points for the display
6322 for (int i = 0; i < 3; i++)
6324 Axis axis = viewer.getAxis().get(i);
6325 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6326 axis.getXPos(), axis.getYPos(), axis.getZPos());
6329 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6330 "label.calc_title", "PCA", modelName), 475, 450);
6332 } catch (Exception ex)
6334 Cache.log.error("Error loading PCA: " + ex.toString());
6339 * Populates an XML model of the feature colour scheme for one feature type
6341 * @param featureType
6345 public static Colour marshalColour(String featureType,
6346 FeatureColourI fcol)
6348 Colour col = new Colour();
6349 if (fcol.isSimpleColour())
6351 col.setRGB(Format.getHexString(fcol.getColour()));
6355 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6356 col.setMin(fcol.getMin());
6357 col.setMax(fcol.getMax());
6358 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6359 col.setAutoScale(fcol.isAutoScaled());
6360 col.setThreshold(fcol.getThreshold());
6361 col.setColourByLabel(fcol.isColourByLabel());
6362 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6363 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6364 : ThresholdType.NONE));
6365 if (fcol.isColourByAttribute())
6367 final String[] attName = fcol.getAttributeName();
6368 col.getAttributeName().add(attName[0]);
6369 if (attName.length > 1)
6371 col.getAttributeName().add(attName[1]);
6374 Color noColour = fcol.getNoColour();
6375 if (noColour == null)
6377 col.setNoValueColour(NoValueColour.NONE);
6379 else if (noColour == fcol.getMaxColour())
6381 col.setNoValueColour(NoValueColour.MAX);
6385 col.setNoValueColour(NoValueColour.MIN);
6388 col.setName(featureType);
6393 * Populates an XML model of the feature filter(s) for one feature type
6395 * @param firstMatcher
6396 * the first (or only) match condition)
6398 * remaining match conditions (if any)
6400 * if true, conditions are and-ed, else or-ed
6402 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6403 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6406 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6408 if (filters.hasNext())
6413 CompoundMatcher compound = new CompoundMatcher();
6414 compound.setAnd(and);
6415 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6416 firstMatcher, Collections.emptyIterator(), and);
6417 // compound.addMatcherSet(matcher1);
6418 compound.getMatcherSet().add(matcher1);
6419 FeatureMatcherI nextMatcher = filters.next();
6420 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6421 nextMatcher, filters, and);
6422 // compound.addMatcherSet(matcher2);
6423 compound.getMatcherSet().add(matcher2);
6424 result.setCompoundMatcher(compound);
6429 * single condition matcher
6431 // MatchCondition matcherModel = new MatchCondition();
6432 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6433 matcherModel.setCondition(
6434 firstMatcher.getMatcher().getCondition().getStableName());
6435 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6436 if (firstMatcher.isByAttribute())
6438 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6439 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6440 String[] attName = firstMatcher.getAttribute();
6441 matcherModel.getAttributeName().add(attName[0]); // attribute
6442 if (attName.length > 1)
6444 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6447 else if (firstMatcher.isByLabel())
6449 matcherModel.setBy(FilterBy.BY_LABEL);
6451 else if (firstMatcher.isByScore())
6453 matcherModel.setBy(FilterBy.BY_SCORE);
6455 result.setMatchCondition(matcherModel);
6462 * Loads one XML model of a feature filter to a Jalview object
6464 * @param featureType
6465 * @param matcherSetModel
6468 public static FeatureMatcherSetI parseFilter(String featureType,
6469 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6471 FeatureMatcherSetI result = new FeatureMatcherSet();
6474 parseFilterConditions(result, matcherSetModel, true);
6475 } catch (IllegalStateException e)
6477 // mixing AND and OR conditions perhaps
6479 String.format("Error reading filter conditions for '%s': %s",
6480 featureType, e.getMessage()));
6481 // return as much as was parsed up to the error
6488 * Adds feature match conditions to matcherSet as unmarshalled from XML
6489 * (possibly recursively for compound conditions)
6492 * @param matcherSetModel
6494 * if true, multiple conditions are AND-ed, else they are OR-ed
6495 * @throws IllegalStateException
6496 * if AND and OR conditions are mixed
6498 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6499 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6502 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6503 .getMatchCondition();
6509 FilterBy filterBy = mc.getBy();
6510 Condition cond = Condition.fromString(mc.getCondition());
6511 String pattern = mc.getValue();
6512 FeatureMatcherI matchCondition = null;
6513 if (filterBy == FilterBy.BY_LABEL)
6515 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6517 else if (filterBy == FilterBy.BY_SCORE)
6519 matchCondition = FeatureMatcher.byScore(cond, pattern);
6522 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6524 final List<String> attributeName = mc.getAttributeName();
6525 String[] attNames = attributeName
6526 .toArray(new String[attributeName.size()]);
6527 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6532 * note this throws IllegalStateException if AND-ing to a
6533 * previously OR-ed compound condition, or vice versa
6537 matcherSet.and(matchCondition);
6541 matcherSet.or(matchCondition);
6547 * compound condition
6549 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6550 .getCompoundMatcher().getMatcherSet();
6551 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6552 if (matchers.size() == 2)
6554 parseFilterConditions(matcherSet, matchers.get(0), anded);
6555 parseFilterConditions(matcherSet, matchers.get(1), anded);
6559 System.err.println("Malformed compound filter condition");
6565 * Loads one XML model of a feature colour to a Jalview object
6567 * @param colourModel
6570 public static FeatureColourI parseColour(Colour colourModel)
6572 FeatureColourI colour = null;
6574 if (colourModel.getMax() != null)
6576 Color mincol = null;
6577 Color maxcol = null;
6578 Color noValueColour = null;
6582 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
6583 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6584 } catch (Exception e)
6586 Cache.log.warn("Couldn't parse out graduated feature color.", e);
6589 NoValueColour noCol = colourModel.getNoValueColour();
6590 if (noCol == NoValueColour.MIN)
6592 noValueColour = mincol;
6594 else if (noCol == NoValueColour.MAX)
6596 noValueColour = maxcol;
6599 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
6600 safeFloat(colourModel.getMin()),
6601 safeFloat(colourModel.getMax()));
6602 final List<String> attributeName = colourModel.getAttributeName();
6603 String[] attributes = attributeName
6604 .toArray(new String[attributeName.size()]);
6605 if (attributes != null && attributes.length > 0)
6607 colour.setAttributeName(attributes);
6609 if (colourModel.isAutoScale() != null)
6611 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
6613 if (colourModel.isColourByLabel() != null)
6615 colour.setColourByLabel(
6616 colourModel.isColourByLabel().booleanValue());
6618 if (colourModel.getThreshold() != null)
6620 colour.setThreshold(colourModel.getThreshold().floatValue());
6622 ThresholdType ttyp = colourModel.getThreshType();
6623 if (ttyp == ThresholdType.ABOVE)
6625 colour.setAboveThreshold(true);
6627 else if (ttyp == ThresholdType.BELOW)
6629 colour.setBelowThreshold(true);
6634 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
6635 colour = new FeatureColour(color);