2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.project;
23 import static jalview.math.RotatableMatrix.Axis.X;
24 import static jalview.math.RotatableMatrix.Axis.Y;
25 import static jalview.math.RotatableMatrix.Axis.Z;
27 import java.awt.Color;
29 import java.awt.Rectangle;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.OutputStream;
39 import java.io.OutputStreamWriter;
40 import java.io.PrintWriter;
41 import java.lang.reflect.InvocationTargetException;
42 import java.math.BigInteger;
43 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.BitSet;
48 import java.util.Collections;
49 import java.util.Enumeration;
50 import java.util.GregorianCalendar;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Hashtable;
54 import java.util.IdentityHashMap;
55 import java.util.Iterator;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Locale;
60 import java.util.Map.Entry;
62 import java.util.Vector;
63 import java.util.jar.JarEntry;
64 import java.util.jar.JarInputStream;
65 import java.util.jar.JarOutputStream;
67 import javax.swing.JInternalFrame;
68 import javax.swing.SwingUtilities;
69 import javax.xml.bind.JAXBContext;
70 import javax.xml.bind.JAXBElement;
71 import javax.xml.bind.Marshaller;
72 import javax.xml.datatype.DatatypeConfigurationException;
73 import javax.xml.datatype.DatatypeFactory;
74 import javax.xml.datatype.XMLGregorianCalendar;
75 import javax.xml.stream.XMLInputFactory;
76 import javax.xml.stream.XMLStreamReader;
78 import jalview.analysis.Conservation;
79 import jalview.analysis.PCA;
80 import jalview.analysis.scoremodels.ScoreModels;
81 import jalview.analysis.scoremodels.SimilarityParams;
82 import jalview.api.FeatureColourI;
83 import jalview.api.ViewStyleI;
84 import jalview.api.analysis.ScoreModelI;
85 import jalview.api.analysis.SimilarityParamsI;
86 import jalview.api.structures.JalviewStructureDisplayI;
87 import jalview.bin.Cache;
88 import jalview.bin.Console;
89 import jalview.bin.Jalview;
90 import jalview.datamodel.AlignedCodonFrame;
91 import jalview.datamodel.Alignment;
92 import jalview.datamodel.AlignmentAnnotation;
93 import jalview.datamodel.AlignmentI;
94 import jalview.datamodel.ContactListI;
95 import jalview.datamodel.ContactMatrix;
96 import jalview.datamodel.ContactMatrixI;
97 import jalview.datamodel.DBRefEntry;
98 import jalview.datamodel.FloatContactMatrix;
99 import jalview.datamodel.GeneLocus;
100 import jalview.datamodel.GraphLine;
101 import jalview.datamodel.GroupSet;
102 import jalview.datamodel.GroupSetI;
103 import jalview.datamodel.PDBEntry;
104 import jalview.datamodel.Point;
105 import jalview.datamodel.RnaViewerModel;
106 import jalview.datamodel.SequenceFeature;
107 import jalview.datamodel.SequenceGroup;
108 import jalview.datamodel.SequenceI;
109 import jalview.datamodel.StructureViewerModel;
110 import jalview.datamodel.StructureViewerModel.StructureData;
111 import jalview.datamodel.features.FeatureMatcher;
112 import jalview.datamodel.features.FeatureMatcherI;
113 import jalview.datamodel.features.FeatureMatcherSet;
114 import jalview.datamodel.features.FeatureMatcherSetI;
115 import jalview.ext.varna.RnaModel;
116 import jalview.gui.AlignFrame;
117 import jalview.gui.AlignViewport;
118 import jalview.gui.AlignmentPanel;
119 import jalview.gui.AppVarna;
120 import jalview.gui.Desktop;
121 import jalview.gui.JvOptionPane;
122 import jalview.gui.OOMWarning;
123 import jalview.gui.OverviewPanel;
124 import jalview.gui.PCAPanel;
125 import jalview.gui.PaintRefresher;
126 import jalview.gui.SplitFrame;
127 import jalview.gui.StructureViewer;
128 import jalview.gui.StructureViewer.ViewerType;
129 import jalview.gui.StructureViewerBase;
130 import jalview.gui.TreePanel;
131 import jalview.io.BackupFiles;
132 import jalview.io.DataSourceType;
133 import jalview.io.FileFormat;
134 import jalview.io.NewickFile;
135 import jalview.math.Matrix;
136 import jalview.math.MatrixI;
137 import jalview.renderer.ResidueShaderI;
138 import jalview.schemes.AnnotationColourGradient;
139 import jalview.schemes.ColourSchemeI;
140 import jalview.schemes.ColourSchemeProperty;
141 import jalview.schemes.FeatureColour;
142 import jalview.schemes.ResidueProperties;
143 import jalview.schemes.UserColourScheme;
144 import jalview.structure.StructureSelectionManager;
145 import jalview.structures.models.AAStructureBindingModel;
146 import jalview.util.Format;
147 import jalview.util.HttpUtils;
148 import jalview.util.MessageManager;
149 import jalview.util.Platform;
150 import jalview.util.StringUtils;
151 import jalview.util.jarInputStreamProvider;
152 import jalview.util.matcher.Condition;
153 import jalview.viewmodel.AlignmentViewport;
154 import jalview.viewmodel.PCAModel;
155 import jalview.viewmodel.ViewportRanges;
156 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
157 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
158 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
159 import jalview.ws.datamodel.MappableContactMatrixI;
160 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
161 import jalview.ws.jws2.Jws2Discoverer;
162 import jalview.ws.jws2.dm.AAConSettings;
163 import jalview.ws.jws2.jabaws2.Jws2Instance;
164 import jalview.ws.params.ArgumentI;
165 import jalview.ws.params.AutoCalcSetting;
166 import jalview.ws.params.WsParamSetI;
167 import jalview.xml.binding.jalview.AlcodonFrame;
168 import jalview.xml.binding.jalview.AlcodonFrame.AlcodMap;
169 import jalview.xml.binding.jalview.Annotation;
170 import jalview.xml.binding.jalview.Annotation.ThresholdLine;
171 import jalview.xml.binding.jalview.AnnotationColourScheme;
172 import jalview.xml.binding.jalview.AnnotationElement;
173 import jalview.xml.binding.jalview.DoubleMatrix;
174 import jalview.xml.binding.jalview.DoubleVector;
175 import jalview.xml.binding.jalview.Feature;
176 import jalview.xml.binding.jalview.Feature.OtherData;
177 import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher;
178 import jalview.xml.binding.jalview.FilterBy;
179 import jalview.xml.binding.jalview.JalviewModel;
180 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings;
181 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Group;
182 import jalview.xml.binding.jalview.JalviewModel.FeatureSettings.Setting;
183 import jalview.xml.binding.jalview.JalviewModel.JGroup;
184 import jalview.xml.binding.jalview.JalviewModel.JSeq;
185 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids;
186 import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState;
187 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer;
188 import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure;
189 import jalview.xml.binding.jalview.JalviewModel.PcaViewer;
190 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis;
191 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax;
192 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin;
193 import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint;
194 import jalview.xml.binding.jalview.JalviewModel.Tree;
195 import jalview.xml.binding.jalview.JalviewModel.UserColours;
196 import jalview.xml.binding.jalview.JalviewModel.Viewport;
197 import jalview.xml.binding.jalview.JalviewModel.Viewport.CalcIdParam;
198 import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
199 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
200 import jalview.xml.binding.jalview.JalviewUserColours;
201 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
202 import jalview.xml.binding.jalview.MapListType;
203 import jalview.xml.binding.jalview.MapListType.MapListFrom;
204 import jalview.xml.binding.jalview.MapListType.MapListTo;
205 import jalview.xml.binding.jalview.MapOnAMatrixType;
206 import jalview.xml.binding.jalview.Mapping;
207 import jalview.xml.binding.jalview.MatrixType;
208 import jalview.xml.binding.jalview.NoValueColour;
209 import jalview.xml.binding.jalview.ObjectFactory;
210 import jalview.xml.binding.jalview.PcaDataType;
211 import jalview.xml.binding.jalview.Pdbentry.Property;
212 import jalview.xml.binding.jalview.Sequence;
213 import jalview.xml.binding.jalview.Sequence.DBRef;
214 import jalview.xml.binding.jalview.SequenceSet;
215 import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
216 import jalview.xml.binding.jalview.ThresholdType;
217 import jalview.xml.binding.jalview.VAMSAS;
220 * Write out the current jalview desktop state as a Jalview XML stream.
222 * Note: the vamsas objects referred to here are primitive versions of the
223 * VAMSAS project schema elements - they are not the same and most likely never
227 * @version $Revision: 1.134 $
229 public class Jalview2XML
232 // BH 2018 we add the .jvp binary extension to J2S so that
233 // it will declare that binary when we do the file save from the browser
237 Platform.addJ2SBinaryType(".jvp?");
240 private static final String VIEWER_PREFIX = "viewer_";
242 private static final String RNA_PREFIX = "rna_";
244 private static final String UTF_8 = "UTF-8";
247 * used in decision if quit confirmation should be issued
249 private static boolean stateSavedUpToDate = false;
252 * prefix for recovering datasets for alignments with multiple views where
253 * non-existent dataset IDs were written for some views
255 private static final String UNIQSEQSETID = "uniqueSeqSetId.";
257 // use this with nextCounter() to make unique names for entities
258 private int counter = 0;
261 * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
262 * of sequence objects are created.
264 IdentityHashMap<SequenceI, String> seqsToIds = null;
267 * jalview XML Sequence ID to jalview sequence object reference (both dataset
268 * and alignment sequences. Populated as XML reps of sequence objects are
271 Map<String, SequenceI> seqRefIds = null;
273 Map<String, SequenceI> incompleteSeqs = null;
275 List<forwardRef> frefedSequence = null;
277 boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
280 * Map of reconstructed AlignFrame objects that appear to have come from
281 * SplitFrame objects (have a dna/protein complement view).
283 private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
286 * Map from displayed rna structure models to their saved session state jar
289 private Map<RnaModel, String> rnaSessions = new HashMap<>();
292 * map from contact matrices to their XML ids
294 private Map<ContactMatrixI, String> contactMatrices = new HashMap<>();
296 private Map<String, ContactMatrixI> contactMatrixRefs = new HashMap<>();
298 private List<jalview.xml.binding.jalview.MatrixType> xmlMatrices = new ArrayList<>();
301 * A helper method for safely using the value of an optional attribute that
302 * may be null if not present in the XML. Answers the boolean value, or false
308 public static boolean safeBoolean(Boolean b)
310 return b == null ? false : b.booleanValue();
314 * A helper method for safely using the value of an optional attribute that
315 * may be null if not present in the XML. Answers the integer value, or zero
321 public static int safeInt(Integer i)
323 return i == null ? 0 : i.intValue();
327 * A helper method for safely using the value of an optional attribute that
328 * may be null if not present in the XML. Answers the float value, or zero if
334 public static float safeFloat(Float f)
336 return f == null ? 0f : f.floatValue();
340 * create/return unique hash string for sq
343 * @return new or existing unique string for sq
345 String seqHash(SequenceI sq)
347 if (seqsToIds == null)
351 if (seqsToIds.containsKey(sq))
353 return seqsToIds.get(sq);
357 // create sequential key
358 String key = "sq" + (seqsToIds.size() + 1);
359 key = makeHashCode(sq, key); // check we don't have an external reference
361 seqsToIds.put(sq, key);
368 if (seqsToIds == null)
370 seqsToIds = new IdentityHashMap<>();
372 if (seqRefIds == null)
374 seqRefIds = new HashMap<>();
376 if (incompleteSeqs == null)
378 incompleteSeqs = new HashMap<>();
380 if (frefedSequence == null)
382 frefedSequence = new ArrayList<>();
390 public Jalview2XML(boolean raiseGUI)
392 this.raiseGUI = raiseGUI;
396 * base class for resolving forward references to an as-yet unmarshalled
397 * object referenced by already unmarshalled objects
402 abstract class forwardRef
408 public forwardRef(String _sref, String type)
414 public String getSref()
419 public abstract boolean isResolvable();
422 * @return true if the forward reference was fully resolved
424 abstract boolean resolve();
427 public String toString()
429 return type + " reference to " + sref;
434 * resolve forward references to sequences by their ID
438 abstract class SeqFref extends forwardRef
440 public SeqFref(String _sref, String type)
445 public SequenceI getSrefSeq()
447 return seqRefIds.get(sref);
450 public boolean isResolvable()
452 return seqRefIds.get(sref) != null;
455 public SequenceI getSrefDatasetSeq()
457 SequenceI sq = seqRefIds.get(sref);
460 while (sq.getDatasetSequence() != null)
462 sq = sq.getDatasetSequence();
470 * create forward reference for a mapping
476 public SeqFref newMappingRef(final String sref,
477 final jalview.datamodel.Mapping _jmap)
479 SeqFref fref = new SeqFref(sref, "Mapping")
481 public jalview.datamodel.Mapping jmap = _jmap;
486 SequenceI seq = getSrefDatasetSeq();
498 public SeqFref newAlcodMapRef(final String sref,
499 final AlignedCodonFrame _cf,
500 final jalview.datamodel.Mapping _jmap)
503 SeqFref fref = new SeqFref(sref, "Codon Frame")
505 AlignedCodonFrame cf = _cf;
507 public jalview.datamodel.Mapping mp = _jmap;
510 public boolean isResolvable()
512 return super.isResolvable() && mp.getTo() != null;
518 SequenceI seq = getSrefDatasetSeq();
523 cf.addMap(seq, mp.getTo(), mp.getMap());
530 public forwardRef newMatrixFref(final String matRef,
531 final jalview.util.MapList mapping, final AlignmentAnnotation jaa)
533 forwardRef fref = new forwardRef(matRef,
534 "Matrix Reference for sequence and annotation")
540 ContactMatrixI cm = contactMatrixRefs.get(matRef);
541 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
544 jaa.sequenceRef.addContactListFor(jaa, newpae);
549 public boolean isResolvable()
551 return (contactMatrixRefs.get(matRef) != null);
557 public void resolveFrefedSequences()
559 Iterator<forwardRef> nextFref = frefedSequence.iterator();
560 int toresolve = frefedSequence.size();
561 int unresolved = 0, failedtoresolve = 0;
562 while (nextFref.hasNext())
564 forwardRef ref = nextFref.next();
565 if (ref.isResolvable())
577 } catch (Exception x)
579 jalview.bin.Console.errPrintln(
580 "IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
593 jalview.bin.Console.errPrintln("Jalview Project Import: There were "
595 + " forward references left unresolved on the stack.");
597 if (failedtoresolve > 0)
599 jalview.bin.Console.errPrintln("SERIOUS! " + failedtoresolve
600 + " resolvable forward references failed to resolve.");
602 if (incompleteSeqs != null && incompleteSeqs.size() > 0)
604 jalview.bin.Console.errPrintln(
605 "Jalview Project Import: There are " + incompleteSeqs.size()
606 + " sequences which may have incomplete metadata.");
607 if (incompleteSeqs.size() < 10)
609 for (SequenceI s : incompleteSeqs.values())
611 jalview.bin.Console.errPrintln(s.toString());
616 jalview.bin.Console.errPrintln(
617 "Too many to report. Skipping output of incomplete sequences.");
623 * This maintains a map of viewports, the key being the seqSetId. Important to
624 * set historyItem and redoList for multiple views
626 Map<String, AlignViewport> viewportsAdded = new HashMap<>();
628 Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
630 String uniqueSetSuffix = "";
633 * List of pdbfiles added to Jar
635 List<String> pdbfiles = null;
637 // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
638 public void saveState(File statefile)
640 FileOutputStream fos = null;
645 fos = new FileOutputStream(statefile);
647 JarOutputStream jout = new JarOutputStream(fos);
651 } catch (Exception e)
653 Console.error("Couln't write Jalview state to " + statefile, e);
654 // TODO: inform user of the problem - they need to know if their data was
656 if (errorMessage == null)
658 errorMessage = "Did't write Jalview Archive to output file '"
659 + statefile + "' - See console error log for details";
663 errorMessage += "(Didn't write Jalview Archive to output file '"
674 } catch (IOException e)
684 * Writes a jalview project archive to the given Jar output stream.
688 public void saveState(JarOutputStream jout)
690 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
692 setStateSavedUpToDate(true);
694 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
696 int n = debugDelaySave;
700 Console.debug("***** debugging save sleep " + i + "/" + n);
704 } catch (InterruptedException e)
706 // TODO Auto-generated catch block
717 saveAllFrames(Arrays.asList(frames), jout);
721 * core method for storing state for a set of AlignFrames.
724 * - frames involving all data to be exported (including containing
727 * - project output stream
729 private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
731 Hashtable<String, AlignFrame> dsses = new Hashtable<>();
734 * ensure cached data is clear before starting
736 // todo tidy up seqRefIds, seqsToIds initialisation / reset
738 splitFrameCandidates.clear();
743 // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
744 // //////////////////////////////////////////////////
746 List<String> shortNames = new ArrayList<>();
747 List<String> viewIds = new ArrayList<>();
750 for (int i = frames.size() - 1; i > -1; i--)
752 AlignFrame af = frames.get(i);
754 if (skipList != null && skipList
755 .containsKey(af.getViewport().getSequenceSetId()))
760 String shortName = makeFilename(af, shortNames);
762 int apSize = af.getAlignPanels().size();
764 for (int ap = 0; ap < apSize; ap++)
766 AlignmentPanel apanel = (AlignmentPanel) af.getAlignPanels()
768 String fileName = apSize == 1 ? shortName : ap + shortName;
769 if (!fileName.endsWith(".xml"))
771 fileName = fileName + ".xml";
774 saveState(apanel, fileName, jout, viewIds);
776 String dssid = getDatasetIdRef(
777 af.getViewport().getAlignment().getDataset());
778 if (!dsses.containsKey(dssid))
780 dsses.put(dssid, af);
785 writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix,
791 } catch (Exception foo)
795 } catch (Exception ex)
797 // TODO: inform user of the problem - they need to know if their data was
799 if (errorMessage == null)
801 errorMessage = "Couldn't write Jalview Archive - see error output for details";
803 ex.printStackTrace();
808 * Generates a distinct file name, based on the title of the AlignFrame, by
809 * appending _n for increasing n until an unused name is generated. The new
810 * name (without its extension) is added to the list.
814 * @return the generated name, with .xml extension
816 protected String makeFilename(AlignFrame af, List<String> namesUsed)
818 String shortName = af.getTitle();
820 if (shortName.indexOf(File.separatorChar) > -1)
822 shortName = shortName
823 .substring(shortName.lastIndexOf(File.separatorChar) + 1);
828 while (namesUsed.contains(shortName))
830 if (shortName.endsWith("_" + (count - 1)))
832 shortName = shortName.substring(0, shortName.lastIndexOf("_"));
835 shortName = shortName.concat("_" + count);
839 namesUsed.add(shortName);
841 if (!shortName.endsWith(".xml"))
843 shortName = shortName + ".xml";
848 // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
849 public boolean saveAlignment(AlignFrame af, String jarFile,
854 // create backupfiles object and get new temp filename destination
855 boolean doBackup = BackupFiles.getEnabled();
856 BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
857 FileOutputStream fos = new FileOutputStream(
858 doBackup ? backupfiles.getTempFilePath() : jarFile);
860 if (Cache.getDefault("DEBUG_DELAY_SAVE", false))
862 int n = debugDelaySave;
866 Console.debug("***** debugging save sleep " + i + "/" + n);
870 } catch (InterruptedException e)
872 // TODO Auto-generated catch block
879 JarOutputStream jout = new JarOutputStream(fos);
880 List<AlignFrame> frames = new ArrayList<>();
882 // resolve splitframes
883 if (af.getViewport().getCodingComplement() != null)
885 frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
891 saveAllFrames(frames, jout);
895 } catch (Exception foo)
899 boolean success = true;
903 backupfiles.setWriteSuccess(success);
904 success = backupfiles.rollBackupsAndRenameTempFile();
908 } catch (Exception ex)
910 errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details";
911 ex.printStackTrace();
916 private void writeDatasetFor(Hashtable<String, AlignFrame> dsses,
917 String fileName, JarOutputStream jout)
920 for (String dssids : dsses.keySet())
922 AlignFrame _af = dsses.get(dssids);
923 String jfileName = fileName + " Dataset for " + _af.getTitle();
924 if (!jfileName.endsWith(".xml"))
926 jfileName = jfileName + ".xml";
928 saveState(_af.alignPanel, jfileName, true, jout, null);
933 * create a JalviewModel from an alignment view and marshall it to a
937 * panel to create jalview model for
939 * name of alignment panel written to output stream
946 public JalviewModel saveState(AlignmentPanel ap, String fileName,
947 JarOutputStream jout, List<String> viewIds)
949 return saveState(ap, fileName, false, jout, viewIds);
953 * create a JalviewModel from an alignment view and marshall it to a
957 * panel to create jalview model for
959 * name of alignment panel written to output stream
961 * when true, only write the dataset for the alignment, not the data
962 * associated with the view.
968 public JalviewModel saveState(AlignmentPanel ap, String fileName,
969 boolean storeDS, JarOutputStream jout, List<String> viewIds)
973 viewIds = new ArrayList<>();
978 List<UserColourScheme> userColours = new ArrayList<>();
980 AlignViewport av = ap.av;
981 ViewportRanges vpRanges = av.getRanges();
983 final ObjectFactory objectFactory = new ObjectFactory();
984 JalviewModel object = objectFactory.createJalviewModel();
985 object.setVamsasModel(new VAMSAS());
987 // object.setCreationDate(new java.util.Date(System.currentTimeMillis()));
990 GregorianCalendar c = new GregorianCalendar();
991 DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
992 XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(c);// gregorianCalendar);
993 object.setCreationDate(now);
994 } catch (DatatypeConfigurationException e)
996 jalview.bin.Console.errPrintln("error writing date: " + e.toString());
998 object.setVersion(Cache.getDefault("VERSION", "Development Build"));
1001 * rjal is full height alignment, jal is actual alignment with full metadata
1002 * but excludes hidden sequences.
1004 jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
1006 if (av.hasHiddenRows())
1008 rjal = jal.getHiddenSequences().getFullAlignment();
1011 SequenceSet vamsasSet = new SequenceSet();
1013 // JalviewModelSequence jms = new JalviewModelSequence();
1015 vamsasSet.setGapChar(jal.getGapCharacter() + "");
1017 if (jal.getDataset() != null)
1019 // dataset id is the dataset's hashcode
1020 vamsasSet.setDatasetId(getDatasetIdRef(jal.getDataset()));
1023 // switch jal and the dataset
1024 jal = jal.getDataset();
1028 if (jal.getProperties() != null)
1030 Enumeration en = jal.getProperties().keys();
1031 while (en.hasMoreElements())
1033 String key = en.nextElement().toString();
1034 SequenceSetProperties ssp = new SequenceSetProperties();
1036 ssp.setValue(jal.getProperties().get(key).toString());
1037 // vamsasSet.addSequenceSetProperties(ssp);
1038 vamsasSet.getSequenceSetProperties().add(ssp);
1043 Set<String> calcIdSet = new HashSet<>();
1044 // record the set of vamsas sequence XML POJO we create.
1045 HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
1047 for (final SequenceI jds : rjal.getSequences())
1049 final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
1050 : jds.getDatasetSequence();
1051 String id = seqHash(jds);
1052 if (vamsasSetIds.get(id) == null)
1054 if (seqRefIds.get(id) != null && !storeDS)
1056 // This happens for two reasons: 1. multiple views are being
1058 // 2. the hashCode has collided with another sequence's code. This
1060 // HAPPEN! (PF00072.15.stk does this)
1061 // JBPNote: Uncomment to debug writing out of files that do not read
1062 // back in due to ArrayOutOfBoundExceptions.
1063 // jalview.bin.Console.errPrintln("vamsasSeq backref: "+id+"");
1064 // jalview.bin.Console.errPrintln(jds.getName()+"
1065 // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
1066 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(jds));
1067 // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
1068 // jalview.bin.Console.errPrintln(rsq.getName()+"
1069 // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
1070 // jalview.bin.Console.errPrintln("Hashcode: "+seqHash(rsq));
1074 vamsasSeq = createVamsasSequence(id, jds);
1075 // vamsasSet.addSequence(vamsasSeq);
1076 vamsasSet.getSequence().add(vamsasSeq);
1077 vamsasSetIds.put(id, vamsasSeq);
1078 seqRefIds.put(id, jds);
1082 jseq.setStart(jds.getStart());
1083 jseq.setEnd(jds.getEnd());
1084 jseq.setColour(av.getSequenceColour(jds).getRGB());
1086 jseq.setId(id); // jseq id should be a string not a number
1089 // Store any sequences this sequence represents
1090 if (av.hasHiddenRows())
1092 // use rjal, contains the full height alignment
1094 av.getAlignment().getHiddenSequences().isHidden(jds));
1096 if (av.isHiddenRepSequence(jds))
1098 jalview.datamodel.SequenceI[] reps = av
1099 .getRepresentedSequences(jds).getSequencesInOrder(rjal);
1101 for (int h = 0; h < reps.length; h++)
1105 // jseq.addHiddenSequences(rjal.findIndex(reps[h]));
1106 jseq.getHiddenSequences().add(rjal.findIndex(reps[h]));
1111 // mark sequence as reference - if it is the reference for this view
1112 if (jal.hasSeqrep())
1114 jseq.setViewreference(jds == jal.getSeqrep());
1118 // TODO: omit sequence features from each alignment view's XML dump if we
1119 // are storing dataset
1120 List<SequenceFeature> sfs = jds.getSequenceFeatures();
1121 for (SequenceFeature sf : sfs)
1123 // Features features = new Features();
1124 Feature features = new Feature();
1126 features.setBegin(sf.getBegin());
1127 features.setEnd(sf.getEnd());
1128 features.setDescription(sf.getDescription());
1129 features.setType(sf.getType());
1130 features.setFeatureGroup(sf.getFeatureGroup());
1131 features.setScore(sf.getScore());
1132 if (sf.links != null)
1134 for (int l = 0; l < sf.links.size(); l++)
1136 OtherData keyValue = new OtherData();
1137 keyValue.setKey("LINK_" + l);
1138 keyValue.setValue(sf.links.elementAt(l).toString());
1139 // features.addOtherData(keyValue);
1140 features.getOtherData().add(keyValue);
1143 if (sf.otherDetails != null)
1146 * save feature attributes, which may be simple strings or
1147 * map valued (have sub-attributes)
1149 for (Entry<String, Object> entry : sf.otherDetails.entrySet())
1151 String key = entry.getKey();
1152 Object value = entry.getValue();
1153 if (value instanceof Map<?, ?>)
1155 for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
1158 OtherData otherData = new OtherData();
1159 otherData.setKey(key);
1160 otherData.setKey2(subAttribute.getKey());
1161 otherData.setValue(subAttribute.getValue().toString());
1162 // features.addOtherData(otherData);
1163 features.getOtherData().add(otherData);
1168 OtherData otherData = new OtherData();
1169 otherData.setKey(key);
1170 otherData.setValue(value.toString());
1171 // features.addOtherData(otherData);
1172 features.getOtherData().add(otherData);
1177 // jseq.addFeatures(features);
1178 jseq.getFeatures().add(features);
1181 if (jdatasq.getAllPDBEntries() != null)
1183 Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
1184 while (en.hasMoreElements())
1186 Pdbids pdb = new Pdbids();
1187 jalview.datamodel.PDBEntry entry = en.nextElement();
1189 String pdbId = entry.getId();
1191 pdb.setType(entry.getType());
1194 * Store any structure views associated with this sequence. This
1195 * section copes with duplicate entries in the project, so a dataset
1196 * only view *should* be coped with sensibly.
1198 // This must have been loaded, is it still visible?
1199 List<JalviewStructureDisplayI> viewFrames = new ArrayList<>();
1200 if (Desktop.desktop != null)
1202 JInternalFrame[] jifs = Desktop.desktop.getAllFrames();
1205 for (JInternalFrame jif : jifs)
1207 if (jif instanceof JalviewStructureDisplayI)
1209 viewFrames.add((JalviewStructureDisplayI) jif);
1214 else if (Jalview.isHeadlessMode()
1215 && Jalview.getInstance().getCommands() != null)
1218 StructureViewerBase.getAllStructureViewerBases());
1221 String matchedFile = null;
1222 for (JalviewStructureDisplayI viewFrame : viewFrames)
1224 matchedFile = saveStructureViewer(ap, jds, pdb, entry, viewIds,
1225 matchedFile, viewFrame);
1227 * Only store each structure viewer's state once in the project
1228 * jar. First time through only (storeDS==false)
1230 String viewId = viewFrame.getViewId();
1231 String viewerType = viewFrame.getViewerType().toString();
1232 if (!storeDS && !viewIds.contains(viewId))
1234 viewIds.add(viewId);
1235 File viewerState = viewFrame.saveSession();
1236 if (viewerState != null)
1238 copyFileToJar(jout, viewerState.getPath(),
1239 getViewerJarEntryName(viewId), viewerType);
1244 "Failed to save viewer state for " + viewerType);
1249 if (matchedFile != null || entry.getFile() != null)
1251 if (entry.getFile() != null)
1254 matchedFile = entry.getFile();
1256 pdb.setFile(matchedFile); // entry.getFile());
1257 if (pdbfiles == null)
1259 pdbfiles = new ArrayList<>();
1262 if (!pdbfiles.contains(pdbId))
1264 pdbfiles.add(pdbId);
1265 copyFileToJar(jout, matchedFile, pdbId, pdbId);
1269 Enumeration<String> props = entry.getProperties();
1270 if (props.hasMoreElements())
1272 // PdbentryItem item = new PdbentryItem();
1273 while (props.hasMoreElements())
1275 Property prop = new Property();
1276 String key = props.nextElement();
1278 prop.setValue(entry.getProperty(key).toString());
1279 // item.addProperty(prop);
1280 pdb.getProperty().add(prop);
1282 // pdb.addPdbentryItem(item);
1285 // jseq.addPdbids(pdb);
1286 jseq.getPdbids().add(pdb);
1290 saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
1292 // jms.addJSeq(jseq);
1293 object.getJSeq().add(jseq);
1296 if (!storeDS && av.hasHiddenRows())
1298 jal = av.getAlignment();
1302 if (storeDS && jal.getCodonFrames() != null)
1304 List<AlignedCodonFrame> jac = jal.getCodonFrames();
1305 for (AlignedCodonFrame acf : jac)
1307 AlcodonFrame alc = new AlcodonFrame();
1308 if (acf.getProtMappings() != null
1309 && acf.getProtMappings().length > 0)
1311 boolean hasMap = false;
1312 SequenceI[] dnas = acf.getdnaSeqs();
1313 jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1314 for (int m = 0; m < pmaps.length; m++)
1316 AlcodMap alcmap = new AlcodMap();
1317 alcmap.setDnasq(seqHash(dnas[m]));
1319 createVamsasMapping(pmaps[m], dnas[m], null, false));
1320 // alc.addAlcodMap(alcmap);
1321 alc.getAlcodMap().add(alcmap);
1326 // vamsasSet.addAlcodonFrame(alc);
1327 vamsasSet.getAlcodonFrame().add(alc);
1330 // TODO: delete this ? dead code from 2.8.3->2.9 ?
1332 // AlcodonFrame alc = new AlcodonFrame();
1333 // vamsasSet.addAlcodonFrame(alc);
1334 // for (int p = 0; p < acf.aaWidth; p++)
1336 // Alcodon cmap = new Alcodon();
1337 // if (acf.codons[p] != null)
1339 // // Null codons indicate a gapped column in the translated peptide
1341 // cmap.setPos1(acf.codons[p][0]);
1342 // cmap.setPos2(acf.codons[p][1]);
1343 // cmap.setPos3(acf.codons[p][2]);
1345 // alc.addAlcodon(cmap);
1347 // if (acf.getProtMappings() != null
1348 // && acf.getProtMappings().length > 0)
1350 // SequenceI[] dnas = acf.getdnaSeqs();
1351 // jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
1352 // for (int m = 0; m < pmaps.length; m++)
1354 // AlcodMap alcmap = new AlcodMap();
1355 // alcmap.setDnasq(seqHash(dnas[m]));
1356 // alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
1358 // alc.addAlcodMap(alcmap);
1365 // /////////////////////////////////
1366 if (!storeDS && av.getCurrentTree() != null)
1368 // FIND ANY ASSOCIATED TREES
1369 // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT
1370 if (Desktop.desktop != null)
1372 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
1374 for (int t = 0; t < frames.length; t++)
1376 if (frames[t] instanceof TreePanel)
1378 TreePanel tp = (TreePanel) frames[t];
1380 if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
1382 JalviewModel.Tree tree = new JalviewModel.Tree();
1383 tree.setTitle(tp.getTitle());
1384 tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
1385 tree.setNewick(tp.getTree().print());
1386 tree.setThreshold(tp.getTreeCanvas().getThreshold());
1388 tree.setFitToWindow(tp.fitToWindow.getState());
1389 tree.setFontName(tp.getTreeFont().getName());
1390 tree.setFontSize(tp.getTreeFont().getSize());
1391 tree.setFontStyle(tp.getTreeFont().getStyle());
1392 tree.setMarkUnlinked(tp.placeholdersMenu.getState());
1394 tree.setShowBootstrap(tp.bootstrapMenu.getState());
1395 tree.setShowDistances(tp.distanceMenu.getState());
1397 tree.setHeight(tp.getHeight());
1398 tree.setWidth(tp.getWidth());
1399 tree.setXpos(tp.getX());
1400 tree.setYpos(tp.getY());
1401 tree.setId(makeHashCode(tp, null));
1402 tree.setLinkToAllViews(
1403 tp.getTreeCanvas().isApplyToAllViews());
1406 if (tp.isColumnWise())
1408 tree.setColumnWise(true);
1409 String annId = tp.getAssocAnnotation().annotationId;
1410 tree.setColumnReference(annId);
1412 // jms.addTree(tree);
1413 object.getTree().add(tree);
1423 if (!storeDS && Desktop.desktop != null)
1425 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
1427 if (frame instanceof PCAPanel)
1429 PCAPanel panel = (PCAPanel) frame;
1430 if (panel.getAlignViewport().getAlignment() == jal)
1432 savePCA(panel, object);
1440 * store forward refs from an annotationRow to any groups
1442 IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
1445 for (SequenceI sq : jal.getSequences())
1447 // Store annotation on dataset sequences only
1448 AlignmentAnnotation[] aa = sq.getAnnotation();
1449 if (aa != null && aa.length > 0)
1451 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1458 if (jal.getAlignmentAnnotation() != null)
1460 // Store the annotation shown on the alignment.
1461 AlignmentAnnotation[] aa = jal.getAlignmentAnnotation();
1462 storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS,
1467 if (jal.getGroups() != null)
1469 JGroup[] groups = new JGroup[jal.getGroups().size()];
1471 for (jalview.datamodel.SequenceGroup sg : jal.getGroups())
1473 JGroup jGroup = new JGroup();
1474 groups[++i] = jGroup;
1476 jGroup.setStart(sg.getStartRes());
1477 jGroup.setEnd(sg.getEndRes());
1478 jGroup.setName(sg.getName());
1479 if (groupRefs.containsKey(sg))
1481 // group has references so set its ID field
1482 jGroup.setId(groupRefs.get(sg));
1484 ColourSchemeI colourScheme = sg.getColourScheme();
1485 if (colourScheme != null)
1487 ResidueShaderI groupColourScheme = sg.getGroupColourScheme();
1488 if (groupColourScheme.conservationApplied())
1490 jGroup.setConsThreshold(groupColourScheme.getConservationInc());
1492 if (colourScheme instanceof jalview.schemes.UserColourScheme)
1494 jGroup.setColour(setUserColourScheme(colourScheme,
1495 userColours, object));
1499 jGroup.setColour(colourScheme.getSchemeName());
1502 else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
1504 jGroup.setColour("AnnotationColourGradient");
1505 jGroup.setAnnotationColours(constructAnnotationColours(
1506 (jalview.schemes.AnnotationColourGradient) colourScheme,
1507 userColours, object));
1509 else if (colourScheme instanceof jalview.schemes.UserColourScheme)
1512 setUserColourScheme(colourScheme, userColours, object));
1516 jGroup.setColour(colourScheme.getSchemeName());
1519 jGroup.setPidThreshold(groupColourScheme.getThreshold());
1522 jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
1523 jGroup.setDisplayBoxes(sg.getDisplayBoxes());
1524 jGroup.setDisplayText(sg.getDisplayText());
1525 jGroup.setColourText(sg.getColourText());
1526 jGroup.setTextCol1(sg.textColour.getRGB());
1527 jGroup.setTextCol2(sg.textColour2.getRGB());
1528 jGroup.setTextColThreshold(sg.thresholdTextColour);
1529 jGroup.setShowUnconserved(sg.getShowNonconserved());
1530 jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus());
1531 jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram());
1532 jGroup.setShowSequenceLogo(sg.isShowSequenceLogo());
1533 jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo());
1534 for (SequenceI seq : sg.getSequences())
1536 // jGroup.addSeq(seqHash(seq));
1537 jGroup.getSeq().add(seqHash(seq));
1541 // jms.setJGroup(groups);
1543 for (JGroup grp : groups)
1545 object.getJGroup().add(grp);
1550 // /////////SAVE VIEWPORT
1551 Viewport view = new Viewport();
1552 view.setTitle(ap.alignFrame.getTitle());
1553 view.setSequenceSetId(
1554 makeHashCode(av.getSequenceSetId(), av.getSequenceSetId()));
1555 view.setId(av.getViewId());
1556 if (av.getCodingComplement() != null)
1558 view.setComplementId(av.getCodingComplement().getViewId());
1560 view.setViewName(av.getViewName());
1561 view.setGatheredViews(av.isGatherViewsHere());
1563 Rectangle size = ap.av.getExplodedGeometry();
1564 Rectangle position = size;
1567 size = ap.alignFrame.getBounds();
1568 if (av.getCodingComplement() != null)
1570 position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
1578 view.setXpos(position.x);
1579 view.setYpos(position.y);
1581 view.setWidth(size.width);
1582 view.setHeight(size.height);
1584 view.setStartRes(vpRanges.getStartRes());
1585 view.setStartSeq(vpRanges.getStartSeq());
1587 OverviewPanel ov = ap.getOverviewPanel();
1590 Overview overview = new Overview();
1591 overview.setTitle(ov.getTitle());
1592 Rectangle bounds = ov.getFrameBounds();
1593 overview.setXpos(bounds.x);
1594 overview.setYpos(bounds.y);
1595 overview.setWidth(bounds.width);
1596 overview.setHeight(bounds.height);
1597 overview.setShowHidden(ov.isShowHiddenRegions());
1598 overview.setGapColour(ov.getCanvas().getGapColour().getRGB());
1599 overview.setResidueColour(
1600 ov.getCanvas().getResidueColour().getRGB());
1601 overview.setHiddenColour(ov.getCanvas().getHiddenColour().getRGB());
1602 view.setOverview(overview);
1604 if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
1606 view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
1607 userColours, object));
1610 .getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
1612 AnnotationColourScheme ac = constructAnnotationColours(
1613 (jalview.schemes.AnnotationColourGradient) av
1614 .getGlobalColourScheme(),
1615 userColours, object);
1617 view.setAnnotationColours(ac);
1618 view.setBgColour("AnnotationColourGradient");
1622 view.setBgColour(ColourSchemeProperty
1623 .getColourName(av.getGlobalColourScheme()));
1626 ResidueShaderI vcs = av.getResidueShading();
1627 ColourSchemeI cs = av.getGlobalColourScheme();
1631 if (vcs.conservationApplied())
1633 view.setConsThreshold(vcs.getConservationInc());
1634 if (cs instanceof jalview.schemes.UserColourScheme)
1636 view.setBgColour(setUserColourScheme(cs, userColours, object));
1639 view.setPidThreshold(vcs.getThreshold());
1642 view.setConservationSelected(av.getConservationSelected());
1643 view.setPidSelected(av.getAbovePIDThreshold());
1644 view.setCharHeight(av.getCharHeight());
1645 view.setCharWidth(av.getCharWidth());
1646 final Font font = av.getFont();
1647 view.setFontName(font.getName());
1648 view.setFontSize(font.getSize());
1649 view.setFontStyle(font.getStyle());
1650 view.setScaleProteinAsCdna(av.getViewStyle().isScaleProteinAsCdna());
1651 view.setRenderGaps(av.isRenderGaps());
1652 view.setShowAnnotation(av.isShowAnnotation());
1653 view.setShowBoxes(av.getShowBoxes());
1654 view.setShowColourText(av.getColourText());
1655 view.setShowFullId(av.getShowJVSuffix());
1656 view.setRightAlignIds(av.isRightAlignIds());
1657 view.setIdWidth(av.getIdWidth());
1658 view.setIdWidthManuallyAdjusted(
1659 ap.getIdPanel().getIdCanvas().isManuallyAdjusted());
1661 view.setShowSequenceFeatures(av.isShowSequenceFeatures());
1662 view.setShowText(av.getShowText());
1663 view.setShowUnconserved(av.getShowUnconserved());
1664 view.setWrapAlignment(av.getWrapAlignment());
1665 view.setTextCol1(av.getTextColour().getRGB());
1666 view.setTextCol2(av.getTextColour2().getRGB());
1667 view.setTextColThreshold(av.getThresholdTextColour());
1668 view.setShowConsensusHistogram(av.isShowConsensusHistogram());
1669 view.setShowSequenceLogo(av.isShowSequenceLogo());
1670 view.setNormaliseSequenceLogo(av.isNormaliseSequenceLogo());
1671 view.setShowGroupConsensus(av.isShowGroupConsensus());
1672 view.setShowGroupConservation(av.isShowGroupConservation());
1673 view.setShowNPfeatureTooltip(av.isShowNPFeats());
1674 view.setShowDbRefTooltip(av.isShowDBRefs());
1675 view.setFollowHighlight(av.isFollowHighlight());
1676 view.setFollowSelection(av.followSelection);
1677 view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
1678 view.setShowComplementFeatures(av.isShowComplementFeatures());
1679 view.setShowComplementFeaturesOnTop(
1680 av.isShowComplementFeaturesOnTop());
1681 if (av.getFeaturesDisplayed() != null)
1683 FeatureSettings fs = new FeatureSettings();
1685 FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
1686 .getFeatureRenderer();
1687 String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
1689 Vector<String> settingsAdded = new Vector<>();
1690 if (renderOrder != null)
1692 for (String featureType : renderOrder)
1694 FeatureSettings.Setting setting = new FeatureSettings.Setting();
1695 setting.setType(featureType);
1698 * save any filter for the feature type
1700 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1703 Iterator<FeatureMatcherI> filters = filter.getMatchers()
1705 FeatureMatcherI firstFilter = filters.next();
1706 setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
1707 filters, filter.isAnded()));
1711 * save colour scheme for the feature type
1713 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1714 if (!fcol.isSimpleColour())
1716 setting.setColour(fcol.getMaxColour().getRGB());
1717 setting.setMincolour(fcol.getMinColour().getRGB());
1718 setting.setMin(fcol.getMin());
1719 setting.setMax(fcol.getMax());
1720 setting.setColourByLabel(fcol.isColourByLabel());
1721 if (fcol.isColourByAttribute())
1723 String[] attName = fcol.getAttributeName();
1724 setting.getAttributeName().add(attName[0]);
1725 if (attName.length > 1)
1727 setting.getAttributeName().add(attName[1]);
1730 setting.setAutoScale(fcol.isAutoScaled());
1731 setting.setThreshold(fcol.getThreshold());
1732 Color noColour = fcol.getNoColour();
1733 if (noColour == null)
1735 setting.setNoValueColour(NoValueColour.NONE);
1737 else if (noColour.equals(fcol.getMaxColour()))
1739 setting.setNoValueColour(NoValueColour.MAX);
1743 setting.setNoValueColour(NoValueColour.MIN);
1745 // -1 = No threshold, 0 = Below, 1 = Above
1746 setting.setThreshstate(fcol.isAboveThreshold() ? 1
1747 : (fcol.isBelowThreshold() ? 0 : -1));
1751 setting.setColour(fcol.getColour().getRGB());
1755 av.getFeaturesDisplayed().isVisible(featureType));
1756 float rorder = fr.getOrder(featureType);
1759 setting.setOrder(rorder);
1761 /// fs.addSetting(setting);
1762 fs.getSetting().add(setting);
1763 settingsAdded.addElement(featureType);
1767 // is groups actually supposed to be a map here ?
1768 Iterator<String> en = fr.getFeatureGroups().iterator();
1769 Vector<String> groupsAdded = new Vector<>();
1770 while (en.hasNext())
1772 String grp = en.next();
1773 if (groupsAdded.contains(grp))
1777 Group g = new Group();
1779 g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
1782 fs.getGroup().add(g);
1783 groupsAdded.addElement(grp);
1785 // jms.setFeatureSettings(fs);
1786 object.setFeatureSettings(fs);
1789 if (av.hasHiddenColumns())
1791 jalview.datamodel.HiddenColumns hidden = av.getAlignment()
1792 .getHiddenColumns();
1796 "REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
1800 Iterator<int[]> hiddenRegions = hidden.iterator();
1801 while (hiddenRegions.hasNext())
1803 int[] region = hiddenRegions.next();
1804 HiddenColumns hc = new HiddenColumns();
1805 hc.setStart(region[0]);
1806 hc.setEnd(region[1]);
1807 // view.addHiddenColumns(hc);
1808 view.getHiddenColumns().add(hc);
1812 if (calcIdSet.size() > 0)
1814 for (String calcId : calcIdSet)
1816 if (calcId.trim().length() > 0)
1818 CalcIdParam cidp = createCalcIdParam(calcId, av);
1819 // Some calcIds have no parameters.
1822 // view.addCalcIdParam(cidp);
1823 view.getCalcIdParam().add(cidp);
1829 // jms.addViewport(view);
1830 object.getViewport().add(view);
1835 // store matrices referenced by any views or annotation in this dataset
1836 if (xmlMatrices != null && xmlMatrices.size() > 0)
1839 "Adding " + xmlMatrices.size() + " matrices to dataset.");
1840 vamsasSet.getMatrix().addAll(xmlMatrices);
1841 xmlMatrices.clear();
1845 // object.setJalviewModelSequence(jms);
1846 // object.getVamsasModel().addSequenceSet(vamsasSet);
1847 object.getVamsasModel().getSequenceSet().add(vamsasSet);
1849 if (jout != null && fileName != null)
1851 // We may not want to write the object to disk,
1852 // eg we can copy the alignViewport to a new view object
1853 // using save and then load
1856 fileName = fileName.replace('\\', '/');
1857 jalview.bin.Console.outPrintln("Writing jar entry " + fileName);
1858 JarEntry entry = new JarEntry(fileName);
1859 jout.putNextEntry(entry);
1860 PrintWriter pout = new PrintWriter(
1861 new OutputStreamWriter(jout, UTF_8));
1862 JAXBContext jaxbContext = JAXBContext
1863 .newInstance(JalviewModel.class);
1864 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1866 // output pretty printed
1867 // jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
1868 jaxbMarshaller.marshal(
1869 new ObjectFactory().createJalviewModel(object), pout);
1871 // jaxbMarshaller.marshal(object, pout);
1872 // marshaller.marshal(object);
1875 } catch (Exception ex)
1877 // TODO: raise error in GUI if marshalling failed.
1878 jalview.bin.Console.errPrintln("Error writing Jalview project");
1879 ex.printStackTrace();
1886 * Writes PCA viewer attributes and computed values to an XML model object and
1887 * adds it to the JalviewModel. Any exceptions are reported by logging.
1889 protected void savePCA(PCAPanel panel, JalviewModel object)
1893 PcaViewer viewer = new PcaViewer();
1894 viewer.setHeight(panel.getHeight());
1895 viewer.setWidth(panel.getWidth());
1896 viewer.setXpos(panel.getX());
1897 viewer.setYpos(panel.getY());
1898 viewer.setTitle(panel.getTitle());
1899 PCAModel pcaModel = panel.getPcaModel();
1900 viewer.setScoreModelName(pcaModel.getScoreModelName());
1901 viewer.setXDim(panel.getSelectedDimensionIndex(X));
1902 viewer.setYDim(panel.getSelectedDimensionIndex(Y));
1903 viewer.setZDim(panel.getSelectedDimensionIndex(Z));
1905 panel.getRotatableCanvas().getBackgroundColour().getRGB());
1906 viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
1907 float[] spMin = panel.getRotatableCanvas().getSeqMin();
1908 SeqPointMin spmin = new SeqPointMin();
1909 spmin.setXPos(spMin[0]);
1910 spmin.setYPos(spMin[1]);
1911 spmin.setZPos(spMin[2]);
1912 viewer.setSeqPointMin(spmin);
1913 float[] spMax = panel.getRotatableCanvas().getSeqMax();
1914 SeqPointMax spmax = new SeqPointMax();
1915 spmax.setXPos(spMax[0]);
1916 spmax.setYPos(spMax[1]);
1917 spmax.setZPos(spMax[2]);
1918 viewer.setSeqPointMax(spmax);
1919 viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
1920 viewer.setLinkToAllViews(
1921 panel.getRotatableCanvas().isApplyToAllViews());
1922 SimilarityParamsI sp = pcaModel.getSimilarityParameters();
1923 viewer.setIncludeGaps(sp.includeGaps());
1924 viewer.setMatchGaps(sp.matchGaps());
1925 viewer.setIncludeGappedColumns(sp.includeGappedColumns());
1926 viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
1929 * sequence points on display
1931 for (jalview.datamodel.SequencePoint spt : pcaModel
1932 .getSequencePoints())
1934 SequencePoint point = new SequencePoint();
1935 point.setSequenceRef(seqHash(spt.getSequence()));
1936 point.setXPos(spt.coord.x);
1937 point.setYPos(spt.coord.y);
1938 point.setZPos(spt.coord.z);
1939 viewer.getSequencePoint().add(point);
1943 * (end points of) axes on display
1945 for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
1948 Axis axis = new Axis();
1952 viewer.getAxis().add(axis);
1956 * raw PCA data (note we are not restoring PCA inputs here -
1957 * alignment view, score model, similarity parameters)
1959 PcaDataType data = new PcaDataType();
1960 viewer.setPcaData(data);
1961 PCA pca = pcaModel.getPcaData();
1963 DoubleMatrix pm = new DoubleMatrix();
1964 saveDoubleMatrix(pca.getPairwiseScores(), pm);
1965 data.setPairwiseMatrix(pm);
1967 DoubleMatrix tm = new DoubleMatrix();
1968 saveDoubleMatrix(pca.getTridiagonal(), tm);
1969 data.setTridiagonalMatrix(tm);
1971 DoubleMatrix eigenMatrix = new DoubleMatrix();
1972 data.setEigenMatrix(eigenMatrix);
1973 saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
1975 object.getPcaViewer().add(viewer);
1976 } catch (Throwable t)
1978 Console.error("Error saving PCA: " + t.getMessage());
1983 * Stores values from a matrix into an XML element, including (if present) the
1988 * @see #loadDoubleMatrix(DoubleMatrix)
1990 protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
1992 xmlMatrix.setRows(m.height());
1993 xmlMatrix.setColumns(m.width());
1994 for (int i = 0; i < m.height(); i++)
1996 DoubleVector row = new DoubleVector();
1997 for (int j = 0; j < m.width(); j++)
1999 row.getV().add(m.getValue(i, j));
2001 xmlMatrix.getRow().add(row);
2003 if (m.getD() != null)
2005 DoubleVector dVector = new DoubleVector();
2006 for (double d : m.getD())
2008 dVector.getV().add(d);
2010 xmlMatrix.setD(dVector);
2012 if (m.getE() != null)
2014 DoubleVector eVector = new DoubleVector();
2015 for (double e : m.getE())
2017 eVector.getV().add(e);
2019 xmlMatrix.setE(eVector);
2024 * Loads XML matrix data into a new Matrix object, including the D and/or E
2025 * vectors (if present)
2029 * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
2031 protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
2033 int rows = mData.getRows();
2034 double[][] vals = new double[rows][];
2036 for (int i = 0; i < rows; i++)
2038 List<Double> dVector = mData.getRow().get(i).getV();
2039 vals[i] = new double[dVector.size()];
2041 for (Double d : dVector)
2047 MatrixI m = new Matrix(vals);
2049 if (mData.getD() != null)
2051 List<Double> dVector = mData.getD().getV();
2052 double[] vec = new double[dVector.size()];
2054 for (Double d : dVector)
2060 if (mData.getE() != null)
2062 List<Double> dVector = mData.getE().getV();
2063 double[] vec = new double[dVector.size()];
2065 for (Double d : dVector)
2076 * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
2077 * for each viewer, with
2079 * <li>viewer geometry (position, size, split pane divider location)</li>
2080 * <li>index of the selected structure in the viewer (currently shows gapped
2082 * <li>the id of the annotation holding RNA secondary structure</li>
2083 * <li>(currently only one SS is shown per viewer, may be more in future)</li>
2085 * Varna viewer state is also written out (in native Varna XML) to separate
2086 * project jar entries. A separate entry is written for each RNA structure
2087 * displayed, with the naming convention
2089 * <li>rna_viewId_sequenceId_annotationId_[gapped|trimmed]</li>
2097 * @param storeDataset
2099 protected void saveRnaViewers(JarOutputStream jout, JSeq jseq,
2100 final SequenceI jds, List<String> viewIds, AlignmentPanel ap,
2101 boolean storeDataset)
2103 if (Desktop.desktop == null)
2107 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2108 for (int f = frames.length - 1; f > -1; f--)
2110 if (frames[f] instanceof AppVarna)
2112 AppVarna varna = (AppVarna) frames[f];
2114 * link the sequence to every viewer that is showing it and is linked to
2115 * its alignment panel
2117 if (varna.isListeningFor(jds) && ap == varna.getAlignmentPanel())
2119 String viewId = varna.getViewId();
2120 RnaViewer rna = new RnaViewer();
2121 rna.setViewId(viewId);
2122 rna.setTitle(varna.getTitle());
2123 rna.setXpos(varna.getX());
2124 rna.setYpos(varna.getY());
2125 rna.setWidth(varna.getWidth());
2126 rna.setHeight(varna.getHeight());
2127 rna.setDividerLocation(varna.getDividerLocation());
2128 rna.setSelectedRna(varna.getSelectedIndex());
2129 // jseq.addRnaViewer(rna);
2130 jseq.getRnaViewer().add(rna);
2133 * Store each Varna panel's state once in the project per sequence.
2134 * First time through only (storeDataset==false)
2136 // boolean storeSessions = false;
2137 // String sequenceViewId = viewId + seqsToIds.get(jds);
2138 // if (!storeDataset && !viewIds.contains(sequenceViewId))
2140 // viewIds.add(sequenceViewId);
2141 // storeSessions = true;
2143 for (RnaModel model : varna.getModels())
2145 if (model.seq == jds)
2148 * VARNA saves each view (sequence or alignment secondary
2149 * structure, gapped or trimmed) as a separate XML file
2151 String jarEntryName = rnaSessions.get(model);
2152 if (jarEntryName == null)
2155 String varnaStateFile = varna.getStateInfo(model.rna);
2156 jarEntryName = RNA_PREFIX + viewId + "_" + nextCounter();
2157 copyFileToJar(jout, varnaStateFile, jarEntryName, "Varna");
2158 rnaSessions.put(model, jarEntryName);
2160 SecondaryStructure ss = new SecondaryStructure();
2161 String annotationId = varna.getAnnotation(jds).annotationId;
2162 ss.setAnnotationId(annotationId);
2163 ss.setViewerState(jarEntryName);
2164 ss.setGapped(model.gapped);
2165 ss.setTitle(model.title);
2166 // rna.addSecondaryStructure(ss);
2167 rna.getSecondaryStructure().add(ss);
2176 * Copy the contents of a file to a new entry added to the output jar
2180 * @param jarEntryName
2182 * additional identifying info to log to the console
2184 protected void copyFileToJar(JarOutputStream jout, String infilePath,
2185 String jarEntryName, String msg)
2187 try (InputStream is = new FileInputStream(infilePath))
2189 File file = new File(infilePath);
2190 if (file.exists() && jout != null)
2192 jalview.bin.Console.outPrintln(
2193 "Writing jar entry " + jarEntryName + " (" + msg + ")");
2194 jout.putNextEntry(new JarEntry(jarEntryName));
2197 // dis = new DataInputStream(new FileInputStream(file));
2198 // byte[] data = new byte[(int) file.length()];
2199 // dis.readFully(data);
2200 // writeJarEntry(jout, jarEntryName, data);
2202 } catch (Exception ex)
2204 ex.printStackTrace();
2209 * Copies input to output, in 4K buffers; handles any data (text or binary)
2213 * @throws IOException
2215 protected void copyAll(InputStream in, OutputStream out)
2218 byte[] buffer = new byte[4096];
2220 while ((bytesRead = in.read(buffer)) != -1)
2222 out.write(buffer, 0, bytesRead);
2227 * Save the state of a structure viewer
2232 * the archive XML element under which to save the state
2235 * @param matchedFile
2239 protected String saveStructureViewer(AlignmentPanel ap, SequenceI jds,
2240 Pdbids pdb, PDBEntry entry, List<String> viewIds,
2241 String matchedFile, JalviewStructureDisplayI viewFrame)
2243 final AAStructureBindingModel bindingModel = viewFrame.getBinding();
2246 * Look for any bindings for this viewer to the PDB file of interest
2247 * (including part matches excluding chain id)
2249 for (int peid = 0; peid < bindingModel.getPdbCount(); peid++)
2251 final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
2252 final String pdbId = pdbentry.getId();
2253 if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
2254 && entry.getId().toLowerCase(Locale.ROOT)
2255 .startsWith(pdbId.toLowerCase(Locale.ROOT))))
2258 * not interested in a binding to a different PDB entry here
2262 if (matchedFile == null)
2264 matchedFile = pdbentry.getFile();
2266 else if (!matchedFile.equals(pdbentry.getFile()))
2269 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
2270 + pdbentry.getFile());
2274 // can get at it if the ID
2275 // match is ambiguous (e.g.
2278 for (int smap = 0; smap < viewFrame.getBinding()
2279 .getSequence()[peid].length; smap++)
2281 // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
2282 if (jds == viewFrame.getBinding().getSequence()[peid][smap])
2284 StructureState state = new StructureState();
2285 state.setVisible(true);
2286 state.setXpos(viewFrame.getY());
2287 state.setYpos(viewFrame.getY());
2288 state.setWidth(viewFrame.getWidth());
2289 state.setHeight(viewFrame.getHeight());
2290 final String viewId = viewFrame.getViewId();
2291 state.setViewId(viewId);
2292 state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
2293 state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
2294 state.setColourByJmol(viewFrame.isColouredByViewer());
2295 state.setType(viewFrame.getViewerType().toString());
2296 // pdb.addStructureState(state);
2297 pdb.getStructureState().add(state);
2305 * Populates the AnnotationColourScheme xml for save. This captures the
2306 * settings of the options in the 'Colour by Annotation' dialog.
2309 * @param userColours
2313 private AnnotationColourScheme constructAnnotationColours(
2314 AnnotationColourGradient acg, List<UserColourScheme> userColours,
2317 AnnotationColourScheme ac = new AnnotationColourScheme();
2318 ac.setAboveThreshold(acg.getAboveThreshold());
2319 ac.setThreshold(acg.getAnnotationThreshold());
2320 // 2.10.2 save annotationId (unique) not annotation label
2321 ac.setAnnotation(acg.getAnnotation().annotationId);
2322 if (acg.getBaseColour() instanceof UserColourScheme)
2325 setUserColourScheme(acg.getBaseColour(), userColours, jm));
2330 ColourSchemeProperty.getColourName(acg.getBaseColour()));
2333 ac.setMaxColour(acg.getMaxColour().getRGB());
2334 ac.setMinColour(acg.getMinColour().getRGB());
2335 ac.setPerSequence(acg.isSeqAssociated());
2336 ac.setPredefinedColours(acg.isPredefinedColours());
2340 private void storeAlignmentAnnotation(AlignmentAnnotation[] aa,
2341 IdentityHashMap<SequenceGroup, String> groupRefs,
2342 AlignmentViewport av, Set<String> calcIdSet, boolean storeDS,
2343 SequenceSet vamsasSet)
2346 for (int i = 0; i < aa.length; i++)
2348 Annotation an = new Annotation();
2350 AlignmentAnnotation annotation = aa[i];
2351 if (annotation.annotationId != null)
2353 annotationIds.put(annotation.annotationId, annotation);
2356 an.setId(annotation.annotationId);
2358 an.setVisible(annotation.visible);
2360 an.setDescription(annotation.description);
2362 if (annotation.sequenceRef != null)
2364 // 2.9 JAL-1781 xref on sequence id rather than name
2365 an.setSequenceRef(seqsToIds.get(annotation.sequenceRef));
2367 if (annotation.groupRef != null)
2369 String groupIdr = groupRefs.get(annotation.groupRef);
2370 if (groupIdr == null)
2372 // make a locally unique String
2373 groupRefs.put(annotation.groupRef,
2374 groupIdr = ("" + System.currentTimeMillis()
2375 + annotation.groupRef.getName()
2376 + groupRefs.size()));
2378 an.setGroupRef(groupIdr.toString());
2381 // store all visualization attributes for annotation
2382 an.setGraphHeight(annotation.graphHeight);
2383 an.setCentreColLabels(annotation.centreColLabels);
2384 an.setScaleColLabels(annotation.scaleColLabel);
2385 an.setShowAllColLabels(annotation.showAllColLabels);
2386 an.setBelowAlignment(annotation.belowAlignment);
2388 if (annotation.graph > 0)
2391 an.setGraphType(annotation.graph);
2392 an.setGraphGroup(annotation.graphGroup);
2393 if (annotation.getThreshold() != null)
2395 ThresholdLine line = new ThresholdLine();
2396 line.setLabel(annotation.getThreshold().label);
2397 line.setValue(annotation.getThreshold().value);
2398 line.setColour(annotation.getThreshold().colour.getRGB());
2399 an.setThresholdLine(line);
2401 if (annotation.graph == AlignmentAnnotation.CONTACT_MAP)
2403 if (annotation.sequenceRef.getContactMaps() != null)
2405 ContactMatrixI cm = annotation.sequenceRef
2406 .getContactMatrixFor(annotation);
2409 storeMatrixFor(vamsasSet, an, annotation, cm);
2419 an.setLabel(annotation.label);
2421 if (annotation == av.getAlignmentQualityAnnot()
2422 || annotation == av.getAlignmentConservationAnnotation()
2423 || annotation == av.getAlignmentConsensusAnnotation()
2424 || annotation.autoCalculated)
2426 // new way of indicating autocalculated annotation -
2427 an.setAutoCalculated(annotation.autoCalculated);
2429 if (annotation.hasScore())
2431 an.setScore(annotation.getScore());
2434 if (annotation.getCalcId() != null)
2436 calcIdSet.add(annotation.getCalcId());
2437 an.setCalcId(annotation.getCalcId());
2439 if (annotation.hasProperties())
2441 for (String pr : annotation.getProperties())
2443 jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
2445 prop.setValue(annotation.getProperty(pr));
2446 an.getProperty().add(prop);
2450 AnnotationElement ae;
2451 if (annotation.annotations != null)
2453 an.setScoreOnly(false);
2454 for (int a = 0; a < annotation.annotations.length; a++)
2456 if ((annotation == null) || (annotation.annotations[a] == null))
2461 ae = new AnnotationElement();
2462 if (annotation.annotations[a].description != null)
2464 ae.setDescription(annotation.annotations[a].description);
2466 if (annotation.annotations[a].displayCharacter != null)
2468 ae.setDisplayCharacter(
2469 annotation.annotations[a].displayCharacter);
2472 if (!Float.isNaN(annotation.annotations[a].value))
2474 ae.setValue(annotation.annotations[a].value);
2478 if (annotation.annotations[a].secondaryStructure > ' ')
2480 ae.setSecondaryStructure(
2481 annotation.annotations[a].secondaryStructure + "");
2484 if (annotation.annotations[a].colour != null
2485 && annotation.annotations[a].colour != java.awt.Color.black)
2487 ae.setColour(annotation.annotations[a].colour.getRGB());
2490 // an.addAnnotationElement(ae);
2491 an.getAnnotationElement().add(ae);
2492 if (annotation.autoCalculated)
2494 // only write one non-null entry into the annotation row -
2495 // sufficient to get the visualization attributes necessary to
2503 an.setScoreOnly(true);
2505 if (!storeDS || (storeDS && !annotation.autoCalculated))
2507 // skip autocalculated annotation - these are only provided for
2509 // vamsasSet.addAnnotation(an);
2510 vamsasSet.getAnnotation().add(an);
2516 private void storeMatrixFor(SequenceSet root, Annotation an,
2517 AlignmentAnnotation annotation, ContactMatrixI cm)
2519 String cmId = contactMatrices.get(cm);
2520 MatrixType xmlmat = null;
2522 // first create an xml ref for the matrix data, if none exist
2525 xmlmat = new MatrixType();
2526 xmlmat.setType(cm.getType());
2527 xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
2528 xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
2529 // consider using an opaque to/from -> allow instance to control
2530 // its representation ?
2531 xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
2534 for (BitSet gp : cm.getGroups())
2536 xmlmat.getGroups().add(stringifyBitset(gp));
2541 // provenance object for tree ?
2542 xmlmat.getNewick().add(cm.getNewick());
2543 xmlmat.setTreeMethod(cm.getTreeMethod());
2545 if (cm.hasCutHeight())
2547 xmlmat.setCutHeight(cm.getCutHeight());
2549 xmlmat.setId(cmId = "m" + contactMatrices.size()
2550 + System.currentTimeMillis());
2551 Console.trace("Matrix data stored :" + cmId);
2552 contactMatrices.put(cm, cmId);
2553 contactMatrixRefs.put(cmId, cm);
2554 xmlMatrices.add(xmlmat);
2558 Console.trace("Existing Matrix stored :" + cmId);
2561 // now store mapping
2563 MapOnAMatrixType xmlmatmapping = new MapOnAMatrixType();
2564 xmlmatmapping.setMatrix(cmId);
2566 // Pretty much all matrices currently managed in this way are
2567 // mappableContactMatrixI implementations - but check anyway
2568 if (cm instanceof MappableContactMatrixI)
2570 jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
2571 .getMapFor(annotation.sequenceRef);
2574 MapListType mp = new MapListType();
2575 List<int[]> r = mlst.getFromRanges();
2576 for (int[] range : r)
2578 MapListFrom mfrom = new MapListFrom();
2579 mfrom.setStart(range[0]);
2580 mfrom.setEnd(range[1]);
2581 // mp.addMapListFrom(mfrom);
2582 mp.getMapListFrom().add(mfrom);
2584 r = mlst.getToRanges();
2585 for (int[] range : r)
2587 MapListTo mto = new MapListTo();
2588 mto.setStart(range[0]);
2589 mto.setEnd(range[1]);
2590 // mp.addMapListTo(mto);
2591 mp.getMapListTo().add(mto);
2593 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2594 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2595 xmlmatmapping.setMapping(mp);
2599 an.getContactmatrix().add(xmlmatmapping);
2602 private String stringifyBitset(BitSet gp)
2604 StringBuilder sb = new StringBuilder();
2605 for (long val : gp.toLongArray())
2607 if (sb.length() > 0)
2613 return sb.toString();
2616 private BitSet deStringifyBitset(String stringified)
2618 if ("".equals(stringified) || stringified == null)
2620 return new BitSet();
2622 String[] longvals = stringified.split(",");
2623 long[] newlongvals = new long[longvals.length];
2624 for (int lv = 0; lv < longvals.length; lv++)
2628 newlongvals[lv] = Long.valueOf(longvals[lv]);
2629 } catch (Exception x)
2631 errorMessage += "Couldn't destringify bitset from: '" + stringified
2633 newlongvals[lv] = 0;
2636 return BitSet.valueOf(newlongvals);
2640 private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
2642 AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
2643 if (settings != null)
2645 CalcIdParam vCalcIdParam = new CalcIdParam();
2646 vCalcIdParam.setCalcId(calcId);
2647 // vCalcIdParam.addServiceURL(settings.getServiceURI());
2648 vCalcIdParam.getServiceURL().add(settings.getServiceURI());
2649 // generic URI allowing a third party to resolve another instance of the
2650 // service used for this calculation
2651 for (String url : settings.getServiceURLs())
2653 // vCalcIdParam.addServiceURL(urls);
2654 vCalcIdParam.getServiceURL().add(url);
2656 vCalcIdParam.setVersion("1.0");
2657 if (settings.getPreset() != null)
2659 WsParamSetI setting = settings.getPreset();
2660 vCalcIdParam.setName(setting.getName());
2661 vCalcIdParam.setDescription(setting.getDescription());
2665 vCalcIdParam.setName("");
2666 vCalcIdParam.setDescription("Last used parameters");
2668 // need to be able to recover 1) settings 2) user-defined presets or
2669 // recreate settings from preset 3) predefined settings provided by
2670 // service - or settings that can be transferred (or discarded)
2671 vCalcIdParam.setParameters(
2672 settings.getWsParamFile().replace("\n", "|\\n|"));
2673 vCalcIdParam.setAutoUpdate(settings.isAutoUpdate());
2674 // todo - decide if updateImmediately is needed for any projects.
2676 return vCalcIdParam;
2681 private boolean recoverCalcIdParam(CalcIdParam calcIdParam,
2684 if (calcIdParam.getVersion().equals("1.0"))
2686 final String[] calcIds = calcIdParam.getServiceURL()
2687 .toArray(new String[0]);
2688 Jws2Instance service = Jws2Discoverer.getDiscoverer()
2689 .getPreferredServiceFor(calcIds);
2690 if (service != null)
2692 WsParamSetI parmSet = null;
2695 parmSet = service.getParamStore().parseServiceParameterFile(
2696 calcIdParam.getName(), calcIdParam.getDescription(),
2698 calcIdParam.getParameters().replace("|\\n|", "\n"));
2699 } catch (IOException x)
2701 Console.warn("Couldn't parse parameter data for "
2702 + calcIdParam.getCalcId(), x);
2705 List<ArgumentI> argList = null;
2706 if (calcIdParam.getName().length() > 0)
2708 parmSet = service.getParamStore()
2709 .getPreset(calcIdParam.getName());
2710 if (parmSet != null)
2712 // TODO : check we have a good match with settings in AACon -
2713 // otherwise we'll need to create a new preset
2718 argList = parmSet.getArguments();
2721 AAConSettings settings = new AAConSettings(
2722 calcIdParam.isAutoUpdate(), service, parmSet, argList);
2723 av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
2724 calcIdParam.isNeedsUpdate());
2730 "Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
2734 throw new Error(MessageManager.formatMessage(
2735 "error.unsupported_version_calcIdparam", new Object[]
2736 { calcIdParam.toString() }));
2740 * External mapping between jalview objects and objects yielding a valid and
2741 * unique object ID string. This is null for normal Jalview project IO, but
2742 * non-null when a jalview project is being read or written as part of a
2745 IdentityHashMap jv2vobj = null;
2748 * Construct a unique ID for jvobj using either existing bindings or if none
2749 * exist, the result of the hashcode call for the object.
2752 * jalview data object
2753 * @return unique ID for referring to jvobj
2755 private String makeHashCode(Object jvobj, String altCode)
2757 if (jv2vobj != null)
2759 Object id = jv2vobj.get(jvobj);
2762 return id.toString();
2764 // check string ID mappings
2765 if (jvids2vobj != null && jvobj instanceof String)
2767 id = jvids2vobj.get(jvobj);
2771 return id.toString();
2773 // give up and warn that something has gone wrong
2775 "Cannot find ID for object in external mapping : " + jvobj);
2781 * return local jalview object mapped to ID, if it exists
2785 * @return null or object bound to idcode
2787 private Object retrieveExistingObj(String idcode)
2789 if (idcode != null && vobj2jv != null)
2791 return vobj2jv.get(idcode);
2797 * binding from ID strings from external mapping table to jalview data model
2800 private Hashtable vobj2jv;
2802 private Sequence createVamsasSequence(String id, SequenceI jds)
2804 return createVamsasSequence(true, id, jds, null);
2807 private Sequence createVamsasSequence(boolean recurse, String id,
2808 SequenceI jds, SequenceI parentseq)
2810 Sequence vamsasSeq = new Sequence();
2811 vamsasSeq.setId(id);
2812 vamsasSeq.setName(jds.getName());
2813 vamsasSeq.setSequence(jds.getSequenceAsString());
2814 vamsasSeq.setDescription(jds.getDescription());
2815 List<DBRefEntry> dbrefs = null;
2816 if (jds.getDatasetSequence() != null)
2818 vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
2822 // seqId==dsseqid so we can tell which sequences really are
2823 // dataset sequences only
2824 vamsasSeq.setDsseqid(id);
2825 dbrefs = jds.getDBRefs();
2826 if (parentseq == null)
2833 * save any dbrefs; special subclass GeneLocus is flagged as 'locus'
2837 for (int d = 0, nd = dbrefs.size(); d < nd; d++)
2839 DBRef dbref = new DBRef();
2840 DBRefEntry ref = dbrefs.get(d);
2841 dbref.setSource(ref.getSource());
2842 dbref.setVersion(ref.getVersion());
2843 dbref.setAccessionId(ref.getAccessionId());
2844 dbref.setCanonical(ref.isCanonical());
2845 if (ref instanceof GeneLocus)
2847 dbref.setLocus(true);
2851 Mapping mp = createVamsasMapping(ref.getMap(), parentseq, jds,
2853 dbref.setMapping(mp);
2855 vamsasSeq.getDBRef().add(dbref);
2861 private Mapping createVamsasMapping(jalview.datamodel.Mapping jmp,
2862 SequenceI parentseq, SequenceI jds, boolean recurse)
2865 if (jmp.getMap() != null)
2869 jalview.util.MapList mlst = jmp.getMap();
2870 List<int[]> r = mlst.getFromRanges();
2871 for (int[] range : r)
2873 MapListFrom mfrom = new MapListFrom();
2874 mfrom.setStart(range[0]);
2875 mfrom.setEnd(range[1]);
2876 // mp.addMapListFrom(mfrom);
2877 mp.getMapListFrom().add(mfrom);
2879 r = mlst.getToRanges();
2880 for (int[] range : r)
2882 MapListTo mto = new MapListTo();
2883 mto.setStart(range[0]);
2884 mto.setEnd(range[1]);
2885 // mp.addMapListTo(mto);
2886 mp.getMapListTo().add(mto);
2888 mp.setMapFromUnit(BigInteger.valueOf(mlst.getFromRatio()));
2889 mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
2890 if (jmp.getTo() != null)
2892 // MappingChoice mpc = new MappingChoice();
2894 // check/create ID for the sequence referenced by getTo()
2897 SequenceI ps = null;
2898 if (parentseq != jmp.getTo()
2899 && parentseq.getDatasetSequence() != jmp.getTo())
2901 // chaining dbref rather than a handshaking one
2902 jmpid = seqHash(ps = jmp.getTo());
2906 jmpid = seqHash(ps = parentseq);
2908 // mpc.setDseqFor(jmpid);
2909 mp.setDseqFor(jmpid);
2910 if (!seqRefIds.containsKey(jmpid))
2912 Console.debug("creatign new DseqFor ID");
2913 seqRefIds.put(jmpid, ps);
2917 Console.debug("reusing DseqFor ID");
2920 // mp.setMappingChoice(mpc);
2926 String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
2927 List<UserColourScheme> userColours, JalviewModel jm)
2930 jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
2931 boolean newucs = false;
2932 if (!userColours.contains(ucs))
2934 userColours.add(ucs);
2937 id = "ucs" + userColours.indexOf(ucs);
2940 // actually create the scheme's entry in the XML model
2941 java.awt.Color[] colours = ucs.getColours();
2942 UserColours uc = new UserColours();
2943 // UserColourScheme jbucs = new UserColourScheme();
2944 JalviewUserColours jbucs = new JalviewUserColours();
2946 for (int i = 0; i < colours.length; i++)
2948 Colour col = new Colour();
2949 col.setName(ResidueProperties.aa[i]);
2950 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2951 // jbucs.addColour(col);
2952 jbucs.getColour().add(col);
2954 if (ucs.getLowerCaseColours() != null)
2956 colours = ucs.getLowerCaseColours();
2957 for (int i = 0; i < colours.length; i++)
2959 Colour col = new Colour();
2960 col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
2961 col.setRGB(jalview.util.Format.getHexString(colours[i]));
2962 // jbucs.addColour(col);
2963 jbucs.getColour().add(col);
2968 uc.setUserColourScheme(jbucs);
2969 // jm.addUserColours(uc);
2970 jm.getUserColours().add(uc);
2976 jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
2979 List<UserColours> uc = jm.getUserColours();
2980 UserColours colours = null;
2982 for (int i = 0; i < uc.length; i++)
2984 if (uc[i].getId().equals(id))
2991 for (UserColours c : uc)
2993 if (c.getId().equals(id))
3000 java.awt.Color[] newColours = new java.awt.Color[24];
3002 for (int i = 0; i < 24; i++)
3004 newColours[i] = new java.awt.Color(Integer.parseInt(
3005 // colours.getUserColourScheme().getColour(i).getRGB(), 16));
3006 colours.getUserColourScheme().getColour().get(i).getRGB(),
3010 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
3013 if (colours.getUserColourScheme().getColour().size()/*Count()*/ > 24)
3015 newColours = new java.awt.Color[23];
3016 for (int i = 0; i < 23; i++)
3018 newColours[i] = new java.awt.Color(
3019 Integer.parseInt(colours.getUserColourScheme().getColour()
3020 .get(i + 24).getRGB(), 16));
3022 ucs.setLowerCaseColours(newColours);
3029 * contains last error message (if any) encountered by XML loader.
3031 String errorMessage = null;
3034 * flag to control whether the Jalview2XML_V1 parser should be deferred to if
3035 * exceptions are raised during project XML parsing
3037 public boolean attemptversion1parse = false;
3040 * Load a jalview project archive from a jar file
3043 * - HTTP URL or filename
3045 public AlignFrame loadJalviewAlign(final Object file)
3048 jalview.gui.AlignFrame af = null;
3052 // create list to store references for any new Jmol viewers created
3053 newStructureViewers = new Vector<>();
3054 // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
3055 // Workaround is to make sure caller implements the JarInputStreamProvider
3057 // so we can re-open the jar input stream for each entry.
3059 jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
3060 af = loadJalviewAlign(jprovider);
3063 af.setMenusForViewport();
3065 } catch (MalformedURLException e)
3067 errorMessage = "Invalid URL format for '" + file + "'";
3073 SwingUtilities.invokeAndWait(new Runnable()
3078 setLoadingFinishedForNewStructureViewers();
3081 } catch (Exception x)
3084 .errPrintln("Error loading alignment: " + x.getMessage());
3090 @SuppressWarnings("unused")
3091 private jarInputStreamProvider createjarInputStreamProvider(
3092 final Object ofile) throws MalformedURLException
3095 // BH 2018 allow for bytes already attached to File object
3098 String file = (ofile instanceof File
3099 ? ((File) ofile).getCanonicalPath()
3100 : ofile.toString());
3101 byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
3104 errorMessage = null;
3105 uniqueSetSuffix = null;
3107 viewportsAdded.clear();
3108 frefedSequence = null;
3110 if (HttpUtils.startsWithHttpOrHttps(file))
3112 url = new URL(file);
3114 final URL _url = url;
3115 return new jarInputStreamProvider()
3119 public JarInputStream getJarInputStream() throws IOException
3123 // jalview.bin.Console.outPrintln("Jalview2XML: opening byte
3124 // jarInputStream for
3125 // bytes.length=" + bytes.length);
3126 return new JarInputStream(new ByteArrayInputStream(bytes));
3130 // jalview.bin.Console.outPrintln("Jalview2XML: opening url
3131 // jarInputStream for "
3133 return new JarInputStream(_url.openStream());
3137 // jalview.bin.Console.outPrintln("Jalview2XML: opening file
3138 // jarInputStream for
3140 return new JarInputStream(new FileInputStream(file));
3145 public String getFilename()
3150 } catch (IOException e)
3152 e.printStackTrace();
3158 * Recover jalview session from a jalview project archive. Caller may
3159 * initialise uniqueSetSuffix, seqRefIds, viewportsAdded and frefedSequence
3160 * themselves. Any null fields will be initialised with default values,
3161 * non-null fields are left alone.
3166 public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
3168 errorMessage = null;
3169 if (uniqueSetSuffix == null)
3171 uniqueSetSuffix = System.currentTimeMillis() % 100000 + "";
3173 if (seqRefIds == null)
3177 AlignFrame af = null, _af = null;
3178 List<AlignFrame> toRepaint = new ArrayList<AlignFrame>();
3179 IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
3180 Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
3181 final String file = jprovider.getFilename();
3184 JarInputStream jin = null;
3185 JarEntry jarentry = null;
3190 jin = jprovider.getJarInputStream();
3191 for (int i = 0; i < entryCount; i++)
3193 jarentry = jin.getNextJarEntry();
3196 if (jarentry != null && jarentry.getName().endsWith(".xml"))
3198 JAXBContext jc = JAXBContext
3199 .newInstance("jalview.xml.binding.jalview");
3200 XMLStreamReader streamReader = XMLInputFactory.newInstance()
3201 .createXMLStreamReader(jin);
3202 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
3203 JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
3204 JalviewModel.class);
3205 JalviewModel object = jbe.getValue();
3207 if (true) // !skipViewport(object))
3209 _af = loadFromObject(object, file, true, jprovider);
3210 if (_af != null && object.getViewport().size() > 0)
3211 // getJalviewModelSequence().getViewportCount() > 0)
3216 // store a reference to the first view
3219 if (_af.getViewport().isGatherViewsHere())
3221 // if this is a gathered view, keep its reference since
3222 // after gathering views, only this frame will remain
3224 gatherToThisFrame.put(_af.getViewport().getSequenceSetId(),
3227 // Save dataset to register mappings once all resolved
3228 importedDatasets.put(
3229 af.getViewport().getAlignment().getDataset(),
3230 af.getViewport().getAlignment().getDataset());
3235 else if (jarentry != null)
3237 // Some other file here.
3240 } while (jarentry != null);
3242 resolveFrefedSequences();
3243 for (AlignFrame alignFrame : toRepaint)
3245 alignFrame.repaint();
3247 } catch (IOException ex)
3249 ex.printStackTrace();
3250 errorMessage = "Couldn't locate Jalview XML file : " + file;
3251 jalview.bin.Console.errPrintln(
3252 "Exception whilst loading jalview XML file : " + ex + "\n");
3253 } catch (Exception ex)
3256 .errPrintln("Parsing as Jalview Version 2 file failed.");
3257 ex.printStackTrace(System.err);
3258 if (attemptversion1parse)
3260 // used to attempt to parse as V1 castor-generated xml
3262 if (Desktop.instance != null)
3264 Desktop.instance.stopLoading();
3268 jalview.bin.Console.outPrintln("Successfully loaded archive file");
3271 ex.printStackTrace();
3273 jalview.bin.Console.errPrintln(
3274 "Exception whilst loading jalview XML file : " + ex + "\n");
3275 } catch (OutOfMemoryError e)
3277 // Don't use the OOM Window here
3278 errorMessage = "Out of memory loading jalview XML file";
3280 .errPrintln("Out of memory whilst loading jalview XML file");
3281 e.printStackTrace();
3285 * Regather multiple views (with the same sequence set id) to the frame (if
3286 * any) that is flagged as the one to gather to, i.e. convert them to tabbed
3287 * views instead of separate frames. Note this doesn't restore a state where
3288 * some expanded views in turn have tabbed views - the last "first tab" read
3289 * in will play the role of gatherer for all.
3291 for (AlignFrame fr : gatherToThisFrame.values())
3293 Desktop.instance.gatherViews(fr);
3296 restoreSplitFrames();
3297 for (AlignmentI ds : importedDatasets.keySet())
3299 if (ds.getCodonFrames() != null)
3301 StructureSelectionManager
3302 .getStructureSelectionManager(Desktop.instance)
3303 .registerMappings(ds.getCodonFrames());
3306 if (errorMessage != null)
3311 if (Desktop.instance != null)
3313 Desktop.instance.stopLoading();
3320 * Try to reconstruct and display SplitFrame windows, where each contains
3321 * complementary dna and protein alignments. Done by pairing up AlignFrame
3322 * objects (created earlier) which have complementary viewport ids associated.
3324 protected void restoreSplitFrames()
3326 List<SplitFrame> gatherTo = new ArrayList<>();
3327 List<AlignFrame> addedToSplitFrames = new ArrayList<>();
3328 Map<String, AlignFrame> dna = new HashMap<>();
3331 * Identify the DNA alignments
3333 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3336 AlignFrame af = candidate.getValue();
3337 if (af.getViewport().getAlignment().isNucleotide())
3339 dna.put(candidate.getKey().getId(), af);
3344 * Try to match up the protein complements
3346 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3349 AlignFrame af = candidate.getValue();
3350 if (!af.getViewport().getAlignment().isNucleotide())
3352 String complementId = candidate.getKey().getComplementId();
3353 // only non-null complements should be in the Map
3354 if (complementId != null && dna.containsKey(complementId))
3356 final AlignFrame dnaFrame = dna.get(complementId);
3357 SplitFrame sf = createSplitFrame(dnaFrame, af);
3358 addedToSplitFrames.add(dnaFrame);
3359 addedToSplitFrames.add(af);
3360 dnaFrame.setMenusForViewport();
3361 af.setMenusForViewport();
3362 if (af.getViewport().isGatherViewsHere())
3371 * Open any that we failed to pair up (which shouldn't happen!) as
3372 * standalone AlignFrame's.
3374 for (Entry<Viewport, AlignFrame> candidate : splitFrameCandidates
3377 AlignFrame af = candidate.getValue();
3378 if (!addedToSplitFrames.contains(af))
3380 Viewport view = candidate.getKey();
3381 Desktop.addInternalFrame(af, view.getTitle(),
3382 safeInt(view.getWidth()), safeInt(view.getHeight()));
3383 af.setMenusForViewport();
3384 jalview.bin.Console.errPrintln("Failed to restore view "
3385 + view.getTitle() + " to split frame");
3390 * Gather back into tabbed views as flagged.
3392 for (SplitFrame sf : gatherTo)
3394 Desktop.instance.gatherViews(sf);
3397 splitFrameCandidates.clear();
3401 * Construct and display one SplitFrame holding DNA and protein alignments.
3404 * @param proteinFrame
3407 protected SplitFrame createSplitFrame(AlignFrame dnaFrame,
3408 AlignFrame proteinFrame)
3410 SplitFrame splitFrame = new SplitFrame(dnaFrame, proteinFrame);
3411 String title = MessageManager.getString("label.linked_view_title");
3412 int width = (int) dnaFrame.getBounds().getWidth();
3413 int height = (int) (dnaFrame.getBounds().getHeight()
3414 + proteinFrame.getBounds().getHeight() + 50);
3417 * SplitFrame location is saved to both enclosed frames
3419 splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
3420 Desktop.addInternalFrame(splitFrame, title, width, height);
3423 * And compute cDNA consensus (couldn't do earlier with consensus as
3424 * mappings were not yet present)
3426 proteinFrame.getViewport().alignmentChanged(proteinFrame.alignPanel);
3432 * check errorMessage for a valid error message and raise an error box in the
3433 * GUI or write the current errorMessage to stderr and then clear the error
3436 protected void reportErrors()
3438 reportErrors(false);
3441 protected void reportErrors(final boolean saving)
3443 if (errorMessage != null)
3445 final String finalErrorMessage = errorMessage;
3448 javax.swing.SwingUtilities.invokeLater(new Runnable()
3453 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3455 "Error " + (saving ? "saving" : "loading")
3457 JvOptionPane.WARNING_MESSAGE);
3463 jalview.bin.Console.errPrintln(
3464 "Problem loading Jalview file: " + errorMessage);
3467 errorMessage = null;
3470 Map<String, String> alreadyLoadedPDB = new HashMap<>();
3473 * when set, local views will be updated from view stored in JalviewXML
3474 * Currently (28th Sep 2008) things will go horribly wrong in vamsas document
3475 * sync if this is set to true.
3477 private final boolean updateLocalViews = false;
3480 * Returns the path to a temporary file holding the PDB file for the given PDB
3481 * id. The first time of asking, searches for a file of that name in the
3482 * Jalview project jar, and copies it to a new temporary file. Any repeat
3483 * requests just return the path to the file previously created.
3489 String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
3492 if (alreadyLoadedPDB.containsKey(pdbId))
3494 return alreadyLoadedPDB.get(pdbId).toString();
3497 String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
3499 if (tempFile != null)
3501 alreadyLoadedPDB.put(pdbId, tempFile);
3507 * Copies the jar entry of given name to a new temporary file and returns the
3508 * path to the file, or null if the entry is not found.
3511 * @param jarEntryName
3513 * a prefix for the temporary file name, must be at least three
3515 * @param suffixModel
3516 * null or original file - so new file can be given the same suffix
3520 protected String copyJarEntry(jarInputStreamProvider jprovider,
3521 String jarEntryName, String prefix, String suffixModel)
3523 String suffix = ".tmp";
3524 if (suffixModel == null)
3526 suffixModel = jarEntryName;
3528 int sfpos = suffixModel.lastIndexOf(".");
3529 if (sfpos > -1 && sfpos < (suffixModel.length() - 1))
3531 suffix = "." + suffixModel.substring(sfpos + 1);
3534 try (JarInputStream jin = jprovider.getJarInputStream())
3536 JarEntry entry = null;
3539 entry = jin.getNextJarEntry();
3540 } while (entry != null && !entry.getName().equals(jarEntryName));
3544 // in = new BufferedReader(new InputStreamReader(jin, UTF_8));
3545 File outFile = File.createTempFile(prefix, suffix);
3546 outFile.deleteOnExit();
3547 try (OutputStream os = new FileOutputStream(outFile))
3551 String t = outFile.getAbsolutePath();
3557 "Couldn't find entry in Jalview Jar for " + jarEntryName);
3559 } catch (Exception ex)
3561 ex.printStackTrace();
3567 private class JvAnnotRow
3569 public JvAnnotRow(int i, AlignmentAnnotation jaa)
3576 * persisted version of annotation row from which to take vis properties
3578 public jalview.datamodel.AlignmentAnnotation template;
3581 * original position of the annotation row in the alignment
3587 * Load alignment frame from jalview XML DOM object
3589 * @param jalviewModel
3592 * filename source string
3593 * @param loadTreesAndStructures
3594 * when false only create Viewport
3596 * data source provider
3597 * @return alignment frame created from view stored in DOM
3599 AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
3600 boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
3602 SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
3604 List<Sequence> vamsasSeqs = vamsasSet.getSequence();
3606 // JalviewModelSequence jms = object.getJalviewModelSequence();
3608 // Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0)
3610 Viewport view = (jalviewModel.getViewport().size() > 0)
3611 ? jalviewModel.getViewport().get(0)
3614 // ////////////////////////////////
3615 // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
3618 // If we just load in the same jar file again, the sequenceSetId
3619 // will be the same, and we end up with multiple references
3620 // to the same sequenceSet. We must modify this id on load
3621 // so that each load of the file gives a unique id
3624 * used to resolve correct alignment dataset for alignments with multiple
3627 String uniqueSeqSetId = null;
3628 String viewId = null;
3631 uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
3632 viewId = (view.getId() == null ? null
3633 : view.getId() + uniqueSetSuffix);
3636 // ////////////////////////////////
3637 // LOAD MATRICES (IF ANY)
3639 if (vamsasSet.getMatrix() != null && vamsasSet.getMatrix().size() > 0)
3641 importMatrixData(vamsasSet.getMatrix());
3644 // ////////////////////////////////
3647 List<SequenceI> hiddenSeqs = null;
3649 List<SequenceI> tmpseqs = new ArrayList<>();
3651 boolean multipleView = false;
3652 SequenceI referenceseqForView = null;
3653 // JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
3654 List<JSeq> jseqs = jalviewModel.getJSeq();
3655 int vi = 0; // counter in vamsasSeq array
3656 for (int i = 0; i < jseqs.size(); i++)
3658 JSeq jseq = jseqs.get(i);
3659 String seqId = jseq.getId();
3661 SequenceI tmpSeq = seqRefIds.get(seqId);
3664 if (!incompleteSeqs.containsKey(seqId))
3666 // may not need this check, but keep it for at least 2.9,1 release
3667 if (tmpSeq.getStart() != jseq.getStart()
3668 || tmpSeq.getEnd() != jseq.getEnd())
3670 jalview.bin.Console.errPrintln(String.format(
3671 "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
3672 tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
3673 jseq.getStart(), jseq.getEnd()));
3678 incompleteSeqs.remove(seqId);
3680 if (vamsasSeqs.size() > vi
3681 && vamsasSeqs.get(vi).getId().equals(seqId))
3683 // most likely we are reading a dataset XML document so
3684 // update from vamsasSeq section of XML for this sequence
3685 tmpSeq.setName(vamsasSeqs.get(vi).getName());
3686 tmpSeq.setDescription(vamsasSeqs.get(vi).getDescription());
3687 tmpSeq.setSequence(vamsasSeqs.get(vi).getSequence());
3692 // reading multiple views, so vamsasSeq set is a subset of JSeq
3693 multipleView = true;
3695 tmpSeq.setStart(jseq.getStart());
3696 tmpSeq.setEnd(jseq.getEnd());
3697 tmpseqs.add(tmpSeq);
3701 Sequence vamsasSeq = vamsasSeqs.get(vi);
3702 tmpSeq = new jalview.datamodel.Sequence(vamsasSeq.getName(),
3703 vamsasSeq.getSequence());
3704 tmpSeq.setDescription(vamsasSeq.getDescription());
3705 tmpSeq.setStart(jseq.getStart());
3706 tmpSeq.setEnd(jseq.getEnd());
3707 tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
3708 seqRefIds.put(vamsasSeq.getId(), tmpSeq);
3709 tmpseqs.add(tmpSeq);
3713 if (safeBoolean(jseq.isViewreference()))
3715 referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
3718 if (jseq.isHidden() != null && jseq.isHidden().booleanValue())
3720 if (hiddenSeqs == null)
3722 hiddenSeqs = new ArrayList<>();
3725 hiddenSeqs.add(tmpSeq);
3730 // Create the alignment object from the sequence set
3731 // ///////////////////////////////
3732 SequenceI[] orderedSeqs = tmpseqs
3733 .toArray(new SequenceI[tmpseqs.size()]);
3735 AlignmentI al = null;
3736 // so we must create or recover the dataset alignment before going further
3737 // ///////////////////////////////
3738 if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
3740 // older jalview projects do not have a dataset - so creat alignment and
3742 al = new Alignment(orderedSeqs);
3743 al.setDataset(null);
3747 boolean isdsal = jalviewModel.getViewport().isEmpty();
3750 // we are importing a dataset record, so
3751 // recover reference to an alignment already materialsed as dataset
3752 al = getDatasetFor(vamsasSet.getDatasetId());
3756 // materialse the alignment
3757 al = new Alignment(orderedSeqs);
3761 addDatasetRef(vamsasSet.getDatasetId(), al);
3764 // finally, verify all data in vamsasSet is actually present in al
3765 // passing on flag indicating if it is actually a stored dataset
3766 recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
3769 if (referenceseqForView != null)
3771 al.setSeqrep(referenceseqForView);
3773 // / Add the alignment properties
3774 for (int i = 0; i < vamsasSet.getSequenceSetProperties().size(); i++)
3776 SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties()
3778 al.setProperty(ssp.getKey(), ssp.getValue());
3781 // ///////////////////////////////
3783 Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
3786 // load sequence features, database references and any associated PDB
3787 // structures for the alignment
3789 // prior to 2.10, this part would only be executed the first time a
3790 // sequence was encountered, but not afterwards.
3791 // now, for 2.10 projects, this is also done if the xml doc includes
3792 // dataset sequences not actually present in any particular view.
3794 for (int i = 0; i < vamsasSeqs.size(); i++)
3796 JSeq jseq = jseqs.get(i);
3797 if (jseq.getFeatures().size() > 0)
3799 List<Feature> features = jseq.getFeatures();
3800 for (int f = 0; f < features.size(); f++)
3802 Feature feat = features.get(f);
3803 SequenceFeature sf = new SequenceFeature(feat.getType(),
3804 feat.getDescription(), feat.getBegin(), feat.getEnd(),
3805 safeFloat(feat.getScore()), feat.getFeatureGroup());
3806 sf.setStatus(feat.getStatus());
3809 * load any feature attributes - include map-valued attributes
3811 Map<String, Map<String, String>> mapAttributes = new HashMap<>();
3812 for (int od = 0; od < feat.getOtherData().size(); od++)
3814 OtherData keyValue = feat.getOtherData().get(od);
3815 String attributeName = keyValue.getKey();
3816 String attributeValue = keyValue.getValue();
3817 if (attributeName.startsWith("LINK"))
3819 sf.addLink(attributeValue);
3823 String subAttribute = keyValue.getKey2();
3824 if (subAttribute == null)
3826 // simple string-valued attribute
3827 sf.setValue(attributeName, attributeValue);
3831 // attribute 'key' has sub-attribute 'key2'
3832 if (!mapAttributes.containsKey(attributeName))
3834 mapAttributes.put(attributeName, new HashMap<>());
3836 mapAttributes.get(attributeName).put(subAttribute,
3841 for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
3844 sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
3847 // adds feature to datasequence's feature set (since Jalview 2.10)
3848 al.getSequenceAt(i).addSequenceFeature(sf);
3851 if (vamsasSeqs.get(i).getDBRef().size() > 0)
3853 // adds dbrefs to datasequence's set (since Jalview 2.10)
3855 al.getSequenceAt(i).getDatasetSequence() == null
3856 ? al.getSequenceAt(i)
3857 : al.getSequenceAt(i).getDatasetSequence(),
3860 if (jseq.getPdbids().size() > 0)
3862 List<Pdbids> ids = jseq.getPdbids();
3863 for (int p = 0; p < ids.size(); p++)
3865 Pdbids pdbid = ids.get(p);
3866 jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
3867 entry.setId(pdbid.getId());
3868 if (pdbid.getType() != null)
3870 if (PDBEntry.Type.getType(pdbid.getType()) != null)
3872 entry.setType(PDBEntry.Type.getType(pdbid.getType()));
3876 entry.setType(PDBEntry.Type.FILE);
3879 // jprovider is null when executing 'New View'
3880 if (pdbid.getFile() != null && jprovider != null)
3882 if (!pdbloaded.containsKey(pdbid.getFile()))
3884 entry.setFile(loadPDBFile(jprovider, pdbid.getId(),
3889 entry.setFile(pdbloaded.get(pdbid.getId()).toString());
3893 if (pdbid.getPdbentryItem() != null)
3895 for (PdbentryItem item : pdbid.getPdbentryItem())
3897 for (Property pr : item.getProperty())
3899 entry.setProperty(pr.getName(), pr.getValue());
3904 for (Property prop : pdbid.getProperty())
3906 entry.setProperty(prop.getName(), prop.getValue());
3908 StructureSelectionManager
3909 .getStructureSelectionManager(Desktop.instance)
3910 .registerPDBEntry(entry);
3911 // adds PDBEntry to datasequence's set (since Jalview 2.10)
3912 if (al.getSequenceAt(i).getDatasetSequence() != null)
3914 al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
3918 al.getSequenceAt(i).addPDBId(entry);
3923 } // end !multipleview
3925 // ///////////////////////////////
3926 // LOAD SEQUENCE MAPPINGS
3928 if (vamsasSet.getAlcodonFrame().size() > 0)
3930 // TODO Potentially this should only be done once for all views of an
3932 List<AlcodonFrame> alc = vamsasSet.getAlcodonFrame();
3933 for (int i = 0; i < alc.size(); i++)
3935 AlignedCodonFrame cf = new AlignedCodonFrame();
3936 if (alc.get(i).getAlcodMap().size() > 0)
3938 List<AlcodMap> maps = alc.get(i).getAlcodMap();
3939 for (int m = 0; m < maps.size(); m++)
3941 AlcodMap map = maps.get(m);
3942 SequenceI dnaseq = seqRefIds.get(map.getDnasq());
3944 jalview.datamodel.Mapping mapping = null;
3945 // attach to dna sequence reference.
3946 if (map.getMapping() != null)
3948 mapping = addMapping(map.getMapping());
3949 if (dnaseq != null && mapping.getTo() != null)
3951 cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
3957 .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
3961 al.addCodonFrame(cf);
3966 // ////////////////////////////////
3968 List<JvAnnotRow> autoAlan = new ArrayList<>();
3971 * store any annotations which forward reference a group's ID
3973 Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
3975 if (vamsasSet.getAnnotation().size()/*Count()*/ > 0)
3977 List<Annotation> an = vamsasSet.getAnnotation();
3979 for (int i = 0; i < an.size(); i++)
3981 Annotation annotation = an.get(i);
3984 * test if annotation is automatically calculated for this view only
3986 boolean autoForView = false;
3987 if (annotation.getLabel().equals("Quality")
3988 || annotation.getLabel().equals("Conservation")
3989 || annotation.getLabel().equals("Consensus"))
3991 // Kludge for pre 2.5 projects which lacked the autocalculated flag
3993 // JAXB has no has() test; schema defaults value to false
3994 // if (!annotation.hasAutoCalculated())
3996 // annotation.setAutoCalculated(true);
3999 if (autoForView || annotation.isAutoCalculated())
4001 // remove ID - we don't recover annotation from other views for
4002 // view-specific annotation
4003 annotation.setId(null);
4006 // set visibility for other annotation in this view
4007 String annotationId = annotation.getId();
4008 if (annotationId != null && annotationIds.containsKey(annotationId))
4010 AlignmentAnnotation jda = annotationIds.get(annotationId);
4011 // in principle Visible should always be true for annotation displayed
4012 // in multiple views
4013 if (annotation.isVisible() != null)
4015 jda.visible = annotation.isVisible();
4018 al.addAnnotation(jda);
4022 // Construct new annotation from model.
4023 List<AnnotationElement> ae = annotation.getAnnotationElement();
4024 jalview.datamodel.Annotation[] anot = null;
4025 java.awt.Color firstColour = null;
4027 if (!annotation.isScoreOnly())
4029 anot = new jalview.datamodel.Annotation[al.getWidth()];
4030 for (int aa = 0; aa < ae.size() && aa < anot.length; aa++)
4032 AnnotationElement annElement = ae.get(aa);
4033 anpos = annElement.getPosition();
4035 if (anpos >= anot.length)
4040 float value = safeFloat(annElement.getValue());
4041 anot[anpos] = new jalview.datamodel.Annotation(
4042 annElement.getDisplayCharacter(),
4043 annElement.getDescription(),
4044 (annElement.getSecondaryStructure() == null
4045 || annElement.getSecondaryStructure()
4049 .getSecondaryStructure()
4052 anot[anpos].colour = new Color(safeInt(annElement.getColour()));
4053 if (firstColour == null)
4055 firstColour = anot[anpos].colour;
4059 jalview.datamodel.AlignmentAnnotation jaa = null;
4061 if (annotation.isGraph())
4063 float llim = 0, hlim = 0;
4064 // if (autoForView || an[i].isAutoCalculated()) {
4067 jaa = new jalview.datamodel.AlignmentAnnotation(
4068 annotation.getLabel(), annotation.getDescription(), anot,
4069 llim, hlim, safeInt(annotation.getGraphType()));
4071 jaa.graphGroup = safeInt(annotation.getGraphGroup());
4072 jaa._linecolour = firstColour;
4073 if (annotation.getThresholdLine() != null)
4075 jaa.setThreshold(new jalview.datamodel.GraphLine(
4076 safeFloat(annotation.getThresholdLine().getValue()),
4077 annotation.getThresholdLine().getLabel(),
4078 new java.awt.Color(safeInt(
4079 annotation.getThresholdLine().getColour()))));
4081 if (autoForView || annotation.isAutoCalculated())
4083 // Hardwire the symbol display line to ensure that labels for
4084 // histograms are displayed
4090 jaa = new jalview.datamodel.AlignmentAnnotation(
4091 annotation.getLabel(), annotation.getDescription(), anot);
4092 jaa._linecolour = firstColour;
4094 // register new annotation
4095 if (annotation.getId() != null)
4097 annotationIds.put(annotation.getId(), jaa);
4098 jaa.annotationId = annotation.getId();
4100 // recover sequence association
4101 String sequenceRef = annotation.getSequenceRef();
4102 if (sequenceRef != null)
4104 // from 2.9 sequenceRef is to sequence id (JAL-1781)
4105 SequenceI sequence = seqRefIds.get(sequenceRef);
4106 if (sequence == null)
4108 // in pre-2.9 projects sequence ref is to sequence name
4109 sequence = al.findName(sequenceRef);
4111 if (sequence != null)
4113 jaa.createSequenceMapping(sequence, 1, true);
4114 sequence.addAlignmentAnnotation(jaa);
4117 // and make a note of any group association
4118 if (annotation.getGroupRef() != null
4119 && annotation.getGroupRef().length() > 0)
4121 List<jalview.datamodel.AlignmentAnnotation> aal = groupAnnotRefs
4122 .get(annotation.getGroupRef());
4125 aal = new ArrayList<>();
4126 groupAnnotRefs.put(annotation.getGroupRef(), aal);
4131 if (annotation.getScore() != null)
4133 jaa.setScore(annotation.getScore().doubleValue());
4135 if (annotation.isVisible() != null)
4137 jaa.visible = annotation.isVisible().booleanValue();
4140 if (annotation.isCentreColLabels() != null)
4142 jaa.centreColLabels = annotation.isCentreColLabels()
4146 if (annotation.isScaleColLabels() != null)
4148 jaa.scaleColLabel = annotation.isScaleColLabels().booleanValue();
4150 if (annotation.isAutoCalculated())
4152 // newer files have an 'autoCalculated' flag and store calculation
4153 // state in viewport properties
4154 jaa.autoCalculated = true; // means annotation will be marked for
4155 // update at end of load.
4157 if (annotation.getGraphHeight() != null)
4159 jaa.graphHeight = annotation.getGraphHeight().intValue();
4161 jaa.belowAlignment = annotation.isBelowAlignment();
4162 jaa.setCalcId(annotation.getCalcId());
4163 if (annotation.getProperty().size() > 0)
4165 for (jalview.xml.binding.jalview.Property prop : annotation
4168 jaa.setProperty(prop.getName(), prop.getValue());
4171 if (jaa.graph == AlignmentAnnotation.CONTACT_MAP)
4173 if (annotation.getContactmatrix() != null
4174 && annotation.getContactmatrix().size() > 0)
4176 for (MapOnAMatrixType xmlmat : annotation.getContactmatrix())
4178 restoreMatrixFor(jaa.sequenceRef, jaa, xmlmat);
4183 if (jaa.autoCalculated)
4185 autoAlan.add(new JvAnnotRow(i, jaa));
4188 // if (!autoForView)
4190 // add autocalculated group annotation and any user created annotation
4192 al.addAnnotation(jaa);
4196 // ///////////////////////
4198 // Create alignment markup and styles for this view
4199 if (jalviewModel.getJGroup().size() > 0)
4201 List<JGroup> groups = jalviewModel.getJGroup();
4202 boolean addAnnotSchemeGroup = false;
4203 for (int i = 0; i < groups.size(); i++)
4205 JGroup jGroup = groups.get(i);
4206 ColourSchemeI cs = null;
4207 if (jGroup.getColour() != null)
4209 if (jGroup.getColour().startsWith("ucs"))
4211 cs = getUserColourScheme(jalviewModel, jGroup.getColour());
4213 else if (jGroup.getColour().equals("AnnotationColourGradient")
4214 && jGroup.getAnnotationColours() != null)
4216 addAnnotSchemeGroup = true;
4220 cs = ColourSchemeProperty.getColourScheme(null, al,
4221 jGroup.getColour());
4224 int pidThreshold = safeInt(jGroup.getPidThreshold());
4226 Vector<SequenceI> seqs = new Vector<>();
4228 for (int s = 0; s < jGroup.getSeq().size(); s++)
4230 String seqId = jGroup.getSeq().get(s);
4231 SequenceI ts = seqRefIds.get(seqId);
4235 seqs.addElement(ts);
4239 if (seqs.size() < 1)
4244 SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
4245 safeBoolean(jGroup.isDisplayBoxes()),
4246 safeBoolean(jGroup.isDisplayText()),
4247 safeBoolean(jGroup.isColourText()),
4248 safeInt(jGroup.getStart()), safeInt(jGroup.getEnd()));
4249 sg.getGroupColourScheme().setThreshold(pidThreshold, true);
4250 sg.getGroupColourScheme()
4251 .setConservationInc(safeInt(jGroup.getConsThreshold()));
4252 sg.setOutlineColour(new Color(safeInt(jGroup.getOutlineColour())));
4254 sg.textColour = new Color(safeInt(jGroup.getTextCol1()));
4255 sg.textColour2 = new Color(safeInt(jGroup.getTextCol2()));
4256 sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
4257 sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
4258 // attributes with a default in the schema are never null
4259 sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
4260 sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
4261 sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
4262 sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
4263 if (jGroup.getConsThreshold() != null
4264 && jGroup.getConsThreshold().intValue() != 0)
4266 Conservation c = new Conservation("All", sg.getSequences(null), 0,
4269 c.verdict(false, 25);
4270 sg.cs.setConservation(c);
4273 if (jGroup.getId() != null && groupAnnotRefs.size() > 0)
4275 // re-instate unique group/annotation row reference
4276 List<AlignmentAnnotation> jaal = groupAnnotRefs
4277 .get(jGroup.getId());
4280 for (AlignmentAnnotation jaa : jaal)
4283 if (jaa.autoCalculated)
4285 // match up and try to set group autocalc alignment row for this
4287 if (jaa.label.startsWith("Consensus for "))
4289 sg.setConsensus(jaa);
4291 // match up and try to set group autocalc alignment row for this
4293 if (jaa.label.startsWith("Conservation for "))
4295 sg.setConservationRow(jaa);
4302 if (addAnnotSchemeGroup)
4304 // reconstruct the annotation colourscheme
4306 constructAnnotationColour(jGroup.getAnnotationColours(),
4307 null, al, jalviewModel, false));
4313 // only dataset in this model, so just return.
4316 // ///////////////////////////////
4319 AlignFrame af = null;
4320 AlignViewport av = null;
4321 // now check to see if we really need to create a new viewport.
4322 if (multipleView && viewportsAdded.size() == 0)
4324 // We recovered an alignment for which a viewport already exists.
4325 // TODO: fix up any settings necessary for overlaying stored state onto
4326 // state recovered from another document. (may not be necessary).
4327 // we may need a binding from a viewport in memory to one recovered from
4329 // and then recover its containing af to allow the settings to be applied.
4330 // TODO: fix for vamsas demo
4331 jalview.bin.Console.errPrintln(
4332 "About to recover a viewport for existing alignment: Sequence set ID is "
4334 Object seqsetobj = retrieveExistingObj(uniqueSeqSetId);
4335 if (seqsetobj != null)
4337 if (seqsetobj instanceof String)
4339 uniqueSeqSetId = (String) seqsetobj;
4340 jalview.bin.Console.errPrintln(
4341 "Recovered extant sequence set ID mapping for ID : New Sequence set ID is "
4346 jalview.bin.Console.errPrintln(
4347 "Warning : Collision between sequence set ID string and existing jalview object mapping.");
4353 * indicate that annotation colours are applied across all groups (pre
4354 * Jalview 2.8.1 behaviour)
4356 boolean doGroupAnnColour = Jalview2XML.isVersionStringLaterThan("2.8.1",
4357 jalviewModel.getVersion());
4359 AlignmentPanel ap = null;
4360 boolean isnewview = true;
4363 // Check to see if this alignment already has a view id == viewId
4364 jalview.gui.AlignmentPanel views[] = Desktop
4365 .getAlignmentPanels(uniqueSeqSetId);
4366 if (views != null && views.length > 0)
4368 for (int v = 0; v < views.length; v++)
4370 if (views[v].av.getViewId().equalsIgnoreCase(viewId))
4372 // recover the existing alignpanel, alignframe, viewport
4373 af = views[v].alignFrame;
4376 // TODO: could even skip resetting view settings if we don't want to
4377 // change the local settings from other jalview processes
4386 af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
4387 uniqueSeqSetId, viewId, autoAlan);
4388 av = af.getViewport();
4393 * Load any trees, PDB structures and viewers, Overview
4395 * Not done if flag is false (when this method is used for New View)
4397 if (loadTreesAndStructures)
4399 loadTrees(jalviewModel, view, af, av, ap);
4400 loadPCAViewers(jalviewModel, ap);
4401 loadPDBStructures(jprovider, jseqs, af, ap);
4402 loadRnaViewers(jprovider, jseqs, ap);
4403 loadOverview(view, jalviewModel.getVersion(), af);
4405 // and finally return.
4409 private void importMatrixData(List<MatrixType> xmlmatrices)
4411 for (MatrixType xmlmat : xmlmatrices)
4413 if (!PAEContactMatrix.PAEMATRIX.equals(xmlmat.getType()))
4415 Console.error("Ignoring matrix '" + xmlmat.getId() + "' of type '"
4416 + xmlmat.getType());
4420 if (!xmlmat.getRows().equals(xmlmat.getCols()))
4422 Console.error("Can't handle non square matrices");
4426 float[][] elements = ContactMatrix.fromFloatStringToContacts(
4427 xmlmat.getElements(), xmlmat.getCols().intValue(),
4428 xmlmat.getRows().intValue());
4430 List<BitSet> newgroups = new ArrayList<BitSet>();
4431 if (xmlmat.getGroups().size() > 0)
4433 for (String sgroup : xmlmat.getGroups())
4435 newgroups.add(deStringifyBitset(sgroup));
4438 String nwk = xmlmat.getNewick().size() > 0 ? xmlmat.getNewick().get(0)
4440 if (xmlmat.getNewick().size() > 1)
4443 .info("Ignoring additional clusterings for contact matrix");
4445 String treeMethod = xmlmat.getTreeMethod();
4446 double thresh = xmlmat.getCutHeight() != null ? xmlmat.getCutHeight()
4448 GroupSet grpset = new GroupSet();
4449 grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
4451 FloatContactMatrix newcm = new FloatContactMatrix(elements, grpset);
4452 contactMatrixRefs.put(xmlmat.getId(), newcm);
4453 Console.trace("Restored base contact matrix " + xmlmat.getId());
4457 private void restoreMatrixFor(SequenceI sequenceRef,
4458 AlignmentAnnotation jaa, MapOnAMatrixType xmlmatmapping)
4460 // restore mapping data to matrix data
4461 jalview.util.MapList mapping = null;
4462 if (xmlmatmapping.getMapping() != null)
4464 MapListType m = xmlmatmapping.getMapping();
4465 // Mapping m = dr.getMapping();
4466 int fr[] = new int[m.getMapListFrom().size() * 2];
4467 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
4468 for (int _i = 0; from.hasNext(); _i += 2)
4470 MapListFrom mf = from.next();
4471 fr[_i] = mf.getStart();
4472 fr[_i + 1] = mf.getEnd();
4474 int fto[] = new int[m.getMapListTo().size() * 2];
4475 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
4476 for (int _i = 0; to.hasNext(); _i += 2)
4478 MapListTo mf = to.next();
4479 fto[_i] = mf.getStart();
4480 fto[_i + 1] = mf.getEnd();
4483 mapping = new jalview.util.MapList(fr, fto,
4484 m.getMapFromUnit().intValue(), m.getMapToUnit().intValue());
4487 // locate matrix data in project XML and import
4488 ContactMatrixI cm = contactMatrixRefs.get(xmlmatmapping.getMatrix());
4492 .add(newMatrixFref(xmlmatmapping.getMatrix(), mapping, jaa));
4496 // create the PAEMatrix now
4497 PAEContactMatrix newpae = new PAEContactMatrix(jaa.sequenceRef,
4500 jaa.sequenceRef.addContactListFor(jaa, newpae);
4507 * Load Overview window, restoring colours, 'show hidden regions' flag, title
4508 * and geometry as saved
4513 protected void loadOverview(Viewport view, String version, AlignFrame af)
4515 if (!isVersionStringLaterThan("2.11.3", version)
4516 && view.getOverview() == null)
4521 * first close any Overview that was opened automatically
4522 * (if so configured in Preferences) so that the view is
4523 * restored in the same state as saved
4525 af.alignPanel.closeOverviewPanel();
4527 Overview overview = view.getOverview();
4528 if (overview != null)
4530 OverviewPanel overviewPanel = af
4531 .openOverviewPanel(overview.isShowHidden());
4532 overviewPanel.setTitle(overview.getTitle());
4533 overviewPanel.setFrameBounds(overview.getXpos(), overview.getYpos(),
4534 overview.getWidth(), overview.getHeight());
4535 Color gap = new Color(overview.getGapColour());
4536 Color residue = new Color(overview.getResidueColour());
4537 Color hidden = new Color(overview.getHiddenColour());
4538 overviewPanel.getCanvas().setColours(gap, residue, hidden);
4543 * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
4544 * panel is restored from separate jar entries, two (gapped and trimmed) per
4545 * sequence and secondary structure.
4547 * Currently each viewer shows just one sequence and structure (gapped and
4548 * trimmed), however this method is designed to support multiple sequences or
4549 * structures in viewers if wanted in future.
4555 private void loadRnaViewers(jarInputStreamProvider jprovider,
4556 List<JSeq> jseqs, AlignmentPanel ap)
4559 * scan the sequences for references to viewers; create each one the first
4560 * time it is referenced, add Rna models to existing viewers
4562 for (JSeq jseq : jseqs)
4564 for (int i = 0; i < jseq.getRnaViewer().size(); i++)
4566 RnaViewer viewer = jseq.getRnaViewer().get(i);
4567 AppVarna appVarna = findOrCreateVarnaViewer(viewer, uniqueSetSuffix,
4570 for (int j = 0; j < viewer.getSecondaryStructure().size(); j++)
4572 SecondaryStructure ss = viewer.getSecondaryStructure().get(j);
4573 SequenceI seq = seqRefIds.get(jseq.getId());
4574 AlignmentAnnotation ann = this.annotationIds
4575 .get(ss.getAnnotationId());
4578 * add the structure to the Varna display (with session state copied
4579 * from the jar to a temporary file)
4581 boolean gapped = safeBoolean(ss.isGapped());
4582 String rnaTitle = ss.getTitle();
4583 String sessionState = ss.getViewerState();
4584 String tempStateFile = copyJarEntry(jprovider, sessionState,
4586 RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
4587 appVarna.addModelSession(rna, rnaTitle, tempStateFile);
4589 appVarna.setInitialSelection(safeInt(viewer.getSelectedRna()));
4595 * Locate and return an already instantiated matching AppVarna, or create one
4599 * @param viewIdSuffix
4603 protected AppVarna findOrCreateVarnaViewer(RnaViewer viewer,
4604 String viewIdSuffix, AlignmentPanel ap)
4607 * on each load a suffix is appended to the saved viewId, to avoid conflicts
4608 * if load is repeated
4610 String postLoadId = viewer.getViewId() + viewIdSuffix;
4611 for (JInternalFrame frame : getAllFrames())
4613 if (frame instanceof AppVarna)
4615 AppVarna varna = (AppVarna) frame;
4616 if (postLoadId.equals(varna.getViewId()))
4618 // this viewer is already instantiated
4619 // could in future here add ap as another 'parent' of the
4620 // AppVarna window; currently just 1-to-many
4627 * viewer not found - make it
4629 RnaViewerModel model = new RnaViewerModel(postLoadId, viewer.getTitle(),
4630 safeInt(viewer.getXpos()), safeInt(viewer.getYpos()),
4631 safeInt(viewer.getWidth()), safeInt(viewer.getHeight()),
4632 safeInt(viewer.getDividerLocation()));
4633 AppVarna varna = new AppVarna(model, ap);
4639 * Load any saved trees
4647 protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
4648 AlignViewport av, AlignmentPanel ap)
4650 // TODO result of automated refactoring - are all these parameters needed?
4653 for (int t = 0; t < jm.getTree().size(); t++)
4656 Tree tree = jm.getTree().get(t);
4658 TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
4661 if (tree.isColumnWise())
4663 AlignmentAnnotation aa = annotationIds
4664 .get(tree.getColumnReference());
4668 "Null alignment annotation when restoring columnwise tree");
4670 tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
4671 tree.getTitle(), safeInt(tree.getWidth()),
4672 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4673 safeInt(tree.getYpos()));
4678 tp = af.showNewickTree(new NewickFile(tree.getNewick()),
4679 tree.getTitle(), safeInt(tree.getWidth()),
4680 safeInt(tree.getHeight()), safeInt(tree.getXpos()),
4681 safeInt(tree.getYpos()));
4683 if (tree.getId() != null)
4685 // perhaps bind the tree id to something ?
4690 // update local tree attributes ?
4691 // TODO: should check if tp has been manipulated by user - if so its
4692 // settings shouldn't be modified
4693 tp.setTitle(tree.getTitle());
4694 tp.setBounds(new Rectangle(safeInt(tree.getXpos()),
4695 safeInt(tree.getYpos()), safeInt(tree.getWidth()),
4696 safeInt(tree.getHeight())));
4697 tp.setViewport(av); // af.viewport;
4698 // TODO: verify 'associate with all views' works still
4699 tp.getTreeCanvas().setViewport(av); // af.viewport;
4700 tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
4702 tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
4706 "There was a problem recovering stored Newick tree: \n"
4707 + tree.getNewick());
4711 tp.fitToWindow.setState(safeBoolean(tree.isFitToWindow()));
4712 tp.fitToWindow_actionPerformed(null);
4714 if (tree.getFontName() != null)
4717 new Font(tree.getFontName(), safeInt(tree.getFontStyle()),
4718 safeInt(tree.getFontSize())));
4723 new Font(view.getFontName(), safeInt(view.getFontStyle()),
4724 safeInt(view.getFontSize())));
4727 tp.showPlaceholders(safeBoolean(tree.isMarkUnlinked()));
4728 tp.showBootstrap(safeBoolean(tree.isShowBootstrap()));
4729 tp.showDistances(safeBoolean(tree.isShowDistances()));
4731 tp.getTreeCanvas().setThreshold(safeFloat(tree.getThreshold()));
4733 if (safeBoolean(tree.isCurrentTree()))
4735 af.getViewport().setCurrentTree(tp.getTree());
4739 } catch (Exception ex)
4741 ex.printStackTrace();
4746 * Load and link any saved structure viewers.
4753 protected void loadPDBStructures(jarInputStreamProvider jprovider,
4754 List<JSeq> jseqs, AlignFrame af, AlignmentPanel ap)
4757 * Run through all PDB ids on the alignment, and collect mappings between
4758 * distinct view ids and all sequences referring to that view.
4760 Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
4762 for (int i = 0; i < jseqs.size(); i++)
4764 JSeq jseq = jseqs.get(i);
4765 if (jseq.getPdbids().size() > 0)
4767 List<Pdbids> ids = jseq.getPdbids();
4768 for (int p = 0; p < ids.size(); p++)
4770 Pdbids pdbid = ids.get(p);
4771 final int structureStateCount = pdbid.getStructureState().size();
4772 for (int s = 0; s < structureStateCount; s++)
4774 // check to see if we haven't already created this structure view
4775 final StructureState structureState = pdbid.getStructureState()
4777 String sviewid = (structureState.getViewId() == null) ? null
4778 : structureState.getViewId() + uniqueSetSuffix;
4779 jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
4780 // Originally : pdbid.getFile()
4781 // : TODO: verify external PDB file recovery still works in normal
4782 // jalview project load
4784 loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()));
4785 jpdb.setId(pdbid.getId());
4787 int x = safeInt(structureState.getXpos());
4788 int y = safeInt(structureState.getYpos());
4789 int width = safeInt(structureState.getWidth());
4790 int height = safeInt(structureState.getHeight());
4792 // Probably don't need to do this anymore...
4793 // Desktop.desktop.getComponentAt(x, y);
4794 // TODO: NOW: check that this recovers the PDB file correctly.
4795 String pdbFile = loadPDBFile(jprovider, pdbid.getId(),
4797 jalview.datamodel.SequenceI seq = seqRefIds
4798 .get(jseq.getId() + "");
4799 if (sviewid == null)
4801 sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width + ","
4804 if (!structureViewers.containsKey(sviewid))
4806 String viewerType = structureState.getType();
4807 if (viewerType == null) // pre Jalview 2.9
4809 viewerType = ViewerType.JMOL.toString();
4811 structureViewers.put(sviewid,
4812 new StructureViewerModel(x, y, width, height, false,
4813 false, true, structureState.getViewId(),
4815 // Legacy pre-2.7 conversion JAL-823 :
4816 // do not assume any view has to be linked for colour by
4820 // assemble String[] { pdb files }, String[] { id for each
4821 // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
4822 // seqs_file 2}, boolean[] {
4823 // linkAlignPanel,superposeWithAlignpanel}} from hash
4824 StructureViewerModel jmoldat = structureViewers.get(sviewid);
4825 jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
4826 || structureState.isAlignwithAlignPanel());
4829 * Default colour by linked panel to false if not specified (e.g.
4830 * for pre-2.7 projects)
4832 boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
4833 colourWithAlignPanel |= structureState.isColourwithAlignPanel();
4834 jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
4837 * Default colour by viewer to true if not specified (e.g. for
4840 boolean colourByViewer = jmoldat.isColourByViewer();
4841 colourByViewer &= structureState.isColourByJmol();
4842 jmoldat.setColourByViewer(colourByViewer);
4844 if (jmoldat.getStateData().length() < structureState.getValue()
4845 /*Content()*/.length())
4847 jmoldat.setStateData(structureState.getValue());// Content());
4849 if (pdbid.getFile() != null)
4851 File mapkey = new File(pdbid.getFile());
4852 StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
4853 if (seqstrmaps == null)
4855 jmoldat.getFileData().put(mapkey,
4856 seqstrmaps = jmoldat.new StructureData(pdbFile,
4859 if (!seqstrmaps.getSeqList().contains(seq))
4861 seqstrmaps.getSeqList().add(seq);
4867 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");
4868 Console.warn(errorMessage);
4874 // Instantiate the associated structure views
4875 for (Entry<String, StructureViewerModel> entry : structureViewers
4880 createOrLinkStructureViewer(entry, af, ap, jprovider);
4881 } catch (Exception e)
4883 jalview.bin.Console.errPrintln(
4884 "Error loading structure viewer: " + e.getMessage());
4885 // failed - try the next one
4897 protected void createOrLinkStructureViewer(
4898 Entry<String, StructureViewerModel> viewerData, AlignFrame af,
4899 AlignmentPanel ap, jarInputStreamProvider jprovider)
4901 final StructureViewerModel stateData = viewerData.getValue();
4904 * Search for any viewer windows already open from other alignment views
4905 * that exactly match the stored structure state
4907 StructureViewerBase comp = findMatchingViewer(viewerData);
4911 linkStructureViewer(ap, comp, stateData);
4915 String type = stateData.getType();
4918 ViewerType viewerType = ViewerType.valueOf(type);
4919 createStructureViewer(viewerType, viewerData, af, jprovider);
4920 } catch (IllegalArgumentException | NullPointerException e)
4922 // TODO JAL-3619 show error dialog / offer an alternative viewer
4923 Console.error("Invalid structure viewer type: " + type);
4928 * Generates a name for the entry in the project jar file to hold state
4929 * information for a structure viewer
4934 protected String getViewerJarEntryName(String viewId)
4936 return VIEWER_PREFIX + viewId;
4940 * Returns any open frame that matches given structure viewer data. The match
4941 * is based on the unique viewId, or (for older project versions) the frame's
4947 protected StructureViewerBase findMatchingViewer(
4948 Entry<String, StructureViewerModel> viewerData)
4950 final String sviewid = viewerData.getKey();
4951 final StructureViewerModel svattrib = viewerData.getValue();
4952 StructureViewerBase comp = null;
4953 JInternalFrame[] frames = getAllFrames();
4954 for (JInternalFrame frame : frames)
4956 if (frame instanceof StructureViewerBase)
4959 * Post jalview 2.4 schema includes structure view id
4961 if (sviewid != null && ((StructureViewerBase) frame).getViewId()
4964 comp = (StructureViewerBase) frame;
4965 break; // break added in 2.9
4968 * Otherwise test for matching position and size of viewer frame
4970 else if (frame.getX() == svattrib.getX()
4971 && frame.getY() == svattrib.getY()
4972 && frame.getHeight() == svattrib.getHeight()
4973 && frame.getWidth() == svattrib.getWidth())
4975 comp = (StructureViewerBase) frame;
4976 // no break in faint hope of an exact match on viewId
4984 * Link an AlignmentPanel to an existing structure viewer.
4989 * @param useinViewerSuperpos
4990 * @param usetoColourbyseq
4991 * @param viewerColouring
4993 protected void linkStructureViewer(AlignmentPanel ap,
4994 StructureViewerBase viewer, StructureViewerModel stateData)
4996 // NOTE: if the jalview project is part of a shared session then
4997 // view synchronization should/could be done here.
4999 final boolean useinViewerSuperpos = stateData.isAlignWithPanel();
5000 final boolean usetoColourbyseq = stateData.isColourWithAlignPanel();
5001 final boolean viewerColouring = stateData.isColourByViewer();
5002 Map<File, StructureData> oldFiles = stateData.getFileData();
5005 * Add mapping for sequences in this view to an already open viewer
5007 final AAStructureBindingModel binding = viewer.getBinding();
5008 for (File id : oldFiles.keySet())
5010 // add this and any other pdb files that should be present in the
5012 StructureData filedat = oldFiles.get(id);
5013 String pdbFile = filedat.getFilePath();
5014 SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
5015 binding.getSsm().setMapping(seq, null, pdbFile, DataSourceType.FILE,
5017 binding.addSequenceForStructFile(pdbFile, seq);
5019 // and add the AlignmentPanel's reference to the view panel
5020 viewer.addAlignmentPanel(ap);
5021 if (useinViewerSuperpos)
5023 viewer.useAlignmentPanelForSuperposition(ap);
5027 viewer.excludeAlignmentPanelForSuperposition(ap);
5029 if (usetoColourbyseq)
5031 viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
5035 viewer.excludeAlignmentPanelForColourbyseq(ap);
5040 * Get all frames within the Desktop.
5044 protected JInternalFrame[] getAllFrames()
5046 JInternalFrame[] frames = null;
5047 // TODO is this necessary - is it safe - risk of hanging?
5052 frames = Desktop.desktop.getAllFrames();
5053 } catch (ArrayIndexOutOfBoundsException e)
5055 // occasional No such child exceptions are thrown here...
5059 } catch (InterruptedException f)
5063 } while (frames == null);
5068 * Answers true if 'version' is equal to or later than 'supported', where each
5069 * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
5070 * changes. Development and test values for 'version' are leniently treated
5074 * - minimum version we are comparing against
5076 * - version of data being processsed
5077 * @return true if version is equal to or later than supported
5079 public static boolean isVersionStringLaterThan(String supported,
5082 if (supported == null || version == null
5083 || version.equalsIgnoreCase("DEVELOPMENT BUILD")
5084 || version.equalsIgnoreCase("Test")
5085 || version.equalsIgnoreCase("AUTOMATED BUILD"))
5087 jalview.bin.Console.errPrintln("Assuming project file with "
5088 + (version == null ? "null" : version)
5089 + " is compatible with Jalview version " + supported);
5094 return StringUtils.compareVersions(version, supported, "b") >= 0;
5098 Vector<JalviewStructureDisplayI> newStructureViewers = null;
5100 protected void addNewStructureViewer(JalviewStructureDisplayI sview)
5102 if (newStructureViewers != null)
5104 sview.getBinding().setFinishedLoadingFromArchive(false);
5105 newStructureViewers.add(sview);
5109 protected void setLoadingFinishedForNewStructureViewers()
5111 if (newStructureViewers != null)
5113 for (JalviewStructureDisplayI sview : newStructureViewers)
5115 sview.getBinding().setFinishedLoadingFromArchive(true);
5117 newStructureViewers.clear();
5118 newStructureViewers = null;
5122 AlignFrame loadViewport(String file, List<JSeq> JSEQ,
5123 List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
5124 Viewport view, String uniqueSeqSetId, String viewId,
5125 List<JvAnnotRow> autoAlan)
5127 AlignFrame af = null;
5128 af = new AlignFrame(al, safeInt(view.getWidth()),
5129 safeInt(view.getHeight()), uniqueSeqSetId, viewId)
5133 // protected void processKeyEvent(java.awt.event.KeyEvent e) {
5134 // jalview.bin.Console.outPrintln("Jalview2XML AF " + e);
5135 // super.processKeyEvent(e);
5142 af.setFileName(file, FileFormat.Jalview);
5144 final AlignViewport viewport = af.getViewport();
5145 for (int i = 0; i < JSEQ.size(); i++)
5147 int colour = safeInt(JSEQ.get(i).getColour());
5148 viewport.setSequenceColour(viewport.getAlignment().getSequenceAt(i),
5154 viewport.setColourByReferenceSeq(true);
5155 viewport.setDisplayReferenceSeq(true);
5158 viewport.setGatherViewsHere(safeBoolean(view.isGatheredViews()));
5160 if (view.getSequenceSetId() != null)
5162 AlignmentViewport av = viewportsAdded.get(uniqueSeqSetId);
5164 viewport.setSequenceSetId(uniqueSeqSetId);
5167 // propagate shared settings to this new view
5168 viewport.setHistoryList(av.getHistoryList());
5169 viewport.setRedoList(av.getRedoList());
5173 viewportsAdded.put(uniqueSeqSetId, viewport);
5175 // TODO: check if this method can be called repeatedly without
5176 // side-effects if alignpanel already registered.
5177 PaintRefresher.Register(af.alignPanel, uniqueSeqSetId);
5179 // apply Hidden regions to view.
5180 if (hiddenSeqs != null)
5182 for (int s = 0; s < JSEQ.size(); s++)
5184 SequenceGroup hidden = new SequenceGroup();
5185 boolean isRepresentative = false;
5186 for (int r = 0; r < JSEQ.get(s).getHiddenSequences().size(); r++)
5188 isRepresentative = true;
5189 SequenceI sequenceToHide = al
5190 .getSequenceAt(JSEQ.get(s).getHiddenSequences().get(r));
5191 hidden.addSequence(sequenceToHide, false);
5192 // remove from hiddenSeqs list so we don't try to hide it twice
5193 hiddenSeqs.remove(sequenceToHide);
5195 if (isRepresentative)
5197 SequenceI representativeSequence = al.getSequenceAt(s);
5198 hidden.addSequence(representativeSequence, false);
5199 viewport.hideRepSequences(representativeSequence, hidden);
5203 SequenceI[] hseqs = hiddenSeqs
5204 .toArray(new SequenceI[hiddenSeqs.size()]);
5205 viewport.hideSequence(hseqs);
5208 // recover view properties and display parameters
5210 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5211 viewport.setAbovePIDThreshold(safeBoolean(view.isPidSelected()));
5212 final int pidThreshold = safeInt(view.getPidThreshold());
5213 viewport.setThreshold(pidThreshold);
5215 viewport.setColourText(safeBoolean(view.isShowColourText()));
5217 viewport.setConservationSelected(
5218 safeBoolean(view.isConservationSelected()));
5219 viewport.setIncrement(safeInt(view.getConsThreshold()));
5220 viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
5221 viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
5223 new Font(view.getFontName(), safeInt(view.getFontStyle()),
5224 safeInt(view.getFontSize())),
5225 (view.getCharWidth() != null) ? false : true);
5226 if (view.getCharWidth() != null)
5228 viewport.setCharWidth(view.getCharWidth());
5229 viewport.setCharHeight(view.getCharHeight());
5231 ViewStyleI vs = viewport.getViewStyle();
5232 vs.setScaleProteinAsCdna(view.isScaleProteinAsCdna());
5233 viewport.setViewStyle(vs);
5234 // TODO: allow custom charWidth/Heights to be restored by updating them
5235 // after setting font - which means set above to false
5236 viewport.setRenderGaps(safeBoolean(view.isRenderGaps()));
5237 viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
5238 viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
5240 viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
5242 viewport.setShowText(safeBoolean(view.isShowText()));
5244 viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
5245 viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
5246 viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
5247 viewport.setShowUnconserved(view.isShowUnconserved());
5248 viewport.getRanges().setStartRes(safeInt(view.getStartRes()));
5250 if (view.getViewName() != null)
5252 viewport.setViewName(view.getViewName());
5253 af.setInitialTabVisible();
5255 af.setBounds(safeInt(view.getXpos()), safeInt(view.getYpos()),
5256 safeInt(view.getWidth()), safeInt(view.getHeight()));
5258 af.alignPanel.fontChanged(); // make sure font is updated *before* we set ID
5260 if (view.getIdWidth() == null)
5262 if (!isVersionStringLaterThan("2.11.3", jm.getVersion()))
5264 // Pre 2.11.3 jalview projects do not store the id width
5265 // idWidth was also calculated in a different way.
5266 viewport.setIdWidth(af.alignPanel.getLegacyIdWidth());
5267 af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(true);
5272 viewport.setIdWidth(view.getIdWidth());
5273 af.alignPanel.getIdPanel().getIdCanvas()
5274 .setManuallyAdjusted(view.isIdWidthManuallyAdjusted());
5277 // startSeq set in af.alignPanel.updateLayout below
5278 af.alignPanel.updateLayout();
5279 ColourSchemeI cs = null;
5280 // apply colourschemes
5281 if (view.getBgColour() != null)
5283 if (view.getBgColour().startsWith("ucs"))
5285 cs = getUserColourScheme(jm, view.getBgColour());
5287 else if (view.getBgColour().startsWith("Annotation"))
5289 AnnotationColourScheme viewAnnColour = view.getAnnotationColours();
5290 cs = constructAnnotationColour(viewAnnColour, af, al, jm, true);
5297 cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5298 view.getBgColour());
5303 * turn off 'alignment colour applies to all groups'
5304 * while restoring global colour scheme
5306 viewport.setColourAppliesToAllGroups(false);
5307 viewport.setGlobalColourScheme(cs);
5308 viewport.getResidueShading().setThreshold(pidThreshold,
5309 view.isIgnoreGapsinConsensus());
5310 viewport.getResidueShading()
5311 .setConsensus(viewport.getSequenceConsensusHash());
5312 if (safeBoolean(view.isConservationSelected()) && cs != null)
5314 viewport.getResidueShading()
5315 .setConservationInc(safeInt(view.getConsThreshold()));
5317 af.changeColour(cs);
5318 viewport.setColourAppliesToAllGroups(true);
5320 viewport.setShowSequenceFeatures(
5321 safeBoolean(view.isShowSequenceFeatures()));
5323 viewport.setCentreColumnLabels(view.isCentreColumnLabels());
5324 viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
5325 viewport.setFollowHighlight(view.isFollowHighlight());
5326 viewport.followSelection = view.isFollowSelection();
5327 viewport.setShowConsensusHistogram(view.isShowConsensusHistogram());
5328 viewport.setShowSequenceLogo(view.isShowSequenceLogo());
5329 viewport.setNormaliseSequenceLogo(view.isNormaliseSequenceLogo());
5330 viewport.setShowDBRefs(safeBoolean(view.isShowDbRefTooltip()));
5331 viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
5332 viewport.setShowGroupConsensus(view.isShowGroupConsensus());
5333 viewport.setShowGroupConservation(view.isShowGroupConservation());
5334 viewport.setShowComplementFeatures(view.isShowComplementFeatures());
5335 viewport.setShowComplementFeaturesOnTop(
5336 view.isShowComplementFeaturesOnTop());
5338 // recover feature settings
5339 if (jm.getFeatureSettings() != null)
5341 FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
5342 .getFeatureRenderer();
5343 FeaturesDisplayed fdi;
5344 viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
5345 String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
5347 Map<String, FeatureColourI> featureColours = new Hashtable<>();
5348 Map<String, Float> featureOrder = new Hashtable<>();
5350 for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
5353 Setting setting = jm.getFeatureSettings().getSetting().get(fs);
5354 String featureType = setting.getType();
5357 * restore feature filters (if any)
5359 jalview.xml.binding.jalview.FeatureMatcherSet filters = setting
5361 if (filters != null)
5363 FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
5365 if (!filter.isEmpty())
5367 fr.setFeatureFilter(featureType, filter);
5372 * restore feature colour scheme
5374 Color maxColour = new Color(setting.getColour());
5375 if (setting.getMincolour() != null)
5378 * minColour is always set unless a simple colour
5379 * (including for colour by label though it doesn't use it)
5381 Color minColour = new Color(setting.getMincolour().intValue());
5382 Color noValueColour = minColour;
5383 NoValueColour noColour = setting.getNoValueColour();
5384 if (noColour == NoValueColour.NONE)
5386 noValueColour = null;
5388 else if (noColour == NoValueColour.MAX)
5390 noValueColour = maxColour;
5392 float min = safeFloat(safeFloat(setting.getMin()));
5393 float max = setting.getMax() == null ? 1f
5394 : setting.getMax().floatValue();
5395 FeatureColourI gc = new FeatureColour(maxColour, minColour,
5396 maxColour, noValueColour, min, max);
5397 if (setting.getAttributeName().size() > 0)
5399 gc.setAttributeName(setting.getAttributeName().toArray(
5400 new String[setting.getAttributeName().size()]));
5402 if (setting.getThreshold() != null)
5404 gc.setThreshold(setting.getThreshold().floatValue());
5405 int threshstate = safeInt(setting.getThreshstate());
5406 // -1 = None, 0 = Below, 1 = Above threshold
5407 if (threshstate == 0)
5409 gc.setBelowThreshold(true);
5411 else if (threshstate == 1)
5413 gc.setAboveThreshold(true);
5416 gc.setAutoScaled(true); // default
5417 if (setting.isAutoScale() != null)
5419 gc.setAutoScaled(setting.isAutoScale());
5421 if (setting.isColourByLabel() != null)
5423 gc.setColourByLabel(setting.isColourByLabel());
5425 // and put in the feature colour table.
5426 featureColours.put(featureType, gc);
5430 featureColours.put(featureType, new FeatureColour(maxColour));
5432 renderOrder[fs] = featureType;
5433 if (setting.getOrder() != null)
5435 featureOrder.put(featureType, setting.getOrder().floatValue());
5439 featureOrder.put(featureType, Float.valueOf(
5440 fs / jm.getFeatureSettings().getSetting().size()));
5442 if (safeBoolean(setting.isDisplay()))
5444 fdi.setVisible(featureType);
5447 Map<String, Boolean> fgtable = new Hashtable<>();
5448 for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
5450 Group grp = jm.getFeatureSettings().getGroup().get(gs);
5451 fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
5453 // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5454 // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
5455 // jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
5456 FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
5457 fgtable, featureColours, 1.0f, featureOrder);
5458 fr.transferSettings(frs);
5461 if (view.getHiddenColumns().size() > 0)
5463 for (int c = 0; c < view.getHiddenColumns().size(); c++)
5465 final HiddenColumns hc = view.getHiddenColumns().get(c);
5466 viewport.hideColumns(safeInt(hc.getStart()),
5467 safeInt(hc.getEnd()) /* +1 */);
5470 if (view.getCalcIdParam() != null)
5472 for (CalcIdParam calcIdParam : view.getCalcIdParam())
5474 if (calcIdParam != null)
5476 if (recoverCalcIdParam(calcIdParam, viewport))
5481 Console.warn("Couldn't recover parameters for "
5482 + calcIdParam.getCalcId());
5487 af.setMenusFromViewport(viewport);
5488 af.setTitle(view.getTitle());
5489 // TODO: we don't need to do this if the viewport is aready visible.
5491 * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
5492 * has a 'cdna/protein complement' view, in which case save it in order to
5493 * populate a SplitFrame once all views have been read in.
5495 String complementaryViewId = view.getComplementId();
5496 if (complementaryViewId == null)
5498 Desktop.addInternalFrame(af, view.getTitle(),
5499 safeInt(view.getWidth()), safeInt(view.getHeight()));
5500 // recompute any autoannotation
5501 af.alignPanel.updateAnnotation(false, true);
5502 reorderAutoannotation(af, al, autoAlan);
5503 af.alignPanel.alignmentChanged();
5507 splitFrameCandidates.put(view, af);
5514 * Reads saved data to restore Colour by Annotation settings
5516 * @param viewAnnColour
5520 * @param checkGroupAnnColour
5523 private ColourSchemeI constructAnnotationColour(
5524 AnnotationColourScheme viewAnnColour, AlignFrame af,
5525 AlignmentI al, JalviewModel model, boolean checkGroupAnnColour)
5527 boolean propagateAnnColour = false;
5528 AlignmentI annAlignment = af != null ? af.getViewport().getAlignment()
5530 if (checkGroupAnnColour && al.getGroups() != null
5531 && al.getGroups().size() > 0)
5533 // pre 2.8.1 behaviour
5534 // check to see if we should transfer annotation colours
5535 propagateAnnColour = true;
5536 for (SequenceGroup sg : al.getGroups())
5538 if (sg.getColourScheme() instanceof AnnotationColourGradient)
5540 propagateAnnColour = false;
5546 * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
5548 String annotationId = viewAnnColour.getAnnotation();
5549 AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
5552 * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
5554 if (matchedAnnotation == null
5555 && annAlignment.getAlignmentAnnotation() != null)
5557 for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
5560 .equals(annAlignment.getAlignmentAnnotation()[i].label))
5562 matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
5567 if (matchedAnnotation == null)
5570 .errPrintln("Failed to match annotation colour scheme for "
5574 // belt-and-braces create a threshold line if the
5575 // colourscheme needs one but the matchedAnnotation doesn't have one
5576 if (safeInt(viewAnnColour.getAboveThreshold()) != 0
5577 && matchedAnnotation.getThreshold() == null)
5579 matchedAnnotation.setThreshold(
5580 new GraphLine(safeFloat(viewAnnColour.getThreshold()),
5581 "Threshold", Color.black));
5584 AnnotationColourGradient cs = null;
5585 if (viewAnnColour.getColourScheme().equals("None"))
5587 cs = new AnnotationColourGradient(matchedAnnotation,
5588 new Color(safeInt(viewAnnColour.getMinColour())),
5589 new Color(safeInt(viewAnnColour.getMaxColour())),
5590 safeInt(viewAnnColour.getAboveThreshold()));
5592 else if (viewAnnColour.getColourScheme().startsWith("ucs"))
5594 cs = new AnnotationColourGradient(matchedAnnotation,
5595 getUserColourScheme(model, viewAnnColour.getColourScheme()),
5596 safeInt(viewAnnColour.getAboveThreshold()));
5600 cs = new AnnotationColourGradient(matchedAnnotation,
5601 ColourSchemeProperty.getColourScheme(af.getViewport(), al,
5602 viewAnnColour.getColourScheme()),
5603 safeInt(viewAnnColour.getAboveThreshold()));
5606 boolean perSequenceOnly = safeBoolean(viewAnnColour.isPerSequence());
5607 boolean useOriginalColours = safeBoolean(
5608 viewAnnColour.isPredefinedColours());
5609 cs.setSeqAssociated(perSequenceOnly);
5610 cs.setPredefinedColours(useOriginalColours);
5612 if (propagateAnnColour && al.getGroups() != null)
5614 // Also use these settings for all the groups
5615 for (int g = 0; g < al.getGroups().size(); g++)
5617 SequenceGroup sg = al.getGroups().get(g);
5618 if (sg.getGroupColourScheme() == null)
5623 AnnotationColourGradient groupScheme = new AnnotationColourGradient(
5624 matchedAnnotation, sg.getColourScheme(),
5625 safeInt(viewAnnColour.getAboveThreshold()));
5626 sg.setColourScheme(groupScheme);
5627 groupScheme.setSeqAssociated(perSequenceOnly);
5628 groupScheme.setPredefinedColours(useOriginalColours);
5634 private void reorderAutoannotation(AlignFrame af, AlignmentI al,
5635 List<JvAnnotRow> autoAlan)
5637 // copy over visualization settings for autocalculated annotation in the
5639 if (al.getAlignmentAnnotation() != null)
5642 * Kludge for magic autoannotation names (see JAL-811)
5644 String[] magicNames = new String[] { "Consensus", "Quality",
5646 JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
5647 Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
5648 for (String nm : magicNames)
5650 visan.put(nm, nullAnnot);
5652 for (JvAnnotRow auan : autoAlan)
5654 visan.put(auan.template.label
5655 + (auan.template.getCalcId() == null ? ""
5656 : "\t" + auan.template.getCalcId()),
5659 int hSize = al.getAlignmentAnnotation().length;
5660 List<JvAnnotRow> reorder = new ArrayList<>();
5661 // work through any autoCalculated annotation already on the view
5662 // removing it if it should be placed in a different location on the
5663 // annotation panel.
5664 List<String> remains = new ArrayList<>(visan.keySet());
5665 for (int h = 0; h < hSize; h++)
5667 jalview.datamodel.AlignmentAnnotation jalan = al
5668 .getAlignmentAnnotation()[h];
5669 if (jalan.autoCalculated)
5672 JvAnnotRow valan = visan.get(k = jalan.label);
5673 if (jalan.getCalcId() != null)
5675 valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
5680 // delete the auto calculated row from the alignment
5681 al.deleteAnnotation(jalan, false);
5685 if (valan != nullAnnot)
5687 if (jalan != valan.template)
5689 // newly created autoannotation row instance
5690 // so keep a reference to the visible annotation row
5691 // and copy over all relevant attributes
5692 if (valan.template.graphHeight >= 0)
5695 jalan.graphHeight = valan.template.graphHeight;
5697 jalan.visible = valan.template.visible;
5699 reorder.add(new JvAnnotRow(valan.order, jalan));
5704 // Add any (possibly stale) autocalculated rows that were not appended to
5705 // the view during construction
5706 for (String other : remains)
5708 JvAnnotRow othera = visan.get(other);
5709 if (othera != nullAnnot && othera.template.getCalcId() != null
5710 && othera.template.getCalcId().length() > 0)
5712 reorder.add(othera);
5715 // now put the automatic annotation in its correct place
5716 int s = 0, srt[] = new int[reorder.size()];
5717 JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
5718 for (JvAnnotRow jvar : reorder)
5721 srt[s++] = jvar.order;
5724 jalview.util.QuickSort.sort(srt, rws);
5725 // and re-insert the annotation at its correct position
5726 for (JvAnnotRow jvar : rws)
5728 al.addAnnotation(jvar.template, jvar.order);
5730 af.alignPanel.adjustAnnotationHeight();
5734 Hashtable skipList = null;
5737 * TODO remove this method
5740 * @return AlignFrame bound to sequenceSetId from view, if one exists. private
5741 * AlignFrame getSkippedFrame(Viewport view) { if (skipList==null) {
5742 * throw new Error("Implementation Error. No skipList defined for this
5743 * Jalview2XML instance."); } return (AlignFrame)
5744 * skipList.get(view.getSequenceSetId()); }
5748 * Check if the Jalview view contained in object should be skipped or not.
5751 * @return true if view's sequenceSetId is a key in skipList
5753 private boolean skipViewport(JalviewModel object)
5755 if (skipList == null)
5759 String id = object.getViewport().get(0).getSequenceSetId();
5760 if (skipList.containsKey(id))
5762 Console.debug("Skipping seuqence set id " + id);
5768 public void addToSkipList(AlignFrame af)
5770 if (skipList == null)
5772 skipList = new Hashtable();
5774 skipList.put(af.getViewport().getSequenceSetId(), af);
5777 public void clearSkipList()
5779 if (skipList != null)
5786 private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
5787 boolean ignoreUnrefed, String uniqueSeqSetId)
5789 jalview.datamodel.AlignmentI ds = getDatasetFor(
5790 vamsasSet.getDatasetId());
5791 AlignmentI xtant_ds = ds;
5792 if (xtant_ds == null)
5794 // good chance we are about to create a new dataset, but check if we've
5795 // seen some of the dataset sequence IDs before.
5796 // TODO: skip this check if we are working with project generated by
5797 // version 2.11 or later
5798 xtant_ds = checkIfHasDataset(vamsasSet.getSequence());
5799 if (xtant_ds != null)
5802 addDatasetRef(vamsasSet.getDatasetId(), ds);
5805 Vector<SequenceI> dseqs = null;
5808 // recovering an alignment View
5809 AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
5810 if (seqSetDS != null)
5812 if (ds != null && ds != seqSetDS)
5815 "JAL-3171 regression: Overwriting a dataset reference for an alignment"
5816 + " - CDS/Protein crossreference data may be lost");
5817 if (xtant_ds != null)
5819 // This can only happen if the unique sequence set ID was bound to a
5820 // dataset that did not contain any of the sequences in the view
5821 // currently being restored.
5823 "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.");
5827 addDatasetRef(vamsasSet.getDatasetId(), ds);
5832 // try even harder to restore dataset
5833 AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence());
5834 // create a list of new dataset sequences
5835 dseqs = new Vector<>();
5837 for (int i = 0, iSize = vamsasSet.getSequence().size(); i < iSize; i++)
5839 Sequence vamsasSeq = vamsasSet.getSequence().get(i);
5840 ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
5842 // create a new dataset
5845 SequenceI[] dsseqs = new SequenceI[dseqs.size()];
5846 dseqs.copyInto(dsseqs);
5847 ds = new jalview.datamodel.Alignment(dsseqs);
5848 Console.debug("Created new dataset " + vamsasSet.getDatasetId()
5849 + " for alignment " + System.identityHashCode(al));
5850 addDatasetRef(vamsasSet.getDatasetId(), ds);
5852 // set the dataset for the newly imported alignment.
5853 if (al.getDataset() == null && !ignoreUnrefed)
5856 // register dataset for the alignment's uniqueSeqSetId for legacy projects
5857 addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
5859 updateSeqDatasetBinding(vamsasSet.getSequence(), ds);
5863 * XML dataset sequence ID to materialised dataset reference
5865 HashMap<String, AlignmentI> seqToDataset = new HashMap<>();
5868 * @return the first materialised dataset reference containing a dataset
5869 * sequence referenced in the given view
5871 * - sequences from the view
5873 AlignmentI checkIfHasDataset(List<Sequence> list)
5875 for (Sequence restoredSeq : list)
5877 AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid());
5878 if (datasetFor != null)
5887 * Register ds as the containing dataset for the dataset sequences referenced
5888 * by sequences in list
5891 * - sequences in a view
5894 void updateSeqDatasetBinding(List<Sequence> list, AlignmentI ds)
5896 for (Sequence restoredSeq : list)
5898 AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
5899 if (prevDS != null && prevDS != ds)
5901 Console.warn("Dataset sequence appears in many datasets: "
5902 + restoredSeq.getDsseqid());
5903 // TODO: try to merge!
5911 * sequence definition to create/merge dataset sequence for
5915 * vector to add new dataset sequence to
5916 * @param ignoreUnrefed
5917 * - when true, don't create new sequences from vamsasSeq if it's id
5918 * doesn't already have an asssociated Jalview sequence.
5920 * - used to reorder the sequence in the alignment according to the
5921 * vamsasSeq array ordering, to preserve ordering of dataset
5923 private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
5924 AlignmentI ds, Vector<SequenceI> dseqs, boolean ignoreUnrefed,
5927 // JBP TODO: Check this is called for AlCodonFrames to support recovery of
5929 SequenceI sq = seqRefIds.get(vamsasSeq.getId());
5930 boolean reorder = false;
5931 SequenceI dsq = null;
5932 if (sq != null && sq.getDatasetSequence() != null)
5934 dsq = sq.getDatasetSequence();
5940 if (sq == null && ignoreUnrefed)
5944 String sqid = vamsasSeq.getDsseqid();
5947 // need to create or add a new dataset sequence reference to this sequence
5950 dsq = seqRefIds.get(sqid);
5955 // make a new dataset sequence
5956 dsq = sq.createDatasetSequence();
5959 // make up a new dataset reference for this sequence
5960 sqid = seqHash(dsq);
5962 dsq.setVamsasId(uniqueSetSuffix + sqid);
5963 seqRefIds.put(sqid, dsq);
5968 dseqs.addElement(dsq);
5973 ds.addSequence(dsq);
5979 { // make this dataset sequence sq's dataset sequence
5980 sq.setDatasetSequence(dsq);
5981 // and update the current dataset alignment
5986 if (!dseqs.contains(dsq))
5993 if (ds.findIndex(dsq) < 0)
5995 ds.addSequence(dsq);
6002 // TODO: refactor this as a merge dataset sequence function
6003 // now check that sq (the dataset sequence) sequence really is the union of
6004 // all references to it
6005 // boolean pre = sq.getStart() < dsq.getStart();
6006 // boolean post = sq.getEnd() > dsq.getEnd();
6010 // StringBuffer sb = new StringBuffer();
6011 String newres = jalview.analysis.AlignSeq.extractGaps(
6012 jalview.util.Comparison.GapChars, sq.getSequenceAsString());
6013 if (!newres.equalsIgnoreCase(dsq.getSequenceAsString())
6014 && newres.length() > dsq.getLength())
6016 // Update with the longer sequence.
6020 * if (pre) { sb.insert(0, newres .substring(0, dsq.getStart() -
6021 * sq.getStart())); dsq.setStart(sq.getStart()); } if (post) {
6022 * sb.append(newres.substring(newres.length() - sq.getEnd() -
6023 * dsq.getEnd())); dsq.setEnd(sq.getEnd()); }
6025 dsq.setSequence(newres);
6027 // TODO: merges will never happen if we 'know' we have the real dataset
6028 // sequence - this should be detected when id==dssid
6029 jalview.bin.Console.errPrintln(
6030 "DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // ("
6031 // + (pre ? "prepended" : "") + " "
6032 // + (post ? "appended" : ""));
6037 // sequence refs are identical. We may need to update the existing dataset
6038 // alignment with this one, though.
6039 if (ds != null && dseqs == null)
6041 int opos = ds.findIndex(dsq);
6042 SequenceI tseq = null;
6043 if (opos != -1 && vseqpos != opos)
6045 // remove from old position
6046 ds.deleteSequence(dsq);
6048 if (vseqpos < ds.getHeight())
6050 if (vseqpos != opos)
6052 // save sequence at destination position
6053 tseq = ds.getSequenceAt(vseqpos);
6054 ds.replaceSequenceAt(vseqpos, dsq);
6055 ds.addSequence(tseq);
6060 ds.addSequence(dsq);
6067 * TODO use AlignmentI here and in related methods - needs
6068 * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
6070 Hashtable<String, AlignmentI> datasetIds = null;
6072 IdentityHashMap<AlignmentI, String> dataset2Ids = null;
6074 private AlignmentI getDatasetFor(String datasetId)
6076 if (datasetIds == null)
6078 datasetIds = new Hashtable<>();
6081 if (datasetIds.containsKey(datasetId))
6083 return datasetIds.get(datasetId);
6088 private void addDatasetRef(String datasetId, AlignmentI dataset)
6090 if (datasetIds == null)
6092 datasetIds = new Hashtable<>();
6094 datasetIds.put(datasetId, dataset);
6098 * make a new dataset ID for this jalview dataset alignment
6103 private String getDatasetIdRef(AlignmentI dataset)
6105 if (dataset.getDataset() != null)
6108 "Serious issue! Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
6110 String datasetId = makeHashCode(dataset, null);
6111 if (datasetId == null)
6113 // make a new datasetId and record it
6114 if (dataset2Ids == null)
6116 dataset2Ids = new IdentityHashMap<>();
6120 datasetId = dataset2Ids.get(dataset);
6122 if (datasetId == null)
6124 datasetId = "ds" + dataset2Ids.size() + 1;
6125 dataset2Ids.put(dataset, datasetId);
6132 * Add any saved DBRefEntry's to the sequence. An entry flagged as 'locus' is
6133 * constructed as a special subclass GeneLocus.
6135 * @param datasetSequence
6138 private void addDBRefs(SequenceI datasetSequence, Sequence sequence)
6140 for (int d = 0; d < sequence.getDBRef().size(); d++)
6142 DBRef dr = sequence.getDBRef().get(d);
6146 entry = new GeneLocus(dr.getSource(), dr.getVersion(),
6147 dr.getAccessionId());
6151 entry = new DBRefEntry(dr.getSource(), dr.getVersion(),
6152 dr.getAccessionId());
6154 if (dr.getMapping() != null)
6156 entry.setMap(addMapping(dr.getMapping()));
6158 entry.setCanonical(dr.isCanonical());
6159 datasetSequence.addDBRef(entry);
6163 private jalview.datamodel.Mapping addMapping(Mapping m)
6165 SequenceI dsto = null;
6166 // Mapping m = dr.getMapping();
6167 int fr[] = new int[m.getMapListFrom().size() * 2];
6168 Iterator<MapListFrom> from = m.getMapListFrom().iterator();// enumerateMapListFrom();
6169 for (int _i = 0; from.hasNext(); _i += 2)
6171 MapListFrom mf = from.next();
6172 fr[_i] = mf.getStart();
6173 fr[_i + 1] = mf.getEnd();
6175 int fto[] = new int[m.getMapListTo().size() * 2];
6176 Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
6177 for (int _i = 0; to.hasNext(); _i += 2)
6179 MapListTo mf = to.next();
6180 fto[_i] = mf.getStart();
6181 fto[_i + 1] = mf.getEnd();
6183 jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr,
6184 fto, m.getMapFromUnit().intValue(),
6185 m.getMapToUnit().intValue());
6188 * (optional) choice of dseqFor or Sequence
6190 if (m.getDseqFor() != null)
6192 String dsfor = m.getDseqFor();
6193 if (seqRefIds.containsKey(dsfor))
6198 jmap.setTo(seqRefIds.get(dsfor));
6202 frefedSequence.add(newMappingRef(dsfor, jmap));
6205 else if (m.getSequence() != null)
6208 * local sequence definition
6210 Sequence ms = m.getSequence();
6211 SequenceI djs = null;
6212 String sqid = ms.getDsseqid();
6213 if (sqid != null && sqid.length() > 0)
6216 * recover dataset sequence
6218 djs = seqRefIds.get(sqid);
6222 jalview.bin.Console.errPrintln(
6223 "Warning - making up dataset sequence id for DbRef sequence map reference");
6224 sqid = ((Object) ms).toString(); // make up a new hascode for
6225 // undefined dataset sequence hash
6226 // (unlikely to happen)
6232 * make a new dataset sequence and add it to refIds hash
6234 djs = new jalview.datamodel.Sequence(ms.getName(),
6236 djs.setStart(jmap.getMap().getToLowest());
6237 djs.setEnd(jmap.getMap().getToHighest());
6238 djs.setVamsasId(uniqueSetSuffix + sqid);
6240 incompleteSeqs.put(sqid, djs);
6241 seqRefIds.put(sqid, djs);
6244 Console.debug("about to recurse on addDBRefs.");
6253 * Provides a 'copy' of an alignment view (on action New View) by 'saving' the
6254 * view as XML (but not to file), and then reloading it
6259 public AlignmentPanel copyAlignPanel(AlignmentPanel ap)
6262 JalviewModel jm = saveState(ap, null, null, null);
6265 jm.getVamsasModel().getSequenceSet().get(0).getDatasetId(),
6266 ap.getAlignment().getDataset());
6268 uniqueSetSuffix = "";
6269 // jm.getJalviewModelSequence().getViewport(0).setId(null);
6270 jm.getViewport().get(0).setId(null);
6271 // we don't overwrite the view we just copied
6273 if (this.frefedSequence == null)
6275 frefedSequence = new Vector<>();
6278 viewportsAdded.clear();
6280 AlignFrame af = loadFromObject(jm, null, false, null);
6281 af.getAlignPanels().clear();
6282 af.closeMenuItem_actionPerformed(true);
6285 * if(ap.av.getAlignment().getAlignmentAnnotation()!=null) { for(int i=0;
6286 * i<ap.av.getAlignment().getAlignmentAnnotation().length; i++) {
6287 * if(!ap.av.getAlignment().getAlignmentAnnotation()[i].autoCalculated) {
6288 * af.alignPanel.av.getAlignment().getAlignmentAnnotation()[i] =
6289 * ap.av.getAlignment().getAlignmentAnnotation()[i]; } } }
6292 return af.alignPanel;
6295 private Hashtable jvids2vobj;
6298 * set the object to ID mapping tables used to write/recover objects and XML
6299 * ID strings for the jalview project. If external tables are provided then
6300 * finalize and clearSeqRefs will not clear the tables when the Jalview2XML
6301 * object goes out of scope. - also populates the datasetIds hashtable with
6302 * alignment objects containing dataset sequences
6305 * Map from ID strings to jalview datamodel
6307 * Map from jalview datamodel to ID strings
6311 public void setObjectMappingTables(Hashtable vobj2jv,
6312 IdentityHashMap jv2vobj)
6314 this.jv2vobj = jv2vobj;
6315 this.vobj2jv = vobj2jv;
6316 Iterator ds = jv2vobj.keySet().iterator();
6318 while (ds.hasNext())
6320 Object jvobj = ds.next();
6321 id = jv2vobj.get(jvobj).toString();
6322 if (jvobj instanceof jalview.datamodel.Alignment)
6324 if (((jalview.datamodel.Alignment) jvobj).getDataset() == null)
6326 addDatasetRef(id, (jalview.datamodel.Alignment) jvobj);
6329 else if (jvobj instanceof jalview.datamodel.Sequence)
6331 // register sequence object so the XML parser can recover it.
6332 if (seqRefIds == null)
6334 seqRefIds = new HashMap<>();
6336 if (seqsToIds == null)
6338 seqsToIds = new IdentityHashMap<>();
6340 seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
6341 seqsToIds.put((SequenceI) jvobj, id);
6343 else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
6346 AlignmentAnnotation jvann = (AlignmentAnnotation) jvobj;
6347 annotationIds.put(anid = jv2vobj.get(jvobj).toString(), jvann);
6348 if (jvann.annotationId == null)
6350 jvann.annotationId = anid;
6352 if (!jvann.annotationId.equals(anid))
6354 // TODO verify that this is the correct behaviour
6355 Console.warn("Overriding Annotation ID for " + anid
6356 + " from different id : " + jvann.annotationId);
6357 jvann.annotationId = anid;
6360 else if (jvobj instanceof String)
6362 if (jvids2vobj == null)
6364 jvids2vobj = new Hashtable();
6365 jvids2vobj.put(jvobj, jv2vobj.get(jvobj).toString());
6370 Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
6376 * set the uniqueSetSuffix used to prefix/suffix object IDs for jalview
6377 * objects created from the project archive. If string is null (default for
6378 * construction) then suffix will be set automatically.
6382 public void setUniqueSetSuffix(String string)
6384 uniqueSetSuffix = string;
6389 * uses skipList2 as the skipList for skipping views on sequence sets
6390 * associated with keys in the skipList
6394 public void setSkipList(Hashtable skipList2)
6396 skipList = skipList2;
6400 * Reads the jar entry of given name and returns its contents, or null if the
6401 * entry is not found.
6404 * @param jarEntryName
6407 protected String readJarEntry(jarInputStreamProvider jprovider,
6408 String jarEntryName)
6410 String result = null;
6411 BufferedReader in = null;
6416 * Reopen the jar input stream and traverse its entries to find a matching
6419 JarInputStream jin = jprovider.getJarInputStream();
6420 JarEntry entry = null;
6423 entry = jin.getNextJarEntry();
6424 } while (entry != null && !entry.getName().equals(jarEntryName));
6428 StringBuilder out = new StringBuilder(256);
6429 in = new BufferedReader(new InputStreamReader(jin, UTF_8));
6432 while ((data = in.readLine()) != null)
6436 result = out.toString();
6441 "Couldn't find entry in Jalview Jar for " + jarEntryName);
6443 } catch (Exception ex)
6445 ex.printStackTrace();
6453 } catch (IOException e)
6464 * Returns an incrementing counter (0, 1, 2...)
6468 private synchronized int nextCounter()
6474 * Loads any saved PCA viewers
6479 protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
6483 List<PcaViewer> pcaviewers = model.getPcaViewer();
6484 for (PcaViewer viewer : pcaviewers)
6486 String modelName = viewer.getScoreModelName();
6487 SimilarityParamsI params = new SimilarityParams(
6488 viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
6489 viewer.isIncludeGaps(),
6490 viewer.isDenominateByShortestLength());
6493 * create the panel (without computing the PCA)
6495 PCAPanel panel = new PCAPanel(ap, modelName, params);
6497 panel.setTitle(viewer.getTitle());
6498 panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
6499 viewer.getWidth(), viewer.getHeight()));
6501 boolean showLabels = viewer.isShowLabels();
6502 panel.setShowLabels(showLabels);
6503 panel.getRotatableCanvas().setShowLabels(showLabels);
6504 panel.getRotatableCanvas()
6505 .setBgColour(new Color(viewer.getBgColour()));
6506 panel.getRotatableCanvas()
6507 .setApplyToAllViews(viewer.isLinkToAllViews());
6510 * load PCA output data
6512 ScoreModelI scoreModel = ScoreModels.getInstance()
6513 .getScoreModel(modelName, ap);
6514 PCA pca = new PCA(null, scoreModel, params);
6515 PcaDataType pcaData = viewer.getPcaData();
6517 MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
6518 pca.setPairwiseScores(pairwise);
6520 MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
6521 pca.setTridiagonal(triDiag);
6523 MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
6524 pca.setEigenmatrix(result);
6526 panel.getPcaModel().setPCA(pca);
6529 * we haven't saved the input data! (JAL-2647 to do)
6531 panel.setInputData(null);
6534 * add the sequence points for the PCA display
6536 List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
6537 for (SequencePoint sp : viewer.getSequencePoint())
6539 String seqId = sp.getSequenceRef();
6540 SequenceI seq = seqRefIds.get(seqId);
6543 throw new IllegalStateException(
6544 "Unmatched seqref for PCA: " + seqId);
6546 Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
6547 jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
6549 seqPoints.add(seqPoint);
6551 panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
6554 * set min-max ranges and scale after setPoints (which recomputes them)
6556 panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
6557 SeqPointMin spMin = viewer.getSeqPointMin();
6558 float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
6560 SeqPointMax spMax = viewer.getSeqPointMax();
6561 float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
6563 panel.getRotatableCanvas().setSeqMinMax(min, max);
6565 // todo: hold points list in PCAModel only
6566 panel.getPcaModel().setSequencePoints(seqPoints);
6568 panel.setSelectedDimensionIndex(viewer.getXDim(), X);
6569 panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
6570 panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
6572 // is this duplication needed?
6573 panel.setTop(seqPoints.size() - 1);
6574 panel.getPcaModel().setTop(seqPoints.size() - 1);
6577 * add the axes' end points for the display
6579 for (int i = 0; i < 3; i++)
6581 Axis axis = viewer.getAxis().get(i);
6582 panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
6583 axis.getXPos(), axis.getYPos(), axis.getZPos());
6586 Desktop.addInternalFrame(panel, MessageManager.formatMessage(
6587 "label.calc_title", "PCA", modelName), 475, 450);
6589 } catch (Exception ex)
6591 Console.error("Error loading PCA: " + ex.toString());
6596 * Creates a new structure viewer window
6603 protected void createStructureViewer(ViewerType viewerType,
6604 final Entry<String, StructureViewerModel> viewerData,
6605 AlignFrame af, jarInputStreamProvider jprovider)
6607 final StructureViewerModel viewerModel = viewerData.getValue();
6608 String sessionFilePath = null;
6610 if (viewerType == ViewerType.JMOL)
6612 sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
6616 String viewerJarEntryName = getViewerJarEntryName(
6617 viewerModel.getViewId());
6618 sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
6619 "viewerSession", ".tmp");
6621 final String sessionPath = sessionFilePath;
6622 final String sviewid = viewerData.getKey();
6625 SwingUtilities.invokeAndWait(new Runnable()
6630 JalviewStructureDisplayI sview = null;
6633 sview = StructureViewer.createView(viewerType, af.alignPanel,
6634 viewerModel, sessionPath, sviewid);
6635 addNewStructureViewer(sview);
6636 } catch (OutOfMemoryError ex)
6638 new OOMWarning("Restoring structure view for " + viewerType,
6639 (OutOfMemoryError) ex.getCause());
6640 if (sview != null && sview.isVisible())
6642 sview.closeViewer(false);
6643 sview.setVisible(false);
6649 } catch (InvocationTargetException | InterruptedException ex)
6651 Console.warn("Unexpected error when opening " + viewerType
6652 + " structure viewer", ex);
6657 * Rewrites a Jmol session script, saves it to a temporary file, and returns
6658 * the path of the file. "load file" commands are rewritten to change the
6659 * original PDB file names to those created as the Jalview project is loaded.
6665 private String rewriteJmolSession(StructureViewerModel svattrib,
6666 jarInputStreamProvider jprovider)
6668 String state = svattrib.getStateData(); // Jalview < 2.9
6669 if (state == null || state.isEmpty()) // Jalview >= 2.9
6671 String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
6672 state = readJarEntry(jprovider, jarEntryName);
6674 // TODO or simpler? for each key in oldFiles,
6675 // replace key.getPath() in state with oldFiles.get(key).getFilePath()
6676 // (allowing for different path escapings)
6677 StringBuilder rewritten = new StringBuilder(state.length());
6678 int cp = 0, ncp, ecp;
6679 Map<File, StructureData> oldFiles = svattrib.getFileData();
6680 while ((ncp = state.indexOf("load ", cp)) > -1)
6684 // look for next filename in load statement
6685 rewritten.append(state.substring(cp,
6686 ncp = (state.indexOf("\"", ncp + 1) + 1)));
6687 String oldfilenam = state.substring(ncp,
6688 ecp = state.indexOf("\"", ncp));
6689 // recover the new mapping data for this old filename
6690 // have to normalize filename - since Jmol and jalview do
6691 // filename translation differently.
6692 StructureData filedat = oldFiles.get(new File(oldfilenam));
6693 if (filedat == null)
6695 String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
6696 filedat = oldFiles.get(new File(reformatedOldFilename));
6698 rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
6699 rewritten.append("\"");
6700 cp = ecp + 1; // advance beyond last \" and set cursor so we can
6701 // look for next file statement.
6702 } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
6706 // just append rest of state
6707 rewritten.append(state.substring(cp));
6711 System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
6712 rewritten = new StringBuilder(state);
6713 rewritten.append("; load append ");
6714 for (File id : oldFiles.keySet())
6716 // add pdb files that should be present in the viewer
6717 StructureData filedat = oldFiles.get(id);
6718 rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
6720 rewritten.append(";");
6723 if (rewritten.length() == 0)
6727 final String history = "history = ";
6728 int historyIndex = rewritten.indexOf(history);
6729 if (historyIndex > -1)
6732 * change "history = [true|false];" to "history = [1|0];"
6734 historyIndex += history.length();
6735 String val = rewritten.substring(historyIndex, historyIndex + 5);
6736 if (val.startsWith("true"))
6738 rewritten.replace(historyIndex, historyIndex + 4, "1");
6740 else if (val.startsWith("false"))
6742 rewritten.replace(historyIndex, historyIndex + 5, "0");
6748 File tmp = File.createTempFile("viewerSession", ".tmp");
6749 try (OutputStream os = new FileOutputStream(tmp))
6751 InputStream is = new ByteArrayInputStream(
6752 rewritten.toString().getBytes());
6754 return tmp.getAbsolutePath();
6756 } catch (IOException e)
6758 Console.error("Error restoring Jmol session: " + e.toString());
6764 * Populates an XML model of the feature colour scheme for one feature type
6766 * @param featureType
6770 public static Colour marshalColour(String featureType,
6771 FeatureColourI fcol)
6773 Colour col = new Colour();
6774 if (fcol.isSimpleColour())
6776 col.setRGB(Format.getHexString(fcol.getColour()));
6780 col.setRGB(Format.getHexString(fcol.getMaxColour()));
6781 col.setMin(fcol.getMin());
6782 col.setMax(fcol.getMax());
6783 col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
6784 col.setAutoScale(fcol.isAutoScaled());
6785 col.setThreshold(fcol.getThreshold());
6786 col.setColourByLabel(fcol.isColourByLabel());
6787 col.setThreshType(fcol.isAboveThreshold() ? ThresholdType.ABOVE
6788 : (fcol.isBelowThreshold() ? ThresholdType.BELOW
6789 : ThresholdType.NONE));
6790 if (fcol.isColourByAttribute())
6792 final String[] attName = fcol.getAttributeName();
6793 col.getAttributeName().add(attName[0]);
6794 if (attName.length > 1)
6796 col.getAttributeName().add(attName[1]);
6799 Color noColour = fcol.getNoColour();
6800 if (noColour == null)
6802 col.setNoValueColour(NoValueColour.NONE);
6804 else if (noColour == fcol.getMaxColour())
6806 col.setNoValueColour(NoValueColour.MAX);
6810 col.setNoValueColour(NoValueColour.MIN);
6813 col.setName(featureType);
6818 * Populates an XML model of the feature filter(s) for one feature type
6820 * @param firstMatcher
6821 * the first (or only) match condition)
6823 * remaining match conditions (if any)
6825 * if true, conditions are and-ed, else or-ed
6827 public static jalview.xml.binding.jalview.FeatureMatcherSet marshalFilter(
6828 FeatureMatcherI firstMatcher, Iterator<FeatureMatcherI> filters,
6831 jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
6833 if (filters.hasNext())
6838 CompoundMatcher compound = new CompoundMatcher();
6839 compound.setAnd(and);
6840 jalview.xml.binding.jalview.FeatureMatcherSet matcher1 = marshalFilter(
6841 firstMatcher, Collections.emptyIterator(), and);
6842 // compound.addMatcherSet(matcher1);
6843 compound.getMatcherSet().add(matcher1);
6844 FeatureMatcherI nextMatcher = filters.next();
6845 jalview.xml.binding.jalview.FeatureMatcherSet matcher2 = marshalFilter(
6846 nextMatcher, filters, and);
6847 // compound.addMatcherSet(matcher2);
6848 compound.getMatcherSet().add(matcher2);
6849 result.setCompoundMatcher(compound);
6854 * single condition matcher
6856 // MatchCondition matcherModel = new MatchCondition();
6857 jalview.xml.binding.jalview.FeatureMatcher matcherModel = new jalview.xml.binding.jalview.FeatureMatcher();
6858 matcherModel.setCondition(
6859 firstMatcher.getMatcher().getCondition().getStableName());
6860 matcherModel.setValue(firstMatcher.getMatcher().getPattern());
6861 if (firstMatcher.isByAttribute())
6863 matcherModel.setBy(FilterBy.BY_ATTRIBUTE);
6864 // matcherModel.setAttributeName(firstMatcher.getAttribute());
6865 String[] attName = firstMatcher.getAttribute();
6866 matcherModel.getAttributeName().add(attName[0]); // attribute
6867 if (attName.length > 1)
6869 matcherModel.getAttributeName().add(attName[1]); // sub-attribute
6872 else if (firstMatcher.isByLabel())
6874 matcherModel.setBy(FilterBy.BY_LABEL);
6876 else if (firstMatcher.isByScore())
6878 matcherModel.setBy(FilterBy.BY_SCORE);
6880 result.setMatchCondition(matcherModel);
6887 * Loads one XML model of a feature filter to a Jalview object
6889 * @param featureType
6890 * @param matcherSetModel
6893 public static FeatureMatcherSetI parseFilter(String featureType,
6894 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
6896 FeatureMatcherSetI result = new FeatureMatcherSet();
6899 parseFilterConditions(result, matcherSetModel, true);
6900 } catch (IllegalStateException e)
6902 // mixing AND and OR conditions perhaps
6903 jalview.bin.Console.errPrintln(
6904 String.format("Error reading filter conditions for '%s': %s",
6905 featureType, e.getMessage()));
6906 // return as much as was parsed up to the error
6913 * Adds feature match conditions to matcherSet as unmarshalled from XML
6914 * (possibly recursively for compound conditions)
6917 * @param matcherSetModel
6919 * if true, multiple conditions are AND-ed, else they are OR-ed
6920 * @throws IllegalStateException
6921 * if AND and OR conditions are mixed
6923 protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
6924 jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
6927 jalview.xml.binding.jalview.FeatureMatcher mc = matcherSetModel
6928 .getMatchCondition();
6934 FilterBy filterBy = mc.getBy();
6935 Condition cond = Condition.fromString(mc.getCondition());
6936 String pattern = mc.getValue();
6937 FeatureMatcherI matchCondition = null;
6938 if (filterBy == FilterBy.BY_LABEL)
6940 matchCondition = FeatureMatcher.byLabel(cond, pattern);
6942 else if (filterBy == FilterBy.BY_SCORE)
6944 matchCondition = FeatureMatcher.byScore(cond, pattern);
6947 else if (filterBy == FilterBy.BY_ATTRIBUTE)
6949 final List<String> attributeName = mc.getAttributeName();
6950 String[] attNames = attributeName
6951 .toArray(new String[attributeName.size()]);
6952 matchCondition = FeatureMatcher.byAttribute(cond, pattern,
6957 * note this throws IllegalStateException if AND-ing to a
6958 * previously OR-ed compound condition, or vice versa
6962 matcherSet.and(matchCondition);
6966 matcherSet.or(matchCondition);
6972 * compound condition
6974 List<jalview.xml.binding.jalview.FeatureMatcherSet> matchers = matcherSetModel
6975 .getCompoundMatcher().getMatcherSet();
6976 boolean anded = matcherSetModel.getCompoundMatcher().isAnd();
6977 if (matchers.size() == 2)
6979 parseFilterConditions(matcherSet, matchers.get(0), anded);
6980 parseFilterConditions(matcherSet, matchers.get(1), anded);
6985 .errPrintln("Malformed compound filter condition");
6991 * Loads one XML model of a feature colour to a Jalview object
6993 * @param colourModel
6996 public static FeatureColourI parseColour(Colour colourModel)
6998 FeatureColourI colour = null;
7000 if (colourModel.getMax() != null)
7002 Color mincol = null;
7003 Color maxcol = null;
7004 Color noValueColour = null;
7008 mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
7009 maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7010 } catch (Exception e)
7012 Console.warn("Couldn't parse out graduated feature color.", e);
7015 NoValueColour noCol = colourModel.getNoValueColour();
7016 if (noCol == NoValueColour.MIN)
7018 noValueColour = mincol;
7020 else if (noCol == NoValueColour.MAX)
7022 noValueColour = maxcol;
7025 colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
7026 safeFloat(colourModel.getMin()),
7027 safeFloat(colourModel.getMax()));
7028 final List<String> attributeName = colourModel.getAttributeName();
7029 String[] attributes = attributeName
7030 .toArray(new String[attributeName.size()]);
7031 if (attributes != null && attributes.length > 0)
7033 colour.setAttributeName(attributes);
7035 if (colourModel.isAutoScale() != null)
7037 colour.setAutoScaled(colourModel.isAutoScale().booleanValue());
7039 if (colourModel.isColourByLabel() != null)
7041 colour.setColourByLabel(
7042 colourModel.isColourByLabel().booleanValue());
7044 if (colourModel.getThreshold() != null)
7046 colour.setThreshold(colourModel.getThreshold().floatValue());
7048 ThresholdType ttyp = colourModel.getThreshType();
7049 if (ttyp == ThresholdType.ABOVE)
7051 colour.setAboveThreshold(true);
7053 else if (ttyp == ThresholdType.BELOW)
7055 colour.setBelowThreshold(true);
7060 Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
7061 colour = new FeatureColour(color);
7067 public static void setStateSavedUpToDate(boolean s)
7069 Console.debug("Setting overall stateSavedUpToDate to " + s);
7070 stateSavedUpToDate = s;
7073 public static boolean stateSavedUpToDate()
7075 Console.debug("Returning overall stateSavedUpToDate value: "
7076 + stateSavedUpToDate);
7077 return stateSavedUpToDate;
7080 public static boolean allSavedUpToDate()
7082 if (stateSavedUpToDate()) // nothing happened since last project save
7085 AlignFrame[] frames = Desktop.getDesktopAlignFrames();
7088 for (int i = 0; i < frames.length; i++)
7090 if (frames[i] == null)
7092 if (!frames[i].getViewport().savedUpToDate())
7093 return false; // at least one alignment is not individually saved
7099 // used for debugging and tests
7100 private static int debugDelaySave = 20;
7102 public static void setDebugDelaySave(int n)